ActionScript, NetStream.Play.Failed iOS AIR mobile - ios

I'm trying to stream local audio files in m4a (aac) similar to Tiberiu-IonuČ› Stan (http://stackoverflow.com/questions/2036107/aac-mp4-not-working-in-actionscript-3s-netstream):
package
{
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.events.NetStatusEvent;
import flash.events.AsyncErrorEvent;
import flash.events.Event;
public class Mysound
{
private var _connection:NetConnection;
private var _netStream:NetStream;
private var _filePath:String;
private var _client:Object;
public function MainDocument(filePath:String):void
{
_filePath = filePath;
connect();
}
private function connect():void
{
_connection=new NetConnection();
_connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
_connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
_connection.connect(null);
}
private function netStatusHandler(event:NetStatusEvent):void
{
switch (event.info.code)
{
case "NetConnection.Connect.Success":
requestAudio();
break;
}
}
private function requestAudio():void
{
_netStream=new NetStream(_connection);
_netStream.addEventListener(NetStatusEvent.NET_STATUS, this._netStatusHandler);
_netStream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, this._asyncErrorHandler);
_client = new Object();
_client.onMetaData = onMetaData;
_netStream.client = _client;
_netStream.backBufferTime = 0;
_netStream.bufferTime = 0.5;
_netStream.bufferTimeMax = 5;
_netStream.play(filePath);
}
private function asyncErrorHandler(event:AsyncErrorEvent):void
{
trace(event);
}
private function onMetaData(metadata:Object):void
{
var str:String = "";
for (var key:String in metadata) {
str += key + ": " + metadata[key];
}
trace(str);
}
}
}
It works for me on emulator but it doesn't on devices (ipads).
I found out that netStatusHandler on device catches status "NetStream.Play.Failed", but i have no idea why, I know that it correctly reads file as it does get correct metadata, it also starts to buffer sound, but fails to play it. Files are in folder next to my app swf so it shouln't be sandbox problem. What else should I try to get it working?

Related

How can I get native MediaStreamTrack from WebRtc MediaStreamTrackWeb object

I want to mix MediaStreamTrack objects in Dart using the package:universal_html/js.dart library.
JsAudioContext audioContext = JsAudioContext();
audioContext.initialize();
var senders = await call!.peerConnection!.getSenders();
for (var sender in senders) {
for (var track in senderTracks) {
if (sender.track!.id != track.id) {
audioContext.connect(track);
}
}
}
But WebRtc hides the jsTrack native object inside the MediaStreamTrackWeb object.
How can I access this object ?
Is there anyone have an idea ?
I found the solution using the js_bindings library.
The library's MediaStream.getTracks() method throws a type error.
I solved this problem using js_util interop.
JsAudioContext.dart:
import 'dart:convert';
import 'package:flutter_webrtc/flutter_webrtc.dart' as webrtc;
import 'package:dart_webrtc/src/media_stream_track_impl.dart' as track_impl;
import 'package:js_bindings/js_bindings.dart' as js_bindings;
import 'package:universal_html/html.dart' as html;
import 'dart:js_util' as js_util;
class JsAudioContext {
js_bindings.AudioContext? audioContext;
js_bindings.MediaStreamAudioDestinationNode? destinationNode;
JsAudioContext() {
audioContext = js_bindings.AudioContext();
}
void createMediaStreamDestination() {
destinationNode = audioContext?.createMediaStreamDestination();
}
void connect(webrtc.MediaStreamTrack? trackWeb) {
track_impl.MediaStreamTrackWeb mediaStreamTrackWeb =
trackWeb as track_impl.MediaStreamTrackWeb;
html.MediaStreamTrack htmlTrack = mediaStreamTrackWeb.jsTrack;
var sourceStream = audioContext?.createMediaStreamSource(
js_bindings.MediaStream([htmlTrack as js_bindings.MediaStreamTrack]));
sourceStream?.connect(destinationNode!);
}
webrtc.MediaStreamTrack getMixedTrack() {
List<dynamic> outputTrack =
js_util.callMethod(destinationNode!.stream, 'getTracks', []);
webrtc.MediaStreamTrack rtcTrack = track_impl.MediaStreamTrackWeb(
outputTrack.toList()[0] as html.MediaStreamTrack);
return rtcTrack;
}
}
sip_call_event_service.dart:
#override
Future startConference(List<SipCallData> activeCallList) async {
List<webrtc.MediaStreamTrack> receivedTracks = <webrtc.MediaStreamTrack>[];
for (var item in activeCallList) {
Call? call = sipuaHelper!.findCall(item.id!);
var receives = await call!.peerConnection!.getReceivers();
for (var element in receives) {
receivedTracks.add(element.track!);
}
}
JsAudioContext jsAudioContext = JsAudioContext();
for (var item in activeCallList) {
Call? call = sipuaHelper!.findCall(item.id!);
jsAudioContext.createMediaStreamDestination();
var receivers = await call!.peerConnection!.getReceivers();
for (var receiver in receivers) {
for (var track in receivedTracks) {
if (receiver.track!.id != track.id) {
jsAudioContext.connect(track);
}
}
}
var senders = await call.peerConnection!.getSenders();
for (var sender in senders) {
jsAudioContext.connect(sender.track);
}
await senders.first.replaceTrack(jsAudioContext.getMixedTrack());
}
}

ActionScript 3.0 and 'TypeError: Error#1034: type Coercion failed'

I'm currently following a tutorial, and I watched it like 6-7 times over, but for some reason I keep getting:
TypeError: Error#1034: type Coercion failed.
I'm trying to make a matching game for a school assignment, and I currently have this:
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
import flash.events.MouseEvent;
public class MatchingGame extends MovieClip {
var fClip:Logo
var sClip:Logo
var myTimer:Timer
var frames:Array = new Array(1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10);
public function MatchingGame() {
// Constructor code
for(var i:Number=1; i<=5; i++) {
for(var j:Number=1; j<=4; j++) {
var myLogo:Logo = new Logo();
var index = Math.floor(Math.random() * frames.length)
myLogo.frameNo = frames[index];
frames.splice(index, 1);
addChild(myLogo);
myLogo.x = j*100;
myLogo.y = i*100;
myLogo.gotoAndStop(11);
myLogo.addEventListener(MouseEvent.CLICK, openLogo);
}
}
}
private function openLogo(e:MouseEvent) {
var clickObj:Logo = Logo(e.target);
if(fClip == null) {
fClip = clickObj;
fClip.gotoAndStop(fClip.frameNo);
}
else if(sClip == null && fClip != clickObj) {
sClip = clickObj;
sClip.gotoAndStop(sClip.frameNo);
if(fClip.frameNo == sClip.frameNo) {
myTimer = new Timer(1000, 1);
myTimer.start();
myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, removeLogos);
}
else {
myTimer = new Timer(1000, 1);
myTimer.start();
myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, resetLogos);
}
}
}
private function removeLogos(e:TimerEvent) {
removeChild(fClip);
removeChild(sClip);
myTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, removeLogos);
fClip = null;
sClip = null;
}
private function resetLogos(e:TimerEvent) {
fClip.gotoAndStop(11);
sClip.gotoAndStop(11);
myTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, resetLogos);
fClip = null;
sClip = null;
}
}
}
The error pops up at line 38 and when I try debugging it tell me that clickObj is undefined.
How can I fix this problem?
This is the entire error message:
TypeError: Error #1034: Type Coercion failed: cannot convert flash.display::MovieClip#a3e4a61 to Logo.
at MatchingGame/openLogo()[H:\Informatica\Matching game\MatchingGame.as:39]
It looks like the cast from MovieClip to Logo isn't working.
put a trace before that line to see what event.target is.
Depending on the display list structure and event bubbling, you might be getting a different element that what you expect.
Try var clickObj:Logo = Logo(e.currentTarget); as a quick test.
Be sure to go through Trevor McCauley's article to get a better understanding of event bubbling.

Upload Library or captured images on iOS with Flex Mobile 4.6

Does anyone have any experience with the Camera APIs in Flex 4.6 with iOS? I'm running into a lot of setup issues and the documentation is lacking. I'm trying to setup an image upload component where a user can either capture a new photo or choose an existing from their library.
For capturing, there seems to be a huge hang (like 10 seconds where the app just sits non-responsive) when the image is being saved as a JPEG, and I'm using the Alchemy swc.
private var cam:CameraUI;
protected function takePhotoHandler(event:MouseEvent):void
{
if(CameraUI.isSupported) {
cam = new CameraUI();
cam.addEventListener(MediaEvent.COMPLETE, mediaEventComplete);
cam.launch(MediaType.IMAGE);
}
}
protected function mediaEventComplete(e:MediaEvent):void
{
cam.removeEventListener(MediaEvent.COMPLETE, mediaEventComplete);
status.text = "Media captured..." ;
var imagePromise:MediaPromise = e.data;
var loader:Loader = new Loader();
if(imagePromise.isAsync) {
status.text = "Asynchronous media promise." ;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, asyncImageLoadHandler);
loader.addEventListener(IOErrorEvent.IO_ERROR, asyncImageErrorHandler);
loader.loadFilePromise(imagePromise);
} else {
status.text = "Synchronous media promise.";
loader.loadFilePromise(imagePromise);
img.source = loader.content;
saveImage(loader.contentLoaderInfo);
}
}
protected function asyncImageLoadHandler(e:Event):void
{
status.text = "Media loaded in memory.";
img.source = e.currentTarget.loader.content;
saveImage(e.currentTarget.loader.contentLoaderInfo);
}
protected function saveImage(loaderInfo:LoaderInfo):void
{
if(CameraRoll.supportsAddBitmapData){
var bitmapData:BitmapData = new BitmapData(loaderInfo.width, loaderInfo.height);
bitmapData.draw(loaderInfo.loader);
d_trace("bitmapDraw");
//var c:CameraRoll = new CameraRoll();
//c.addBitmapData(bitmapData);
d_trace("writing to disk");
var f:File = File.applicationStorageDirectory.resolvePath("temp");
var stream:FileStream = new FileStream()
stream.open(f, FileMode.WRITE);
d_trace("encoding start");
var baSource: ByteArray = bitmapData.clone().getPixels( new Rectangle( 0, 0, loaderInfo.width, loaderInfo.height) );
var bytes: ByteArray = as3_jpeg_wrapper.write_jpeg_file(baSource, loaderInfo.width, loaderInfo.height, 3, 2, 80);
d_trace("encoding end");
stream.writeBytes(bytes,0,bytes.bytesAvailable);
stream.close();
d_trace(f.url);
img.source = f.url;
d_trace("UPLOADING START");
f.addEventListener(Event.COMPLETE,uploadCompleteHandler);
f.addEventListener(Event.OPEN,openUploadHandler);
f.upload(urlRequest);
}
}
For choosing from the library, I can't get a file reference to actually start the upload. When the select is made, the mediaPromise.file value is null. mediaPromise.isAsync is true and I can attach a loader listener but that only returns the contentLoaderInfo, which has no reference to the actual File or a FileRefernce, so I can't call the upload method without creating a temp image, which seems expensive and crazy.
protected function chooseImage(): void {
if(CameraRoll.supportsBrowseForImage) {
var roll: CameraRoll = newCameraRoll();
roll.addEventListener( MediaEvent.SELECT, roll_selectHandler );
var options:CameraRollBrowseOptions = new CameraRollBrowseOptions();
roll.browseForImage(options);
}}
private function roll_selectHandler( event: MediaEvent ): void
{
var imagePromise:MediaPromise = event.data;
if(imagePromise.isAsync) {
// Here's where I get. Not sure how to get the reference to the file I just selected.
}}
Any help would be appreciated.
Thanks!
I think I found a solution for works for my case so I wanted to share it in case it can help someone out. shaunhusain's post definitely got me moving in the right direction. I was able to avoid using the Alchemy swc all together which saves a TON of time in the app. The key is this AS3 library I found that formats a URLRequest in a way that mimics a standard file upload POST operation. Here's the basic outline:
I have a small component called 'status' thats an overlay with an icon and status text for the user. When a user wants to add a photo, they get a ViewMenu with the choices to get the photo from their library or take a new photo. The meat of the code is below.
//IMAGE HANDLING
//Helpful Links:
//http://www.quietless.com/kitchen/dynamically-create-an-image-in-flash-and-save-it-to-the-desktop-or-server/
//http://stackoverflow.com/questions/597947/how-can-i-send-a-bytearray-from-flash-and-some-form-data-to-php
// GET WRAPPER CLASS Here: http://code.google.com/p/asfeedback/source/browse/trunk/com/marston/utils/URLRequestWrapper.as
//This part is basically all based on http://www.adobe.com/devnet/air/articles/uploading-images-media-promise.html
protected var cameraRoll:CameraRoll = new CameraRoll();
//User choose to pick a photo from their library
protected function chooseImage():void {
if( CameraRoll.supportsBrowseForImage )
{
cameraRoll.addEventListener( MediaEvent.SELECT, imageSelected );
cameraRoll.addEventListener( Event.CANCEL, browseCanceled );
cameraRoll.addEventListener( ErrorEvent.ERROR, mediaError );
cameraRoll.browseForImage();
} else {
trace( "Image browsing is not supported on this device.");
}
}
//User choose to take a new photo!
protected var cameraUI:CameraUI = new CameraUI();
protected function captureImage():void
{
if( CameraUI.isSupported )
{
trace( "Initializing..." );
cameraUI.addEventListener( MediaEvent.COMPLETE, imageSelected );
cameraUI.addEventListener( Event.CANCEL, browseCanceled );
cameraUI.addEventListener( ErrorEvent.ERROR, mediaError );
cameraUI.launch( MediaType.IMAGE );
} else {
trace( "CameraUI is not supported.");
}
}
private function browseCanceled (e:Event):void
{
trace ("Camera Operation Cancelled");
}
private function mediaError (e:ErrorEvent):void
{
trace ("mediaError");
}
private var dataSource:IDataInput;
private function imageSelected( event:MediaEvent ):void
{
trace( "Media selected..." );
var imagePromise:MediaPromise = event.data;
dataSource = imagePromise.open();
if( imagePromise.isAsync )
{
trace( "Asynchronous media promise." );
var eventSource:IEventDispatcher = dataSource as IEventDispatcher;
eventSource.addEventListener( Event.COMPLETE, onMediaLoaded );
} else {
trace( "Synchronous media promise." );
readMediaData();
}
}
private function onMediaLoaded( event:Event ):void
{
trace("Media load complete");
readMediaData();
}
private function readMediaData():void
{
var imageBytes:ByteArray = new ByteArray();
dataSource.readBytes( imageBytes );
upload(imageBytes);
}
//OK Here's where it gets sent. Once the IDataInput has read the bytes of the image, we can send it via our custom URLRequestWrapper
//which will format the request so the server interprets it was a normal file upload. Your params will get encoded as well
//I used Uploadify this time but I've used this Wrapper class in other projects with success
protected function upload( ba:ByteArray, fileName:String = null ):void
{
if( fileName == null ) //Make a name with correct file type
{
var now:Date = new Date();
fileName = "IMG" + now.fullYear + now.month +now.day +
now.hours + now.minutes + now.seconds + ".jpg";
}
var loader:URLLoader = new URLLoader();
loader.dataFormat= URLLoaderDataFormat.BINARY;
var params:Object = {};
params.name = fileName;
params.user_id = model.user.user_id;
var wrapper:URLRequestWrapper = new URLRequestWrapper(ba, fileName, null, params);
wrapper.url = "http://www.your-domain.com/uploadify.php";
loader.addEventListener( Event.COMPLETE, onUploadComplete );
loader.addEventListener(IOErrorEvent.IO_ERROR, onUploadError );
loader.load(wrapper.request);
}
private function onUploadComplete(e:Event):void
{
trace("UPLOAD COMPLETE");
var bytes:ByteArray = e.currentTarget.data as ByteArray;
//Most likely you'd want a server response. It will be returned as a ByteArray, so you can get back to the string:
trace("RESPONSE", bytes.toString());
}
private function onUploadError(e:IOErrorEvent):void
{
trace("IOERROR", e.text);
}

AIR application: Cannot access a property or method of a null object reference. No idea what's causing this

I'm using code for the open source MP3 player Howler and trying to port it to a Spark MobileApplication type. I'm getting a null pointer exception and I have no idea what's causing it. I've tried debugging extensively with breakpoints at what I think is causing the error, and set breakpoints in the untouched Howler project but all the variables in scope seem to be identical between my non-working project, and the Howler project. The only thing I can think of is that Howler uses MX components and I am using spark. I've pasted all my code below (which is very long) but I've bolded the lines that are throwing the error. The error occurs immediately after I choose a folder in the browse folder dialog.
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="Home"
xmlns:Comp="components.*" xmlns:display="flash.display.*">
<s:Button id="browse" x="546" y="43" label="Open Directory" click="browseForFolder()"/>
<s:DataGrid id="dgPlaylist" width="82" height="141" itemRenderer="components.DurationFormatter">
</s:DataGrid>
<s:Button id="btnForward" x="187" y="126" label="Forward"/>
<s:Button id="btnPause" x="90" y="39" label="Pause"/>
<s:Button id="btnBack" x="55" y="166" label="Back" click="changeSoundIndex(-1)"/>
<s:Button id="btnPlay" x="336" y="199" label="Button"/>
<s:Button id="btnStop" x="366" y="89" label="Stop"/>
<s:VScrollBar id="sldrPosition" x="280" y="43" mouseDown="thumbTimer.stop()"
mouseUp="thumbTimer.start()"
/>
<s:VScrollBar id="sldrVolume" x="265" y="234" change="ChangeSoundTransform()"
/>
<s:RichText id="txtID3" x="236" y="41" width="99">
</s:RichText>
<fx:Declarations>
</fx:Declarations>
<fx:Script>
<![CDATA[
import com.ericcarlisle.PlayList;
import com.ericcarlisle.PlayModes;
import com.ericcarlisle.Utility;
import flash.desktop.NativeDragManager;
import flash.media.Sound;
import mx.core.UIComponent;
import mx.events.CloseEvent;
import mx.events.DragEvent;
import org.osmf.traits.PlayTrait;
import spark.components.DataGrid;
// Player properties
private var playMode:String = "STOP";
private var volume:uint;
private const panning:int = 0;
private var selectedFileCount:uint;
private var loadedFileCount:uint;
private var soundIndex:uint;
// Player objects
private var SoundObj:Sound;
private var Channel:SoundChannel;
private var Transform:SoundTransform;
private var thumbTimer:Timer;
private var PlayList:com.ericcarlisle.PlayList;
private var SoundFilter:FileFilter = new FileFilter("Sounds", "*.mp3;*.wav");
//private var PlaylistFilter:FileFilter = new FileFilter("Sounds", "*.pls;*.m3u");
// Visualization objects.
private var Spectrum:ByteArray;
private const VISUALIZER_HEIGHT:Number = 50;
private const VISUALIZER_COLOR:Number = 0x336699;
// ID3 and other metadata
private var ID3:ID3Info;
private var Duration:int;
/*---------- PLAYER INITIALIZER ----------*/
// Initialization function used to add event handlers and set initial settings.
private function init():void
{
// Set player initial settings.
playMode = PlayModes.STOP;
selectedFileCount = 0;
loadedFileCount = 0;
soundIndex = 0;
// Set initial application height.
//this.height= cvsControlBar.height + cvsPlayer.height;
// Set volume.
volume = sldrVolume.value;
// Instantiate sound objects.
Channel = new SoundChannel();
Transform = new SoundTransform(volume/100, panning);
PlayList = new com.ericcarlisle.PlayList();
// Bind playlist data to datagrid.
dgPlaylist.dataProvider = PlayList.Sounds;
// Create a timer to control the song position hslider.
thumbTimer = new Timer(500);
thumbTimer.addEventListener(TimerEvent.TIMER, onTimerTick);
// Create event handlers for application.
this.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, onPlayerDragInto);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, onPlayerDropInto);
this.addEventListener(InvokeEvent.INVOKE, onInvoke);
}
/*---------- DRAG/DROP & FILE MANAGEMENT ----------*/
private function onInvoke(event:InvokeEvent):void
{
if (event.arguments.length > 0)
{
var file:File;
var files:Array = new Array();
for (var i:int = 0; i < event.arguments.length; i++)
{
file = new File(event.arguments[i]);
files.push(file);
}
if (PlayList.Sounds.length > 0) removeAllSounds();
loadFiles(files);
}
}
// Handles file selection event dispatched by browse dialog.
private function onFileSelect(event:FileListEvent):void
{
loadFiles(event.files);
}
// Handles folder selection event dispatched by browse dialog.
private function onDirectorySelect(event:Event):void
{
var directory:File = event.target as File;
**loadFiles(directory.getDirectoryListing());**
}
// Loads a batch of files into the playlist.
private function loadFiles(files:Array):void
{
var file:File;
// Count the number of files selected. Only accept files with .mp3 extension.
selectedFileCount = 0;
for (var i:uint = 0; i < files.length; i++)
{
file = files[i];
if (file.extension == "mp3") selectedFileCount++;
}
// Reset the count on files currently loaded.
loadedFileCount = 0;
**// Set the player mode so that loaded files are played automatically.
if (PlayList.Sounds.length == 0) playMode = PlayModes.LOADTOPLAY;**
// Load files as sound objects.
for(var j:uint = 0; j < files.length; j++)
{
file = files[j];
if (file.extension == "mp3" || file.extension == "wav")
{
var sound:Sound = new Sound(new URLRequest(file.url));
sound.addEventListener(Event.ID3,onID3);
}
}
}
// Presents file browse (multiple file) dialog.
private function browseForFiles():void
{
var SoundFile:File = new File();
SoundFile.browseForOpenMultiple("Open", [SoundFilter]);//, PlaylistFilter]);
SoundFile.addEventListener(FileListEvent.SELECT_MULTIPLE, onFileSelect);
}
// Presents file browse (folder) dialog.
private function browseForFolder():void
{
var directory:File = File.documentsDirectory;
directory.browseForDirectory("Select Directory");
directory.addEventListener(Event.SELECT, onDirectorySelect);
}
// Accept files dragged into player.
private function onPlayerDragInto(event:Event):void
{
NativeDragManager.acceptDragDrop(this);
}
// Manages files dropped into player.
private function onPlayerDropInto(event:NativeDragEvent):void
{
// Accept only files.
if (event.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
{
// Parse dragged contents into array of files.
var dragFiles:Array = event.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
// Load the files.
loadFiles(dragFiles);
}
}
/*---------- SOUND MANAGEMENT ----------*/
private function loadSound():void
{
SoundObj = new Sound();
SoundObj.load(new URLRequest(PlayList.Sounds[soundIndex]["url"]));
SoundObj.addEventListener(Event.COMPLETE, onSoundLoaded);
}
private function onSoundLoaded(event:Event):void
{
// Retrieve data for current sound from playlist.
var soundData:Object = PlayList.Sounds[soundIndex];
// Place ID3 information into the readout panel.
//txtID3.htmlText = Utility.ReadoutHTML(soundData["title"], soundData["track"], soundData["album"], soundData["artist"], soundData["year"], soundData["duration"]);
// Configure the holizontal slider to act as a playhead.
sldrPosition.maximum = soundData["duration"];
// Set the selected row in the playlist display.
dgPlaylist.selectedIndex = soundIndex;
// Start the player if the mode is correct.
if (playMode == PlayModes.LOADTOPLAY)
{
playSound();
}
else
{
playMode = PlayModes.LOADED;
}
}
// Plays the current sound.
public function playSound():void
{
// Load sound into channel.
Channel.stop();
Channel = SoundObj.play(sldrPosition.value,0,Transform);
playMode = PlayModes.PLAY;
// Start position timer.
thumbTimer.start();
// Configure UI controls.
btnPlay.visible = false;
btnPause.visible = true;
sldrPosition.enabled = true;
btnPlay.enabled = true;
btnStop.enabled = true;
setBackForwardButtons();
Channel.addEventListener(Event.SOUND_COMPLETE, onSoundComplete);
}
private function setBackForwardButtons():void
{
if (soundIndex == PlayList.Sounds.length-1 || PlayList.Sounds.length == 0)
{
btnForward.enabled = false;
}
else
{
btnForward.enabled = true;
}
if (soundIndex == 0 || PlayList.Sounds.length == 0)
{
btnBack.enabled = false;
}
else
{
btnBack.enabled = true;
}
}
// Stops the current sound.
public function stopSound():void
{
Channel.stop();
thumbTimer.stop();
sldrPosition.value = 0;
playMode = PlayModes.STOP;
//Visualizer.graphics.clear();
btnPlay.visible = true;
btnPause.visible = false;
}
// Pause a playing sound.
private function pauseSound():void
{
Channel.stop();
thumbTimer.stop();
btnPlay.visible = true;
btnPause.visible = false;
}
// Change the sound index
private function changeSoundIndex(delta:int):void
{
stopSound();
playMode = PlayModes.LOADTOPLAY;
soundIndex = soundIndex + delta;
loadSound();
}
// Change the volume and panning via the sound transform object.
private function ChangeSoundTransform():void
{
volume = Math.round(sldrVolume.value);
Channel.soundTransform = new SoundTransform(volume/100, panning);
}
// Handles event for sound completing.
private function onSoundComplete(event:Event):void
{
stopSound();
soundIndex++;
if (soundIndex < PlayList.Sounds.length)
{
playMode = PlayModes.LOADTOPLAY;
loadSound();
}
}
// Load ID3 information into local variables.
// Update the readout panel.
// Configure position slider.
private function onID3(event:Event):void
{
var sound:Sound = Sound(event.target);
ID3 = ID3Info(sound.id3);
Duration = Math.floor(sound.length);
// Load sound id3 data into the playlist.
PlayList.AddSound(ID3.songName, ID3.album, ID3.artist, ID3.track, ID3.year, ID3.genre, Duration, sound.url);
// Increment the loaded file count.
loadedFileCount++;
if (loadedFileCount == selectedFileCount * 2)
{
// Refresh the playlist so that new results will be visually displayed.
PlayList.Sounds.refresh();
// Set the count properties.
selectedFileCount = 0;
loadedFileCount = 0;
soundIndex = 0;
if (playMode == PlayModes.LOADTOPLAY) loadSound();
}
}
/*---------- VISUALIZATION ----------*/
private function UpdateVisualizer():void
{
// Instantiate a new byte array to contain spectrum data.
Spectrum = new ByteArray();
// Clear the visualizer graphics.
//Visualizer.graphics.clear();
// Dump the spectrum data into the byte array.
SoundMixer.computeSpectrum(Spectrum,false,0);
var f:Number;
var i:int;
var ave:int;
//Visualizer.graphics.lineStyle(1, VISUALIZER_COLOR,1);
//Visualizer.graphics.beginFill(VISUALIZER_COLOR, 0.75);
for (i = 0; i < 512; i=i+10)
{
f = Spectrum.readFloat();
//Visualizer.drawRoundRect(Math.floor(i*0.7) + 7, cvsReadout.height - 10, 4, -Math.abs(f) * (cvsReadout.height-10));
}
//Visualizer.graphics.endFill();
}
// Updates the position of the hslider thumb.
private function onTimerTick(event:TimerEvent):void
{
sldrPosition.value = Math.round(Channel.position);
}
// Update the wave visualizer if the sound is playing.
private function onEnterFrame(event:Event):void
{
if (playMode == PlayModes.PLAY)
{
UpdateVisualizer();
}
}
// Show application information.
private function showHowlerInfo():void
{
//cvsAbout.visible = true;
}
private function togglePlayList():void
{
}
private function onItemDoubleClick(event:Event):void
{
this.playMode = PlayModes.LOADTOPLAY;
thumbTimer.stop();
sldrPosition.value = 0;
loadSound();
}
/*---------- ERROR HANDLING ----------*/
// Handles IO errors.
private function onIOError(event:IOErrorEvent):void
{
//Alert.show("File load error: " + event.text);
}
private function startMove():void
{
stage.nativeWindow.startMove();
}
private function unloadSound():void
{
stopSound();
txtID3.text = "";
btnPlay.visible = true;
btnPause.visible = false;
btnPlay.enabled = false;
btnStop.enabled = false;
}
private function removeSound():void
{
var index:int = dgPlaylist.selectedIndex;
if (index >= 0)
{
if (index == soundIndex)
{
unloadSound();
}
PlayList.RemoveSoundAt(index);
PlayList.Sounds.refresh();
setBackForwardButtons();
}
}
private function removeAllSounds():void
{
unloadSound();
PlayList.Sounds.removeAll();
PlayList.Sounds.refresh();
setBackForwardButtons();
}
private function onKeyDown(event:KeyboardEvent):void
{
if (event.charCode.toString() == "8" || event.charCode.toString() == "127")
{
removeSound();
}
}
]]>
</fx:Script>
</s:View>
I'm new to Flex so I don't know if this is causing the problem or not, but the Howler app uses an MX:DataGrid defined like this:
<mx:DataGrid x="6"
y="7"
width="388"
height="310"
id="dgPlaylist"
keyDown="onKeyDown(event)"
dragMoveEnabled="true"
doubleClickEnabled="true"
dragEnabled="true"
dropEnabled="true"
dragComplete="onPlaylistDragDrop(event)"
itemDoubleClick="onItemDoubleClick(event)">
<mx:columns>
<mx:DataGridColumn width="168" headerText="Title" dataField="title" />
<mx:DataGridColumn width="160" headerText="Album" dataField="album"/>
<mx:DataGridColumn width="60" headerText="Duration" dataField="duration" textAlign="right" itemRenderer="components.DurationFormatter"/>
</mx:columns>
</mx:DataGrid>
It has additional columns that I'm not using. Could this be the cause?
We are going to need the error message. Generally what you are experiencing is called a null pointer exception ( just like the error said ). Which basically means you tried to access a property of an object that is null. For example, running the following code will cause the same problem
var arrayCollection:ArrayCollection;
arrayCollection.addItem( new Object() );
To fix your error, you should find the object that the error is referring to in your code and make sure it isn't null when your program executes whatever line it is complaining about, or add an if-loop in the event it is null.

Adobe Air how to check if URL is online\gives any response exists?

I have url I want to check if it is live. I want to get bool value. How to do such thing?
You can use an URLLoader and listen for the events to check if it loads, and if not what might be the problem. Would be handy to use the AIRMonitor first to make sure the client's computer is online in the first place.
Here is a class I started to write to illustrate the idea:
package
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.HTTPStatusEvent;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.SecurityErrorEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
/**
* ...
* #author George Profenza
*/
public class URLChecker extends EventDispatcher
{
private var _url:String;
private var _request:URLRequest;
private var _loader:URLLoader;
private var _isLive:Boolean;
private var _liveStatuses:Array;
private var _completeEvent:Event;
private var _dispatched:Boolean;
private var _log:String = '';
public function URLChecker(target:IEventDispatcher = null)
{
super(target);
init();
}
private function init():void
{
_loader = new URLLoader();
_loader.addEventListener(Event.COMPLETE, _completeHandler);
_loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, _httpStatusHandler);
_loader.addEventListener(IOErrorEvent.IO_ERROR, _ioErrorEventHandler);
_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityErrorHandler);
_completeEvent = new Event(Event.COMPLETE, false, true);
_liveStatuses = [];//add other acceptable http statuses here
}
public function check(url:String = 'http://stackoverflow.com'):void {
_dispatched = false;
_url = url;
_request = new URLRequest(url);
_loader.load(_request);
_log += 'load for ' + _url + ' started : ' + new Date() + '\n';
}
private function _completeHandler(e:Event):void
{
_log += e.toString() + ' at ' + new Date();
_isLive = true;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
private function _httpStatusHandler(e:HTTPStatusEvent):void
{
/* comment this in when you're sure what statuses you're after
var statusesLen:int = _liveStatuses.length;
for (var i:int = statusesLen; i > 0; i--) {
if (e.status == _liveStatuses[i]) {
_isLive = true;
dispatchEvent(_completeEvent);
}
}
*/
//200 range
_log += e.toString() + ' at ' + new Date();
if (e.status >= 200 && e.status < 300) _isLive = true;
else _isLive = false;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
private function _ioErrorEventHandler(e:IOErrorEvent):void
{
_log += e.toString() + ' at ' + new Date();
_isLive = false;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
private function _securityErrorHandler(e:SecurityErrorEvent):void
{
_log += e.toString() + ' at ' + new Date();
_isLive = false;
if (!_dispatched) {
dispatchEvent(_completeEvent);
_dispatched = true;
}
}
public function get isLive():Boolean { return _isLive; }
public function get log():String { return _log; }
}
}
and here's a basic usage example:
var urlChecker:URLChecker = new URLChecker();
urlChecker.addEventListener(Event.COMPLETE, urlChecked);
urlChecker.check('wrong_place.url');
function urlChecked(event:Event):void {
trace('is Live: ' + event.target.isLive);
trace('log: ' + event.target.log);
}
The idea is simple:
1. You create a checked
2. Listen for the COMPLETE event(triggered when it has a result
3. In the handler check if it's live and what it logged.
In the HTTP specs, 200 area seems ok, but depending on what you load, you might need
to adjust the class. Also you need to handle security/cross domain issue better, but at least it's a start.
HTH
An important consideration that George's answer left out is the URLRequestMethod. If one were trying to verify the existence of rather large files (e.g, media files) and not just a webpage, you'd want to make sure to set the method property on the URLRequest to URLRequestMethod.HEAD.
As stated in the HTTP1.1 Protocol:
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response.
Hence, if you really only want to verify the existence of the URL, this is the way to go.
For those who need the code spelled out:
var _request:URLRequest = URLRequest(url);
_request.method = URLRequestMethod.HEAD; // bandwidth :)
Otherwise, George's answer is a good reference point.
NB: This particular URLRequestMethod is only available in AIR.

Resources