I'm doing a html5 audio player so I'm trying to use a custom player. I don't want to use the default <audio> tag interface. I want to do my own html/css styles for the player.
My actual code(it works)
if('webkitAudioContext' in window) {
var myAudioContext = new webkitAudioContext();
}
request = new XMLHttpRequest();
request.open('GET', 'http://96.47.236.72:8364/;', true);
request.responseType = 'arraybuffer';
request.addEventListener('load', bufferSound, false);
request.send();
function bufferSound(event) {
var request = event.target;
var source = myAudioContext.createBufferSource();
source.buffer = myAudioContext.createBuffer(request.response, false);
source.connect(myAudioContext.destination);
source.noteOn(0);
}
http://jsfiddle.net/EY54q/1/
Does someone know how can to edit this player style, or do something to use my own html/css code to execute this player?
You can completely make your own style. just forget about the controls option (you can simply use controls and do not need to use controls="controls"). Just create buttons/divs/whatever, style them, and add an eventlistener that controls the audio interface:
html:
<button id="playpause">play
<!--you can style the content with anything!-->
</button>
<audio id="player">
<source src="http://96.47.236.72:8364/;" />
</audio>
JS:
window.player = document.getElementById('player');
document.getElementById('playpause').onclick = function () {
if (player.paused) {
player.play();
this.innerHTML = 'pause';
} else {
player.pause();
this.innerHTML = 'play';
}
}
http://jsfiddle.net/LqM9D/1/
I see you are also using the audio api. Please note that you can't just dump an audio file in a buffer. It needs to be decoded to raw PCM. This takes a lot of time. A really easy method is to create a source node which is linked to the audio element:
var source = context.createMediaElementSoure(player); //we defined player in the first block of code
To make your page a bit more cross-browser capable:
window.AudioContext = window.AudioContext||window.webkitAudioContext;
context = new AudioContext();
Edit:
I think you want to know what else you can do with the element.
You can also make a slider for the timeline, and a volume slider/mute button, although I'd prefer the latter two to do that on a gainnode at the end of a line of filters and such.
Yes. It is possible via "shadow dom". You just need to enable it in your browser and write styles for elements, that will arrive.
As I understend - it is browser specific feature. But for webkit-based styling of "shadow dom" work perfect.
There is not so many info, however this feature already used in full. For example see this question: Why do no user-agents implement the CSS cursor style for video elements
If you enable displaying shadow dom in inspector setting, you will se how it works. (Also there is public list with selectors list - https://gist.github.com/afabbro/3759334)
For other browsers you need check support of working with "shadow dom".
Related
I'm working on a project where I'm using <video> elements as sources for canvas animations, and I'm aiming to send their audio through the Web Audio API using Tone.js. The canvas animations are fine, it's the audio that's giving me trouble. I'd like to keep the audio synced to the video if possible, so I'm using MediaStream.
When a video loads, it's initially muted on the element itself. I do muted="false" once audio is enabled with a button press that runs Tone.start(). I grab the video's audio via captureStream(), and hook it up to a gain node with the gain set to 0, essentially muting it again. In Firefox, everything works fine, and I can set the gain to whatever desired value. But in Chrome, I can't get rid of the original video audio – it's still going in the background. My "unmute" works, but it clearly plays a second copy of the audio, causing comb filtering.
I'm intending on doing more than just muting and unmuting, so while it's tempting to just use video.volume instead of putting in all this work, this is just a proof of concept that isn't proving much at all right now. Any help is appreciated!
let video = document.querySelector(video);
// lower the video element's audio until we're ready
// might not be necessary, but it's just a cautionary step
video.volume = 0;
// unhook the audio from the video; works in FF, but not Chrome
let stream = video.mozCaptureStream ? video.mozCaptureStream() : video.captureStream();
let audioTrack = new MediaStream(stream.getAudioTracks());
let speaker = Tone.context.createMediaStreamSource(audioTrack);
// gain node is the *actual* volume control that I'm intending to use; it starts at 0 to mute the unhooked audio
let gain = new Tone.Gain(0);
Tone.connect(speaker, gain);
Tone.connect(gain, Tone.context.destination);
// if video.volume stays at 0, we hear nothing
video.volume = 1;
Edit: It may be worth mentioning that I did start with this Vonage API support page to better understand how to go about using captureStream() like this, but the cloning and disabling process described in that article didn't work for me in FF or Chrome.
Chrome's behavior is actually the "more correct" one here (surprisingly given the many bugs they have in that area).
You are creating a clone MediaStream from the MediaElement's source. This MediaStream should not be affected by the volume set on the <video> element (specs), both Firefox and Chrome do fail here.
The captured MediaStream should thus have its own graph and when you connect it to the AudioContext, the original stream from the MediaElement should continue its life and completely ignore the captured MediaStream. This however is correctly handled by Chrome, but Firefox has it wrong (which is in part why they still do prefix the MediaElement#mozCaptureStream() method name).
But since what you want is actually Firefox's behavior, you can reproduce it by using a MediaElementAudioSourceNode, which will take the ownership of the MediaElement's audio stream, and disconnect it entirely from the MediaElement's graph. You'll thus have complete control over the output volume.
const btn = document.querySelector("button");
const vid = document.querySelector("video");
const inp = document.querySelector("input");
btn.onclick = evt => {
btn.remove();
vid.play();
const context = new AudioContext();
const gain = context.createGain();
const source = context.createMediaElementSource(vid);
source.connect(gain);
gain.connect(context.destination);
inp.oninput = evt => {
gain.gain.value = inp.value;
};
gain.gain.value = 0;
const meter = new OscilloMeter(document.querySelector("canvas"));
meter.listen(source, context);
};
button~*,button~.cont { display: none }
.cont { display: flex }
<script>class OscilloMeter{constructor(a){this.ctx=a.getContext("2d")}listen(a,b){function c(){g.getByteTimeDomainData(j),d.clearRect(0,0,e,f),d.beginPath();let a=0;for(let c=0;c<h;c++){const e=j[c]/128;var b=e*f/2;d.lineTo(a,b),a+=k}d.lineTo(d.canvas.width,d.canvas.height/2),d.stroke(),requestAnimationFrame(c)}const d=this.ctx,e=d.canvas.width,f=d.canvas.height,g=b.createAnalyser(),h=g.fftSize=256,j=new Uint8Array(h),k=e/h;d.lineWidth=2,a.connect(g),c()}}</script>
<button>Start</button>
<label>Output volume: <input type=range min=0 max=1 step=0.01 value=0></label>
<div class="cont">
<section>
<p>You can still control the input's volume through the video's UI:</p>
<video src=https://upload.wikimedia.org/wikipedia/commons/2/22/Volcano_Lava_Sample.webm id=vid controls crossorigin=anonymous height=200></video>
</section>
<section>
<p>
Processed audio (using input volume):<br>
<canvas></canvas>
</p>
</section>
</div>
I am playing a small audio clip on click of each link in my navigation
HTML Code:
<audio tabindex="0" id="beep-one" controls preload="auto" >
<source src="audio/Output 1-2.mp3">
<source src="audio/Output 1-2.ogg">
</audio>
JS code:
$('#links a').click(function(e) {
e.preventDefault();
var beepOne = $("#beep-one")[0];
beepOne.play();
});
It's working fine so far.
Issue is when a sound clip is already running and i click on any link nothing happens.
I tried to stop the already playing sound on click of link, but there is no direct event for that in HTML5's Audio API
I tried following code but it's not working
$.each($('audio'), function () {
$(this).stop();
});
Any suggestions please?
Instead of stop() you could try with:
sound.pause();
sound.currentTime = 0;
This should have the desired effect.
first you have to set an id for your audio element
in your js :
var ply = document.getElementById('player');
var oldSrc = ply.src;// just to remember the old source
ply.src = "";// to stop the player you have to replace the source with nothing
I was having same issue. A stop should stop the stream and onplay go to live if it is a radio. All solutions I saw had a disadvantage:
player.currentTime = 0 keeps downloading the stream.
player.src = '' raise error event
My solution:
var player = document.getElementById('radio');
player.pause();
player.src = player.src;
And the HTML
<audio src="http://radio-stream" id="radio" class="hidden" preload="none"></audio>
Here is my way of doing stop() method:
Somewhere in code:
audioCh1: document.createElement("audio");
and then in stop():
this.audioCh1.pause()
this.audioCh1.src = 'data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAVFYAAFRWAAABAAgAZGF0YQAAAAA=';
In this way we don`t produce additional request, the old one is cancelled and our audio element is in clean state (tested in Chrome and FF) :>
This method works:
audio.pause();
audio.currentTime = 0;
But if you don't want to have to write these two lines of code every time you stop an audio you could do one of two things. The second I think is the more appropriate one and I'm not sure why the "gods of javascript standards" have not made this standard.
First method: create a function and pass the audio
function stopAudio(audio) {
audio.pause();
audio.currentTime = 0;
}
//then using it:
stopAudio(audio);
Second method (favoured): extend the Audio class:
Audio.prototype.stop = function() {
this.pause();
this.currentTime = 0;
};
I have this in a javascript file I called "AudioPlus.js" which I include in my html before any script that will be dealing with audio.
Then you can call the stop function on audio objects:
audio.stop();
FINALLY CHROME ISSUE WITH "canplaythrough":
I have not tested this in all browsers but this is a problem I came across in Chrome. If you try to set currentTime on an audio that has a "canplaythrough" event listener attached to it then you will trigger that event again which can lead to undesirable results.
So the solution, similar to all cases when you have attached an event listener that you really want to make sure it is not triggered again, is to remove the event listener after the first call. Something like this:
//note using jquery to attach the event. You can use plain javascript as well of course.
$(audio).on("canplaythrough", function() {
$(this).off("canplaythrough");
// rest of the code ...
});
BONUS:
Note that you can add even more custom methods to the Audio class (or any native javascript class for that matter).
For example if you wanted a "restart" method that restarted the audio it could look something like:
Audio.prototype.restart= function() {
this.pause();
this.currentTime = 0;
this.play();
};
It doesn't work sometimes in chrome,
sound.pause();
sound.currentTime = 0;
just change like that,
sound.currentTime = 0;
sound.pause();
From my own javascript function to toggle Play/Pause - since I'm handling a radio stream, I wanted it to clear the buffer so that the listener does not end up coming out of sync with the radio station.
function playStream() {
var player = document.getElementById('player');
(player.paused == true) ? toggle(0) : toggle(1);
}
function toggle(state) {
var player = document.getElementById('player');
var link = document.getElementById('radio-link');
var src = "http://192.81.248.91:8159/;";
switch(state) {
case 0:
player.src = src;
player.load();
player.play();
link.innerHTML = 'Pause';
player_state = 1;
break;
case 1:
player.pause();
player.currentTime = 0;
player.src = '';
link.innerHTML = 'Play';
player_state = 0;
break;
}
}
Turns out, just clearing the currentTime doesn't cut it under Chrome, needed to clear the source too and load it back in. Hope this helps.
As a side note and because I was recently using the stop method provided in the accepted answer, according to this link:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element. In the link it mentions Firefox, but I encountered this event firing after setting currentTime manually on Chrome. So if you have behavior attached to this event you might end up in an audio loop.
shamangeorge wrote:
by setting currentTime manually one may fire the 'canplaythrough' event on the audio element.
This is indeed what will happen, and pausing will also trigger the pause event, both of which make this technique unsuitable for use as a "stop" method. Moreover, setting the src as suggested by zaki will make the player try to load the current page's URL as a media file (and fail) if autoplay is enabled - setting src to null is not allowed; it will always be treated as a URL. Short of destroying the player object there seems to be no good way of providing a "stop" method, so I would suggest just dropping the dedicated stop button and providing pause and skip back buttons instead - a stop button wouldn't really add any functionality.
This approach is "brute force", but it works assuming using jQuery is "allowed". Surround your "player" <audio></audio> tags with a div (here with an id of "plHolder").
<div id="plHolder">
<audio controls id="player">
...
</audio>
<div>
Then this javascript should work:
function stopAudio() {
var savePlayer = $('#plHolder').html(); // Save player code
$('#player').remove(); // Remove player from DOM
$('#FlHolder').html(savePlayer); // Restore it
}
I was looking for something similar due to making an application that could be used to layer sounds with each other for focus. What I ended up doing was - when selecting a sound, create the audio element with Javascript:
const audio = document.createElement('audio') as HTMLAudioElement;
audio.src = getSoundURL(clickedTrackId);
audio.id = `${clickedTrackId}-audio`;
console.log(audio.id);
audio.volume = 20/100;
audio.load();
audio.play();
Then, append child to document to actually surface the audio element
document.body.appendChild(audio);
Finally, when unselecting audio, you can stop and remove the audio element altogether - this will also stop streaming.
const audio = document.getElementById(`${clickedTrackId}-audio`) as HTMLAudioElement;
audio.pause();
audio.remove();
If you have several audio players on your site and you like to pause all of them:
$('audio').each( function() {
$(this)[0].pause();
});
I believe it would be good to check if the audio is playing state and reset the currentTime property.
if (sound.currentTime !== 0 && (sound.currentTime > 0 && sound.currentTime < sound.duration) {
sound.currentTime = 0;
}
sound.play();
for me that code working fine. (IE10+)
var Wmp = document.getElementById("MediaPlayer");
Wmp.controls.stop();
<object classid="clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"
standby="Loading áudio..." style="width: 100%; height: 170px" id="MediaPlayer">...
Hope this help.
What I like to do is completely remove the control using Angular2 then it's reloaded when the next song has an audio path:
<audio id="audioplayer" *ngIf="song?.audio_path">
Then when I want to unload it in code I do this:
this.song = Object.assign({},this.song,{audio_path: null});
When the next song is assigned, the control gets completely recreated from scratch:
this.song = this.songOnDeck;
The simple way to get around this error is to catch the error.
audioElement.play() returns a promise, so the following code with a .catch() should suffice manage this issue:
function playSound(sound) {
sfx.pause();
sfx.currentTime = 0;
sfx.src = sound;
sfx.play().catch(e => e);
}
Note: You may want to replace the arrow function with an anonymous function for backward compatibility.
In IE 11 I used combined variant:
player.currentTime = 0;
player.pause();
player.currentTime = 0;
Only 2 times repeat prevents IE from continuing loading media stream after pause() and flooding a disk by that.
What's wrong with simply this?
audio.load()
As stated by the spec and on MDN, respectively:
Playback of any previously playing media resource for this element stops.
Calling load() aborts all ongoing operations involving this media element
I am working on a project based on jquery animation its animation works fine on desktop (Firefox,chrome,opera,IE) also support HTML 5 audio tag but in Ipad/iphone/ Android safari audio tag doesn’t support.Its works fine on Ipad/iphone/ Android firefox.i have searched it in many forum don’t get desire Result. I have used this function :
function playmusic(file1,file2)
{
document.getElementById('music11').innerHTML='<audio id="music1"><source src="'+file1+'" type="audio/ogg"><source src="'+file2+'" type="audio/mpeg"></audio>';
$("#music1").get(0).play();
}
I have called function like : playmusic(2.ogg','2.mp3');
If I give autoplay in audio tag it works but play method not working and I have to use play method as in my application needs sound in particular event see the link
http://solutions.hariomtech.com/jarmies/
I have also changed my function and give direct audio tag in div and call function the same problem I face as I mentioned above. I need sound play in background without any click.if I use auto play method so it play sound only one time but I need sound multiple time on event.
Try to add an autoplay attribute on the audio tag:
function playmusic(file1, file2) {
document.getElementById('music11').innerHTML='<audio autoplay id="music1"><source src="'+file1+'" type="audio/ogg"><source src="'+file2+'" type="audio/mpeg"></audio>';
}
I would however recommend building a proper element and insert that into the DOM - something like this:
function playmusic(file1, file2) {
var audio = document.createElement('audio');
audio.preload = 'auto';
audio.autoplay = true;
if (audio.canPlayType('audio/ogg')) {
audio.src = file1;
}
else if (audio.canPlayType('audio/mpg')) {
audio.src = file2;
}
document.getElementById('music11').appendChild(audio);
}
This question already has answers here:
Play mp3 file using javascript
(3 answers)
Closed 10 years ago.
I have a directory on my website with several mp3's.
I dynamically create a list of them in the website using php.
I also have a drag and drop function associated to them and I can select a list of those mp3 to play.
Now, giving that list, how can I click on a button (Play) and make the website play the first mp3 of the list? (I also know where the music is on the website)
new Audio('<url>').play()
If you want a version that works for old browsers, I have made this library:
// source: https://stackoverflow.com/a/11331200/4298200
function Sound(source, volume, loop)
{
this.source = source;
this.volume = volume;
this.loop = loop;
var son;
this.son = son;
this.finish = false;
this.stop = function()
{
document.body.removeChild(this.son);
}
this.start = function()
{
if (this.finish) return false;
this.son = document.createElement("embed");
this.son.setAttribute("src", this.source);
this.son.setAttribute("hidden", "true");
this.son.setAttribute("volume", this.volume);
this.son.setAttribute("autostart", "true");
this.son.setAttribute("loop", this.loop);
document.body.appendChild(this.son);
}
this.remove = function()
{
document.body.removeChild(this.son);
this.finish = true;
}
this.init = function(volume, loop)
{
this.finish = false;
this.volume = volume;
this.loop = loop;
}
}
Documentation:
Sound takes three arguments. The source url of the sound, the volume (from 0 to 100), and the loop (true to loop, false not to loop).
stop allow to start after (contrary to remove).
init re-set the argument volume and loop.
Example:
var foo = new Sound("url", 100, true);
foo.start();
foo.stop();
foo.start();
foo.init(100, false);
foo.remove();
//Here you you cannot start foo any more
You will probably want to use the new HTML5 audio element to create an Audio object, load the mp3, and play it.
Due to browser inconsistencies, this sample code is a bit lengthly, but it should suit your needs with a bit of tweaking.
//Create the audio tag
var soundFile = document.createElement("audio");
soundFile.preload = "auto";
//Load the sound file (using a source element for expandability)
var src = document.createElement("source");
src.src = fileName + ".mp3";
soundFile.appendChild(src);
//Load the audio tag
//It auto plays as a fallback
soundFile.load();
soundFile.volume = 0.000000;
soundFile.play();
//Plays the sound
function play() {
//Set the current time for the audio file to the beginning
soundFile.currentTime = 0.01;
soundFile.volume = volume;
//Due to a bug in Firefox, the audio needs to be played after a delay
setTimeout(function(){soundFile.play();},1);
}
Edit:
To add Flash support, you would append an object element inside the audio tag.
You can use <audio> HTML5 tag to play audio using JavaScript.
But this is not cross-browser solution. It supported only in modern browsers. For cross-browser compatibility you probably need to use Flash for that (for example jPlayer).
Browsers compatibility table is provided at link I mentioned above.
You could try SoundManager 2: it will transparently handle the <audio> tag wherever it's supported, and use Flash wherever it isn't.
Assuming that the browser supports MP3 playback and is fairly new to support newer JavaScript features, I would suggest taking a look at jPlayer.
You can see a short demo tutorial on how to implement it.
Jquery plugin for audio mp3 player http://www.jplayer.org/0.2.1/demos/
Enjoy it ;)
<html>
<head>
<title>Play my music....</title>
</head>
<body>
<ul>
<li>
<a id="PlayLink" href="http://www.moderntalking.ru/real/music/Modern_Talking-You_Can_Win(DEMO).mp3" onclick="pplayMusic(this, 'music_select');">U Can Win</a>
</li>
<li>
<a id="A1" href="http://www.moderntalking.ru/real/music/Modern_Talking-Brother_Louie(DEMO).mp3" onclick="pplayMusic(this, 'music_select');">Brother Louie</a>
</li>
</ul>
<script type="text/javascript" src="http://mediaplayer.yahoo.com/js"></script>
</body>
</html>
My question is how to add new components(control buttons) on video.js player.
For example, adding a button to allow to change the video playback rate.
Giving a simple example would be much helpful. Thank you very much.
It doesn't appear VideoJS Supports playback-rate directly, but from my understanding it's just a fancy wrapper for an HTML5 Video Element.
According to this stack overflow question/answer you can change the playback rate of HTML5 video directly on the DOM Element as referenced by the W3C HTML5 Video Wiki Entry.
You probably will have to side-step VideoJS to do this as the support doesn't look baked in. Also, there may be issues between browsers over support of this attribute.
As for simply adding controls, VideoJS implements a Javascript API you can use to control the element but it seems pretty limited to the most basic of controls (play/pause/goto/fullscreen/etc...)
The default controls the player has don't seem to be greatly customizable so if you wish to provide a clearer experience, you can probably disable the in-video controls and re-implement your own in html/dom/js underneath the video element.
Example:
With some really simple html & Javascript, you can wire up some simple controls.
HTML:
<video id="Vid" ...>
</video>
<div id="Controls">
<a id="Play" href="#Play">Play</a> - <a id="Pause" href="#Pause">Pause</a>
</div>
JS:
_V_("Vid").ready(function() {
var player = this;
var playbutton = document.getElementById("Play");
var pausebutton = document.getElementById("Pause");
playbutton.onclick = function(event) {
player.play();
};
pausebutton.onclick = function(event) {
player.pause();
};
});
After searching for this myself, I have found a similar thing happening at the very bottom of the tracks.js file.
// Add Buttons to controlBar
_V_.merge(_V_.ControlBar.prototype.options.components, {
"subtitlesButton": {},
"captionsButton": {},
"chaptersButton": {}
});
From tracks.js https://github.com/videojs/video.js/blob/master/src/js/tracks.js