Menu

[r229]: / trunk / libs / testing / NetMocker / org / osmf / netmocker / MockNetStream.as  Maximize  Restore  History

Download this file

491 lines (414 with data), 14.2 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
/*****************************************************
*
* Copyright 2009 Adobe Systems Incorporated. All Rights Reserved.
*
*****************************************************
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
*
* The Initial Developer of the Original Code is Adobe Systems Incorporated.
* Portions created by Adobe Systems Incorporated are Copyright (C) 2009 Adobe Systems
* Incorporated. All Rights Reserved.
*
*****************************************************/
package org.osmf.netmocker
{
import flash.events.TimerEvent;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.net.NetStreamPlayOptions;
import flash.net.NetStreamPlayTransitions;
import flash.utils.Timer;
import org.osmf.net.NetStreamCodes;
public class MockNetStream extends NetStream
{
/**
* Constructor.
**/
public function MockNetStream(connection:NetConnection)
{
super(connection);
_connection = connection;
// Intercept all NetStatusEvents dispatched from the base class.
eventInterceptor = new NetStatusEventInterceptor(this);
playheadTimer = new Timer(TIMER_DELAY);
playheadTimer.addEventListener(TimerEvent.TIMER, onPlayheadTimer);
}
/**
* The expected duration of the stream, in seconds. Necessary so that
* this mock stream class knows when to dispatch the events related
* to a stream completing. The default is zero.
**/
public function set expectedDuration(value:Number):void
{
this._expectedDuration = value;
}
public function get expectedDuration():Number
{
return _expectedDuration;
}
/**
* The expected total number of bytes of the stream. Applies to progressive
* media only. The default is 0.
**/
public function set expectedBytesTotal(value:uint):void
{
this._expectedBytesTotal = value;
}
public function get expectedBytesTotal():uint
{
return _expectedBytesTotal;
}
/**
* The expected duration of the stream when it's a subclip, in seconds.
* This is different from expectedDuration when the stream being played
* is a subclip. The default is NaN.
**/
public function set expectedSubclipDuration(value:Number):void
{
this._expectedSubclipDuration = value;
}
public function get expectedSubclipDuration():Number
{
return _expectedSubclipDuration;
}
/**
* The expected width of the stream, in pixels. Necessary so that
* this mock stream class knows the dimensions to include in the
* onMetaData callback. The default is zero.
**/
public function set expectedWidth(value:Number):void
{
this._expectedWidth = value;
}
public function get expectedWidth():Number
{
return _expectedWidth;
}
/**
* The expected array of cue points. Necessary so that this
* mock stream class can call the in-stream callback
* onCuePoint with the data you expect.
*
* Each value in the array should be an object
* with the following properties:
* <ul>
* <li>type - should be "event", "navigation"</li>
* <li>time - the time in seconds of the cue point</li>
* <li>name - the name of the cue point (can be any string)</li>
* <li>parameters - optional array of key/value pairs</li>
* </ul>
*/
public function set expectedCuePoints(value:Array):void
{
this._expectedCuePoints = value;
}
public function get expectedCuePoints():Array
{
return this._expectedCuePoints;
}
/**
* The expected height of the stream, in pixels. Necessary so that
* this mock stream class knows the dimensions to include in the
* onMetaData callback. The default is zero.
**/
public function set expectedHeight(value:Number):void
{
this._expectedHeight = value;
}
public function get expectedHeight():Number
{
return _expectedHeight;
}
/**
* An Array of EventInfos, representing the events that are expected
* to be dispatched when the playhead has passed a certain position.
**/
public function set expectedEvents(value:Array):void
{
this._expectedEvents = value;
}
public function get expectedEvents():Array
{
return _expectedEvents;
}
// Overrides
//
override public function get bufferLength():Number
{
return bufferLengthSet ? _bufferLength : super.bufferLength;
}
public function set bufferLength(value:Number):void
{
bufferLengthSet = true;
_bufferLength = value;
}
override public function get bytesLoaded():uint
{
return _bytesLoaded;
}
override public function get bytesTotal():uint
{
// The bytesTotal value doesn't "register" until playback begins.
return (playing || elapsedTime > 0) ? _expectedBytesTotal : 0;
}
override public function get time():Number
{
// Return value is in seconds.
return playing
? (elapsedTime + (flash.utils.getTimer() - absoluteTimeAtLastPlay))/1000
: elapsedTime;
}
override public function close():void
{
playing = false;
elapsedTime = 0;
playheadTimer.stop();
}
override public function play(...arguments):void
{
// The flash player sets the bufferTime to a 0.1 minimum for VOD (http://).
if (arguments != null && arguments.length > 0 && arguments[0].toString().substr(0,4) == "http")
{
isProgressive = true;
bufferTime = bufferTime < .1 ? .1 : bufferTime;
}
else
{
isProgressive = false;
_expectedBytesTotal = 0;
}
commonPlay();
}
override public function play2(nso:NetStreamPlayOptions):void
{
if (nso.transition == NetStreamPlayTransitions.SWITCH)
{
var infos:Array =
[ {"code":NetStreamCodes.NETSTREAM_PLAY_TRANSITION, "details":nso.streamName, "level":LEVEL_STATUS}
];
eventInterceptor.dispatchNetStatusEvents(infos, EVENT_DELAY);
var newTimer:Timer = new Timer(350, 1);
switchCompleteTimers.push(newTimer);
newTimer.addEventListener(TimerEvent.TIMER_COMPLETE, sendSwitchCompleteMsg);
newTimer.start();
}
else
{
isProgressive = false;
_expectedBytesTotal = 0;
commonPlay();
}
}
override public function pause():void
{
if (playing)
{
elapsedTime += ((flash.utils.getTimer() - absoluteTimeAtLastPlay) /1000);
}
playing = false;
playheadTimer.stop();
var infos:Array =
[ {"code":NetStreamCodes.NETSTREAM_PAUSE_NOTIFY, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_BUFFER_FLUSH, "level":LEVEL_STATUS}
];
eventInterceptor.dispatchNetStatusEvents(infos, EVENT_DELAY);
}
override public function resume():void
{
absoluteTimeAtLastPlay = flash.utils.getTimer();
playing = true;
playheadTimer.start();
var infos:Array =
[ {"code":NetStreamCodes.NETSTREAM_UNPAUSE_NOTIFY, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_PLAY_START, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_BUFFER_FULL, "level":LEVEL_STATUS}
];
eventInterceptor.dispatchNetStatusEvents(infos, EVENT_DELAY);
}
override public function seek(offset:Number):void
{
// Offset is in seconds.
if (offset >= 0 && offset <= normalizedExpectedDuration)
{
// Reset the fake cue point logic
this.lastFiredCuePointTime = -1;
//elapsedTime = offset;
if (playing)
{
absoluteTimeAtLastPlay = flash.utils.getTimer();
}
var infos:Array =
[ {"code":NetStreamCodes.NETSTREAM_SEEK_NOTIFY, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_PLAY_START, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_BUFFER_FULL, "level":LEVEL_STATUS}
];
eventInterceptor.dispatchNetStatusEvents(infos, EVENT_DELAY);
// There's a bug in NetStream (FP-1705) where NetStream.time
// doesn't get updated until after the NetStream.Seek.Notify
// event is dispatched. We mirror this bug here.
var timer:Timer = new Timer(300, 1);
timer.addEventListener(TimerEvent.TIMER, onNetStreamSeekBugTimer);
timer.start();
function onNetStreamSeekBugTimer(event:TimerEvent):void
{
timer.removeEventListener(TimerEvent.TIMER, onNetStreamSeekBugTimer);
elapsedTime = offset;
}
}
else
{
// TODO
}
}
// Internals
//
private function onPlayheadTimer(event:TimerEvent):void
{
var infos:Array;
if (time >= normalizedExpectedDuration)
{
elapsedTime = normalizedExpectedDuration;
playing = false;
playheadTimer.stop();
// For progressive, the NetStream.Play.Stop event is fired upon
// completion. For streaming, the NetStream.Play.Complete event
// is fired to onPlayStatus upon completion (and you might get
// a number of NetStream.Play.Stop events during playback).
//
infos =
[ {"code":NetStreamCodes.NETSTREAM_PLAY_STOP, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_BUFFER_FLUSH, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_BUFFER_EMPTY, "level":LEVEL_STATUS}
];
eventInterceptor.dispatchNetStatusEvents(infos);
if (isProgressive == false)
{
this.client.onPlayStatus({code:NetStreamCodes.NETSTREAM_PLAY_COMPLETE});
}
}
else
{
infos = getInfosForPosition(time);
if (infos.length > 0)
{
eventInterceptor.dispatchNetStatusEvents(infos);
}
// Call in-stream onCuePoint if we passed an expected cue point.
if (expectedCuePoints.length > 0)
{
for each (var info:Object in expectedCuePoints)
{
if ((time >= info.time) && (info.time > this.lastFiredCuePointTime))
{
// This will throw a Reference error if onCuePoint is not
// implemented on the client object. No reason to eat that
// exception here because this is an error. It means the caller
// added expected cue points on a media element with no
// possible way of detecting them.
this.client.onCuePoint(info);
this.lastFiredCuePointTime = info.time;
break;
}
}
}
}
_bytesLoaded = Math.min(_expectedBytesTotal, _bytesLoaded + _expectedBytesTotal / 4);
}
private function getInfosForPosition(position:Number):Array
{
var infos:Array = [];
for (var i:int = _expectedEvents.length; i > 0; i--)
{
var eventInfo:EventInfo = _expectedEvents[i-1];
if (position >= eventInfo.position)
{
infos.push( {"code":eventInfo.code, "level":eventInfo.level} );
// Remove the eventInfo, we don't want to dispatch
// it twice.
_expectedEvents.splice(i-1, 1);
}
}
return infos;
}
private function get normalizedExpectedDuration():Number
{
return isNaN(expectedSubclipDuration) ? expectedDuration : expectedSubclipDuration;
}
private function commonPlay():void
{
if (expectedDuration != 0)
{
var info:Object = {};
info["duration"] = expectedDuration;
if (expectedWidth > 0)
{
info["width"] = expectedWidth;
}
if (expectedHeight > 0)
{
info["height"] = expectedHeight;
}
if (expectedCuePoints != null && expectedCuePoints.length > 0)
{
info["cuePoints"] = expectedCuePoints;
}
try
{
client.onMetaData(info);
}
catch (e:ReferenceError)
{
// Swallow, there's no such property on the client
// and that's OK.
}
}
absoluteTimeAtLastPlay = flash.utils.getTimer();
playing = true;
playheadTimer.start();
var infos:Array =
[ {"code":NetStreamCodes.NETSTREAM_PLAY_RESET, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_PLAY_START, "level":LEVEL_STATUS}
, {"code":NetStreamCodes.NETSTREAM_BUFFER_FULL, "level":LEVEL_STATUS}
];
eventInterceptor.dispatchNetStatusEvents(infos, EVENT_DELAY);
}
private function sendSwitchCompleteMsg(event:TimerEvent):void
{
var oldTimer:Timer = switchCompleteTimers.shift();
oldTimer.removeEventListener(TimerEvent.TIMER, sendSwitchCompleteMsg);
this.client.onPlayStatus({code:NetStreamCodes.NETSTREAM_PLAY_TRANSITION_COMPLETE});
}
private var _connection:NetConnection;
private var eventInterceptor:NetStatusEventInterceptor;
private var _expectedDuration:Number = 0;
private var _expectedBytesTotal:uint = 0;
private var _expectedSubclipDuration:Number = NaN;
private var _expectedWidth:Number = 0;
private var _expectedHeight:Number = 0;
private var _expectedEvents:Array = [];
private var _expectedCuePoints:Array = [];
private var lastFiredCuePointTime:int = -1;
private var bufferLengthSet:Boolean = false;
private var _bufferLength:Number;
private var playheadTimer:Timer;
private var switchCompleteTimers:Vector.<Timer> = new Vector.<Timer>;
private var playing:Boolean = false;
private var elapsedTime:Number = 0; // seconds
private var absoluteTimeAtLastPlay:Number = 0; // milliseconds
private var isProgressive:Boolean;
private var _bytesLoaded:uint = 0;
private static const TIMER_DELAY:int = 100;
private static const EVENT_DELAY:int = 100;
private static const LEVEL_STATUS:String = "status";
private static const LEVEL_ERROR:String = "error";
}
}
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.