getMicrophone() in as3 only works when using setLoopBack() - actionscript-3

I want to monitor the microphone audio input with flash ( as3 ).
This is just a tiny part of my code, but actually the problem is in there.
var mic:Microphone = Microphone.getMicrophone();
mic.setLoopBack(true);
addEventListener( Event.ENTER_FRAME, loop );
function loop( event:Event ):void {
trace( mic.activityLevel );
}
If i use the code like it is, i can trace the activityLevel and actually can see some values.. ( i think it is the volume ? )
Well, the only problem is, that the audio is also outputed to the speakers, what i DON'T want... ( mic.setLoopBack(true); )
But when i try mic.setLoopBack(false);, flash doesn't ask for microphone premissions anymore and the traced activityLevel stays "-1".....
So what can i do to disable the audio loopback OR to just monitor the audio data from the mic. ?
( when i say "audio data", i mean all the data that is necessary for later BPM detection... i think it's an byte array of the audio, isn't it ? )

As a temp solution to mute the mic you can try :
var st:SoundTransform = new SoundTransform(0);
mic.soundTransform = st;
You should still see the activity level.

Instead of using setLoopBack(), you just need to listen for SampleDataEvent's from the Microphone. Note the section titled "Detecting Microphone Activity" in this Adobe article, and in particular this note that talks about ways you can listen for microphone activity:
Note: A Microphone object only dispatches Activity events when your application is monitoring the microphone. Thus, if you do not call setLoopBack( true ), add a listener for sample data events, or attach the microphone to a NetStream object, then no activity events are dispatched.
var mic:Microhpone = Microphone.getMicrophone;
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
function onSampleData(event:SampleDataEvent):void
{
trace("activity from: " + mic.name + " level: " + mic.activityLevel);
}
This should be a more optimal solution, as the SampleDataEvent's are only dispatched when the microphone detects sound, as opposed to your current approach that works on every frame.

Related

Expand menu (movieclip) and music in music setting error

I have make a menu in Flash that can expand and there music setting inside.
The music plays when the application starts. To stop the music you must expand the menu and click the music icon.
It's working fine after I open the program and stop the music.
And it's working if I want to play again.
But there's problems after that:
I can't stop the music again and the music playing double in background.
This is my FLA file:
https://drive.google.com/file/d/1DpqdH64kDnI8xN6fBAt3pwi_bIRQ52mT/view?usp=drivesdk
Can anyone tell me the fault of my program? Thanks.
About "music playing double" does your (audio) playback function create a new anything? (eg: = new Sound or = new SoundChannel)? If yes...
Create your audio variables once outside of functions, then use your functions only to stop/start audio playback.
Use new Sound only when loading a new track, once loaded then use one SoundChannel to play/stop that Sound object.
You need a Boolean to keep track of whether a Sound is already playing or not. If true then don't send another .play() command (now gives two sounds to output/speakers).
See if the code logic below guides you toward a better setup:
//# declare variables globally (not trapped inside some function)
var snd_Obj :Sound;
var snd_Chann :SoundChannel = new SoundChannel();
var snd_isPlaying :Boolean = false;
//# main app code
loadTrack("someSong.mp3"); //run a function, using "filename" as input parameter
//# supporting functions
function loadTrack (input_filename :String) : void
{
snd_Obj = new Sound();
snd_Obj.addEventListener(Event.COMPLETE, finished_LoadTrack);
snd_Obj.load( input_filename ); //read from function's input parameter
}
function finished_LoadTrack (event:Event) : void
{
snd_Chann = snd_Obj.play(); //# Play returned Speech convert result
snd_Obj.removeEventListener(Event.COMPLETE, onSoundLoaded);
//# now make your Play and Stop buttons active
btn_play.addEventListener(MouseEvent.CLICK, play_Track);
btn_stop.addEventListener(MouseEvent.CLICK, stop_Track);
}
function play_Track (event:Event) : void
{
//# responds to click of Play button
if(snd_isPlaying != true) //# check if NOT TRUE, only then start playback
{
snd_Chann = snd_Obj.play();
snd_isPlaying = true; //# now set TRUE to avoid multiple "Play" commands at once
}
}
function stop_Track (event:Event) : void
{
//# responds to click of Play button
snd_Chann.stop();
snd_isPlaying = false; //# now set FALSE to reset for next Play check
}

Streaming FLV videos

I have 3 flv videos that I'm streaming. The first one is the intro. Then the second one is playing after the intro right after the intro ends. And the second video is looping. Everything seemed to be fine. But some times when i load the swf it starts from the second video. Any ideas why ?
import flash.events.MouseEvent
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
loader.vid.Video_1.attachNetStream(ns);
var listener:Object = new Object();
listener.onMetaData = function(evt:Object):void {};
ns.client = listener;
ns.play("video_1.flv");
ns.addEventListener(NetStatusEvent.NET_STATUS, NCListener);
function NCListener(e:NetStatusEvent){
if (e.info.code == "NetStream.Buffer.Empty") {
ns.play("video_2.flv");
}
};
loader.button_01.addEventListener(MouseEvent.CLICK, play_video_01);
loader.button_01.addEventListener(MouseEvent.ROLL_OVER, play_effect_01);
function play_video_01 (event:Event):void{
ns.play("video_3.flv");
loader.button_01_mc.gotoAndPlay (21);
}
function play_effect_01 (event:Event):void{
loader.button_01_mc.gotoAndPlay (2);
}
In your code, playback of your second video is triggered by the message NetStream.Buffer.Empty. That message can get dispatched for several reasons, as well as when playback of a video ends. For example when streaming (which I know you're not doing), NetStream.Buffer.Empty can get dispatched when there is a network problem. This is definitely the cause of your problem, but it's not clear why sometimes the buffer empty message gets dispatched right away.
The first thing I would do is modify your NetStatusEvent listener so that it traces out all of the messages that are being dispatched. That way you can see the sequence of events that occurs when this problem happens.
And second, you should try using another message to trigger playback of the second video. I'm not 100% sure, but I think the message NetStream.Play.Stop is what you want (this gets dispatched when the end of the video is reached, as well as when you programmatically stop playback). The full list of messages you get from a NetStatusEvent is here.
Incorporating both of these suggestions, your NetStatusEvent handler might look like this:
function NCListener(e:NetStatusEvent)
{
var code:String = e.info.code;
trace("code: ", code);
if (code == "NetStream.Record.Stop"
ns.play("video_2.flv");
}
Finally, you might want to add other event listeners to the NetStream. It dispatches an IOErrorEvent and AsyncErrorEvent ... perhaps you're getting one of these when the problem happens.

How to loop FLV seamlessly

I am playing looped FLVs in the "standard way":
netstream.addEventListener(NetStatusEvent.NET_STATUS, onStatus);
...
public function onStatus(item:Object):void {
if (item.info.code == "NetStream.Play.Stop") {
if (loop) netstream.seek(0);
}
When played through Flash CS 5.5 authoring tool (Test Movie or Debug Movie), the videos loop seamlessly. But! When played in the browser or standalone debug Flash player (both v.11.2.202.233) there is an abnormal pause of about 1 sec before the video "rewinds".
Is this a bug with the latest Flash player?
For People who have the same issue, try changing the aforementioned code to this:
public function onStatus(item:Object):void {
if (item.info.code == "NetStream.Buffer.Empty") {
if (loop) netstream.seek(0);
}
It will get rid of the flicker. If you listen to "NetStream.Play.Stop", it will cause a flicker.
You don't need to embed anything. This works just fine on IOS, Android and PC.
This is a known bug with Flash Player 11+ and AIR 3+. Bug report is here, and you should upvote & : https://bugbase.adobe.com/index.cfm?event=bug&id=3349340
Known workarounds that will create a seamless loop:
1) Embed the video in the SWF. Not ideal, and not possible in some cases.
2) Create dual NetSteam objects and switch between them. An example of the event fired when ns1, the first of two NetStreams objects, reaches it's end:
if (e.info.code == "NetStream.Play.Stop"){
vid.attachNetStream(ns2);
ns2.resume();
activeNs = ns2;
ns1.seek(0);
ns1.pause();
}
Replace ns1 with ns2 on the other event listener. A useless duplication of objects and handlers, but there you go.
3) Use AIR 2.x / Flash Player 10.x (not really a solution at all, except for Linux users)
We noticed this on the transition from Flash 10 to to Flash 11. Flash 10 loops seamlessly, but Flash 11 has a ~1 second stall when calling seek(0) from NetStream.Play.Stop.
Embedding the media in the SWF is not an option for us.
The following code provides a more seamless loop - still not perfect, but much better.
var mStream:NetStream;
var mDuration:Number;
...
addEventListener(Event.ENTER_FRAME, onEnterFrame);
...
function onEnterFrame(e:Event):void
{
if( mStream.time > (mDuration-0.05) )
{
if( mLooping )
{
mStream.seek(0);
}
}
}
function onMetaData(info:Object)
{
mDuration = info.duration;
}
Hope it helps.
I seem to have achieved this using an FLVPlayback component along with a few tips.
What's more, it's running seamlessly on desktop, iPhone 4S and 3GS! (via an AIR app)
_videoFLV = new FLVPlayback();
_videoFLV.fullScreenTakeOver = false;
_videoFLV.autoPlay = false;
_videoFLV.autoRewind = true;
_videoFLV.isLive = false;
_videoFLV.skin = null;
_videoFLV.y = 150;
_videoFLV.bufferTime = .1;
_videoFLV.width = 320;
_videoFLV.height = 320;
_videoFLV.addEventListener(MetadataEvent.CUE_POINT, video_cp_listener, false, 0, true);
_videoFLV.source = "includes/10sec.flv";
addChild(_videoFLV);
With the listener function...
function video_cp_listener(eventObject:MetadataEvent):void {
if (eventObject.info.name == "endpoint") {
_videoFLV.seek(0);
_videoFLV.play();
}
}
Importantly I think you must set the width and height to match your flv file. i.e. no scaling whatsoever.
The flv has a cue point named 'endpoint' added 1 frame before the end of the file (assuming your start and end frame are the same this will be required).I added this using Adobe Media Encoder.
The only way to loop an flv seamlessly is to embed inside the swf. It is converted to a MovieClip and you then handle it with play(), stop(), nextFrame(), prevFrame() etc.
When embedding in Flash Authoring tool (dragging flv file on stage), make sure that you select:
"Embed FLV in SWF..."
Symbol Type : "Movie clip"
All checked : "Place instance on stage", "Expand timeline...", "Include audio"

Using AS3WavSound to play WAV - cannot stop instantly

I'm using the AS3WavSound (http://code.google.com/p/as3wavsound/) class to playback externally loaded wavs. This is working successfully. The library is simple and effective.
After decoding the Wav ByteArray the method the library employs for playback is using the SampleDataEvent.SAMPLE_DATA event and then writing the mixed samples to the output stream.
player.addEventListener(SampleDataEvent.SAMPLE_DATA, onSamplesCallback);
private function onSamplesCallback( evt : SampleDataEvent ):void
{
for (var i:int = 0; i < samplesLength; i++)
{
if(_mute == false){
outputStream.writeFloat(samplesLeft[i]);
outputStream.writeFloat(samplesRight[i]);
}
}
}
My problem is that I need to silence this audio output immediately but whatever method I have tried there is a distinct (1 second approx) delay before the silence takes effect.
As you can see I've attempted to add a boolean to block any samples being written to the output stream but this has had no effect on the delay.
My suspicion is that this is a fundamental part of how the samples are buffered and then written out. Essentially by the time a user action on screen (clicking a mute button) has been called and the _mute boolean is set to true there are already samples waiting to be written to the output that cannot be affected.
Any advice or confirmation of my suspicion would be greatly appreciated.
Thanks,
gfte.
Your suspicion is probably right - but why stop it at that level? If you want to turn off the sound, would it not be better to set the volume on the soundTransform-property on the SoundChannel-object returned by the play method? (I assume the wav library returns this in some way)
It looks like the library you are using has a similar design to the native Flash Sound API wherein a SoundChannel object is returned from the play() method. This SoundChannel instance has a stop() method which should stop the sound right away.
var sound:WavSoundPlayer = new WavSoundPlayer();
var channel:WavSoundChannel = new WavSoundChannel();
sound.addEventListener( SampleDataEvent.SAMPLE_DATA, onSampleData );
channel = sound.play();
private function onSamplesData( evt : SampleDataEvent ):void
{
for (var i:int = 0; i < samplesLength; i++)
{
outputStream.writeFloat(samplesLeft[i]);
outputStream.writeFloat(samplesRight[i]);
}
}
channel.stop()
The _mute variable in your example will only be able to change either before or after the loop, not while it is looping.

if I load a flv with netStream, how can I call a function when the flv stops playing

I have a website in ActionScript 3 that has lots of FLV animations that happen when you press buttons. Right now this is how I have it set up.
in AS3,
im loading FLv's (which are animations I exported in FLV form from After Effects)
with net stream. I have a timer set up for the same amount of length of time that the animations (FLV's) play and when the timer stops it calls a function that closes the stream, opens a new one and plays another video. The only problem I noticed using timers is that if the connection is slow and (animation)stops for a second, the timer keeps going, and calls the next flv too early.
Does anyone know a way to load a flv, or swf for that matter, at the end of play of the flv? so that the next FLV will always play at the end of the run time of the previous FLV, rather than using timers?
im thinking onComplete but I don't know how to implement that!?
Sequential playing is pretty easy to achieve with the OSMF framework, you should check it out. Google "osmf tutorials" and you should find a few tutorials online.
The framework is fairly recent, but it looks like it may become the de facto solution for media delivery in Flash as it's not limited to video but also audio & images.
As a developer you won't have to bother with the NetStream & NetConnection classes. Developing video solutions , as well as audio & images solutions should be streamlined and easier to handle. Only limitation is that it requires Flash 10
Here's some code for checking when a FLV ends with NetStream. I just provide snippets as I assume you got the FLV up and running already.
//create a netstream and pass in your connection
var netStream:NetStream = new NetStream(conn);
//add callback function for PlayStatus -event
var client : Object = {};
client.onPlayStatus = onPlayStatus;
netStream.client = client;
//attach your NetStream to the connection as usual
//---
//function that gets called onPlayStatus
function onPlayStatus(info : Object) : void {
trace("onPlayStatus:" +info.code + " " + info.duration);
if (info.code == "NetStream.Play.Complete") {
//play the next FLV and so on
}
}
EDIT: With your example code it will look something like this.
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
var listener:Object = new Object();
listener.onMetaData = function(md:Object):void{};
listener.onPlayStatus = function(info : Object) : void {
trace("onPlayStatus:" +info.code + " " + info.duration);
if (info.code == "NetStream.Play.Complete") {
//play the next FLV and so on
}
};
ns.client = listener;
vid1.attachNetStream(ns);
const moviename1:String = "moviename2.flv";
const moviename1:String = "moviename3.flv";
var movietoplay:String = "moviename.flv";
ns.play(movietoplay);