1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * 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" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla code.
17 : *
18 : * The Initial Developer of the Original Code is the Mozilla Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2007
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Chris Double <chris.double@double.co.nz>
24 : * Chris Pearce <chris@pearce.org.nz>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 : /*
40 : Each video element based on nsBuiltinDecoder has a state machine to manage
41 : its play state and keep the current frame up to date. All state machines
42 : share time in a single shared thread. Each decoder also has one thread
43 : dedicated to decoding audio and video data. This thread is shutdown when
44 : playback is paused. Each decoder also has a thread to push decoded audio
45 : to the hardware. This thread is not created until playback starts, but
46 : currently is not destroyed when paused, only when playback ends.
47 :
48 : The decoder owns the resources for downloading the media file, and the
49 : high level state. It holds an owning reference to the state machine
50 : (a subclass of nsDecoderStateMachine; nsBuiltinDecoderStateMachine) that
51 : owns all the resources related to decoding data, and manages the low level
52 : decoding operations and A/V sync.
53 :
54 : Each state machine runs on the shared state machine thread. Every time some
55 : action is required for a state machine, it is scheduled to run on the shared
56 : the state machine thread. The state machine runs one "cycle" on the state
57 : machine thread, and then returns. If necessary, it will schedule itself to
58 : run again in future. While running this cycle, it must not block the
59 : thread, as other state machines' events may need to run. State shared
60 : between a state machine's threads is synchronised via the monitor owned
61 : by its nsBuiltinDecoder object.
62 :
63 : The Main thread controls the decode state machine by setting the value
64 : of a mPlayState variable and notifying on the monitor based on the
65 : high level player actions required (Seek, Pause, Play, etc).
66 :
67 : The player states are the states requested by the client through the
68 : DOM API. They represent the desired state of the player, while the
69 : decoder's state represents the actual state of the decoder.
70 :
71 : The high level state of the player is maintained via a PlayState value.
72 : It can have the following states:
73 :
74 : START
75 : The decoder has been initialized but has no resource loaded.
76 : PAUSED
77 : A request via the API has been received to pause playback.
78 : LOADING
79 : A request via the API has been received to load a resource.
80 : PLAYING
81 : A request via the API has been received to start playback.
82 : SEEKING
83 : A request via the API has been received to start seeking.
84 : COMPLETED
85 : Playback has completed.
86 : SHUTDOWN
87 : The decoder is about to be destroyed.
88 :
89 : State transition occurs when the Media Element calls the Play, Seek,
90 : etc methods on the nsBuiltinDecoder object. When the transition
91 : occurs nsBuiltinDecoder then calls the methods on the decoder state
92 : machine object to cause it to behave as required by the play state.
93 : State transitions will likely schedule the state machine to run to
94 : affect the change.
95 :
96 : An implementation of the nsDecoderStateMachine class is the event
97 : that gets dispatched to the state machine thread. Each time the event is run,
98 : the state machine must cycle the state machine once, and then return.
99 :
100 : The state machine has the following states:
101 :
102 : DECODING_METADATA
103 : The media headers are being loaded, and things like framerate, etc are
104 : being determined, and the first frame of audio/video data is being decoded.
105 : DECODING
106 : The decode has started. If the PlayState is PLAYING, the decode thread
107 : should be alive and decoding video and audio frame, the audio thread
108 : should be playing audio, and the state machine should run periodically
109 : to update the video frames being displayed.
110 : SEEKING
111 : A seek operation is in progress. The decode thread should be seeking.
112 : BUFFERING
113 : Decoding is paused while data is buffered for smooth playback. If playback
114 : is paused (PlayState transitions to PAUSED) we'll destory the decode thread.
115 : COMPLETED
116 : The resource has completed decoding, but possibly not finished playback.
117 : The decode thread will be destroyed. Once playback finished, the audio
118 : thread will also be destroyed.
119 : SHUTDOWN
120 : The decoder object and its state machine are about to be destroyed.
121 : Once the last state machine has been destroyed, the shared state machine
122 : thread will also be destroyed. It will be recreated later if needed.
123 :
124 : The following result in state transitions.
125 :
126 : Shutdown()
127 : Clean up any resources the nsDecoderStateMachine owns.
128 : Play()
129 : Start decoding and playback of media data.
130 : Buffer
131 : This is not user initiated. It occurs when the
132 : available data in the stream drops below a certain point.
133 : Complete
134 : This is not user initiated. It occurs when the
135 : stream is completely decoded.
136 : Seek(double)
137 : Seek to the time position given in the resource.
138 :
139 : A state transition diagram:
140 :
141 : DECODING_METADATA
142 : | |
143 : v | Shutdown()
144 : | |
145 : v -->-------------------->--------------------------|
146 : |---------------->----->------------------------| v
147 : DECODING | | | | |
148 : ^ v Seek(t) | | | |
149 : | Play() | v | | |
150 : ^-----------<----SEEKING | v Complete v v
151 : | | | | | |
152 : | | | COMPLETED SHUTDOWN-<-|
153 : ^ ^ | |Shutdown() |
154 : | | | >-------->-----^
155 : | Play() |Seek(t) |Buffer() |
156 : -----------<--------<-------BUFFERING |
157 : | ^
158 : v Shutdown() |
159 : | |
160 : ------------>-----|
161 :
162 : The following represents the states that the nsBuiltinDecoder object
163 : can be in, and the valid states the nsDecoderStateMachine can be in at that
164 : time:
165 :
166 : player LOADING decoder DECODING_METADATA
167 : player PLAYING decoder DECODING, BUFFERING, SEEKING, COMPLETED
168 : player PAUSED decoder DECODING, BUFFERING, SEEKING, COMPLETED
169 : player SEEKING decoder SEEKING
170 : player COMPLETED decoder SHUTDOWN
171 : player SHUTDOWN decoder SHUTDOWN
172 :
173 : The general sequence of events is:
174 :
175 : 1) The video element calls Load on nsMediaDecoder. This creates the
176 : state machine and starts the channel for downloading the
177 : file. It instantiates and schedules the nsDecoderStateMachine. The
178 : high level LOADING state is entered, which results in the decode
179 : thread being created and starting to decode metadata. These are
180 : the headers that give the video size, framerate, etc. Load() returns
181 : immediately to the calling video element.
182 :
183 : 2) When the metadata has been loaded by the decode thread, the state machine
184 : will call a method on the video element object to inform it that this
185 : step is done, so it can do the things required by the video specification
186 : at this stage. The decode thread then continues to decode the first frame
187 : of data.
188 :
189 : 3) When the first frame of data has been successfully decoded the state
190 : machine calls a method on the video element object to inform it that
191 : this step has been done, once again so it can do the required things
192 : by the video specification at this stage.
193 :
194 : This results in the high level state changing to PLAYING or PAUSED
195 : depending on any user action that may have occurred.
196 :
197 : While the play state is PLAYING, the decode thread will decode
198 : data, and the audio thread will push audio data to the hardware to
199 : be played. The state machine will run periodically on the shared
200 : state machine thread to ensure video frames are played at the
201 : correct time; i.e. the state machine manages A/V sync.
202 :
203 : The Shutdown method on nsBuiltinDecoder closes the download channel, and
204 : signals to the state machine that it should shutdown. The state machine
205 : shuts down asynchronously, and will release the owning reference to the
206 : state machine once its threads are shutdown.
207 :
208 : The owning object of a nsBuiltinDecoder object *MUST* call Shutdown when
209 : destroying the nsBuiltinDecoder object.
210 :
211 : */
212 : #if !defined(nsBuiltinDecoder_h_)
213 : #define nsBuiltinDecoder_h_
214 :
215 : #include "nsMediaDecoder.h"
216 :
217 : #include "nsISupports.h"
218 : #include "nsCOMPtr.h"
219 : #include "nsIThread.h"
220 : #include "nsIChannel.h"
221 : #include "nsIObserver.h"
222 : #include "nsIFrame.h"
223 : #include "nsAutoPtr.h"
224 : #include "nsSize.h"
225 : #include "prlog.h"
226 : #include "gfxContext.h"
227 : #include "gfxRect.h"
228 : #include "MediaResource.h"
229 : #include "nsMediaDecoder.h"
230 : #include "nsHTMLMediaElement.h"
231 : #include "mozilla/ReentrantMonitor.h"
232 :
233 : class nsAudioStream;
234 :
235 0 : static inline bool IsCurrentThread(nsIThread* aThread) {
236 0 : return NS_GetCurrentThread() == aThread;
237 : }
238 :
239 : // Decoder backends must implement this class to perform the codec
240 : // specific parts of decoding the video/audio format.
241 : class nsDecoderStateMachine : public nsRunnable
242 : {
243 : public:
244 : // Enumeration for the valid decoding states
245 : enum State {
246 : DECODER_STATE_DECODING_METADATA,
247 : DECODER_STATE_DECODING,
248 : DECODER_STATE_SEEKING,
249 : DECODER_STATE_BUFFERING,
250 : DECODER_STATE_COMPLETED,
251 : DECODER_STATE_SHUTDOWN
252 : };
253 :
254 : // Initializes the state machine, returns NS_OK on success, or
255 : // NS_ERROR_FAILURE on failure.
256 : virtual nsresult Init(nsDecoderStateMachine* aCloneDonor) = 0;
257 :
258 : // Return the current decode state. The decoder monitor must be
259 : // obtained before calling this.
260 : virtual State GetState() = 0;
261 :
262 : // Set the audio volume. The decoder monitor must be obtained before
263 : // calling this.
264 : virtual void SetVolume(double aVolume) = 0;
265 :
266 : virtual void Shutdown() = 0;
267 :
268 : // Called from the main thread to get the duration. The decoder monitor
269 : // must be obtained before calling this. It is in units of microseconds.
270 : virtual PRInt64 GetDuration() = 0;
271 :
272 : // Called from the main thread to set the duration of the media resource
273 : // if it is able to be obtained via HTTP headers. Called from the
274 : // state machine thread to set the duration if it is obtained from the
275 : // media metadata. The decoder monitor must be obtained before calling this.
276 : // aDuration is in microseconds.
277 : virtual void SetDuration(PRInt64 aDuration) = 0;
278 :
279 : // Called while decoding metadata to set the end time of the media
280 : // resource. The decoder monitor must be obtained before calling this.
281 : // aEndTime is in microseconds.
282 : virtual void SetEndTime(PRInt64 aEndTime) = 0;
283 :
284 : // Set the media fragment end time. aEndTime is in microseconds.
285 : virtual void SetFragmentEndTime(PRInt64 aEndTime) = 0;
286 :
287 : // Functions used by assertions to ensure we're calling things
288 : // on the appropriate threads.
289 : virtual bool OnDecodeThread() const = 0;
290 :
291 : // Returns true if the current thread is the state machine thread.
292 : virtual bool OnStateMachineThread() const = 0;
293 :
294 : virtual nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus() = 0;
295 :
296 : // Cause state transitions. These methods obtain the decoder monitor
297 : // to synchronise the change of state, and to notify other threads
298 : // that the state has changed.
299 : virtual void Play() = 0;
300 :
301 : // Seeks to aTime in seconds
302 : virtual void Seek(double aTime) = 0;
303 :
304 : // Returns the current playback position in seconds.
305 : // Called from the main thread to get the current frame time. The decoder
306 : // monitor must be obtained before calling this.
307 : virtual double GetCurrentTime() const = 0;
308 :
309 : // Clear the flag indicating that a playback position change event
310 : // is currently queued. This is called from the main thread and must
311 : // be called with the decode monitor held.
312 : virtual void ClearPositionChangeFlag() = 0;
313 :
314 : // Called from the main thread to set whether the media resource can
315 : // seek into unbuffered ranges. The decoder monitor must be obtained
316 : // before calling this.
317 : virtual void SetSeekable(bool aSeekable) = 0;
318 :
319 : // Returns true if the media resource can seek into unbuffered ranges,
320 : // as set by SetSeekable(). The decoder monitor must be obtained before
321 : // calling this.
322 : virtual bool IsSeekable() = 0;
323 :
324 : // Update the playback position. This can result in a timeupdate event
325 : // and an invalidate of the frame being dispatched asynchronously if
326 : // there is no such event currently queued.
327 : // Only called on the decoder thread. Must be called with
328 : // the decode monitor held.
329 : virtual void UpdatePlaybackPosition(PRInt64 aTime) = 0;
330 :
331 : virtual nsresult GetBuffered(nsTimeRanges* aBuffered) = 0;
332 :
333 : virtual PRInt64 VideoQueueMemoryInUse() = 0;
334 : virtual PRInt64 AudioQueueMemoryInUse() = 0;
335 :
336 : virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) = 0;
337 :
338 : // Causes the state machine to switch to buffering state, and to
339 : // immediately stop playback and buffer downloaded data. Must be called
340 : // with the decode monitor held. Called on the state machine thread and
341 : // the main thread.
342 : virtual void StartBuffering() = 0;
343 :
344 : // Sets the current size of the framebuffer used in MozAudioAvailable events.
345 : // Called on the state machine thread and the main thread.
346 : virtual void SetFrameBufferLength(PRUint32 aLength) = 0;
347 :
348 : // Called when a "MozAudioAvailable" event listener is added to the media
349 : // element. Called on the main thread.
350 : virtual void NotifyAudioAvailableListener() = 0;
351 : };
352 :
353 : class nsBuiltinDecoder : public nsMediaDecoder
354 : {
355 : public:
356 : typedef mozilla::MediaChannelStatistics MediaChannelStatistics;
357 :
358 : NS_DECL_ISUPPORTS
359 : NS_DECL_NSIOBSERVER
360 :
361 : // Enumeration for the valid play states (see mPlayState)
362 : enum PlayState {
363 : PLAY_STATE_START,
364 : PLAY_STATE_LOADING,
365 : PLAY_STATE_PAUSED,
366 : PLAY_STATE_PLAYING,
367 : PLAY_STATE_SEEKING,
368 : PLAY_STATE_ENDED,
369 : PLAY_STATE_SHUTDOWN
370 : };
371 :
372 : nsBuiltinDecoder();
373 : ~nsBuiltinDecoder();
374 :
375 : virtual bool Init(nsHTMLMediaElement* aElement);
376 :
377 : // This method must be called by the owning object before that
378 : // object disposes of this decoder object.
379 : virtual void Shutdown();
380 :
381 : virtual double GetCurrentTime();
382 :
383 : virtual nsresult Load(MediaResource* aResource,
384 : nsIStreamListener** aListener,
385 : nsMediaDecoder* aCloneDonor);
386 :
387 : virtual nsDecoderStateMachine* CreateStateMachine() = 0;
388 :
389 : // Start playback of a video. 'Load' must have previously been
390 : // called.
391 : virtual nsresult Play();
392 :
393 : // Seek to the time position in (seconds) from the start of the video.
394 : virtual nsresult Seek(double aTime);
395 :
396 : virtual nsresult PlaybackRateChanged();
397 :
398 : virtual void Pause();
399 : virtual void SetVolume(double aVolume);
400 : virtual double GetDuration();
401 :
402 : virtual void SetInfinite(bool aInfinite);
403 : virtual bool IsInfinite();
404 :
405 0 : virtual MediaResource* GetResource() { return mResource; }
406 : virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
407 :
408 : virtual void NotifySuspendedStatusChanged();
409 : virtual void NotifyBytesDownloaded();
410 : virtual void NotifyDownloadEnded(nsresult aStatus);
411 : // Called by the decode thread to keep track of the number of bytes read
412 : // from the resource.
413 : void NotifyBytesConsumed(PRInt64 aBytes);
414 :
415 : // Called when the video file has completed downloading.
416 : // Call on the main thread only.
417 : void ResourceLoaded();
418 :
419 : // Called if the media file encounters a network error.
420 : // Call on the main thread only.
421 : virtual void NetworkError();
422 :
423 : // Call from any thread safely. Return true if we are currently
424 : // seeking in the media resource.
425 : virtual bool IsSeeking() const;
426 :
427 : // Return true if the decoder has reached the end of playback.
428 : // Call on the main thread only.
429 : virtual bool IsEnded() const;
430 :
431 : // Set the duration of the media resource in units of seconds.
432 : // This is called via a channel listener if it can pick up the duration
433 : // from a content header. Must be called from the main thread only.
434 : virtual void SetDuration(double aDuration);
435 :
436 : // Set a flag indicating whether seeking is supported
437 : virtual void SetSeekable(bool aSeekable);
438 :
439 : // Return true if seeking is supported.
440 : virtual bool IsSeekable();
441 :
442 : virtual nsresult GetSeekable(nsTimeRanges* aSeekable);
443 :
444 : // Set the end time of the media resource. When playback reaches
445 : // this point the media pauses. aTime is in seconds.
446 : virtual void SetEndTime(double aTime);
447 :
448 : virtual Statistics GetStatistics();
449 :
450 : // Suspend any media downloads that are in progress. Called by the
451 : // media element when it is sent to the bfcache. Call on the main
452 : // thread only.
453 : virtual void Suspend();
454 :
455 : // Resume any media downloads that have been suspended. Called by the
456 : // media element when it is restored from the bfcache. Call on the
457 : // main thread only.
458 : virtual void Resume(bool aForceBuffering);
459 :
460 : // Tells our MediaResource to put all loads in the background.
461 : virtual void MoveLoadsToBackground();
462 :
463 : void AudioAvailable(float* aFrameBuffer, PRUint32 aFrameBufferLength, float aTime);
464 :
465 : // Called by the state machine to notify the decoder that the duration
466 : // has changed.
467 : void DurationChanged();
468 :
469 : bool OnStateMachineThread() const;
470 :
471 0 : bool OnDecodeThread() const {
472 0 : return mDecoderStateMachine->OnDecodeThread();
473 : }
474 :
475 : // Returns the monitor for other threads to synchronise access to
476 : // state.
477 0 : ReentrantMonitor& GetReentrantMonitor() {
478 0 : return mReentrantMonitor;
479 : }
480 :
481 : // Constructs the time ranges representing what segments of the media
482 : // are buffered and playable.
483 0 : virtual nsresult GetBuffered(nsTimeRanges* aBuffered) {
484 0 : if (mDecoderStateMachine) {
485 0 : return mDecoderStateMachine->GetBuffered(aBuffered);
486 : }
487 0 : return NS_ERROR_FAILURE;
488 : }
489 :
490 0 : virtual PRInt64 VideoQueueMemoryInUse() {
491 0 : if (mDecoderStateMachine) {
492 0 : return mDecoderStateMachine->VideoQueueMemoryInUse();
493 : }
494 0 : return 0;
495 : }
496 :
497 0 : virtual PRInt64 AudioQueueMemoryInUse() {
498 0 : if (mDecoderStateMachine) {
499 0 : return mDecoderStateMachine->AudioQueueMemoryInUse();
500 : }
501 0 : return 0;
502 : }
503 :
504 0 : virtual void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset) {
505 0 : if (mDecoderStateMachine) {
506 0 : mDecoderStateMachine->NotifyDataArrived(aBuffer, aLength, aOffset);
507 : }
508 0 : }
509 :
510 : // Sets the length of the framebuffer used in MozAudioAvailable events.
511 : // The new size must be between 512 and 16384.
512 : virtual nsresult RequestFrameBufferLength(PRUint32 aLength);
513 :
514 : // Return the current state. Can be called on any thread. If called from
515 : // a non-main thread, the decoder monitor must be held.
516 : PlayState GetState() {
517 : return mPlayState;
518 : }
519 :
520 : // Stop updating the bytes downloaded for progress notifications. Called
521 : // when seeking to prevent wild changes to the progress notification.
522 : // Must be called with the decoder monitor held.
523 : void StopProgressUpdates();
524 :
525 : // Allow updating the bytes downloaded for progress notifications. Must
526 : // be called with the decoder monitor held.
527 : void StartProgressUpdates();
528 :
529 : // Something has changed that could affect the computed playback rate,
530 : // so recompute it. The monitor must be held.
531 : void UpdatePlaybackRate();
532 :
533 : // The actual playback rate computation. The monitor must be held.
534 : double ComputePlaybackRate(bool* aReliable);
535 :
536 : // Make the decoder state machine update the playback position. Called by
537 : // the reader on the decoder thread (Assertions for this checked by
538 : // mDecoderStateMachine). This must be called with the decode monitor
539 : // held.
540 0 : void UpdatePlaybackPosition(PRInt64 aTime)
541 : {
542 0 : mDecoderStateMachine->UpdatePlaybackPosition(aTime);
543 0 : }
544 :
545 : /******
546 : * The following methods must only be called on the main
547 : * thread.
548 : ******/
549 :
550 : // Change to a new play state. This updates the mState variable and
551 : // notifies any thread blocking on this object's monitor of the
552 : // change. Call on the main thread only.
553 : void ChangeState(PlayState aState);
554 :
555 : // Called when the metadata from the media file has been read.
556 : // Call on the main thread only.
557 : void MetadataLoaded(PRUint32 aChannels,
558 : PRUint32 aRate);
559 :
560 : // Called when the first frame has been loaded.
561 : // Call on the main thread only.
562 : void FirstFrameLoaded();
563 :
564 : // Called when the video has completed playing.
565 : // Call on the main thread only.
566 : void PlaybackEnded();
567 :
568 : // Seeking has stopped. Inform the element on the main
569 : // thread.
570 : void SeekingStopped();
571 :
572 : // Seeking has stopped at the end of the resource. Inform the element on the main
573 : // thread.
574 : void SeekingStoppedAtEnd();
575 :
576 : // Seeking has started. Inform the element on the main
577 : // thread.
578 : void SeekingStarted();
579 :
580 : // Called when the backend has changed the current playback
581 : // position. It dispatches a timeupdate event and invalidates the frame.
582 : // This must be called on the main thread only.
583 : void PlaybackPositionChanged();
584 :
585 : // Calls mElement->UpdateReadyStateForData, telling it which state we have
586 : // entered. Main thread only.
587 : void NextFrameUnavailableBuffering();
588 : void NextFrameAvailable();
589 : void NextFrameUnavailable();
590 :
591 : // Calls mElement->UpdateReadyStateForData, telling it whether we have
592 : // data for the next frame and if we're buffering. Main thread only.
593 : void UpdateReadyStateForData();
594 :
595 : // Find the end of the cached data starting at the current decoder
596 : // position.
597 : PRInt64 GetDownloadPosition();
598 :
599 : // Updates the approximate byte offset which playback has reached. This is
600 : // used to calculate the readyState transitions.
601 : void UpdatePlaybackOffset(PRInt64 aOffset);
602 :
603 : // Provide access to the state machine object
604 0 : nsDecoderStateMachine* GetStateMachine() { return mDecoderStateMachine; }
605 :
606 : // Return the current decode state. The decoder monitor must be
607 : // obtained before calling this.
608 0 : nsDecoderStateMachine::State GetDecodeState() { return mDecoderStateMachine->GetState(); }
609 :
610 : // Drop reference to state machine. Only called during shutdown dance.
611 : void ReleaseStateMachine() { mDecoderStateMachine = nsnull; }
612 :
613 : // Called when a "MozAudioAvailable" event listener is added to the media
614 : // element. Called on the main thread.
615 : virtual void NotifyAudioAvailableListener();
616 :
617 : // Notifies the element that decoding has failed.
618 : void DecodeError();
619 :
620 : // Schedules the state machine to run one cycle on the shared state
621 : // machine thread. Main thread only.
622 : nsresult ScheduleStateMachineThread();
623 :
624 : /******
625 : * The following members should be accessed with the decoder lock held.
626 : ******/
627 :
628 : // Current decoding position in the stream. This is where the decoder
629 : // is up to consuming the stream. This is not adjusted during decoder
630 : // seek operations, but it's updated at the end when we start playing
631 : // back again.
632 : PRInt64 mDecoderPosition;
633 : // Current playback position in the stream. This is (approximately)
634 : // where we're up to playing back the stream. This is not adjusted
635 : // during decoder seek operations, but it's updated at the end when we
636 : // start playing back again.
637 : PRInt64 mPlaybackPosition;
638 : // Data needed to estimate playback data rate. The timeline used for
639 : // this estimate is "decode time" (where the "current time" is the
640 : // time of the last decoded video frame).
641 : MediaChannelStatistics mPlaybackStatistics;
642 :
643 : // The current playback position of the media resource in units of
644 : // seconds. This is updated approximately at the framerate of the
645 : // video (if it is a video) or the callback period of the audio.
646 : // It is read and written from the main thread only.
647 : double mCurrentTime;
648 :
649 : // Volume that playback should start at. 0.0 = muted. 1.0 = full
650 : // volume. Readable/Writeable from the main thread.
651 : double mInitialVolume;
652 :
653 : // Position to seek to when the seek notification is received by the
654 : // decode thread. Written by the main thread and read via the
655 : // decode thread. Synchronised using mReentrantMonitor. If the
656 : // value is negative then no seek has been requested. When a seek is
657 : // started this is reset to negative.
658 : double mRequestedSeekTime;
659 :
660 : // Duration of the media resource. Set to -1 if unknown.
661 : // Set when the metadata is loaded. Accessed on the main thread
662 : // only.
663 : PRInt64 mDuration;
664 :
665 : // True if the media resource is seekable (server supports byte range
666 : // requests).
667 : bool mSeekable;
668 :
669 : /******
670 : * The following member variables can be accessed from any thread.
671 : ******/
672 :
673 : // The state machine object for handling the decoding. It is safe to
674 : // call methods of this object from other threads. Its internal data
675 : // is synchronised on a monitor. The lifetime of this object is
676 : // after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
677 : // is safe to access it during this period.
678 : nsCOMPtr<nsDecoderStateMachine> mDecoderStateMachine;
679 :
680 : // Media data resource.
681 : nsAutoPtr<MediaResource> mResource;
682 :
683 : // ReentrantMonitor for detecting when the video play state changes. A call
684 : // to Wait on this monitor will block the thread until the next
685 : // state change.
686 : ReentrantMonitor mReentrantMonitor;
687 :
688 : // Set to one of the valid play states. It is protected by the
689 : // monitor mReentrantMonitor. This monitor must be acquired when reading or
690 : // writing the state. Any change to the state on the main thread
691 : // must call NotifyAll on the monitor so the decode thread can wake up.
692 : PlayState mPlayState;
693 :
694 : // The state to change to after a seek or load operation. It must only
695 : // be changed from the main thread. The decoder monitor must be acquired
696 : // when writing to the state, or when reading from a non-main thread.
697 : // Any change to the state must call NotifyAll on the monitor.
698 : PlayState mNextState;
699 :
700 : // True when we have fully loaded the resource and reported that
701 : // to the element (i.e. reached NETWORK_LOADED state).
702 : // Accessed on the main thread only.
703 : bool mResourceLoaded;
704 :
705 : // True when seeking or otherwise moving the play position around in
706 : // such a manner that progress event data is inaccurate. This is set
707 : // during seek and duration operations to prevent the progress indicator
708 : // from jumping around. Read/Write from any thread. Must have decode monitor
709 : // locked before accessing.
710 : bool mIgnoreProgressData;
711 :
712 : // True if the stream is infinite (e.g. a webradio).
713 : bool mInfiniteStream;
714 : };
715 :
716 : #endif
|