Using URLStream to load part of a file - actionscript-3

When loading a file using a URLStream (or a URLLoader) is there any way to specify a range of bytes to load instead of loading the entire file in to memory?

This is kind of a broad question because of nuances. The short answer is No, loading URLs will give you the complete resource.
The longer answer:
URLLoader - No; it loads the complete resource. You do get progress events which tell you how much of the file has been loaded.
URLStream - Maybe; it makes data available in chunks as it is loaded. You can close the stream before it finishes downloading if the data you care about is at the beginning of the file. Note that the data is in raw binary form.
Revisit URLLoader - Maybe; you could write a server that takes a beginIndex and an endIndex, then call URLLoader.load('http://my-server/file?beginIndex=' + desiredBeginIndex + '&endIndex=' + desiredEndIndex);
You'll end up with only the portion of the file that you care about if you have a way of knowing which indices to specify.

...mmm... You could load and track the number of bytes. Then, when you've reached your desired number of bytes loaded, do a loader.close()... (Tracking and saving them with a progress event, a byte array, and a global number var)
I dont know about getting data from the middle though, but you can load any range of bytes from the beginning using that method.
Loader.close()
Closes the load operation in progress. Any load operation in progress is immediately terminated. If no URL is currently being streamed, an invalid stream error is thrown.

Related

Is there a way to write a |RtmpSampleAccess command to a NetStream in data generation mode?

I'm streaming data from a server and passing it into a net stream in data generation mode. I'm successfully wrapping H264 and PCMU to be played back through NetStream, however I need to be able to capture this output from the video display it's on and store it in an image. When using an RTMP server, I'd configure it to send an RtmpSampleAccess command, with true,true for audio and video access allowed. When using RTMFP I'd do the same, send() a RtmpSampleAccess true,true from the peer to allow access.
I believe I need to send in an FLV tag for a script data object to represent the RtmpSampleAccess command, however I can't find any information on what the format of that tag needs to be. I've tried using the OSMF FLVTagScriptDataObject with the objects set to the following combinations:
["|RtmpSampleAccess", true, true];
["|RtmpSampleAccess", [true, true]];
And various attempts at guessing the naming for object parameters (though looking at the protocol docs, I'm not sure there is one).
Could someone out there help me here, would be much appreciated.
Where you put your Netstream into Data Generation mode you add a second Play command. The second one simply plays "a blank" and for some reason this overrides the security error.
ns.play(null);
ns.play(""); //works to avoid all security errors
ns.appendBytesAction(NetStreamAppendBytesAction.RESET_BEGIN);
Then to draw just setup a button to run the draw_VideoFrame function when clicked, or try real-time drawing with something like below (using enterFrame):
vid_Obj.addEventListener(Event.ENTER_FRAME, draw_VideoFrame);
and then create a function like this example.
function draw_VideoFrame (e:Event) : void
{
vid_BMD.draw( vid_Obj ); //draw into a BitMapData variable
}

How to play a seamless loop from an AudioSprite in AS3, without SAMPLE_DATA

I created a batch of sounds assembled with this tool:
AudioSprite
https://github.com/tonistiigi/audiosprite
The output is generally used for JS libraries, such as Howler, Zynga Jukebox, or SoundJS - but I wanted to see if it's possible to implement in AS3.
I started creating a Sound player that can load, parse and play the sounds based on the JSON and MP3 file this tool generates.
So far so good! ... except for loops.
Now, the big question is - is there a way to play a Sound-loop seamlessly given that all music & sounds coexist in the same MP3 file, and it has a start & end range to play and stop it?
Example of how the sounds are placed in the file:
mygame_sounds.mp3 = [BUZZ + LASER + BOING ... + TRACKLOOP]
I'm looking for a solution that does not involve using the SAMPLE_DATA Event (given it eats up a lot of CPU usage). If there's no way around it, please explain why.
So far I've had mild success using flash.utils.Timer objects triggered after a given AudioSprite's duration, but it's not consistent.
To stop / dispose of a non-looping sound, I rely on a Master Timer (running at very short intervals) and that seems to "cut" the sample appropriately. But I already tried using this Master Timer to play a looped-sound over and over - same latency issues.
Is there any method to predict / measure how much latency is to be expected by the time the sound completes one pass?
In SoundJS we could not find a way to allow smooth looping of audio sprites in AS3 and went with a timer. We found Web Audio was the only api that allowed smooth looping, and therefore recommended staying away from audiosprites for sounds that needed to loop smoothly if any other plugin might be used.
Hope that helps.
The reason of why you can't get smooth loops of a track retrieved from a larger audio file is that you cannot check sound position faster than once per SWF frame, which length depends on stage.frameRate and total processing time of your application and is generally varied. So, if your looping sounds lasts say 5.123 seconds (I don't care how many samples, just that its length does not make a full number of frames regardless of stage.frameRate), your sound will attempt to play for either 5.125 seconds (205 frames at 40 fps, IMO best bet for this particular sound), 5.133 seconds (154 frames at 30 fps) or some weird number of frames if the SWF would experience lag. The excess milliseconds cannot be totally controlled by any means due to AS3/Flash engine optimization. So, consider not using audio sprites and shift into audio packs (several audio files in an SWF, or one sound in an MP3).
Although I'm still working on the perfect solution, this is the best I could come up with:
Load the JSON file / ByteArray.
Parse the JSON file to obtain each sprites' ID, start and end times.
Load the MP3 file / ByteArray (requires loadCompressedDataFromByteArray()) into a master Sound object.
Once loaded, check if any sprites are marked as "loops".
Create separate Sound objects for the above loops, and extract the portion from the master Sound via loadPCMFromByteArray() with some "magic-numbers" (details below).
To play a one-shot sound, call the master Sound's play(sprite.start * 1000) (depending on the format, usually the JSON's start values are in seconds, needs to be in milliseconds).
To play a seamless-loop sound, call the individual Sound object's (created in step #5) play(0, 9999) method.
I won't go too deep in details on how to stop the sounds (SoundChannel.stop(), bam!), but I'll explain the "magic-numbers" mentioned above. See this snippet:
var goldenOffset:UInt = (64 << 5);
var goldenDuration:UInt = (64 << 2);
var sampleRate:UInt = 44100;
for (id in loops) {
var sprite:AudioSpriteItem = _mapSprites.get(id);
var loop:Sound = _mapLoops.get(id);
var sampleBytes = new ByteArray();
var samplesTotal:UInt = cast(sprite.duration * sampleRate + goldenDuration);
var samplesStart:UInt = cast(sprite.start * sampleRate + goldenOffset);
_sound.extract(sampleBytes, samplesTotal, samplesStart);
sampleBytes.position = 0;
loop.loadPCMFromByteArray(sampleBytes, samplesTotal, "float", true);
}
Quite honestly, these magic goldenOffset and goldenDuration values were just found via Trial-and-Error. I could get close to a seamless loop without them by just calculating the start and duration with the sampleRate (assuming 44100 by default), but each endings had a bit of a hiccup to it.
After several adjustments, those couple "64 left bit-shifted" values made the loops sound smoother.
I posted the Haxe project on github (compiled SWC also available in /bin folder) if you wish to try it / read through the code.
FLAudioSprite
Github page: https://github.com/bigp/FLAudioSprite
SWF Demo (Download): bit.ly/FLAudioSpriteSWFDemo

How does the Flash/AS3 player read the length of mp3 files?

I have an AS3 music player built into an app that I'm putting together. It works perfectly with almost every file I've used, but there is one file that it stops early on. The file is roughly 56 seconds long, the player stops at about 44 seconds. I'm using trace to show the length, and for every other song the length is correct. In this case, trace shows roughly 44 seconds instead of 56. Here's the code I use to load the file:
length = 0;
request = new URLRequest(fileAddress);
track = new Sound();
track.load(request);
track.addEventListener(Event.COMPLETE, TrackLoaded);
And here's the TrackLoaded function:
private function TrackLoaded(e:Event):void{
length = track.length;
if (playWhenLoaded == true){
trackChannel = track.play(0);
trackChannel.addEventListener(Event.SOUND_COMPLETE, TrackFinishedPlaying);
playWhenLoaded = false;
}
Works perfectly with every other file. What am I missing?
Are you willing to host this 56 sec MP3 somewhere for download & analysis? Or if you can yourself check the header info via a Hexeditor. I suspect either of two things:
1) Header has incorrect time length embedded and Flash takes that as final duration and stops there. After all why read anymore remaining bytes? they could be just metadata not audio samples Besides what encoder would lie about true duration? So its accepted as final duration even if your ears know that its incorrect.
2) MP3 samplerate /bitrate issue: Consider what sample rate is this one problem MP3? Check the sample rate against of a working MP3. Also are these various found sounds or you made each yourself? I ask to confirm you put the same settings for each file yet this one does not work?
In anycase I think you could solve this particular MP3 by re-encoding it. Maybe save as WAV or AIFF first then take that new uncompressed audio and convert back to a MP3 with samplerate of 44100 khz + Stereo sound + Constant Bitrate (avoid Variable B.Rate like hell if you dont want issues)
Checking and fixing either of the above should get you are correctly parsed MP3. Hope it helps

IOError 2032 happens sometimes

My application loads 60 files at the same time. I mean I create 60 loaders (in an array) and start all loadings in a loop, I don't wait for one to complete before I start the next.
I use a class that extends URLLoader to load xml, bin, png, mp3 and swf.
I log when users get a IOErrorEvent, and I see error 2032 happen sometimes, not always with the same file, and when I try again, the loading completes.
Do you know why I could have a random 2032 error with URLLoader ?
Edit : Is URLLoader appropriate to load many files at a time ? Should I better have an open connection, request all the files, then close the connection ?
It could be because of improper handling of Loader Events and data associated with it.
You can try using:
BulkLoader Class by Arthur Debert
they have done some reliable work in this regard.

WinInet: Why does first ever HttpSendRequest take longer?

I promise this isn't as simple as it sounds. I'm wondering why the the first ever call to HttpSendRequest takes much longer than subsequent calls, even when the later requests are for a different URL. For example:
InternetConnect(... "foo.com" ...) // returns immediately
HttpOpenRequest(...) // returns immediately
HttpSendRequest(...) // takes ~3 sec
HttpSendRequest(...) // takes ~200 ms
InternetConnect(... "bar.com" ...) // returns immediately
HttpOpenRequest(...) // returns immediately
HttpSendRequest(...) // takes ~200 ms
Why does the first HttpSendRequest(...) take so much longer? This is very consistent, regardless of the URLs.
Thanks,
Greg
There are several things that may need to happen on the first request that don't need to happen on the second. DNS lookup and proxy detection immediately come to mind.
It could also be config file loading. Some of the .Net framework classes will attempt to read settings from the application config file, revertign to defaults if no file or setting is found. E.g. WebRequest/WebClient which I think are Http classes use under the hood will check for explicit web proxy settings, if those don't exist then then proxy setting from the OS (as set within IE) are picked up. Allof this contributes to an initial startup lag usually when the class is first used, that is, the work is often done in within a static contructor.
The config settings are defined here:
Configuration File Schema for the .NET Framework