Hi All,

I am using ActionScript 3.0. I am implementing a sound player with the requisite buttons. I also have an audio slider and a volume slider.

A teammate found the following code online:

AbstractPlayer:
Code:
package com.nuance.nlportal.audioplayer
{
	import com.nuance.nlportal.audioplayer.events.DownloadEvent;
	import com.nuance.nlportal.audioplayer.events.Id3Event;
	import com.nuance.nlportal.audioplayer.events.PlayProgressEvent;
	import com.nuance.nlportal.audioplayer.events.PlayerEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.utils.Timer;
	
	import mx.controls.Alert;
	
	/**
	 * This class is the blueprint for the music player, it describes the rules by which player behave.
	 * 
	 */	
	public class AbstractPlayer extends EventDispatcher 
	{
		protected var sound:Sound;
		protected var channel:SoundChannel;
		protected var soundPosition:Timer;
		protected var fileBytesTotal:Number;
		
		/**
		 * Holds the pause position 
		 */		
		protected var mPausePosition:Number;
		
		/**
		 * Flag indicating weather the track is in pause mode 
		 */		
		protected var mIsPause:Boolean = false;
		
		/**
		 * Flag to indicate weather the track is currently playing 
		 */		
		protected var mIsPlaying:Boolean = false;         
		
		/**
		 * Play position in seconds 
		 */        
		private var mAudioPosition:Number;
		
		/**
		 * Total song length in seconds 
		 */        
		private var mAudioLength:Number;
		
		/**
		 * Song URL 
		 */        
		private var mAudioURL:String;
		
		/**
		 * Player volume
		 */
		private var mVolume:Number = 1.0;
		
		public function get songPosition():Number
		{
			return mAudioPosition;
		}
		
		public function set songPosition(val:Number):void
		{
			mAudioPosition = val;
		}
		
		public function get songLength():Number
		{
			return mAudioLength;
		}
		
		public function set songLength(val:Number):void
		{
			mAudioLength = val;
		}
		
		public function get songURL():String
		{
			return mAudioURL;
		}
		
		public function set songURL(val:String):void
		{
			mAudioURL = val;
		}
		
		public function AbstractPlayer()
		{
		}
		
		/**
		 * Method to play track, based on url.  The method handles cases where the user clicked on play after it is already playing and for 
		 * cases where the track was paused. Music file doesn't provide the lenght of the song right away, but it's changing during the progress 
		 * of the music file, so you can pass the lenght of the song, if you know it, other wise you can take if from the <code>PlayProgressEvent</code>
		 *  
		 * @param songUrl song url is the location of the music file.
		 * @param songLenght downloading music file doesn't provide the lenght of the song right away, but after portion of the song downloaded
		 * 
		 */	    
		public function playTrack(songUrl:String, songLenght:Number=0):void
		//public function playTrack(songUrl:String, position:Number=0, songLenght:Number=0):void
		{
			// needs to implement
		}  
		
		/**
		 * Method to pause a track. 
		 * 
		 */        
		public function pauseTrack():void
		{
			soundPosition.stop();
			channel.stop();
			
			mIsPause = true;        	
			mPausePosition = channel.position;
			// [Added by BT 21/12/10] - If mIsPlaying remains true, then the first thing that happens in playAudio()
			// is to stopAudio() -> stopTrack() -> resetPlayer() -> mIsPause = false -> mIsPause check fails in playTrack().
			mIsPlaying = false;
		}
		
		/**
		 * Stop track method 
		 * 
		 */        
		public function stopTrack():void
		{
			soundPosition.stop();
			channel.stop();
			resetPlayer();
		}
		
		/**
		 * Method to change the position of the track 
		 * @param newPosition position is provided in milliseconds
		 * 
		 */        
		public function setTrackPosition(newPosition:Number):void
		//public function setTrackPosition(newPosition:Number, songUrl:String=null):void
		{
			/*if ( !mIsPlaying )
			{
				playTrack( songUrl, newPosition );
				return;
			}*/
			
			soundPosition.stop();
			channel.stop();
			
			var currentPosition:Number = channel.position/1000;
			var position:Number
			
			if (newPosition<currentPosition)
			{
				position = newPosition*1000;
			}
			else
			{
				position = Math.min(sound.length, newPosition*1000);
			}
			
			channel = sound.play(position);
			// [Added by BT 30/12/10] - sound.play(position) removes the SOUND_COMPLETE event listener.
			channel.addEventListener(Event.SOUND_COMPLETE, trackCompleteHandler);
			soundPosition.start();
		}
		
		/**
		 * Method to remove all listener and empty objecs once track stoped. 
		 * 
		 */        
		protected function resetPlayer():void
		{
			// needs to implement
		}        
		
		/**
		 * Method to fast forward a track
		 * @param timeInSeconds time to fast forward, default is 2 seconds
		 * 
		 */        
		public function fastforward(timeInSeconds:Number=2):void
		{
			var currentPosition:Number = channel.position/1000;
			setTrackPosition(timeInSeconds+currentPosition);
		}
		
		/**
		 * Method to rewind a track
		 * @param timeInSeconds time to rewind, default is 2 seconds
		 * 
		 */        
		public function rewind(timeInSeconds:Number=2):void
		{
			var currentPosition:Number = channel.position/1000;
			setTrackPosition(currentPosition-timeInSeconds);     	
		}
		
		
		/**
		 * Method to adjust sound volume 
		 * @param vol volume in precentage between 0-1
		 * 
		 */        
		public function setVolume(vol:Number):void
		{
			mVolume = vol;
			
			if (channel != null)
			{
				var transform:SoundTransform = new SoundTransform(vol);
				channel.soundTransform = transform;
			}
		}  
		
		public function getVolume():Number
		{
			return mVolume;	
		}
		
		public function isPlaying():Boolean
		{
			return mIsPlaying;	
		}
		
		//  Event handlers
		/**
		 * Sends an event once the track position changed.  
		 * @param event
		 * 
		 */	    
		protected function positionTimerHandler(event:TimerEvent):void 
		{
			songPosition = Number((channel.position/1000).toFixed(2));
			var totalPosition:Number = Number((this.sound.length/1000).toFixed(2));
			
			if (songLength < totalPosition)
			{
				songLength = totalPosition;
			}
			
			if (songLength > 0 && songPosition > 0)
			{
				this.dispatchEvent( new PlayProgressEvent(songPosition, songLength) );
			}
		}
		
		/**
		 * Download complete handler
		 * @param event
		 * 
		 */		
		protected function downloadCompleteHandler(event:Event):void 
		{
			sound.removeEventListener(Event.COMPLETE, downloadCompleteHandler);
			sound.removeEventListener(ProgressEvent.PROGRESS, downloadProgressHandler);
			
			this.dispatchEvent(new DownloadEvent(DownloadEvent.DOWNLOAD_COMPLETED, fileBytesTotal, fileBytesTotal));
		}
		
		/**
		 * ID3 information 
		 * @param event
		 * 
		 */		
		protected function id3Handler(event:Id3Event):void 
		{
			this.dispatchEvent(event);
		}
		
		/**
		 * Method to handle io errors. 
		 * @param event
		 * 
		 */		
		protected function ioErrorHandler(event:Event):void 
		{
			sound.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			this.dispatchEvent(new PlayerEvent(PlayerEvent.PLAYER_ERROR, "Error loading music file, please check cross domain policy and that file exists."+event.toString()));
			resetPlayer();
		}
		
		/**
		 * Progress handler
		 *  
		 * @param event
		 * 
		 */
		protected function downloadProgressHandler(event:ProgressEvent):void 
		{
			this.dispatchEvent(new DownloadEvent(DownloadEvent.DOWNLOAD_PROGRESS, event.bytesLoaded, event.bytesTotal));
			fileBytesTotal = event.bytesTotal;
			
			// check if ID3 information is avaliable, needed since id3 event doesn't always work correctly.
			if (this.sound.id3.album != null || this.sound.id3.artist != null || this.sound.id3.songName != null || this.sound.id3.genere != null)
			{
				var evt:Id3Event = new Id3Event(this.sound.id3);
				id3Handler(evt);
			}
		}
		
		/**
		 * Track complete handler
		 * @param event
		 * 
		 */		
		protected function trackCompleteHandler(event:Event):void 
		{
			channel.removeEventListener(Event.SOUND_COMPLETE, trackCompleteHandler);
			resetPlayer();
			this.dispatchEvent(new PlayerEvent(PlayerEvent.TRACK_COMPLETED));
		}
		
	}
}
Player:
Code:
package com.nuance.nlportal.audioplayer
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;

	import flash.media.Sound;
	import flash.media.SoundLoaderContext;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.Timer;
	
	/**
	 *  Dispatched while downloading a music file in progress
	 *
	 *  @eventType com.elad.framework.musicplayer.events.DownloadEvent.DOWNLOAD_PROGRESS
	 */
	[Event(name="downloadProgress", type="com.nuance.nlportal.audioplayer.events.DownloadEvent")]
	
	/**
	 *  Dispatched when music file was downloaded successfully
	 *
	 *  @eventType com.elad.framework.musicplayer.events.DownloadEvent.DOWNLOAD_COMPLETED
	 */
	[Event(name="downloadCompleted", type="com.nuance.nlportal.audioplayer.events.DownloadEvent")]
	
	/**
	 *  Dispatched when track playing is completed
	 *
	 *  @eventType com.elad.framework.musicplayer.events.PlayerEvent.TRACK_COMPLETED
	 */
	[Event(name="playerError", type="com.nuance.nlportal.audioplayer.events.PlayerEvent")]
	
	/**
	 *  Dispatched when there is an error playing a track
	 *
	 *  @eventType com.elad.framework.musicplayer.events.PlayerEvent.PLAYER_ERROR
	 */
	[Event(name="trackCompleted", type="com.nuance.nlportal.audioplayer.events.PlayerEvent")]
	
	/**
	 *  Dispatched while track progress playing
	 *
	 *  @eventType com.elad.framework.musicplayer.events.PlayProgressEvent.PLAYER_PROGRESS
	 */
	[Event(name="playerProgress", type="com.nuance.nlportal.audioplayer.events.PlayProgressEvent")]
	
	/**
	 *  Dispatched when data information is avaliable regarding a track
	 *
	 *  @eventType com.elad.framework.musicplayer.events.ID3
	 */
	[Event(name="id3", type="com.nuance.nlportal.audioplayer.events.Id3Event")]
	
	/**
	 * This class is the foundation for creating an audio music player.  The class includes all the methods needed such as 
	 * play, stop, pause as well as lunch event as the track is playing, downloading and catching track information.
	 * 
	 */		
	public class Player extends AbstractPlayer implements IPlayer 
	{
		
		//
		//  Constructor
		//
		public function Player()
		{
		}
		
		//
		//  Class methods
		//
		/**
		 * Method to play track, based on url.  The method handles cases where the user clicked on play after it is already playing and for 
		 * cases where the track was paused. Music file doesn't provide the lenght of the song right away, but it's changing during the progress 
		 * of the music file, so you can pass the lenght of the song, if you know it, other wise you can take if from the <code>PlayProgressEvent</code>
		 *  
		 * @param songUrl song url is the location of the music file.
		 * @param songLenght downloading music file doesn't provide the lenght of the song right away, but after portion of the song downloaded
		 * 
		 */	    
		override public function playTrack(songUrl:String, songLenght:Number=0):void
		//override public function playTrack(songUrl:String, newPosition:Number=0, songLenght:Number=0):void
		{
			if (mIsPause)
			{
				replay();
				return;
			}
			
			if (mIsPlaying)
			{
				return;
			}
			
			songURL = songUrl;
			songLength = Number((songLenght/1000).toFixed(2));
			
			var request:URLRequest = new URLRequest(songUrl);
			sound = new Sound();
			var slc:SoundLoaderContext = new SoundLoaderContext;
			slc.checkPolicyFile = true;
			
			sound.addEventListener(Event.COMPLETE, downloadCompleteHandler);
			sound.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			sound.addEventListener(ProgressEvent.PROGRESS, downloadProgressHandler);
			sound.load(request, slc);
			
			channel = sound.play();
			
			var transform:SoundTransform = new SoundTransform(getVolume());
			channel.soundTransform = transform;

			/*if ( newPosition != 0 )
			{
				channel.stop();
				
				var currentPosition:Number = channel.position/1000;
				var position:Number
				
				if (newPosition<currentPosition)
				{
					position = newPosition*1000;
				}
				else
				{
					position = Math.min(sound.length, newPosition*1000);
				}
				
				channel = sound.play(position);
			}*/

			channel.addEventListener(Event.SOUND_COMPLETE, trackCompleteHandler);
			
			soundPosition = new Timer(50);
			soundPosition.addEventListener(TimerEvent.TIMER, positionTimerHandler);
			soundPosition.start();
			mIsPlaying = true;
		}
		
		/**
		 * Method to remove all listener and empty objecs once track stoped. 
		 * 
		 */        
		override protected function resetPlayer():void
		{
			this.mIsPause = false;
			this.mIsPlaying = false;
			
			sound.removeEventListener(Event.COMPLETE, downloadCompleteHandler);
			sound.removeEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
			sound.removeEventListener(ProgressEvent.PROGRESS, downloadProgressHandler);
			channel.removeEventListener(Event.SOUND_COMPLETE, trackCompleteHandler);
			soundPosition.removeEventListener(TimerEvent.TIMER, positionTimerHandler);
			
			sound         = null;
			channel       = null;
			soundPosition = null;            
		}
		
		/**
		 * Replay method used internally. 
		 * 
		 */        
		private function replay():void
		{
			channel = sound.play(mPausePosition);
			// [Added by BT 21/12/10] - sound.play(mPausePosition) removes the SOUND_COMPLETE event listener.
			channel.addEventListener(Event.SOUND_COMPLETE, trackCompleteHandler);
			soundPosition.start();
			
			mIsPause = false;
		}
		
		/**
		 * Static method used to convert a time in seconds to the following format '0:00'. 
		 *  
		 * @param time time in seconds
		 * 
		 */        
		public static function formatTimeInSecondsToString(time:Number):String
		{
			var retVal:String = "";
			
			var timeString:String = (time/60).toFixed(2);
			var timeArray:Array = timeString.split(".");
			
			if (timeArray[1] == 60)
			{
				timeArray[0] += 1;
				timeArray[1] -= 60;
			}
			
			var minutes:String = (timeArray[0].toString().length < 2) ? "0"+timeArray[0].toString() : timeArray[0].toString();
			var seconds:String = (timeArray[1].toString().length < 2) ? "0"+timeArray[1].toString() : timeArray[1].toString();
			
			retVal = minutes+":"+seconds;
			
			return retVal;
		}     
		
	}
}
ISSUE
With the code as is, I cannot drag the audio slider until after the Play button is pressed. This functionality should be provided (as is the case for YouTube videos). The problem is that the relevant components (Sound, Channel) are created only after Play is pressed.

ATTEMPTED SOLUTIONS
As you can see, I tried two solutions:
1. In the AbstractPlayer.setTrackPosition method, I called playTrack at the beginning. Unfortunately, the whole audio file gets played still.
2. In the Player.playTrack method, I passed the new position as an argument. I tried calculating the true new position after channel = sound.play(). However, it appears that, until the end of the method, sound.length is still 0.

With the existing code, what changes do I need to make to be able to move the audio slider (i.e. change the current position of the audio file) without having to first press Play? Either moving the slider would start playing the audio file, or moving the slider would just change the position and then this position can be passed to playTrack to properly calculate the new true position, is acceptable.

Thank you for your insight and guidance!
Bonnie