package htmlelements {
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.TimerEvent;
import flash.media.ID3Info;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundLoaderContext;
import flash.media.SoundTransform;
import flash.net.URLRequest;
import flash.utils.Timer;
public class AudioElement implements IMediaElement {
private var _sound:Sound;
private var _soundTransform:SoundTransform;
private var _soundChannel:SoundChannel;
private var _soundLoaderContext:SoundLoaderContext;
private var _volume:Number = 1;
private var _preMuteVolume:Number = 0;
private var _isMuted:Boolean = false;
private var _isPaused:Boolean = true;
private var _isEnded:Boolean = false;
private var _isLoaded:Boolean = false;
private var _currentTime:Number = 0;
private var _duration:Number = 0;
private var _bytesLoaded:Number = 0;
private var _bytesTotal:Number = 0;
private var _bufferedTime:Number = 0;
private var _bufferingChanged:Boolean = false;
private var _currentUrl:String = "";
private var _autoplay:Boolean = true;
private var _preload:String = "";
private var _element:FlashMediaElement;
private var _timer:Timer;
private var _firedCanPlay:Boolean = false;
public function setSize(width:Number, height:Number):void {
// do nothing!
}
public function duration():Number {
return _duration;
}
public function currentTime():Number {
return _currentTime;
}
public function currentProgress():Number {
return Math.round(_bytesLoaded/_bytesTotal*100);
}
public function AudioElement(element:FlashMediaElement, autoplay:Boolean, preload:String, timerRate:Number, startVolume:Number):void {
_element = element;
_autoplay = autoplay;
_volume = startVolume;
_preload = preload;
_timer = new Timer(timerRate);
_timer.addEventListener(TimerEvent.TIMER, timerEventHandler);
_soundTransform = new SoundTransform(_volume);
_soundLoaderContext = new SoundLoaderContext();
}
// events
private function progressHandler(e:ProgressEvent):void {
_bytesLoaded = e.bytesLoaded;
_bytesTotal = e.bytesTotal;
// this happens too much to send every time
//sendEvent(HtmlMediaEvent.PROGRESS);
// so now we just trigger a flag and send with the timer
_bufferingChanged = true;
}
private function id3Handler(e:Event):void {
sendEvent(HtmlMediaEvent.LOADEDMETADATA);
try {
var id3:ID3Info = _sound.id3;
var obj:Object = {
type:'id3',
album:id3.album,
artist:id3.artist,
comment:id3.comment,
genre:id3.genre,
songName:id3.songName,
track:id3.track,
year:id3.year
};
} catch (err:Error) {}
}
private function timerEventHandler(e:TimerEvent):void {
_currentTime = _soundChannel.position/1000;
// calculate duration
var duration:Number = Math.round(_sound.length * _sound.bytesTotal/_sound.bytesLoaded/100) / 10;
// check to see if the estimated duration changed
if (_duration != duration && !isNaN(duration)) {
_duration = duration;
sendEvent(HtmlMediaEvent.LOADEDMETADATA);
}
// check for progress
if (_bufferingChanged) {
sendEvent(HtmlMediaEvent.PROGRESS);
_bufferingChanged = false;
}
// send timeupdate
sendEvent(HtmlMediaEvent.TIMEUPDATE);
// sometimes the ended event doesn't fire, here's a fake one
if (_duration > 0 && _currentTime >= _duration-0.2) {
handleEnded();
}
}
private function soundCompleteHandler(e:Event):void {
handleEnded();
}
private function handleEnded():void {
_isEnded = true;
pause();
sendEvent(HtmlMediaEvent.ENDED);
_isEnded = false;
_currentTime = 0;
}
//events
// METHODS
public function setSrc(url:String):void {
_currentUrl = url;
_isLoaded = false;
}
public function load():void {
if (_currentUrl == "") {
return;
}
if (_sound) {
if (_sound.hasEventListener(ProgressEvent.PROGRESS)) {
_sound.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
}
if (_sound.hasEventListener(Event.ID3)) {
_sound.removeEventListener(Event.ID3, id3Handler);
}
try {
_sound.close();
} catch (err:Error) {}
}
_sound = new Sound();
//sound.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
_sound.addEventListener(ProgressEvent.PROGRESS,progressHandler);
_sound.addEventListener(Event.ID3,id3Handler);
_sound.load(new URLRequest(_currentUrl));
_currentTime = 0;
sendEvent(HtmlMediaEvent.LOADSTART);
_isLoaded = true;
sendEvent(HtmlMediaEvent.LOADEDDATA);
sendEvent(HtmlMediaEvent.CANPLAY);
_firedCanPlay = true;
if (_playAfterLoading) {
_playAfterLoading = false;
play();
}
}
private var _playAfterLoading:Boolean= false;
public function play():void {
if (!_isLoaded) {
_playAfterLoading = true;
load();
return;
}
_timer.stop();
_soundChannel = _sound.play(_currentTime*1000, 0, _soundTransform);
_soundChannel.removeEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
_soundChannel.addEventListener(Event.SOUND_COMPLETE, soundCompleteHandler);
_timer.start();
didStartPlaying();
}
public function pause():void {
_timer.stop();
if (_soundChannel != null) {
_currentTime = _soundChannel.position/1000;
_soundChannel.stop();
}
_isPaused = true;
sendEvent(HtmlMediaEvent.PAUSE);
}
public function stop():void {
if (_timer != null) {
_timer.stop();
}
if (_soundChannel != null) {
_soundChannel.stop();
_sound.close();
}
unload();
sendEvent(HtmlMediaEvent.STOP);
}
public function setCurrentTime(pos:Number):void {
_timer.stop();
sendEvent(HtmlMediaEvent.SEEKING);
_currentTime = pos;
_soundChannel.stop();
_soundChannel = _sound.play(_currentTime * 1000, 0, _soundTransform);
sendEvent(HtmlMediaEvent.SEEKED);
_timer.start();
didStartPlaying();
}
public function seekLimit():Number {
return NaN;
}
private function didStartPlaying():void {
_isPaused = false;
if (!_firedCanPlay) {
sendEvent(HtmlMediaEvent.LOADEDDATA);
sendEvent(HtmlMediaEvent.CANPLAY);
_firedCanPlay = true;
}
sendEvent(HtmlMediaEvent.PLAY);
sendEvent(HtmlMediaEvent.PLAYING);
}
public function setVolume(volume:Number):void {
_volume = volume;
_soundTransform.volume = volume;
if (_soundChannel != null) {
_soundChannel.soundTransform = _soundTransform;
}
_isMuted = (_volume == 0);
sendEvent(HtmlMediaEvent.VOLUMECHANGE);
}
public function getVolume():Number {
if(_isMuted) {
return 0;
} else {
return _volume;
}
}
public function setMuted(muted:Boolean):void {
// ignore if already set
if ( (muted && _isMuted) || (!muted && !_isMuted))
return;
if (muted) {
_preMuteVolume = _soundTransform.volume;
setVolume(0);
} else {
setVolume(_preMuteVolume);
}
_isMuted = muted;
}
public function unload():void {
_sound = null;
_isLoaded = false;
}
private function sendEvent(eventName:String):void {
// calculate this to mimic HTML5
_bufferedTime = _bytesLoaded / _bytesTotal * _duration;
// build JSON
var values:String =
"duration:" + _duration +
",currentTime:" + _currentTime +
",muted:" + _isMuted +
",paused:" + _isPaused +
",ended:" + _isEnded +
",volume:" + _volume +
",src:\"" + _currentUrl + "\"" +
",bytesTotal:" + _bytesTotal +
",bufferedBytes:" + _bytesLoaded +
",bufferedTime:" + _bufferedTime +
"";
_element.sendEvent(eventName, values);
}
}
}