rozklad
4/21/2013 - 6:39 AM

AS3 media player

AS3 media player

package {
  
  import flash.geom.*;  
	import flash.display.Loader;
	import flash.display.MovieClip;
	import flash.display.Stage;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.display.StageDisplayState;
	import flash.events.Event;
	import flash.events.IOErrorEvent
	import flash.events.MouseEvent;
	import flash.events.NetStatusEvent;
	import flash.events.ProgressEvent;
	import flash.events.AsyncErrorEvent;
	import flash.media.Video;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.net.navigateToURL;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.utils.setInterval;
	import flash.utils.clearInterval;
	
	// Respects ActionScript 3.0 Coding Conventions: http://opensource.adobe.com/wiki/display/flexsdk/Coding+Conventions
	
	public class Player extends MovieClip {
		
		// Settings and factory defaults
		var settings:Object = 	{};
		var factory:Object  =	{	name: 'Player sample',			// Name to show in status bar
									link: 'http://www.example.com', // Link to pop up by clicking on name
									
									//audio: 'media/custom.mp3',		// Default audiofile path
									audio: false,
									video: 'media/video.mp4', 		// Default videofile path
									thumb: 'media/poster.jpg',		// Default thumbnail path
									
									linkColor: 'CCCCCC', 			// Color of links
									hoverColor: 'FFFFFF',			// Hover color of links
									
									buffer: 5, 						// Buffer time in seconds
									expandedBuffer: 20,				// Expanded buffer
									inactiveToHide: 5, 				// Inactive time needed to hide controls in seconds
									controlsHeight: 40, 			// Height of controls panel
									controlsMargin: 0, 				// Margin of controls panel (goes for status bar as well)
									soundVolume: 0.6, 				// Startup volume of sound
									
									autoplay: false, 				// Automatically play on load (true/false)
									scrubVolume: true,				// True enables volume scrubbing, false sets volume to on/off button
									debug: true,					// Debug mode (true/false)
									startMode: true,				// Starting screen mode
									startMargin: 0,					// Starting screen mode margin
									animate: true					// Animate hide and show actions
								}
		
		// netStream
		var nc:NetConnection;
		var ns:NetStream;
		var meta:Object;
		
		// True = video, False = audio
		var media:Boolean;
		
		// Save position for resuming audio
		var position:Number;
		
		// Video data
		var path:String;
		var video:Video;
		var audio:Sound;
		var channel:SoundChannel;
		var sound:SoundTransform;
		var duration:Number;
		var amountLoaded:Number;
		var amountPlayed:Number;
		var currentTime:int;
		
		// References to objects
		var thumbScreen:MovieClip;
		var videoScreen:MovieClip;
		var curtain:MovieClip;
		var controls:MovieClip;
		var status:MovieClip;
		
		// Indicators
		var played:Boolean = false;
		var started:Boolean = false;
		var controlsState:Boolean = true;
		var inactive:int = 0;
		
		// Intervals
		var interval = intervalInit(0);
		var sideInterval;
		
		// Helper variables
		var lastMouseX:int;
		var lastMouseY:int;
		
		// --------------------------------------------------------------------
		//
		// 	Player methods
		//
		// --------------------------------------------------------------------
		
		/**
		 * Player
		 *
		 * Constructor method assigns object references from flash movie
		 * to actionscript class.
		 *
		 * @access	public
		 * @param	thumbScreenRef	MovieClip	Reference to thumbnail screen
		 * @param	videoScreenRef	MovieClip	Reference to video screen
		 * @param	curtainRef		MovieClip	Reference to curtain
		 * @param	controlsRef		MovieClip	Reference to controls panel
		 * @param	statusRef		MovieClip	Reference to status bar
		 * @return	void
		 */
		public function Player(thumbScreenRef:MovieClip, videoScreenRef:MovieClip, curtainRef:MovieClip, controlsRef:MovieClip, statusRef:MovieClip):void {
			thumbScreen = thumbScreenRef;
			videoScreen = videoScreenRef;
			curtain = curtainRef;
			controls = controlsRef;
			status = statusRef;
			
			addEventListener(Event.ADDED_TO_STAGE, init);				// Fire init() when class loaded to stage (addChild() function fires Event.ADDED_TO_STAGE)
		}
		
		// --------------------------------------------------------------------
		
		/**
		 * init
		 *
		 * Initialization of essential settings and functions. Uses custom events
		 * to chain initialization. (When A is loaded => init B, When B is loaded =>
		 * init C etc.)
		 *
		 * @access	private
		 * @param	event	Event	event data by listener
		 * @return	void
		 */
		private function init(event:Event):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);			// Remove firing init()
			settings = settingsFactory(stage.loaderInfo.parameters);	// Load settings or use factory defaults
			
			stage.addEventListener('prepared', thumbInit);
			stage.addEventListener('thumbLoaded', streamInit);
			stage.addEventListener('streamLoaded', controlsInit);
			stage.addEventListener('controlsLoaded', statusInit);
			stage.addEventListener('statusLoaded', soundInit);
			
			prepare();													// Init first init method to start chain initialization
			
			stage.addEventListener(Event.RESIZE, resize);				// Respond to resize
		}
		
		// --------------------------------------------------------------------
		//
		//  Resize methods
		//
		// --------------------------------------------------------------------
		
		private function resize(event:Event):void {
			resizeControls();
			resizeStatus();
			resizeVideo();
			resizeThumb();
		}
		
		private function resizeWidth(element:MovieClip):void {
			element.bg.width = stage.stageWidth - 2*settings.controlsMargin;
		}
		
		private function getCenter(element:MovieClip):int {
			return element.width/2;
		}
		
		private function getMiddle(element:MovieClip):int {
			return element.height/2;
		}
		
		private function resizeControls():void {
			resizeWidth(controls);
			
			controls.bg.height = settings.controlsHeight;
			controls.y = stage.stageHeight - controls.bg.height - settings.controlsMargin;
			
			controls.playBtn.x = getCenter(controls.playBtn);
			controls.playBtn.y = getMiddle(controls.playBtn);
			
			controls.bg.x = 0;
			controls.bg.y = 0;
			
			controls.fullBtn.x = stage.stageWidth - getCenter(controls.fullBtn) - settings.controlsMargin;
			
			controls.soundBtn.x = stage.stageWidth - getCenter(controls.soundBtn) - controls.fullBtn.width - settings.controlsMargin;
			
			controls.volumeScrubber.x = controls.soundBtn.x;
			
			resizeControlsScrubber();
		}
		
		private function resizeControlsScrubber():void {
			controls.scrubber.container.width = stage.stageWidth - 2*settings.controlsMargin - controls.soundBtn.width - controls.fullBtn.width*1.5 - controls.playBtn.width;
			controls.scrubber.x = controls.playBtn.width*1.25;
		}
		
		private function resizeStatus():void {
			resizeWidth(status);
			
			status.heading.bg.width = stage.stageWidth;
			
			status.y = settings.controlsMargin;
			
			status.buffer.y = stage.stageHeight/2 - status.buffer.height/2;
			status.buffer.width = stage.stageWidth;
		}
		
		private function resizeVideo():void {
			status.heading.content.text = stage.stageWidth + ' ' + stage.stageHeight;
			videoScreen.width = stage.stageWidth;
			videoScreen.height = stage.stageHeight;
		}
		
		private function resizeThumb():void {
			thumbScreen.width = stage.stageWidth;
			thumbScreen.height = stage.stageHeight;
		}
		
		// --------------------------------------------------------------------
		//
		//  Interval
		//
		// --------------------------------------------------------------------
		//	Could be achived through Timer Class
		// --------------------------------------------------------------------
		
		private function intervalInit(kind:int):Number {
			switch (kind) {
				case 0:
				{
					return setInterval(streamInterval, 100);
					break;
				}
				
				case 1:
				{
					return setInterval(scrubbingInterval, 10);
					break;
				}
				
				case 2:
				{
					return setInterval(scrubberInterval, 10);
					break;
				}
				
				case 3:
				{
					return setInterval(bufferInterval, 100);
					break;
				}
				
				default:
				{
					return 0;
				}
			}
		}
		
		private function streamInterval() {
			updateTrack();
			currentTime = Math.ceil(ns.time);
			updateTime(currentTime);
			controls.timer.x = controls.scrubber.played.width + controls.timer.width - controls.scrubber.scrubber.width;
			checkMovement();
		}
		
		private function scrubberInterval():void {
			updateTrack();
			controls.timer.x = mouseX - controls.timer.width/2;
			currentTime = pos2Time(controls.timer.x, controls.scrubber.container);
			updateTime(currentTime);
		}
		
		private function scrubbingInterval():void {
			controls.timer.x = controls.scrubber.scrubber.x + controls.timer.width - controls.scrubber.scrubber.width;
			currentTime = pos2Time(controls.timer.x, controls.scrubber.container);
			updateTime(currentTime);
		}
		
		private function bufferInterval():void {
			updateTrack();
			currentTime = Math.ceil(ns.time);
			updateTime(currentTime);
			controls.timer.x = controls.scrubber.played.width + controls.timer.width - controls.scrubber.scrubber.width;
			var buffered = getBuffered();
			if (buffered > 99) {
				status.buffer.visible = false;
			} else {
				status.buffer.visible = true;
				status.buffer.text = String(buffered) + '%';
			}
		}
		
		function getBuffered():int {
			return Math.round((ns.bufferLength/ns.bufferTime)*100);
		}
		
		private function checkMovement():void {
			var posMouseX = stage.mouseX;
			var posMouseY = stage.mouseY;
			
			if (played) {
				if (lastMouseX == posMouseX && lastMouseY == posMouseY)
					inactive++;
				else
					inactive = 0;
			}
			
			if (inactive < settings.inactiveToHide * 10) {
				if (!controlsState)
					controlsShow();
			
			} else {
				if (controlsState)
					controlsHide();
			}
			
			lastMouseX = posMouseX;
			lastMouseY = posMouseY;
		}
		
		private function updateTime(currentTime) {
			controls.timer.content.text = formatTime(currentTime);
		}
		
		private function formatTime(time:int):String  {
			var secs:String = (time % 60).toString();
			secs = (secs.length == 1 ? '0' : '') + secs;
			var mins:String = Math.floor(time / 60).toString();
			mins = (mins.length == 1 ? '0' : '') + mins;
			return mins + ':' + secs;
		}
		
		private function mouse2Time():int {
			return pos2Time(mouseX - controls.timer.width/2, controls.scrubber.container);
		}
		
		private function pos2Time(scrubber:int, track:MovieClip):int {
			return Math.ceil(duration * (scrubber/track.width));
		}
		
		private function updateTrack():void {
			amountPlayed = ns.time / duration;
			amountLoaded = ns.bytesLoaded / ns.bytesTotal; 
			
			if (amountPlayed < 0.05 && duration < 20)
				amountPlayed = 0;		// Show less than 5% played as 0% for extremely short videos
			
			controls.scrubber.loaded.width = amountLoaded * controls.scrubber.container.width;
			controls.scrubber.played.width = amountPlayed * controls.scrubber.container.width;
				
			controls.scrubber.scrubber.x = controls.scrubber.played.width;
		}
		
		// --------------------------------------------------------------------
		//
		//  Volume methods
		//
		// --------------------------------------------------------------------
		
		private function volumeButton(show:Boolean):void {
			if (settings.scrubVolume) {
				controls.volumeScrubber.visible = show;
				controls.soundBtn.visible = false;
				
				volumeScrubberDefault();
			} else {
				controls.volumeScrubber.visible = true;
				controls.soundBtn.visible = show;
			}
		}
		
		private function volumeDefault():void {
			volumeButton(true);
		}
		
		private function volumeScrubberDefault():void {
			var buttons:Array /* of MovieClips */ = [controls.volumeScrubber.volume0, controls.volumeScrubber.volume20, controls.volumeScrubber.volume40,
													 controls.volumeScrubber.volume60, controls.volumeScrubber.volume80, controls.volumeScrubber.volume100, 
													 controls.volumeScrubber.volumeMAX];
			
			for (var i = 0; i<buttons.length; i++) {
				buttonize(buttons[i], btnOver, volumeOut, pressVolume);
			}
		}
		
		private function volumeOut(event:MouseEvent):void {
			if (media) {
				if (voumeGetPieceVolume(event) > ns.soundTransform.volume)
					event.currentTarget.gotoAndPlay('out');
			} else {
				if (voumeGetPieceVolume(event) > channel.soundTransform.volume)
					event.currentTarget.gotoAndPlay('out');
			}
		}
		
		private function voumeGetPieceVolume(event:MouseEvent):Number {
			var pieceName:String = event.currentTarget.name.substr(6,3);
			var pieceVolume:Number = 0.0;
			
			if (pieceName == 'MAX') {
				pieceVolume = 100;
			} else {
				pieceVolume = Number(pieceName);
			}
				
			return pieceVolume/100;
		}
		
		private function volumeReflect(volume:Number, originalVolume:Number):void {
			var buttons:Array /* of MovieClips */ = [controls.volumeScrubber.volume20, controls.volumeScrubber.volume40,
													 controls.volumeScrubber.volume60, controls.volumeScrubber.volume80, controls.volumeScrubber.volume100];
			var volumes:Array /* of Numbers */ = [0.2, 0.4, 0.6, 0.8, 1.0];
			
			var loops:int = buttons.length;
			
			for (var i = 0; i<loops; i++) {
				if (volume>=volumes[i])
					buttons[i].gotoAndPlay('over');
				else
					buttons[i].gotoAndPlay('out');
			}
		}
		
		private function pressVolume(event:MouseEvent):void {
			switch (event.currentTarget.name)
			{
				case 'volume0':
				{
					soundSet(0);
					break;
				}
				case 'volume20':
				{
					soundSet(0.2);
					break;
				}
				case 'volume40':
				{
					soundSet(0.4);
					break;
				}
				case 'volume60':
				{
					soundSet(0.6);
					break;
				}
				case 'volume80':
				{
					soundSet(0.8);
					break;
				}
				case 'volume100':
				{
					soundSet(1);
					break;
				}
				case 'volumeMAX':
				{
					soundSet(1);
					break;
				}
			}
			
		}
		
		// --------------------------------------------------------------------
		//
		//  Controls methods
		//
		// --------------------------------------------------------------------
		
		private function controlsScrubberDefault():void {
			controls.scrubber.loaded.width = 1;
			controls.scrubber.played.width = 1;
			
			controlsHideTimer();
		}
		
		private function controlsHideTimer():void {
			controls.timer.visible = false;
		}
		
		private function controlsShowTimer():void {
			controls.timer.visible = true;
		}
		
		private function controlsHide():void {
			debug('controlsHide');
			
			if (settings.animate)
				controlsAnimate(false);
			else
				controls.visible = false;

			controlsState = false;
		}
		
		private function controlsShow():void {
			debug('controlsShow');
			
			if (settings.animate)
				controlsAnimate(true);
			else
				controls.visible = true;
				
			controlsState = true;
		}
		
		private function controlsAnimate(show:Boolean):void {
			clearInterval(sideInterval);
			if (show)
				sideInterval = setInterval(controlsAnimateShow, 10);
			else
				sideInterval = setInterval(controlsAnimateHide, 10);
		}
		
		private function controlsAnimateShow():void {
			controls.y -= 1;
			if (controls.y <= stage.stageHeight - settings.controlsHeight) {
				clearInterval(sideInterval);
			}
		}
		
		private function controlsAnimateHide():void {
			controls.y += 1;
			if (controls.y >= stage.stageHeight) {
				clearInterval(sideInterval);
			}
		}

		private function controlsInit(event:Event):void {
			debug('controlsInit');
			
			// Set scale mode to NO_SCALE (does not resize elements) and put stage to top left corner
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			controlsBtns();
			
			controlsChange();
			
			controlsScrubberDefault();
			
			controlsSwitch(false);
			
			stage.dispatchEvent(new Event('controlsLoaded'));
			stage.dispatchEvent(new Event(Event.RESIZE));				// Fire resize right away to adjust to default resolution
		}
		
		private function controlsSwitch(show:Boolean):void {
			if ( ! started) {
				controls.playBtn.x = controls.playBtn.x + settings.startMargin;
				controls.playBtn.y = controls.playBtn.y - settings.startMargin;
				controls.bg.width = controls.playBtn.width + status.heading.content.width;
				controls.bg.y = controls.bg.y - settings.startMargin;
				controls.bg.x = controls.bg.x + settings.startMargin;
				
				status.heading.x = controls.playBtn.x + getCenter(controls.playBtn);
				status.heading.y = stage.stageHeight - settings.controlsHeight - settings.startMargin;
			} else {
				statusHide();
				resizeControls();
				status.heading.y = 0;
				status.heading.x = settings.controlsMargin;
			}
			controls.scrubber.visible = show;
			controls.fullBtn.visible = show;
			controls.soundBtn.visible = show;
			volumeButton(show);
		}
		
		private function controlsBtns():void {
			var buttons:Array /* of MovieClips */ = [controls.fullBtn, controls.playBtn, controls.pauseBtn, controls.soundBtn, controls.scrubber.container];
			
			var functions:Array /* of functions */ = [pressFullScreen, pressResume, pressPause, pressSound, pressScrubber];
			
			var loops:int = buttons.length;
			
			for (var i = 0; i<loops; i++) {
				buttonize(buttons[i], btnOver, btnOut, functions[i]);
			}
			
			thumbScreen.addEventListener(MouseEvent.CLICK, pressResume);
			videoScreen.addEventListener(MouseEvent.CLICK, pressToggle);
			
			scrubberShowTimerOver();
			
			controls.scrubber.scrubber.addEventListener(MouseEvent.MOUSE_DOWN, scrubberDown);
			controls.scrubber.scrubber.mouseChildren = false;
			controls.scrubber.scrubber.buttonMode = true;
			
			volumeDefault();
		}
		
		// --------------------------------------------------------------------
		//  Turn MovieClip into button
		// --------------------------------------------------------------------
		
		private function buttonize(button:MovieClip, functionOver, functionOut, functionPress) {
			button.addEventListener(MouseEvent.MOUSE_OVER, functionOver);
			button.addEventListener(MouseEvent.MOUSE_OUT, functionOut);
			button.mouseChildren = false;  
			button.buttonMode = true;
			button.addEventListener(MouseEvent.CLICK, functionPress);
		}
		
		// --------------------------------------------------------------------
		//  Scrubber methods
		// --------------------------------------------------------------------
		
		function scrubberShowTimerOver():void {
			controls.scrubber.addEventListener(MouseEvent.MOUSE_OVER, scrubberOver);  
			controls.scrubber.addEventListener(MouseEvent.MOUSE_OUT, scrubberOut); 
		}
		
		function scrubberHideTimerOver():void {
			controls.scrubber.removeEventListener(MouseEvent.MOUSE_OVER, scrubberOver);  
			controls.scrubber.removeEventListener(MouseEvent.MOUSE_OUT, scrubberOut); 
		}
		
		function scrubberDown(event:MouseEvent):void {
			scrubberHideTimerOver();
			
			scrubberClick();
			
			clearInterval(interval);
			interval = intervalInit(1);
			controls.scrubber.scrubber.startDrag(false, new Rectangle(0, controls.scrubber.scrubber.y, controls.scrubber.container.width, 0));  
			stage.addEventListener(MouseEvent.MOUSE_UP, scrubberUp);  
		} 
		
		function scrubberUp(event:MouseEvent):void {  
			scrubberShowTimerOver();
			
			stage.removeEventListener(MouseEvent.MOUSE_UP, scrubberUp);  
			controls.scrubber.scrubber.stopDrag(); 
			scrubIt();
			scrubberOut(event);
			
		}
		
		function scrubIt():void {
			stage.dispatchEvent(new MediaEvent('seek', seeking((controls.scrubber.scrubber.x/controls.scrubber.container.width)*duration)));
		}
		
		function scrubberOver(event:MouseEvent):void {
			clearInterval(interval);
			interval = intervalInit(2);
			controlsShowTimer();
		}
		
		function scrubberOut(event:MouseEvent):void {
			clearInterval(interval);
			interval = intervalInit(0);
			controlsHideTimer();
		}
		
		function scrubberClick():void {
			if (!played)
				stage.dispatchEvent(new Event('play'));
		}
		
		function btnOver(event:MouseEvent):void  {  
			event.currentTarget.gotoAndPlay('over');  
		}
		
		function btnOut(event:MouseEvent):void  {  
			event.currentTarget.gotoAndPlay('out');  
		}
	
		
		private function controlsChange():void {
			if (played) {
				controls.playBtn.visible = false;
				controls.pauseBtn.visible = true;
			} else {
				controls.playBtn.visible = true;
				controls.pauseBtn.visible = false;
			}
		}
		
		function pressFullScreen(event:Event):void {
			if (stage.displayState == StageDisplayState.NORMAL) {
				stage.displayState = StageDisplayState.FULL_SCREEN;
			} else {
				stage.displayState = StageDisplayState.NORMAL;
			}
		}
		
		function pressToggle(event:Event):void {
			if (played)
				pressPause(event);
			else
				pressResume(event);
		}
		
		function pressResume(event:Event):void {
			if (settings.autoplay == false) {
				stage.dispatchEvent(new Event('play'));
				settings.autoplay = true;
			} else {
				stage.dispatchEvent(new Event('resume'));
			}
			
			controlsChange();
		}
		
		function pressPause(event:Event):void {
			stage.dispatchEvent(new Event('pause'));
			
			controlsChange();
		}
		
		function pressSound(event:Event):void {
			soundToggle();
		}
		
		function pressScrubber(event:Event):void {
			stage.dispatchEvent(new MediaEvent('seek', seeking(mouse2Time())));
		}
		
		// --------------------------------------------------------------------
		//
		//  Sound methods
		//
		// --------------------------------------------------------------------
		
		private function soundInit(event:Event):void {
			debug('soundInit');
			
			soundSet(settings.soundVolume);
		}
		
		private function soundToggle():void {
			if (ns.soundTransform.volume > 0)
				soundSet(0);
			else
				soundSet(settings.soundVolume);
		}
		
		private function soundSet(volume:Number):void {				
			if (media) {
				volumeReflect(volume, ns.soundTransform.volume);
				ns.soundTransform = new SoundTransform(volume);
			} else {
				volumeReflect(volume, channel.soundTransform.volume);
				channel.soundTransform = new SoundTransform(volume);
			}
		}
		
		// --------------------------------------------------------------------
		//
		//  Buffer methods
		//
		// --------------------------------------------------------------------
		
		private function showBuffer():void {
			status.buffer.visible = true;
			clearInterval(interval);
			interval = intervalInit(3);
		}
		
		private function hideBuffer():void {
			status.buffer.visible = false;
			clearInterval(interval);
			interval = intervalInit(0);
		}
		
		// --------------------------------------------------------------------
		//
		//  Status methods
		//
		// --------------------------------------------------------------------
		
		private function statusHide():void {
			status.visible = false;
		}
		
		private function statusShow():void {
			status.visible = true;
		}
		
		private function statusToggle():void {
			status.visible = !status.visible;
		}
		
		private function statusInit(event:Event):void {
			debug('statusInit');
			
			hideBuffer();
			
			status.heading.content.text = settings.name;
			status.heading.content.autoSize = TextFieldAutoSize.LEFT;
			
			status.heading.addEventListener(MouseEvent.CLICK, goMedia);
			
			linkify(status.heading);
			
			stage.dispatchEvent(new Event('statusLoaded'));
		}
		
		function linkify(object):void {
			object.addEventListener(MouseEvent.MOUSE_OVER, textRollOver); 
			object.addEventListener(MouseEvent.MOUSE_OUT, textRollOut); 
			object.buttonMode = true; 
			object.mouseChildren = false;
			textBasic(object);
		}
		
		function textBasic(object):void {
			textChange(object, settings.linkColor); 
		}
		
		function textHover(object):void {
			textChange(object, settings.hoverColor);
		}
		
		function textChange(object, color):void {
			var original = object.content.text; 
			object.content.htmlText = '<font color="#' + color + '">' + original + '</font>';
		}
	
		function textRollOut(e:MouseEvent):void {
			textBasic(e.currentTarget);
		}
		
		function textRollOver(e:MouseEvent):void {
			textHover(e.currentTarget);
		}
		
		function goMedia(event:Event):void {
			goLink(settings.link);
		}
		
		function goLink(link):void {
			var request:URLRequest = new URLRequest(link);
			try {
				navigateToURL(request, '_blank');
			} catch (error:Error) {
				debug('URL Request failed on: ' + link);
			}
		}
		
		// --------------------------------------------------------------------
		//
		//  Stream methods
		//
		// --------------------------------------------------------------------
		
		private function streamInit(event:Event):void {
			debug('streamInit');
			
			if (media) {
				video = new Video();
				video.x = 0;
				video.y = 0;
				video.attachNetStream(ns);
				videoScreen.addChild(video);
				linkStreamMethods();
			} else {
				audio = new Sound();
				channel = new SoundChannel();
				audio.load(new URLRequest(path));
				linkAudioMethods();
			}
			
			if (settings.autoplay)
				stage.dispatchEvent(new Event('play'));
			
			stage.dispatchEvent(new Event('streamLoaded'));
		}
		
		private function linkAudioMethods():void {
			stage.addEventListener('play', audioPlay);
			stage.addEventListener('resume', audioResume);
			stage.addEventListener('pause', audioPause);
		}
		
		private function linkStreamMethods():void {
			stage.addEventListener('play', nsPlay);
			stage.addEventListener('resume', nsResume);
			stage.addEventListener('pause', nsPause);
			stage.addEventListener('seek', nsSeek);
		}
		
		private function audioPlay(event:Event):void {
			channel = audio.play();
			
			soundSet(settings.soundVolume);
			
			nsTogglePlayed();
		}
		
		private function audioResume(event:Event):void {
			channel = audio.play(position);
			
			nsTogglePlayed();
		}
		
		private function audioPause(event:Event):void {
			position = channel.position;
			
			nsTogglePlayed();
			
			channel.stop();
		}
		
		private function nsPlay(event:Event):void {
			thumbHide();
			
			ns.play(path);
			
			nsTogglePlayed();
			
			debug('Video ' + path + ' is playing');
		}
		
		private function nsResume(event:Event):void {
			nsTogglePlayed();
			
			statusHide();
			
			ns.resume();
		}
		
		private function nsPause(event:Event):void {
			nsTogglePlayed();
			
			statusShow();
			
			ns.pause();
		}
		
		private function nsTogglePlayed():void {
			played = !played;
			
			if ( ! started) {
				started = true;
				controlsSwitch(true);
			}
			
			debug('Playing' + String(played));
		}
		
		private function nsSeek(event:MediaEvent):void {
			ns.seek(event.data.seconds);
		}
		
		// --------------------------------------------------------------------
		//
		//  Thumb methods
		//
		// --------------------------------------------------------------------
		
		private function thumbInit(event:Event):void {
			debug('thumbInit');
			
			var thumbLoader:Loader = new Loader();
			var thumb:URLRequest = new URLRequest(settings.thumb);
			
			thumbLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, thumbLoaded);
			thumbLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, thumbProgress);
			thumbLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, thumbError);
			thumbLoader.load(thumb);
			thumbScreen.addChild(thumbLoader);
		}
		
		private function thumbHide():void {
			thumbScreen.visible = false;
		}
		
		private function thumbProgress(event:ProgressEvent):void {
			trace(Math.round((event.bytesLoaded/event.bytesTotal)*100) + '%');
		}
		
		
		/**
		 * thumbLoaded
		 *
		 * ThumbLoaded => dispatch thumbLoaded event
		 * to proceed.
		 */
		private function thumbLoaded(event:Event):void {
			curtainHide();
				
			stage.dispatchEvent(new Event('thumbLoaded'));
				
			debug('Thumb ' + settings.thumb + ' was loaded');
		}
		
		/**
		 * thumbError
		 *
		 * ThumbError => dispatch thumbLoaded event
		 * and try to proceed without thumb.
		 */
		private function thumbError(event:IOErrorEvent):void {
			curtainHide();
			
			stage.dispatchEvent(new Event('thumbLoaded'));
			
			debug('ioErrorHandler: ' + event.text);
		} 
		
		// --------------------------------------------------------------------
		//
		//  Curtain methods
		//
		// --------------------------------------------------------------------
		
		private function curtainResize():void {
			curtain.width = stage.stageWidth;
			curtain.height = stage.stageHeight;
		}
		
		private function curtainHide():void {
			curtain.visible = false;
		}
		
		private function curtainShow():void {
			curtain.visible = true;
		}
		
		private function curtainToggle():void {
			curtain.visible = !curtain.visible;
		}
		
		// --------------------------------------------------------------------
		//
		//  NetStream methods
		//
		// --------------------------------------------------------------------
		
		private function prepare():void {
			debug('prepate');
			
			media = setMediaType();
			
			nc = new NetConnection();  
			nc.connect(null);
			ns = new NetStream(nc);   
			
			meta = new Object();
			meta.onMetaData = onMetaData; 
			
			ns.client = meta;
			ns.bufferTime = settings.buffer;
			
			ns.addEventListener(NetStatusEvent.NET_STATUS, netStreamStatus);
			ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
			
			stage.dispatchEvent(new Event('prepared'));
		}
		
		private function setMediaType():Boolean {
			if (settings.audio == false) {
				path = settings.video;
				return true;
			} else {
				path = settings.audio;
				return false;
			}
		}
		
		private function onMetaData(metaData:Object):void {
			video.width = metaData.width;
			video.height = metaData.height;
			duration = metaData.duration; 
		}
		
		function asyncErrorHandler(event:AsyncErrorEvent):void {  
			debug(event.text); 
		} 
		
		private function netStreamStatus(event:NetStatusEvent):void {
			switch(event.info.code)
			{
				case 'NetStream.FileStructureInvalid':
				{
					debug('NetStream.FileStructureInvalid');
					break;
				}
				
				case 'NetStream.NoSupportedTrackFound':
				{
					debug('NetStream.NoSupportedTrackFound');
					break;
				}
				
				case 'NetStream.Buffer.Full':  		//  buffer is full
				{
					debug('NetStream.Buffer.Full');
					ns.bufferTime = settings.exapndedBuffer;
					hideBuffer();
					break;
				}
				
				case 'NetStream.Buffer.Empty':  	//  buffer is empty
				{
					debug('NetStream.Buffer.Empty');
					ns.bufferTime = settings.buffer;
					if (ns.bytesLoaded < ns.bytesTotal) {
						showBuffer();
					}
					break;
				}
				
				case 'NetStream.Play.Start':  		//  ns.play() fires start
				{
					debug('NetStream.Play.Start');
					showBuffer();
					break;
				}
				
				case 'NetStream.Seek.Notify':  		// ns.seek() fires notify (scrubber / rewind)
				{
					debug('NetStream.Seek.Notify');
					showBuffer();
					break;
				}
				
				case 'NetStream.Seek.InvalidTime':	// Scrubber ahead of loaded
				{
					debug('NetStream.Seek.InvalidTime');
					break;
				}
				
				case 'NetStream.Play.Stop':  		// End of netStream
				{
					debug('NetStream.Play.Stop');
					stage.dispatchEvent(new MediaEvent('seek', seeking(0)));
					controls.pauseBtn.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
					break;
				}
				
				case 'NetStream.Play.Flush': 		// Flush of netStream
				{
					debug('NetStream.Play.Flush');
					break;
				}
			}
		}
		
		private function seeking(seconds:int):Object {
			var seeking = new Object();
			seeking.seconds = seconds;
			return seeking;
		}
		
		// --------------------------------------------------------------------
		//
		//  Settings methods
		//
		// --------------------------------------------------------------------
		
		private function settingsFactory(settings:Object):Object {
			for (var key in factory) {
				if (settings[key] == undefined)
					settings[key] = factory[key];
			}
			return settings;
		}
		
		// --------------------------------------------------------------------
		//
		//  Support methods
		//
		// --------------------------------------------------------------------
		
		private function debug(message:String):void {
			if (settings.debug == true)
				trace(message);
		}
		
		// --------------------------------------------------------------------

	}
	
}