source: trunk/as3/com/jeroenwijering/models/RTMPModel.as @ 142

Revision 142, 6.2 KB checked in by jeroen, 4 years ago (diff)

more netstream traces in rtmp and non-0,0 fullscreen offsets in Controller

  • Property svn:executable set to *
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.jeroenwijering.models {
9
10
11import com.jeroenwijering.events.*;
12import com.jeroenwijering.models.BasicModel;
13import com.jeroenwijering.player.Model;
14import com.jeroenwijering.utils.NetClient;
15import com.jeroenwijering.utils.TEA;
16
17import flash.events.*;
18import flash.media.*;
19import flash.net.*;
20import flash.utils.*;
21
22
23public class RTMPModel extends BasicModel {
24
25
26        /** Video object to be instantiated. **/
27        protected var video:Video;
28        /** NetConnection object for setup of the video stream. **/
29        protected var connection:NetConnection;
30        /** NetStream instance that handles the stream IO. **/
31        protected var stream:NetStream;
32        /** Sound control object. **/
33        protected var transform:SoundTransform;
34
35
36        /** Constructor; sets up the connection and display. **/
37        public function RTMPModel(mod:Model):void {
38                super(mod);
39                connection = new NetConnection();
40                connection.addEventListener(NetStatusEvent.NET_STATUS,statusHandler);
41                connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR,errorHandler);
42                connection.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
43                connection.addEventListener(AsyncErrorEvent.ASYNC_ERROR,errorHandler);
44                connection.objectEncoding = ObjectEncoding.AMF0;
45                connection.client = new NetClient(this);
46                video = new Video(320,240);
47                video.smoothing = model.config['smoothing'];
48                transform = new SoundTransform();
49        };
50
51
52        /** Catch security errors. **/
53        protected function errorHandler(evt:ErrorEvent):void {
54                stop();
55                model.sendEvent(ModelEvent.ERROR,{message:evt.text});
56        };
57
58
59        /** Extract the correct rtmp syntax from the file string. **/
60        private function getID(url:String):String {
61                var ext:String = url.substr(-4);
62                if(ext == '.mp3') {
63                        return 'mp3:'+url.substr(0,url.length-4);
64                } else if(ext == '.mp4' || ext == '.mov' || ext == '.aac' || ext == '.m4a') {
65                        return 'mp4:'+url;
66                } else if (ext == '.flv') {
67                        return url.substr(0,url.length-4);
68                } else {
69                        return url;
70                }
71        };
72
73
74        /** Load content. **/
75        override public function load(itm:Object):void {
76                super.load(itm);
77                model.mediaHandler(video);
78                connection.connect(item['streamer']);
79        };
80
81
82        /** Get metadata information from netstream class. **/
83        public function onData(dat:Object):void {
84                if(dat.width) {
85                        video.width = dat.width;
86                        video.height = dat.height;
87                }
88                if(dat.duration) {
89                        dat.duration -= item['start'];
90                }
91                if(dat.type == 'complete') {
92                        clearInterval(interval);
93                        model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.COMPLETED});
94                }
95                model.sendEvent(ModelEvent.META,dat);
96        };
97
98
99        /** Pause playback. **/
100        override public function pause():void {
101                super.pause();
102                stream.pause();
103        };
104
105
106        /** Resume playing. **/
107        override public function play():void {
108                super.play();
109                stream.resume();
110        };
111
112
113        /** Interval for the position progress. **/
114        override protected function positionInterval():void {
115                position = Math.round(stream.time*10)/10;
116                var bfr:Number = Math.round(stream.bufferLength/stream.bufferTime*100);
117                if(bfr < 95 && position < Math.abs(item['duration']-stream.bufferTime-1)) {
118                        model.sendEvent(ModelEvent.BUFFER,{percentage:bfr});
119                        if(model.config['state'] != ModelStates.BUFFERING && bfr < 25) {
120                                model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.BUFFERING});
121                        }
122                } else if (bfr > 95 && model.config['state'] != ModelStates.PLAYING) {
123                        model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.PLAYING});
124                }
125                if(position < item['duration']) {
126                        model.sendEvent(ModelEvent.TIME,{position:position,duration:item['duration']});
127                } else if (item['duration'] > 0) {
128                        pause();
129                        model.sendEvent(ModelEvent.STATE,{newstate:ModelStates.COMPLETED});
130                }
131        };
132
133
134        /** Seek to a new position. **/
135        override public function seek(pos:Number):void {
136                super.seek(pos);
137                stream.seek(pos);
138        };
139
140
141        /** Start the netstream object. **/
142        protected function setStream() {
143                stream = new NetStream(connection);
144                stream.addEventListener(NetStatusEvent.NET_STATUS,statusHandler);
145                stream.addEventListener(IOErrorEvent.IO_ERROR,errorHandler);
146                stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR,errorHandler);
147                stream.bufferTime = model.config['bufferlength'];
148                stream.client = new NetClient(this);
149                video.attachNetStream(stream);
150                model.config['mute'] == true ? volume(0): volume(model.config['volume']);
151                interval = setInterval(positionInterval,100);
152                stream.play(getID(item['file']),item['start']);
153        };
154
155
156        /** Receive NetStream status updates. **/
157        protected function statusHandler(evt:NetStatusEvent):void {
158                switch (evt.info.code) {
159                        case 'NetConnection.Connect.Success':
160                                setStream();
161                                var res:Responder = new Responder(streamlengthHandler);
162                                connection.call("getStreamLength",res,getID(item['file']));
163                                connection.call("checkBandwidth",null);
164                                if(evt.info.secureToken != undefined) {
165                                        connection.call("secureTokenResponse",null,TEA.decrypt(evt.info.secureToken,model.config['token']));
166                                }
167                                break;
168                        case  'NetStream.Seek.Notify':
169                                clearInterval(interval);
170                                interval = setInterval(positionInterval,100);
171                                break;
172                        case 'NetConnection.Connect.Rejected':
173                                if(evt.info.ex.code == 302) {
174                                        item['streamer'] = evt.info.ex.redirect;
175                                        connection.connect(item['streamer']);
176                                }
177                                break;
178                        case 'NetStream.Failed':
179                        case 'NetStream.Play.StreamNotFound':
180                                stop();
181                                model.sendEvent(ModelEvent.ERROR,{message:"Stream not found: "+item['file']});
182                                break;
183                        case 'NetConnection.Connect.Failed':
184                                stop();
185                                model.sendEvent(ModelEvent.ERROR,{message:"Server not found: "+item['streamer']});
186                                break;
187                }
188                model.sendEvent(ModelEvent.META,{info:evt.info.code});
189        };
190
191
192        /** Destroy the stream. **/
193        override public function stop():void {
194                if(stream) {
195                        stream.close();
196                }
197                connection.close();
198                super.stop();
199        };
200
201
202        /** Get the streamlength returned from the connection. **/
203        private function streamlengthHandler(len:Number):void {
204                onData({type:'streamlength',duration:len-item['start']});
205        };
206
207
208        /** Set the volume level. **/
209        override public function volume(vol:Number):void {
210                transform.volume = vol/100;
211                if(stream) {
212                        stream.soundTransform = transform;
213                }
214        };
215
216
217};
218
219
220}
Note: See TracBrowser for help on using the repository browser.