source: trunk/fl5/src/com/longtailvideo/jwplayer/media/RTMPMediaProvider.as @ 523

Revision 523, 9.5 KB checked in by zach, 4 years ago (diff)
  • Added complete and errors functions and updated ImageMediaProvider, MediaProvider, RTMPMediaProvider, SoundMediaProvider, VideoMediaProvider, and YouTubeMediaProvider
  • Fixed YouTube stop / resume problem
  • Fixed RTMP stop / resume problem, buffering info problem, item duration problem
Line 
1/**
2 * Wrapper for playback of video streamed over RTMP.
3 *
4 * All playback functionalities are cross-server (FMS, Wowza, Red5), with the exception of:
5 * - The SecureToken functionality (Wowza).
6 * - getStreamLength / checkBandwidth (FMS3).
7 **/
8package com.longtailvideo.jwplayer.media {
9        import com.jeroenwijering.events.*;
10        import com.longtailvideo.jwplayer.events.MediaEvent;
11        import com.longtailvideo.jwplayer.model.PlayerConfig;
12        import com.longtailvideo.jwplayer.model.PlaylistItem;
13        import com.longtailvideo.jwplayer.player.PlayerState;
14        import com.longtailvideo.jwplayer.utils.NetClient;
15        import com.longtailvideo.jwplayer.utils.TEA;
16       
17        import flash.events.*;
18        import flash.media.*;
19        import flash.net.*;
20        import flash.utils.*;
21       
22       
23        public class RTMPMediaProvider extends MediaProvider {
24                /** Video object to be instantiated. **/
25                protected var video:Video;
26                /** NetConnection object for setup of the video stream. **/
27                protected var connection:NetConnection;
28                /** Loader instance that loads the XML file. **/
29                private var loader:URLLoader;
30                /** NetStream instance that handles the stream IO. **/
31                protected var stream:NetStream;
32                /** Sound control object. **/
33                protected var transformer:SoundTransform;
34                /** Save the location of the XML redirect. **/
35                private var smil:String;
36                /** Save that the video has been started. **/
37                protected var started:Boolean;
38                /** ID for the position interval. **/
39                protected var interval:Number;
40                /** Save that a file is unpublished. **/
41                protected var unpublished:Boolean;
42               
43               
44                public function RTMPMediaProvider() {
45                }
46               
47               
48                /** Constructor; sets up the connection and display. **/
49                public override function initializeMediaProvider(cfg:PlayerConfig):void {
50                        super.initializeMediaProvider(cfg);
51                        _provider = 'rtmp';
52                        connection = new NetConnection();
53                        connection.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
54                        connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
55                        connection.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
56                        connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);
57                        connection.objectEncoding = ObjectEncoding.AMF0;
58                        connection.client = new NetClient(this);
59                        loader = new URLLoader();
60                        loader.addEventListener(Event.COMPLETE, loaderHandler);
61                        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
62                        loader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
63                        video = new Video(320, 240);
64                        video.smoothing = _config.smoothing;
65                        transformer = new SoundTransform();
66                }
67               
68               
69                /** Catch security errors. **/
70                protected function errorHandler(evt:ErrorEvent):void {
71                        error(evt.text);
72                }
73               
74               
75                /** Extract the correct rtmp syntax from the file string. **/
76                protected function getID(url:String):String {
77                        var ext:String = url.substr(-4);
78                        if (ext == '.mp3') {
79                                return 'mp3:' + url.substr(0, url.length - 4);
80                        } else if (ext == '.mp4' || ext == '.mov' || ext == '.aac' || ext == '.m4a' || ext == '.f4v') {
81                                return 'mp4:' + url;
82                        } else if (ext == '.flv') {
83                                return url.substr(0, url.length - 4);
84                        } else {
85                                return url;
86                        }
87                }
88               
89               
90                /** Load content. **/
91                override public function load(itm:PlaylistItem):void {
92                        _item = itm;
93                        _position = 0;
94                        setState(PlayerState.BUFFERING);
95                        sendBufferEvent(0);
96                        if (getConfigProperty('loadbalance') as Boolean == true) {
97                                smil = item.file;
98                                loader.load(new URLRequest(smil));
99                        } else {
100                                finishLoad();
101                        }
102                }
103               
104               
105                /** Get the streamer / file from the loadbalancing XML. **/
106                private function loaderHandler(evt:Event):void {
107                        var xml:XML = XML(evt.currentTarget.data);
108                        item.streamer = xml.children()[0].children()[0].@base.toString();
109                        item.file = xml.children()[1].children()[0].@src.toString();
110                        finishLoad();
111                }
112               
113                /** Finalizes the loading process **/
114                private function finishLoad():void {
115                        if (!media){
116                                media = video;
117                        }
118                        connection.connect(item.streamer);
119                        _config.mute == true ? setVolume(0) : setVolume(_config.volume);
120                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_LOADED);
121                }               
122               
123                /** Get metadata information from netstream class. **/
124                public function onData(dat:Object):void {
125                        if (dat.width) {
126                                video.width = dat.width;
127                                video.height = dat.height;
128                                resize(_width, _height);
129                        }
130                        if (dat.duration && item.duration < 0) {
131                                item.duration = dat.duration;
132                        }
133                        if (dat.type == 'complete') {
134                                complete();
135                        } else if (dat.type == 'close') {
136                                stop();
137                        }
138                        if (_config.ignoremeta != true) {
139                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: dat});
140                        }
141                }
142               
143               
144                /** Pause playback. **/
145                override public function pause():void {
146                        stream.pause();
147                        clearInterval(interval);
148                        super.pause();
149                        if (started && item.duration == 0) {
150                                stop();
151                        }
152                }
153               
154               
155                /** Resume playing. **/
156                override public function play():void {
157                        stream.resume();
158                        interval = setInterval(positionInterval, 100);
159                        super.play();
160                }
161               
162               
163                /** Interval for the position progress. **/
164                protected function positionInterval():void {
165                        _position = Math.round(stream.time * 10) / 10;
166                        var bfr:Number = Math.round(stream.bufferLength / stream.bufferTime * 100);
167                        if (bfr < 95 && position < Math.abs(item.duration - stream.bufferTime - 1)) {
168                                if (state == PlayerState.PLAYING && bfr < 20) {
169                                        stream.pause();
170                                        setState(PlayerState.BUFFERING);
171                                        stream.bufferTime = _config.bufferlength;
172                                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: {bufferlength: _config.bufferlength}});
173                                }
174                        } else if (bfr > 95 && state == PlayerState.BUFFERING) {
175                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_BUFFER_FULL);
176                                stream.bufferTime = _config.bufferlength * 4;
177                                sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: {bufferlength: _config.bufferlength * 4}});
178                        }
179                       
180                        var bufferPercent:Number = Math.round((_position + stream.bufferLength) / item.duration * 100);
181                        if (state == PlayerState.BUFFERING) {
182                                // Totally accurate, but it looks strange
183                                // sendBufferEvent(bufferPercent);
184                        } else if (position < item.duration) {
185                                if (state == PlayerState.PLAYING && position >= 0) {
186                                        // Totally accurate, but it looks strange
187                                        // sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_TIME, {position: position, duration: item.duration, bufferPercent:bufferPercent});
188                                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_TIME, {position: position, duration: item.duration});
189                                }
190                        } else if (!isNaN(position) && item.duration > 0) {
191                                complete();
192                        }
193                }
194               
195               
196                /** Seek to a new position. **/
197                override public function seek(pos:Number):void {
198                        _position = pos;
199                        clearInterval(interval);
200                        stream.seek(position);
201                        interval = setInterval(positionInterval, 100);
202                        //stream.resume();
203                        //super.play();
204                }
205               
206               
207                /** Start the netstream object. **/
208                protected function setStream():void {
209                        stream = new NetStream(connection);
210                        stream.checkPolicyFile = true;
211                        stream.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
212                        stream.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
213                        stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);
214                        stream.bufferTime = _config.bufferlength;
215                        stream.client = new NetClient(this);
216                        video.attachNetStream(stream);
217                        interval = setInterval(positionInterval, 100);
218                        stream.play(getID(item.file));
219                }
220               
221               
222                /** Receive NetStream status updates. **/
223                protected function statusHandler(evt:NetStatusEvent):void {
224                        switch (evt.info.code) {
225                                case 'NetConnection.Connect.Success':
226                                        if (evt.info.secureToken != undefined) {
227                                                connection.call("secureTokenResponse", null, TEA.decrypt(evt.info.secureToken, _config.token));
228                                        }
229                                        setStream();
230                                        var res:Responder = new Responder(streamlengthHandler);
231                                        connection.call("getStreamLength", res, getID(item.file));
232                                        connection.call("checkBandwidth", null);
233                                        break;
234                                case 'NetStream.Play.Start':
235                                        if (item.start > 0 && !started) {
236                                                seek(item.start);
237                                        }
238                                        started = true;
239                                        break;
240                                case 'NetStream.Seek.Notify':
241                                        clearInterval(interval);
242                                        interval = setInterval(positionInterval, 100);
243                                        break;
244                                case 'NetConnection.Connect.Rejected':
245                                        try {
246                                                if (evt.info.ex.code == 302) {
247                                                        item.streamer = evt.info.ex.redirect;
248                                                        setTimeout(load, 100, item);
249                                                        return;
250                                                }
251                                        } catch (err:Error) {
252                                                var msg:String = evt.info.code;
253                                                if (evt.info['description']) {
254                                                        msg = evt.info['description'];
255                                                }
256                                                error(msg);
257                                        }
258                                        break;
259                                case 'NetStream.Failed':
260                                case 'NetStream.Play.StreamNotFound':
261                                        if (unpublished) {
262                                                onData({type: 'complete'});
263                                                unpublished = false;
264                                        } else {
265                                                error("Stream not found: " + item.file);
266                                        }
267                                        break;
268                                case 'NetConnection.Connect.Failed':
269                                        error("Server not found: " + item.streamer);
270                                        break;
271                                case 'NetStream.Play.UnpublishNotify':
272                                        unpublished = true;
273                                        break;
274                        }
275                        sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata: evt.info});
276                }
277               
278               
279                /** Destroy the stream. **/
280                override public function stop():void {
281                        if (stream && stream.time) {
282                                stream.close();
283                        }
284                        connection.close();
285                        started = false;
286                        clearInterval(interval);
287                        super.stop();
288                        if (smil) {
289                                item.file = smil;
290                        }
291                }
292               
293               
294                /** Get the streamlength returned from the connection. **/
295                private function streamlengthHandler(len:Number):void {
296                        if (len > 0) {
297                                onData({type: 'streamlength', duration: len});
298                        }
299                }
300               
301               
302                /** Set the volume level. **/
303                override public function setVolume(vol:Number):void {
304                        transformer.volume = vol / 100;
305                        if (stream) {
306                                stream.soundTransform = transformer;
307                        }
308                }
309        }
310}
Note: See TracBrowser for help on using the repository browser.