1/*****************************************************
2*
3*  Copyright 2009 Adobe Systems Incorporated.  All Rights Reserved.
4*
5*****************************************************
6*  The contents of this file are subject to the Mozilla Public License
7*  Version 1.1 (the "License"); you may not use this file except in
8*  compliance with the License. You may obtain a copy of the License at
9*  http://www.mozilla.org/MPL/
10*
11*  Software distributed under the License is distributed on an "AS IS"
12*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
13*  License for the specific language governing rights and limitations
14*  under the License.
15*
16*
17*  The Initial Developer of the Original Code is Adobe Systems Incorporated.
18*  Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems
19*  Incorporated. All Rights Reserved.
20*
21*****************************************************/
22package org.osmf.net
23{
24	import flash.events.NetStatusEvent;
25	import flash.net.NetStream;
26	import flash.net.NetStreamPlayOptions;
27	import flash.net.NetStreamPlayTransitions;
28
29	import org.osmf.events.MediaError;
30	import org.osmf.events.MediaErrorCodes;
31	import org.osmf.events.MediaErrorEvent;
32	import org.osmf.media.MediaResourceBase;
33	import org.osmf.media.URLResource;
34	import org.osmf.traits.PlayState;
35	import org.osmf.traits.PlayTrait;
36	import org.osmf.utils.OSMFStrings;
37
38	[ExcludeClass]
39
40	/**
41	 * @private
42	 *
43	 * The NetStreamPlayTrait class extends PlayTrait for NetStream-based playback.
44	 *
45	 * @see flash.net.NetStream
46	 */
47	public class NetStreamPlayTrait extends PlayTrait
48	{
49		/**
50		 * 	Constructor.
51		 *
52		 *  @langversion 3.0
53		 *  @playerversion Flash 10
54		 *  @playerversion AIR 1.5
55		 *  @productversion OSMF 1.0
56		 */
57		public function NetStreamPlayTrait(netStream:NetStream, resource:MediaResourceBase)
58		{
59			super();
60
61			if (netStream == null)
62			{
63				throw new ArgumentError(OSMFStrings.getString(OSMFStrings.NULL_PARAM));
64			}
65			this.netStream = netStream;
66			this.urlResource = resource as URLResource;
67
68			// Live streams can't be paused.
69			var streamingResource:StreamingURLResource = resource as StreamingURLResource;
70			if (streamingResource != null && streamingResource.streamType == StreamType.LIVE)
71			{
72				setCanPause(false);
73			}
74
75			// Note that we add the listener (and handler) with a high priority.
76			// The reason for this is that we want to process any Play.Stop (and
77			// Play.Complete) events first, so that we can update our playing
78			// state before the NetStreamTimeTrait processes the event and
79			// dispatches the COMPLETE event.  Clients who register for the
80			// COMPLETE event will expect that the media is no longer playing.
81			netStream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus, false, 1, true);
82			NetClient(netStream.client).addHandler(NetStreamCodes.ON_PLAY_STATUS, onPlayStatus, 1);
83		}
84
85		/**
86		 * @private
87		 * Communicates a <code>playing</code> change to the media through the NetStream.
88		 * <p>For streaming media, parses the URL to extract the stream name.</p>
89		 * @param newPlaying New <code>playing</code> value.
90		 */
91		override protected function playStateChangeStart(newPlayState:String):void
92		{
93			if (newPlayState == PlayState.PLAYING)
94			{
95				var playArgs:Object;
96
97				if (streamStarted)
98				{
99					netStream.resume();
100				}
101				else if (urlResource != null)
102				{
103					// Map the resource to the NetStream.play/play2 arguments.
104					var streamingResource:StreamingURLResource = urlResource as StreamingURLResource;
105					var urlIncludesFMSApplicationInstance:Boolean = streamingResource ? streamingResource.urlIncludesFMSApplicationInstance : false;
106					var streamName:String = NetStreamUtils.getStreamNameFromURL(urlResource.url, urlIncludesFMSApplicationInstance);
107
108					playArgs = NetStreamUtils.getPlayArgsForResource(urlResource);
109
110					var startTime:Number = playArgs.start;
111					var len:Number = playArgs.len;
112
113					var dsResource:DynamicStreamingResource = urlResource as DynamicStreamingResource;
114					if (dsResource != null)
115					{
116						// Play the clip (or the requested portion of the clip).
117						var nso:NetStreamPlayOptions = new NetStreamPlayOptions();
118						nso.start = startTime;
119						nso.len = len;
120						nso.streamName = dsResource.streamItems[dsResource.initialIndex].streamName;
121						nso.transition = NetStreamPlayTransitions.RESET;
122
123						doPlay2(nso);
124					}
125					else
126					{
127						// Play the clip (or the requested portion of the clip).
128						doPlay(streamName, startTime, len);
129					}
130				}
131			}
132			else // PAUSED || STOPPED
133			{
134				netStream.pause();
135			}
136		}
137
138		// Needed to detect when the stream didn't play:  i.e. complete or error cases.
139		private function onNetStatus(event:NetStatusEvent):void
140		{
141			switch (event.info.code)
142			{
143				case NetStreamCodes.NETSTREAM_PLAY_FAILED:
144				case NetStreamCodes.NETSTREAM_PLAY_FILESTRUCTUREINVALID:
145				case NetStreamCodes.NETSTREAM_PLAY_STREAMNOTFOUND:
146				case NetStreamCodes.NETSTREAM_PLAY_NOSUPPORTEDTRACKFOUND:
147				case NetStreamCodes.NETSTREAM_FAILED:
148					// Pause the stream and reset our state, but don't
149					// signal stop().  The MediaElement's netStatus
150					// event handler will catch the error, and coerce
151					// to a MediaError.
152					netStream.pause();
153					streamStarted = false;
154					break;
155				case NetStreamCodes.NETSTREAM_PLAY_STOP:
156					// Fired when streaming connections buffer, but also when
157					// progressive connections finish.  In the latter case, we
158					// halt playback.
159					if (urlResource != null && NetStreamUtils.isStreamingResource(urlResource) == false)
160					{
161						// Explicitly stop to prevent the stream from restarting on seek();
162						stop();
163					}
164					break;
165			}
166		}
167
168		private function onPlayStatus(event:Object):void
169		{
170			switch (event.code)
171			{
172				// Fired when streaming connections finish.  Doesn't fire for
173				// Progressive connections.
174				case NetStreamCodes.NETSTREAM_PLAY_COMPLETE:
175					// Explicitly stop to prevent the stream from restarting on seek();
176					stop();
177					break;
178			}
179		}
180
181		private function doPlay(...args):void
182		{
183			try
184			{
185				netStream.play.apply(this, args);
186
187				streamStarted = true;
188			}
189			catch (error:Error)
190			{
191				streamStarted = false;
192				stop();
193
194				dispatchEvent
195					( new MediaErrorEvent
196						( MediaErrorEvent.MEDIA_ERROR
197						, false
198						, false
199						, new MediaError(MediaErrorCodes.NETSTREAM_PLAY_FAILED)
200						)
201					);
202			}
203		}
204
205		private function doPlay2(nspo:NetStreamPlayOptions):void
206		{
207			netStream.play2(nspo);
208
209			streamStarted = true;
210		}
211
212		private static const NETCONNECTION_FAILURE_ERROR_CODE:int = 2154;
213
214		private var streamStarted:Boolean;
215		private var netStream:NetStream;
216		private var urlResource:URLResource;
217	}
218}
219