video stream: "onBWDone: undefined" and video doesn't play - actionscript-3

I'm trying to stream a video from Amazon's CloudFront/S3 service. Despite my filename being correct, and a "NetConnection.Connect.Success" status, my NetConnection onBWDone callback is giving me an "undefined" error and the video doesn't play or show up anywhere on the stage. The connection reports that it's successful so I don't know where the problem lies. Here is my code:
var amazonCloudFrontDomain:String = "myCloudFrontDistributionID.cloudfront.net";
var amazonCloudFrontStreamURL:String = "rtmp://" + amazonCloudFrontDomain + "/cfx/st/";
var videoFileName:String = "myVideo.flv";
Security.allowDomain(amazonCloudFrontDomain);
Security.allowDomain("rtmp://" + amazonCloudFrontDomain);
Security.allowDomain(amazonCloudFrontStreamURL);
var client:Object = new Object();
client.onBWDone = function(e){trace("onBWDone: " + e);}
client.onMetaData = function(e){trace("onMetaData: " + e);}
client.onCuePoint = function(e){trace("onCuePoint: " + e);}
var video:Video = new Video(300, 400); // create a new Video item and set its width and height
video.x = 0; // position the video's x position
video.y = 0; // position the video's y position
var duration:Number; // use this later to get the duration of the video being played
this.addChild(video);
var nc:NetConnection = new NetConnection(); // variable for a new NetConnection
nc.client = client;
nc.addEventListener(NetStatusEvent.NET_STATUS,netConnectionStatusHandler,false,0,true);
nc.connect(amazonCloudFrontStreamURL); // set the nc variable to null
var ns:NetStream;
function netConnectionStatusHandler(e):void
{
switch(e.info.code)
{
case "NetConnection.Connect.Success":
trace("S3 Connected");
ns = new NetStream(nc); // create a variable for a new NetStream connection & connect it to the nc variable
ns.addEventListener(NetStatusEvent.NET_STATUS, netStreamStatusHandler); // add a listener to the NetStream to listen for any changes that happen with the NetStream
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, netStreamAsyncErrorHandler); // add a listener to the NetStream for any errors that may happen
ns.client = client;
video.attachNetStream(ns); // attach the NetStream variable to the video object
video.smoothing = true;
video.deblocking = 1;
ns.bufferTime = 5; // set the buffer time to 5 seconds
ns.play(videoFileName); // tell the netstream what video to play and play it
break;
}
trace(e.info.code);
}
function netStreamAsyncErrorHandler(Event:AsyncErrorEvent):void
{
// trace(event.text); // this will handle any errors with video playback
}
function netStreamStatusHandler(event:NetStatusEvent):void
{
trace(event.info.code); // this will handle any events that are fired when the video is playing back
switch(event.info.code) // switch statement to handle the various events with the NetConnection
{
case "NetStream.Buffer.Full": // when the buffer is full fire the code below
ns.bufferTime = 10; // set buffer time to 10 seconds break;
case "NetStream.Buffer.Empty": // when the buffer is empty fire, code below
ns.bufferTime = 10; // set buffer time to 10 seconds
break;
case "NetStream.Play.Start": // when the video starts playing, fire the code below
ns.bufferTime = 10; // set the buffer time to 10 seconds
break;
case "NetStream.Seek.Notify": // when you seek with the scrubber it sends a notify signal of the time
ns.bufferTime = 10; // set the buffer time to 10 seconds
break;
case "NetStream.Seek.InvalidTime": // when you release the scrubber ahead of the video that has been loaded, you get this error. it will jump you back to the last frame that has been loaded
ns.bufferTime = 10; // set the buffer time to 10 seconds
break;
case "NetStream.Play.Stop": // when you reach the end of the video
ns.pause(); // pause the video
ns.seek(1); // seek the video to the first frame
break;
}
}
This is the console output:
S3 Connected
netConnectionStatusHandler: NetConnection.Connect.Success
onBWDone: undefined
NetStream.Play.Reset
NetStream.Play.Start
...and nothing happens. No video, no audio, nothing. Can anyone see any problems with my code?

I believe that not all streaming applications have to use the onBWDone function, so if they don't use it, it probably passes null or undefined to the function instead of the kbps.
So you're problem is likely with the e in your trace statement below:
client.onBWDone = function(e){trace("onBWDone: " + e);}
Also, the function does not recieve an event object, but rather a ... rest array that usually only has one item in it. try this instead:
client.onBWDone = function(... rest){ //
if(rest && rest.length > 0){ //since the function might not get any data, you need to check before trying to trace it out
trace("onBWDone: " + rest[0]); //this is the kbps of the bandwidth available
}
};
You can learn more at the Adobe docs:
http://help.adobe.com/en_US/FlashMediaServer/3.5_Deving/WS5b3ccc516d4fbf351e63e3d11a0773d56e-7ffa.html
EDIT
In regards to your video path:
Flash Media Server applications are accessed in the following format over rtmp: "server:port/application/instance". For VOD, instance is the name of your file and for FLV's it doesn't require the extension.
http://help.adobe.com/en_US/FlashMediaServer/3.5_Deving/WS5b3ccc516d4fbf351e63e3d11a0773cfae-7ff3.html

I changed
var videoFileName:String = "myVideo.flv";
to
var videoFileName:String = "myVideo";
and now it works. For some reason, excluding the file extension makes it work for me. I don't know why...strange.

Related

Play two videos simultaneously with sync in AS3

I am busy with a project where two videos have to play on top of each other.
Like the one in the following site, http://kindnessday.sg/home#/kindness/home
Because of the large filesize I cannot embed the videos in the swf. It will become too large. Therefore the video's must be loaded thro' webstream link. But First video plays before the second video and causing the videos unsynced.
Is there a way to play both video at the same time?
var stream = 'http://mydomain/clip1.mp4'
var stream1 = 'https://mydomain/clip2.mp4'
var http_stream:URLStream = null
var http_stream1:URLStream = null
var video:Video = new Video() // the video is used only to ensure that stream is playing
var video1:Video = new Video() // the video is used only to ensure that stream is playing
addChild(video1)
addChild(video)
var nc:NetConnection = new NetConnection()
nc.connect(null)
var ns:NetStream = new NetStream(nc)
ns.client = new Object()
ns.client.onMetaData = function(e){}
ns.play(null)
var ns1:NetStream = new NetStream(nc)
ns1.client = new Object()
ns1.client.onMetaData = function(e){}
ns1.play(null)
video.attachNetStream(ns)
video1.attachNetStream(ns1)
http_stream = new URLStream();
http_stream.addEventListener(ProgressEvent.PROGRESS, on_Progress)
http_stream.load(new URLRequest(stream))
http_stream1 = new URLStream();
//http_stream1.addEventListener(ProgressEvent.PROGRESS, on_Progress1)
http_stream1.load(new URLRequest(stream1))
function on_Progress(e:ProgressEvent):void {
var b:ByteArray = new ByteArray()
http_stream.readBytes(b, 0, http_stream.bytesAvailable)
ns.appendBytes(b)
var b1:ByteArray = new ByteArray()
http_stream1.readBytes(b1, 0, http_stream1.bytesAvailable)
ns1.appendBytes(b1)
if (ns.appendBytes(b)==ns1.appendBytes(b1)){
ns.play(stream);
ns1.play(stream1);
}
}
why not not check how much of each video has loaded and when you have enough amount (you decide) then you can run some function to play both netstreams...
var min_amount : int = 500000; //for 500 kb minimum
var check_if_ready : Boolean = true;
Also on progressEvent function of loading (URLloader or URLstream???)..
if ( check_if_ready == true )
{
if( myA_NetStream.bytesLoaded >= min_amount && myB_NetStream.bytesLoaded >= min_amount )
{
myA_NetStream.play(); myB_NetStream.play();
//reset since not needed on further progressEvents during this load
check_if_ready = false;
}
}
}
This should only play when both videos have loaded x-amount of bytes. Therefore you can be sure none starts before another)
For better synchronization control you should get into handling bytes in Flash/AS3 and using the AppendBytes method because then you can control playback on a frame-by-frame basis for both NetStreams.

Using present time of video to manage all video in Action Script 3.0

I would like to use present time of video to manage all video. For example, I have some cue points, I choose it and video is now playing from this cue point, and after 10 sec video goes to other part and everything depends on present time of video. I do not use it on web so my video isn't loading (I mean that property of VideoProgressEvent like bytesLoaded will not help me). Is it possible to do it in action script 3.0 ? Another question is if I can add some transitions between cue points.
import fl.video.*;
// Video component instance name
var flvControl:FLVPlayback = display;
var flvSource:String = "myMovie.flv";
// Set video
flvControl.source = flvSource;
var myTextFormat:TextFormat = new TextFormat();
myTextFormat.size = 20
btn1.setStyle("textFormat", myTextFormat);
btn2.setStyle("textFormat", myTextFormat);
btn3.setStyle("textFormat", myTextFormat);
btn4.setStyle("textFormat", myTextFormat);
display.autoPlay = false;
// Add seek to time code
function seekToTimeHandler1(event:MouseEvent):void
{
var sec:Number = 15;
flvControl.seek(sec);
}
btn1.addEventListener(MouseEvent.CLICK, seekToTimeHandler1);
// Add seek to time code
function seekToTimeHandler2(event:MouseEvent):void
{
var sec:Number = 61;
flvControl.seek(sec);
}
btn2.addEventListener(MouseEvent.CLICK, seekToTimeHandler2);
// Add seek to time code
function seekToTimeHandler3(event:MouseEvent):void
{
var sec:Number = 63;
flvControl.seek(sec);
}
btn3.addEventListener(MouseEvent.CLICK, seekToTimeHandler3);
// Add seek to time code
function seekToTimeHandler4(event:MouseEvent):void
{
var sec:Number = 80;
flvControl.seek(sec);
}
btn4.addEventListener(MouseEvent.CLICK, seekToTimeHandler4);

How to play sound from microphone byte array in AS3?

I'm trying to play sound from ByteArray captured from the microphone and I'm expecting to hear the sound from the microphone but what I get is only random, distorted sound. This is the code that I'm using now :
var playBa:ByteArray;
var player:Sound = new Sound();
sound.addEventListener(SampleDataEvent.SAMPLE_DATA, playMic);
sound.play();
var mic:Microphone = Microphone.getMicrophone();
mic.gain = 100;
mic.rate = 44;
mic.setSilenceLevel(0, 4000);
mic.addEventListener(SampleDataEvent.SAMPLE_DATA, onMicSample);
function playMic(e:SampleDataEvent):void
{
if (playBa != null) e.data.writeBytes(playBa, 0, playBa.length);
}
function onMicSample(e:SampleDataEvent):void
{
playBa = e.data;
playBa.position = 0;
player.play();
}
And after a few seconds of distorted sounds, this is what I got on the Output Window:
RangeError: Error #2004: One of the parameters is invalid.
at flash.media::Sound/play()
at vclass_fla::MainTimeline/onMicSample()
Please help me. I'm a totally new to AS3 and here. Any help are highly appreciated. Thanks.
Some Microphones are very sensitive. You need to adjust moderate settings like shown below. Also, if speakers are closer to microphone the sound get looped.
var myMic:Microphone = Microphone.getMicrophone(); // detect microphone
myMic.gain = 50;
myMic.setUseEchoSuppression(true);
myMic.setLoopBack(true);
myMic.setSilenceLevel(50, 1000);
To more about Sound Capturing try this,
Capturing microphone sound data
The Problem is that sample data event requires blocks of 2048 to 8192 samples. If the samples recorded by microphone at the call of "playMic" the runtime throw "RangeError: Error #2004...".
function playMic(event:SampleDataEvent):void
{
trace("sample event");
for (var ii:uint = 0; ii < 8192 && playBa.bytesAvailable > 0 ; ii++)
{
var n1:Number = playBa.readFloat();
//trace(n1);
event.data.writeFloat(n1);
event.data.writeFloat(n1);
if(playBa.bytesAvailable == 0)
{
trace("data_finished");
break;
}
}
}

Preload a bit of FLV or F4V with the main project loader

My project has a main loader that load all the assets for the project. I need to load a bit of my video with it.
The video has 16mb, i want to load 3mb to use after the main loader is completed.
I've tried to open a new connection using Netconnection/Netstream to load 3mb and close the connection, but when the project starts and the video is played, a new connection is opened loading it from beginning.
I'm trying to find a way that i can use those 3mb already loaded. Doing this way, the user don't need to wait a main loader and a secondary loader (buffertime).
That's my code, sorry guys.
var loader:Loader = new Loader();
var nc:NetConnection = new NetConnection();
var ns:NetStream = new NetStream(nc);
var client:Object = new Object();
var swfRatio:Number;
var videoRatio:Number;
function init():void
{
nc.connect(null);
client.onCuePoint = cuePointHandler;
client.onMetaData = metaDataHandler;
ns.client = client;
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressLoader);
addEventListener(Event.ENTER_FRAME, progressTotal);
loader.load(new URLRequest("swf/main.swf"));
ns.play("f4v/main_movie.f4v");
ns.pause();
}
function progressLoader(event:ProgressEvent):void
{
swfRatio = (event.bytesLoaded / event.bytesTotal);
}
function progressTotal():void
{
//Here i get the amount that i want to preload from my video, in this case i want 3mb or 3072000 bytes
videoRatio = (ns.bytesLoaded / 3072000);
//This is a variable that i use to fill my loader asset and verify if my content its totaly loaded.
var frameValue:int = ((videoRatio + swfRatio) / 2) * 100;
if (frameValue >= 100)
{
removeEventListener(Event.ENTER_FRAME, progressTotal);
// Here i close my connection, i suppose that i need to use the same connection in my player.
ns.close();
ns = null;
nc.close();
nc = null;
loaderComplete();
}
}
function loaderComplete():void
{
removeChild(assetLoader);
//Here i add my player to the stage, i want to use the preloaded video with him.
addChild(loader.content);
}
function cuePointHandler(infoObject:Object):void {
trace(infoObject.name);
}
function metaDataHandler(infoObject:Object):void {
trace("metaData");
}
Then in my player that i've just loaded and added to the stage i'm using OSMF to help me with controls.
To test the "preloaded video" i'm doing this:
private var mediaPlayer:MediaPlayerSprite;
private function _init(e:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, _init);
mediaPlayer = new MediaPlayerSprite();
addChild(mediaPlayer);
//And here OSMF start to load the entire main_movie.f4v again.
mediaPlayer.resource = new URLResource("f4v/main_movie.f4v");
}
It looks like your strategy would work if you let the video download completely. I'm assuming if the video downloaded completely, the browser may cache it and make it available to the next NetStream that comes along.
Your strategy looks OK otherwise. What you are doing (playing, then pausing the video immediately) is the way to start buffering the video. But since there are two NetStream's being used (one by the main loader, the other by the OSMF player) this won't work.
Perhaps you can devise a scheme where you pass the NetStream from the main loader into the loaded SWF (main.swf). So that it can use the data it's already downloaded. Just a thought, I've never tried this.
Another idea would be to get the OSMF player in your main.swf to do the buffering. That would mean the buffering would start happening only after main.swf is loaded (which may be too late).

Recyclable Sound Object in Actionscript 3?

Using ONE Sound() object in Actionscript3, how can I play a one MP3 and then, when the user chooses a different one, play a second sound, using the SAME Sound() object?
EDIT: See my answer for how I did it.
You cannot use same Sound object to play multiple files.
Once load() is called on a Sound object, you can't later load a different sound file into that Sound object. To load a different sound file, create a new Sound object.
Ok, I actually did it using the following code. My bug was somewhere else in the FLA file, but this works. I made an uninitialized global variable and created the Sound() object LOCALLY inside of a function. While I'm technically using multiple sound objects, my references are all pointing to ONE object. Additionally, I can call these methods over one another for easier coding. This works for me:
/* -------------
Sound player
functions
------------ */
var snd:Sound; //the sound object
var sndC:SoundChannel; //the soudchannel used as "controller"
var sndT:SoundTransform; //soundTransform used for volume
var vol:Number = 1; //the volume of the song
var pan:Number = 0; //panning of the sound
var pos:Number = 0; //position of the song
var currentSound:String; //currently playing song?
function playSound(s:String){ //this function resets the sound and plays it
stopSound(sndC); //stop the sound from playing
snd = new Sound(); //reset the sound
snd.load(new URLRequest(s)); //load the desired sound
sndC = new SoundChannel(); //(re-)apply the sound channel
applyVolume(vol,pan,sndT,sndC); //apply the volume
sndC = snd.play(pos); //play it
sndC.addEventListener(Event.SOUND_COMPLETE, startSound); //remind it to restart playing when it's done
} //end function
function applyVolume(n:Number, p:Number, st:SoundTransform, sc:SoundChannel){ //takes an argument for the volume, pan, soundTYransform and soundChannel
sndT = new SoundTransform(n,p); //applies the soundTransfrom settings
sndC.soundTransform = sndT; //and attaches it to the soundChannel
} //end function
function stopSound(sndC:SoundChannel){ //this function stops a sound from playing
if(sndC != null){ //if the sound was used before (ie: playing)
if(currentLabel == "video-frame"){ //if we are in the video frame
pos = sndC.position; //store the position of the song to play from at a later time
}else{ //otherwise
pos = 0; //set the position at 0
} //end if
sndC.stop(); //stop it
} //end if
} //end function
function startSound(snd:Sound){ //restarts a sound when it's playing
if(snd != null){ //if the sound exists
sndC = snd.play(pos); //play it
} //end if
} //end function