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: ML 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 Foundation.
19 : * Portions created by the Initial Developer are Copyright (C) 2010
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 for a media file has two threads:
41 :
42 : 1) The Audio thread writes the decoded audio data to the audio
43 : hardware. This is done in a separate thread to ensure that the
44 : audio hardware gets a constant stream of data without
45 : interruption due to decoding or display. At some point
46 : libsydneyaudio will be refactored to have a callback interface
47 : where it asks for data and an extra thread will no longer be
48 : needed.
49 :
50 : 2) The decode thread. This thread reads from the media stream and
51 : decodes the Theora and Vorbis data. It places the decoded data into
52 : queues for the other threads to pull from.
53 :
54 : All file reads, seeks, and all decoding must occur on the decode thread.
55 : Synchronisation of state between the thread is done via a monitor owned
56 : by nsBuiltinDecoder.
57 :
58 : The lifetime of the decode and audio threads is controlled by the state
59 : machine when it runs on the shared state machine thread. When playback
60 : needs to occur they are created and events dispatched to them to run
61 : them. These events exit when decoding/audio playback is completed or
62 : no longer required.
63 :
64 : A/V synchronisation is handled by the state machine. It examines the audio
65 : playback time and compares this to the next frame in the queue of video
66 : frames. If it is time to play the video frame it is then displayed, otherwise
67 : it schedules the state machine to run again at the time of the next frame.
68 :
69 : Frame skipping is done in the following ways:
70 :
71 : 1) The state machine will skip all frames in the video queue whose
72 : display time is less than the current audio time. This ensures
73 : the correct frame for the current time is always displayed.
74 :
75 : 2) The decode thread will stop decoding interframes and read to the
76 : next keyframe if it determines that decoding the remaining
77 : interframes will cause playback issues. It detects this by:
78 : a) If the amount of audio data in the audio queue drops
79 : below a threshold whereby audio may start to skip.
80 : b) If the video queue drops below a threshold where it
81 : will be decoding video data that won't be displayed due
82 : to the decode thread dropping the frame immediately.
83 :
84 : When hardware accelerated graphics is not available, YCbCr conversion
85 : is done on the decode thread when video frames are decoded.
86 :
87 : The decode thread pushes decoded audio and videos frames into two
88 : separate queues - one for audio and one for video. These are kept
89 : separate to make it easy to constantly feed audio data to the audio
90 : hardware while allowing frame skipping of video data. These queues are
91 : threadsafe, and neither the decode, audio, or state machine should
92 : be able to monopolize them, and cause starvation of the other threads.
93 :
94 : Both queues are bounded by a maximum size. When this size is reached
95 : the decode thread will no longer decode video or audio depending on the
96 : queue that has reached the threshold. If both queues are full, the decode
97 : thread will wait on the decoder monitor.
98 :
99 : When the decode queues are full (they've reaced their maximum size) and
100 : the decoder is not in PLAYING play state, the state machine may opt
101 : to shut down the decode thread in order to conserve resources.
102 :
103 : During playback the audio thread will be idle (via a Wait() on the
104 : monitor) if the audio queue is empty. Otherwise it constantly pops
105 : audio data off the queue and plays it with a blocking write to the audio
106 : hardware (via nsAudioStream and libsydneyaudio).
107 :
108 : */
109 : #if !defined(nsBuiltinDecoderStateMachine_h__)
110 : #define nsBuiltinDecoderStateMachine_h__
111 :
112 : #include "prmem.h"
113 : #include "nsThreadUtils.h"
114 : #include "nsBuiltinDecoder.h"
115 : #include "nsBuiltinDecoderReader.h"
116 : #include "nsAudioAvailableEventManager.h"
117 : #include "nsHTMLMediaElement.h"
118 : #include "mozilla/ReentrantMonitor.h"
119 : #include "nsITimer.h"
120 :
121 : /*
122 : The state machine class. This manages the decoding and seeking in the
123 : nsBuiltinDecoderReader on the decode thread, and A/V sync on the shared
124 : state machine thread, and controls the audio "push" thread.
125 :
126 : All internal state is synchronised via the decoder monitor. State changes
127 : are either propagated by NotifyAll on the monitor (typically when state
128 : changes need to be propagated to non-state machine threads) or by scheduling
129 : the state machine to run another cycle on the shared state machine thread.
130 :
131 : See nsBuiltinDecoder.h for more details.
132 : */
133 : class nsBuiltinDecoderStateMachine : public nsDecoderStateMachine
134 : {
135 : public:
136 : typedef mozilla::ReentrantMonitor ReentrantMonitor;
137 : typedef mozilla::TimeStamp TimeStamp;
138 : typedef mozilla::TimeDuration TimeDuration;
139 : typedef mozilla::VideoFrameContainer VideoFrameContainer;
140 :
141 : nsBuiltinDecoderStateMachine(nsBuiltinDecoder* aDecoder, nsBuiltinDecoderReader* aReader, bool aRealTime = false);
142 : ~nsBuiltinDecoderStateMachine();
143 :
144 : // nsDecoderStateMachine interface
145 : virtual nsresult Init(nsDecoderStateMachine* aCloneDonor);
146 0 : State GetState()
147 : {
148 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
149 0 : return mState;
150 : }
151 : virtual void SetVolume(double aVolume);
152 : virtual void Shutdown();
153 : virtual PRInt64 GetDuration();
154 : virtual void SetDuration(PRInt64 aDuration);
155 : void SetEndTime(PRInt64 aEndTime);
156 0 : virtual bool OnDecodeThread() const {
157 0 : return IsCurrentThread(mDecodeThread);
158 : }
159 :
160 : virtual nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
161 : virtual void Play();
162 : virtual void Seek(double aTime);
163 : virtual double GetCurrentTime() const;
164 : virtual void ClearPositionChangeFlag();
165 : virtual void SetSeekable(bool aSeekable);
166 : virtual void UpdatePlaybackPosition(PRInt64 aTime);
167 : virtual void StartBuffering();
168 :
169 : // State machine thread run function. Defers to RunStateMachine().
170 : NS_IMETHOD Run();
171 :
172 : // This is called on the state machine thread and audio thread.
173 : // The decoder monitor must be obtained before calling this.
174 0 : bool HasAudio() const {
175 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
176 0 : return mInfo.mHasAudio;
177 : }
178 :
179 : // This is called on the state machine thread and audio thread.
180 : // The decoder monitor must be obtained before calling this.
181 0 : bool HasVideo() const {
182 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
183 0 : return mInfo.mHasVideo;
184 : }
185 :
186 : // Should be called by main thread.
187 : bool HaveNextFrameData() const;
188 :
189 : // Must be called with the decode monitor held.
190 0 : bool IsBuffering() const {
191 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
192 :
193 0 : return mState == nsBuiltinDecoderStateMachine::DECODER_STATE_BUFFERING;
194 : }
195 :
196 : // Must be called with the decode monitor held.
197 0 : bool IsSeeking() const {
198 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
199 :
200 0 : return mState == nsBuiltinDecoderStateMachine::DECODER_STATE_SEEKING;
201 : }
202 :
203 : // Functions used by assertions to ensure we're calling things
204 : // on the appropriate threads.
205 0 : bool OnAudioThread() const {
206 0 : return IsCurrentThread(mAudioThread);
207 : }
208 :
209 : bool OnStateMachineThread() const;
210 :
211 : nsresult GetBuffered(nsTimeRanges* aBuffered);
212 :
213 0 : PRInt64 VideoQueueMemoryInUse() {
214 0 : if (mReader) {
215 0 : return mReader->VideoQueueMemoryInUse();
216 : }
217 0 : return 0;
218 : }
219 :
220 0 : PRInt64 AudioQueueMemoryInUse() {
221 0 : if (mReader) {
222 0 : return mReader->AudioQueueMemoryInUse();
223 : }
224 0 : return 0;
225 : }
226 :
227 : void NotifyDataArrived(const char* aBuffer, PRUint32 aLength, PRInt64 aOffset);
228 :
229 : PRInt64 GetEndMediaTime() const {
230 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
231 : return mEndTime;
232 : }
233 :
234 0 : bool IsSeekable() {
235 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
236 0 : return mSeekable;
237 : }
238 :
239 : // Sets the current frame buffer length for the MozAudioAvailable event.
240 : // Accessed on the main and state machine threads.
241 : virtual void SetFrameBufferLength(PRUint32 aLength);
242 :
243 : // Returns the shared state machine thread.
244 : static nsIThread* GetStateMachineThread();
245 :
246 : // Schedules the shared state machine thread to run the state machine.
247 : // If the state machine thread is the currently running the state machine,
248 : // we wait until that has completely finished before running the state
249 : // machine again.
250 : nsresult ScheduleStateMachine();
251 :
252 : // Schedules the shared state machine thread to run the state machine
253 : // in aUsecs microseconds from now, if it's not already scheduled to run
254 : // earlier, in which case the request is discarded.
255 : nsresult ScheduleStateMachine(PRInt64 aUsecs);
256 :
257 : // Creates and starts a new decode thread. Don't call this directly,
258 : // request a new decode thread by calling
259 : // StateMachineTracker::RequestCreateDecodeThread().
260 : // The decoder monitor must not be held. Called on the state machine thread.
261 : nsresult StartDecodeThread();
262 :
263 : // Timer function to implement ScheduleStateMachine(aUsecs).
264 : void TimeoutExpired();
265 :
266 : // Set the media fragment end time. aEndTime is in microseconds.
267 : void SetFragmentEndTime(PRInt64 aEndTime);
268 :
269 : // Drop reference to decoder. Only called during shutdown dance.
270 0 : void ReleaseDecoder() { mDecoder = nsnull; }
271 :
272 : // Called when a "MozAudioAvailable" event listener is added to the media
273 : // element. Called on the main thread.
274 : void NotifyAudioAvailableListener();
275 :
276 : protected:
277 :
278 : // Returns true if we've got less than aAudioUsecs microseconds of decoded
279 : // and playable data. The decoder monitor must be held.
280 : bool HasLowDecodedData(PRInt64 aAudioUsecs) const;
281 :
282 : // Returns true if we're running low on data which is not yet decoded.
283 : // The decoder monitor must be held.
284 : bool HasLowUndecodedData() const;
285 :
286 : // Returns the number of microseconds of undecoded data available for
287 : // decoding. The decoder monitor must be held.
288 : PRInt64 GetUndecodedData() const;
289 :
290 : // Returns the number of unplayed usecs of audio we've got decoded and/or
291 : // pushed to the hardware waiting to play. This is how much audio we can
292 : // play without having to run the audio decoder. The decoder monitor
293 : // must be held.
294 : PRInt64 AudioDecodedUsecs() const;
295 :
296 : // Returns true when there's decoded audio waiting to play.
297 : // The decoder monitor must be held.
298 : bool HasFutureAudio() const;
299 :
300 : // Returns true if we recently exited "quick buffering" mode.
301 : bool JustExitedQuickBuffering();
302 :
303 : // Waits on the decoder ReentrantMonitor for aUsecs microseconds. If the decoder
304 : // monitor is awoken by a Notify() call, we'll continue waiting, unless
305 : // we've moved into shutdown state. This enables us to ensure that we
306 : // wait for a specified time, and that the myriad of Notify()s we do on
307 : // the decoder monitor don't cause the audio thread to be starved. aUsecs
308 : // values of less than 1 millisecond are rounded up to 1 millisecond
309 : // (see bug 651023). The decoder monitor must be held. Called only on the
310 : // audio thread.
311 : void Wait(PRInt64 aUsecs);
312 :
313 : // Dispatches an asynchronous event to update the media element's ready state.
314 : void UpdateReadyState();
315 :
316 : // Resets playback timing data. Called when we seek, on the decode thread.
317 : void ResetPlayback();
318 :
319 : // Returns the audio clock, if we have audio, or -1 if we don't.
320 : // Called on the state machine thread.
321 : PRInt64 GetAudioClock();
322 :
323 : // Returns the presentation time of the first audio or video frame in the
324 : // media. If the media has video, it returns the first video frame. The
325 : // decoder monitor must be held with exactly one lock count. Called on the
326 : // state machine thread.
327 : VideoData* FindStartTime();
328 :
329 : // Update only the state machine's current playback position (and duration,
330 : // if unknown). Does not update the playback position on the decoder or
331 : // media element -- use UpdatePlaybackPosition for that. Called on the state
332 : // machine thread, caller must hold the decoder lock.
333 : void UpdatePlaybackPositionInternal(PRInt64 aTime);
334 :
335 : // Pushes the image down the rendering pipeline. Called on the shared state
336 : // machine thread. The decoder monitor must *not* be held when calling this.
337 : void RenderVideoFrame(VideoData* aData, TimeStamp aTarget);
338 :
339 : // If we have video, display a video frame if it's time for display has
340 : // arrived, otherwise sleep until it's time for the next frame. Update the
341 : // current frame time as appropriate, and trigger ready state update. The
342 : // decoder monitor must be held with exactly one lock count. Called on the
343 : // state machine thread.
344 : void AdvanceFrame();
345 :
346 : // Write aFrames of audio frames of silence to the audio hardware. Returns
347 : // the number of frames actually written. The write size is capped at
348 : // SILENCE_BYTES_CHUNK (32kB), so must be called in a loop to write the
349 : // desired number of frames. This ensures that the playback position
350 : // advances smoothly, and guarantees that we don't try to allocate an
351 : // impossibly large chunk of memory in order to play back silence. Called
352 : // on the audio thread.
353 : PRUint32 PlaySilence(PRUint32 aFrames,
354 : PRUint32 aChannels,
355 : PRUint64 aFrameOffset);
356 :
357 : // Pops an audio chunk from the front of the audio queue, and pushes its
358 : // audio data to the audio hardware. MozAudioAvailable data is also queued
359 : // here. Called on the audio thread.
360 : PRUint32 PlayFromAudioQueue(PRUint64 aFrameOffset, PRUint32 aChannels);
361 :
362 : // Stops the decode thread, and if we have a pending request for a new
363 : // decode thread it is canceled. The decoder monitor must be held with exactly
364 : // one lock count. Called on the state machine thread.
365 : void StopDecodeThread();
366 :
367 : // Stops the audio thread. The decoder monitor must be held with exactly
368 : // one lock count. Called on the state machine thread.
369 : void StopAudioThread();
370 :
371 : // Ensures the decode thread is running if it already exists, or requests
372 : // a new decode thread be started if there currently is no decode thread.
373 : // The decoder monitor must be held with exactly one lock count. Called on
374 : // the state machine thread.
375 : nsresult ScheduleDecodeThread();
376 :
377 : // Starts the audio thread. The decoder monitor must be held with exactly
378 : // one lock count. Called on the state machine thread.
379 : nsresult StartAudioThread();
380 :
381 : // The main loop for the audio thread. Sent to the thread as
382 : // an nsRunnableMethod. This continually does blocking writes to
383 : // to audio stream to play audio data.
384 : void AudioLoop();
385 :
386 : // Sets internal state which causes playback of media to pause.
387 : // The decoder monitor must be held. Called on the main, state machine,
388 : // and decode threads.
389 : void StopPlayback();
390 :
391 : // Sets internal state which causes playback of media to begin or resume.
392 : // Must be called with the decode monitor held. Called on the state machine
393 : // and decode threads.
394 : void StartPlayback();
395 :
396 : // Moves the decoder into decoding state. Called on the state machine
397 : // thread. The decoder monitor must be held.
398 : void StartDecoding();
399 :
400 : // Returns true if we're currently playing. The decoder monitor must
401 : // be held.
402 : bool IsPlaying();
403 :
404 : // Returns the "media time". This is the absolute time which the media
405 : // playback has reached. i.e. this returns values in the range
406 : // [mStartTime, mEndTime], and mStartTime will not be 0 if the media does
407 : // not start at 0. Note this is different to the value returned
408 : // by GetCurrentTime(), which is in the range [0,duration].
409 0 : PRInt64 GetMediaTime() const {
410 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
411 0 : return mStartTime + mCurrentFrameTime;
412 : }
413 :
414 : // Returns an upper bound on the number of microseconds of audio that is
415 : // decoded and playable. This is the sum of the number of usecs of audio which
416 : // is decoded and in the reader's audio queue, and the usecs of unplayed audio
417 : // which has been pushed to the audio hardware for playback. Note that after
418 : // calling this, the audio hardware may play some of the audio pushed to
419 : // hardware, so this can only be used as a upper bound. The decoder monitor
420 : // must be held when calling this. Called on the decode thread.
421 : PRInt64 GetDecodedAudioDuration();
422 :
423 : // Load metadata. Called on the decode thread. The decoder monitor
424 : // must be held with exactly one lock count.
425 : nsresult DecodeMetadata();
426 :
427 : // Seeks to mSeekTarget. Called on the decode thread. The decoder monitor
428 : // must be held with exactly one lock count.
429 : void DecodeSeek();
430 :
431 : // Decode loop, decodes data until EOF or shutdown.
432 : // Called on the decode thread.
433 : void DecodeLoop();
434 :
435 : // Decode thread run function. Determines which of the Decode*() functions
436 : // to call.
437 : void DecodeThreadRun();
438 :
439 : // State machine thread run function. Defers to RunStateMachine().
440 : nsresult CallRunStateMachine();
441 :
442 : // Performs one "cycle" of the state machine. Polls the state, and may send
443 : // a video frame to be displayed, and generally manages the decode. Called
444 : // periodically via timer to ensure the video stays in sync.
445 : nsresult RunStateMachine();
446 :
447 0 : bool IsStateMachineScheduled() const {
448 0 : mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
449 0 : return !mTimeout.IsNull() || mRunAgain;
450 : }
451 :
452 : // Returns true if we're not playing and the decode thread has filled its
453 : // decode buffers and is waiting. We can shut the decode thread down in this
454 : // case as it may not be needed again.
455 : bool IsPausedAndDecoderWaiting();
456 :
457 : // The decoder object that created this state machine. The state machine
458 : // holds a strong reference to the decoder to ensure that the decoder stays
459 : // alive once media element has started the decoder shutdown process, and has
460 : // dropped its reference to the decoder. This enables the state machine to
461 : // keep using the decoder's monitor until the state machine has finished
462 : // shutting down, without fear of the monitor being destroyed. After
463 : // shutting down, the state machine will then release this reference,
464 : // causing the decoder to be destroyed. This is accessed on the decode,
465 : // state machine, audio and main threads.
466 : nsRefPtr<nsBuiltinDecoder> mDecoder;
467 :
468 : // The decoder monitor must be obtained before modifying this state.
469 : // NotifyAll on the monitor must be called when the state is changed so
470 : // that interested threads can wake up and alter behaviour if appropriate
471 : // Accessed on state machine, audio, main, and AV thread.
472 : State mState;
473 :
474 : // The size of the decoded YCbCr frame.
475 : // Accessed on state machine thread.
476 : PRUint32 mCbCrSize;
477 :
478 : // Accessed on state machine thread.
479 : nsAutoArrayPtr<unsigned char> mCbCrBuffer;
480 :
481 : // Thread for pushing audio onto the audio hardware.
482 : // The "audio push thread".
483 : nsCOMPtr<nsIThread> mAudioThread;
484 :
485 : // Thread for decoding video in background. The "decode thread".
486 : nsCOMPtr<nsIThread> mDecodeThread;
487 :
488 : // Timer to call the state machine Run() method. Used by
489 : // ScheduleStateMachine(). Access protected by decoder monitor.
490 : nsCOMPtr<nsITimer> mTimer;
491 :
492 : // Timestamp at which the next state machine Run() method will be called.
493 : // If this is non-null, a call to Run() is scheduled, either by a timer,
494 : // or via an event. Access protected by decoder monitor.
495 : TimeStamp mTimeout;
496 :
497 : // The time that playback started from the system clock. This is used for
498 : // timing the presentation of video frames when there's no audio.
499 : // Accessed only via the state machine thread.
500 : TimeStamp mPlayStartTime;
501 :
502 : // The amount of time we've spent playing already the media. The current
503 : // playback position is therefore |Now() - mPlayStartTime +
504 : // mPlayDuration|, which must be adjusted by mStartTime if used with media
505 : // timestamps. Accessed only via the state machine thread.
506 : PRInt64 mPlayDuration;
507 :
508 : // Time that buffering started. Used for buffering timeout and only
509 : // accessed on the state machine thread. This is null while we're not
510 : // buffering.
511 : TimeStamp mBufferingStart;
512 :
513 : // Start time of the media, in microseconds. This is the presentation
514 : // time of the first frame decoded from the media, and is used to calculate
515 : // duration and as a bounds for seeking. Accessed on state machine, decode,
516 : // and main threads. Access controlled by decoder monitor.
517 : PRInt64 mStartTime;
518 :
519 : // Time of the last frame in the media, in microseconds. This is the
520 : // end time of the last frame in the media. Accessed on state
521 : // machine, decode, and main threads. Access controlled by decoder monitor.
522 : PRInt64 mEndTime;
523 :
524 : // Position to seek to in microseconds when the seek state transition occurs.
525 : // The decoder monitor lock must be obtained before reading or writing
526 : // this value. Accessed on main and decode thread.
527 : PRInt64 mSeekTime;
528 :
529 : // Media Fragment end time in microseconds. Access controlled by decoder monitor.
530 : PRInt64 mFragmentEndTime;
531 :
532 : // The audio stream resource. Used on the state machine, and audio threads.
533 : // This is created and destroyed on the audio thread, while holding the
534 : // decoder monitor, so if this is used off the audio thread, you must
535 : // first acquire the decoder monitor and check that it is non-null.
536 : nsRefPtr<nsAudioStream> mAudioStream;
537 :
538 : // The reader, don't call its methods with the decoder monitor held.
539 : // This is created in the play state machine's constructor, and destroyed
540 : // in the play state machine's destructor.
541 : nsAutoPtr<nsBuiltinDecoderReader> mReader;
542 :
543 : // The time of the current frame in microseconds. This is referenced from
544 : // 0 which is the initial playback position. Set by the state machine
545 : // thread, and read-only from the main thread to get the current
546 : // time value. Synchronised via decoder monitor.
547 : PRInt64 mCurrentFrameTime;
548 :
549 : // The presentation time of the first audio frame that was played in
550 : // microseconds. We can add this to the audio stream position to determine
551 : // the current audio time. Accessed on audio and state machine thread.
552 : // Synchronized by decoder monitor.
553 : PRInt64 mAudioStartTime;
554 :
555 : // The end time of the last audio frame that's been pushed onto the audio
556 : // hardware in microseconds. This will approximately be the end time of the
557 : // audio stream, unless another frame is pushed to the hardware.
558 : PRInt64 mAudioEndTime;
559 :
560 : // The presentation end time of the last video frame which has been displayed
561 : // in microseconds. Accessed from the state machine thread.
562 : PRInt64 mVideoFrameEndTime;
563 :
564 : // Volume of playback. 0.0 = muted. 1.0 = full volume. Read/Written
565 : // from the state machine and main threads. Synchronised via decoder
566 : // monitor.
567 : double mVolume;
568 :
569 : // Time at which we started decoding. Synchronised via decoder monitor.
570 : TimeStamp mDecodeStartTime;
571 :
572 : // True if the media resource can be seeked. Accessed from the state
573 : // machine and main threads. Synchronised via decoder monitor.
574 : bool mSeekable;
575 :
576 : // True if an event to notify about a change in the playback
577 : // position has been queued, but not yet run. It is set to false when
578 : // the event is run. This allows coalescing of these events as they can be
579 : // produced many times per second. Synchronised via decoder monitor.
580 : // Accessed on main and state machine threads.
581 : bool mPositionChangeQueued;
582 :
583 : // True if the audio playback thread has finished. It is finished
584 : // when either all the audio frames in the Vorbis bitstream have completed
585 : // playing, or we've moved into shutdown state, and the threads are to be
586 : // destroyed. Written by the audio playback thread and read and written by
587 : // the state machine thread. Synchronised via decoder monitor.
588 : bool mAudioCompleted;
589 :
590 : // True if mDuration has a value obtained from an HTTP header, or from
591 : // the media index/metadata. Accessed on the state machine thread.
592 : bool mGotDurationFromMetaData;
593 :
594 : // False while decode thread should be running. Accessed state machine
595 : // and decode threads. Syncrhonised by decoder monitor.
596 : bool mStopDecodeThread;
597 :
598 : // True when the decode thread run function has finished, but the thread
599 : // has not necessarily been shut down yet. This can happen if we switch
600 : // from COMPLETED state to SEEKING before the state machine has a chance
601 : // to run in the COMPLETED state and shutdown the decode thread.
602 : // Synchronised by the decoder monitor.
603 : bool mDecodeThreadIdle;
604 :
605 : // False while audio thread should be running. Accessed state machine
606 : // and audio threads. Syncrhonised by decoder monitor.
607 : bool mStopAudioThread;
608 :
609 : // If this is true while we're in buffering mode, we can exit early,
610 : // as it's likely we may be able to playback. This happens when we enter
611 : // buffering mode soon after the decode starts, because the decode-ahead
612 : // ran fast enough to exhaust all data while the download is starting up.
613 : // Synchronised via decoder monitor.
614 : bool mQuickBuffering;
615 :
616 : // True if the shared state machine thread is currently running this
617 : // state machine.
618 : bool mIsRunning;
619 :
620 : // True if we should run the state machine again once the current
621 : // state machine run has finished.
622 : bool mRunAgain;
623 :
624 : // True if we've dispatched an event to run the state machine. It's
625 : // imperative that we don't dispatch multiple events to run the state
626 : // machine at the same time, as our code assume all events are synchronous.
627 : // If we dispatch multiple events, the second event can run while the
628 : // first is shutting down a thread, causing inconsistent state.
629 : bool mDispatchedRunEvent;
630 :
631 : // True if the decode thread has gone filled its buffers and is now
632 : // waiting to be awakened before it continues decoding. Synchronized
633 : // by the decoder monitor.
634 : bool mDecodeThreadWaiting;
635 :
636 : // True is we are decoding a realtime stream, like a camera stream
637 : bool mRealTime;
638 :
639 : // True if we've requested a new decode thread, but it has not yet been
640 : // created. Synchronized by the decoder monitor.
641 : bool mRequestedNewDecodeThread;
642 :
643 : PRUint32 mBufferingWait;
644 : PRInt64 mLowDataThresholdUsecs;
645 :
646 : private:
647 : // Manager for queuing and dispatching MozAudioAvailable events. The
648 : // event manager is accessed from the state machine and audio threads,
649 : // and takes care of synchronizing access to its internal queue.
650 : nsAudioAvailableEventManager mEventManager;
651 :
652 : // Stores presentation info required for playback. The decoder monitor
653 : // must be held when accessing this.
654 : nsVideoInfo mInfo;
655 : };
656 :
657 : #endif
|