capture currently playing audio with HTML5? - html

Is there any way to capture the soundcard's currently playing audio with getUserMedia? As in, whatever audio is currently playing on the system. I'm pretty sure it can only access the microphone. I'm unaware if you are able to access the current soundcard output, without jacking the input to the output with something like soundflower.

The getUserMedia method is part of the html5 media-capture-streams specification, it will return the MediaStream object provided to it (by the user/browser). The wave output (or your default playback device) won't, or rather shouldn't, be available because it isn't a capture/input device. So, as you mentioned in your question, the way you could do this would be to use something like: 'soundflower' or 'virtual audio cables' to relay the output you wanted into a virtual input device and capture that instead.
W3 Specification: http://www.w3.org/TR/mediacapture-streams/
Alternative apps: http://alternativeto.net/software/soundflower/

Related

Chrome: Wrong sound when changing the audio source for Audio element and MediaStreamAudioDestinationNode

I have a app where I play different code-generated sounds. I place these sounds in a AudioBufferSourceNode.
I allow the the user to choose what output device to play the sound through, so I use a MediaStreamAudioDestinationNode with its stream used as the source for an Audio Element. This way when the user chooses an audio output to play the sound to, I set the Sink Id of the Audio element to the requested audio output.
So I have AudioBufferSourceNode -> some Audio Graph (gain nodes, etc) -> MediaStreamAudioDestinationNode -> Audio element.
When I Play the first sound, it sound fine. But when I create a new source and connect it to the same MediaStreamAudioDestinationNode, the sound is played with the wrong pitch.
I created a Fiddle that shows the problem.
Is this a bug, or am I doing something wrong?
The problem was identified based on the OP Chrome Ticket.
It seems to come from the lack of sync between AudioElement and its source AudioNode (AudioBufferSourceNode, OscillatorNode, etc.) when you pause the source and play it back again.
The solution is to always call AudioElement.pause() and AudioElement.start() alongside your source stop and start.
https://jsfiddle.net/k1r7o0xj/3/
It's possible to dynamically change your graph layout by using .connect() and .disconnect(), even when audio is playing or sent through a stream (which could even be streamed over WebRTC).
I couldn't find a reference in the spec, so I'm pretty sure this is taken for granted.
For example, if you have two AudioBufferSourceNodes bufferSource1 and bufferSource2, and a MediaStreamAudioDestinationNode streamDestination:
bufferSource1.connect(streamDestination);
//do some other things here, and after some time, switch to bufferSource2:
//(streamDestination doesn't need to be explicitly specified here)
bufferSource1.disconnect(streamDestination);
bufferSource2.connect(streamDestination);
Example in action.
Edit 1:
Proper implementation:
According to the Editors Draft on the Audio Output API, it is planned/will be possible to choose a custom audio output device for the AudioContext as well (by means of new AudioContext({ sinkId: requestedSinkId });). I couldn't find any info on the progress, and even found a related discussion which the asker apparently read already. According to this and (many) other references, it doesn't seem te be an easy task, but it's planned for WA V1.
Edit:
That section has been removed from the API Draft, but you can still find it in an older version.
Current workaround:
I played around with your workaround (using a MediaStreamAudioDestinationNode and Audio object), and it seems to be related to nothing being connected. I modified my example to toggle a single buffer (similar to your example but with an AudioBufferSourceNode), and observed a similar frequency drop. However, when using a GainNode inbetween and setting it's gain.value to either 0 or 1, the frequency drops disappeared (this isn't gonna be the solution if you want to create and connect new AudioBuffers dynamically).

Get duration of an HTML5 video (live stream)

I'm looking at options to switch from flash (strobe) to HTML5 solution (using Media Source Extensions with DASH or HLS).
According to the HTML5 specs for video we can't get the duration of a live stream video.
The duration attribute must return the time of the end of the media resource,
in seconds, on the media timeline. If no media data is available, then the
attributes must return the Not-a-Number (NaN) value. If the media resource is
known to be unbounded (e.g. a streaming radio), then the attribute must return
the positive Infinity value.
My live stream is not a "sliding window" meaning that we have a fixed start date. I am currently using Strobe player and it actually increase the duration as it plays whereas HTML5 always returns Infinity.
I wanted to know if some options are available to maintain myself a duration (by parsing fragments for example, this library does that in a way).
I don't have enough reputation to comment, so I'll type it here.
I think it's best to look into the .seekable and .buffered properties of the HTMLMediaElement. You can use the .buffered that returns a TimeRanges object to track the duration of the stream in your media but the media element itself has no means of knowing how long the stream might be.
The problem is that .buffered might not always tell you "how much stream" is there if you have pause for a long time, for example.
When I tested their behaviour on a Android virtual device and an HLS stream in Chrome, after several seconds of playback, buffered returned a TimeRanges object with length 1 and video.buffered.end(0) was 0, and .seekable returned the same thing but with video.seekable.end(0) == Infinity.
If you want precise data, I would agree that a parsing library, that parses the duration of a HLS playlist for example, is the best option, although not elegant at all.

AS3: Recording sound as they are output/played

I understand how to record microphone input in AS3 from this doc.
Is it possible to record sound exactly as they are being output/played?
The reason is I applied some sound transform (via the global SoundMixer) to sounds that are currently playing; and I also want to record this sound data while it is being played.
I just saw this question, to clarify, I am not trying to record just all sounds on the user's computer (which is not possible). My flash app has a Youtube player in it (via their AS3 API), and it's playing some sounds. I applied transforms using SoundMixer.soundTransform, and I want to record what's being played when the user is playing it.
Thanks in advance.
Just a passing suggestion.. on my desktop it seems ABLE to record sound into Flash from a different tab playing Youtube (HTML5).. I don't know how it's doing that!!
I allow microphone here.. (none actually plugged in, and speaker out has in-ear headphones)
http://code.tutsplus.com/tutorials/create-a-useful-audio-recorder-app-in-actionscript-3--active-5836
PS: Anyone trying this must reduce Windows volume since anything above 10-20% is distorted audio into the Flash app.
And this HTML5 youtube trailer was recorded fine into the Wav file produced by Flash app above
http://www.youtube.com/watch?v=MVt32qoyhi0
So after a quick search it seems my Realtek Audio is classed as a Full-Duplex soundcard and also within its own control panel I have an option called "Multi-streaming" which is enabled/ticked. I think Full-Duplex is enough to do this though. Try options within your soundcard's own settings software. Don't know about your end-users. Some hardware will do it, some wont, there is no all-round solution outside of AIR (which makes desktop apps out of your AS3 code).

How does Youtube's HTML5 video player control buffering?

I was watching a youtube video and I decided to investigate some parts of its video player. I noticed that unlike most HTML5 video I have seen, Youtube's video player does not do a normal video source and instead utilizes a blob url as the source.
Previously I have tested HTML5 videos and I found that the server starts streaming the whole video from the start and buffers in the background the complete rest of the video. This means that if your video is 300 megs, all 300 megs will be downloaded. If you seek to the middle, it will start downloading from the seek position all the way to the end.
Youtube does not work this way (at least in chrome). Instead it manages to control buffering so it only buffers a certain amount while paused. It also seems to only buffer the relevant pieces, so if you skip around it will make sure not to buffer pieces that are unlikely to be watched.
In my attempts to investigate how this worked, I noticed the video src tag has a value of blob:http%3A//www.youtube.com/ee625eee-2802-49b2-a13f-eb374d551d54, which pointed me to blobs, which then led me to typed arrays. Using those two resources I am able to load a mp4 video into a blob and display it in a HTML5 video tag.
However, what I am now stuck on is how Youtube deals with the pieces. Looking at the network traffic it appears to sends requests to http://r6---sn-p5q7ynee.c.youtube.com/videoplayback which returns binary video data back in chunks of 1.1mb. It also seems worth noting that most normal requests due to HTML5 video requests seem to receive a 206 response code back while it streams, yet youtube's playvideo calls get a 200 back.
I tried to attempt to only load a range of bytes (via setting the Range http header) which unfortunately failed (I'm assuming because there was no meta-data for the video coming with the video).
At this point I'm stuck on figuring out how Youtube accomplishes this. I came up with several ideas though none of which I am completely sold on:
1) Youtube is sending down self contained video and audio chunks with each /videoplayback call. This seems like a pretty heavy burden on the upload side and it seems like it would be difficult to stitch these together to make it appear like it's one seemless video. Also, the video tag seems to think it's one full video, judging from calling $('video').duration and $('video').currentTime, which leads me to believe that the video tag thinks it's a single video file. Finally, the vidoe src tag never changes which makes me believe it is working with a singular blob and not switching out blobs.
2) Youtube constructs an empty blob pre-sized to the full video array and updates the blob with pieces as it downloads it. It would then make sure the user has not gotten too close to the last downloaded piece (to prevent the user from entering an undownloaded section of the blob). The problem that I see with this that I don't see any way to dynamically update a blob through javascript (although maybe I'm just having trouble googling for it)
3) Youtube downloads the meta data and then starts constructing the blob in order by appending the video pieces as it downloads them. The problem I see with this method is I don't understand how it would handle seeks in post-buffered territory.
Maybe I"m just missing an obvious answer that's right in front of me. Anyone have any ideas?
edit: I just thought of a fourth option. Another idea is they might use the file API to write the binary chunks to a file and use that file to stream off of. The file API seems to have the ability to seek to specific positions, therefore allowing you to fill a video with empty bytes and fill them in as they are received. This would definitely accommodate video seeking as well.
Okay, so few things you need to know is that YouTube is based on this great open source Project. It behaves different for every browser and if your browser supports more intensive decoding like WEBM it will use that to save Google's bandwidth. Also if you look at this Demo
Then you will find a section which downloads the entire video into a thing called "offline storage". I know chrome has it and some other browsers not every in some cases they do have to use the entire video source instead of a blob. So that blob is streaming depending on the user interaction with the video. Yes the video is just 1 file and they have metadata for that video like a little database that tells the time of the video and the points at which chunks can be divided in.
You can find out more by reading the Project's documentation. I really recommend you have a look at the demo.
When you look at the AppData of GoogleChrome, while playing a youtube video, you will see that it buffers in segmented files. The videos uploaded to youtube are segmented, which is why you can't perfectly pinpoint a timeframe in the first click on the bar if that timeframe is outside of the current segment.
The amount of segments depends on the length of the video, and the time from which you start and stop playing back the video.
When you are linked to a timeframe of a video, it will simply skip the buffering of the segments that come before that timeframe.
Unfortunately I don't know much about the coding for video playback, but I hope this points you in the right direction.
there is a canvas element in the page ,Maybe This Will Help
http://html5doctor.com/video-canvas-magic/
we knew the video is been segmented,the question is how to stitch them together.i think the real video element doesn't do the play work,it support the datasource,and draw the seagments each frame to the canvas element。
var v = document.getElementById('v');
var canvas = document.getElementById('c');
v.addEventListener('play', function(){
if(v.paused || v.ended) return false;
c.drawImage(v,0,0,w,h);
setTimeout(draw,20,v,c,w,h);
},false);
Youtube is using this feature only in browsers that support Media Source Extensions so it is up to the browser decide about all the rest because of this feature.

How to apply sound distortion in actionscript-3?

Let's say the sound input is either an embedded mp3 file or the microphone.
Is there an example of how to make it sound demonic and creepy, or like a radio transmission from the battlefield in actionscript-3 dynamically on runtime.
Reference:
http://www.youtube.com/watch?v=JAY88WH0FcU
As far as I know, you simply can't with the microphone, unless you first send it to a server.
With an audio file (embedded or not), you can distort it by playing with its bytes (ref), but its not at all a trivial task (I'm not aware of any library for "easy" sound processing).