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
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/
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
16 * The Original Code is Mozilla code.
18 * The Initial Developer of the Original Code is the Mozilla Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2008
20 * the Initial Developer. All Rights Reserved.
23 * Matthew Gregan <kinetik@flim.org>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
38 #if !defined(nsWaveDecoder_h_)
39 #define nsWaveDecoder_h_
41 #include "nsISupports.h"
43 #include "nsMediaDecoder.h"
44 #include "nsMediaStream.h"
47 nsWaveDecoder provides an implementation of the abstract nsMediaDecoder
48 class that supports parsing and playback of Waveform Audio (WAVE) chunks
49 embedded in Resource Interchange File Format (RIFF) bitstreams as
50 specified by the Multimedia Programming Interface and Data Specification
53 Each decoder instance starts one thread (the playback thread). A single
54 nsWaveStateMachine event is dispatched to this thread to start the
55 thread's state machine running. The Run method of the event is a loop
56 that executes the current state. The state can be changed by the state
57 machine, or from the main thread via threadsafe methods on the event.
58 During playback, the playback thread reads data from the network and
59 writes it to the audio backend, attempting to keep the backend's audio
60 buffers full. It is also responsible for seeking, buffering, and
61 pausing/resuming audio.
63 The decoder also owns an nsMediaStream instance that provides a threadsafe
64 blocking interface to read from network channels. The state machine is
65 the primary user of this stream and holds a weak (raw) pointer to it as
66 the thread, state machine, and stream's lifetimes are all managed by the
69 nsWaveStateMachine has the following states:
72 RIFF/WAVE chunks are being read from the stream, the metadata describing
73 the audio data is parsed.
76 Playback is paused while waiting for additional data.
79 If data is available in the stream and the audio backend can consume
80 more data, it is read from the stream and written to the audio backend.
81 Sleep until approximately half of the backend's buffers have drained.
84 Decoder is seeking to a specified time in the media.
87 Pause the audio backend, then wait for a state transition.
90 Expected PCM data (or stream EOF) reached, wait for the audio backend to
91 play any buffered data, then wait for shutdown.
94 Metadata loading/parsing failed, wait for shutdown.
97 Close the audio backend and return from the run loop.
99 State transitions within the state machine are:
101 LOADING_METADATA -> PLAYING
114 PAUSED -> waits for caller to play, seek, or shutdown
116 ENDED -> waits for caller to shutdown
118 ERROR -> waits for caller to shutdown
120 SHUTDOWN -> exits state machine
122 In addition, the following methods cause state transitions:
124 Shutdown(), Play(), Pause(), Seek(float)
126 The decoder implementation is currently limited to Linear PCM encoded
127 audio data with one or two channels of 8- or 16-bit samples at sample
128 rates from 100 Hz to 96 kHz. The number of channels is limited by what
129 the audio backend (sydneyaudio via nsAudioStream) currently supports. The
130 supported sample rate is artificially limited to arbitrarily selected sane
131 values. Support for additional channels (and other new features) would
132 require extending nsWaveDecoder to support parsing the newer
133 WAVE_FORMAT_EXTENSIBLE chunk format.
136 class nsWaveStateMachine
;
138 class nsWaveDecoder
: public nsMediaDecoder
140 friend class nsWaveStateMachine
;
149 virtual void GetCurrentURI(nsIURI
** aURI
);
150 virtual nsIPrincipal
* GetCurrentPrincipal();
152 // Return the current playback position in the media in seconds.
153 virtual float GetCurrentTime();
155 // Return the total playback length of the media in seconds.
156 virtual float GetDuration();
158 // Get the current audio playback volume; result in range [0.0, 1.0].
159 virtual float GetVolume();
161 // Set the audio playback volume; must be in range [0.0, 1.0].
162 virtual void SetVolume(float aVolume
);
164 virtual nsresult
Play();
166 virtual void Pause();
168 // Set the current time of the media to aTime. This may cause mStream to
169 // create a new channel to fetch data from the appropriate position in the
171 virtual nsresult
Seek(float aTime
);
173 // Report whether the decoder is currently seeking.
174 virtual PRBool
IsSeeking() const;
176 // Start downloading the media at the specified URI. The media's metadata
177 // will be parsed and made available as the load progresses.
178 virtual nsresult
Load(nsIURI
* aURI
, nsIChannel
* aChannel
, nsIStreamListener
** aStreamListener
);
180 // Called by mStream (and possibly the nsChannelToPipeListener used
181 // internally by mStream) when the stream has completed loading.
182 virtual void ResourceLoaded();
184 // Called by mStream (and possibly the nsChannelToPipeListener used
185 // internally by mStream) if the stream encounters a network error.
186 virtual void NetworkError();
188 // Element is notifying us that the requested playback rate has changed.
189 virtual nsresult
PlaybackRateChanged();
191 // Getter/setter for mContentLength.
192 virtual PRInt64
GetTotalBytes();
193 virtual void SetTotalBytes(PRInt64 aBytes
);
195 // Getter/setter for mSeekable.
196 virtual void SetSeekable(PRBool aSeekable
);
197 virtual PRBool
GetSeekable();
199 // Getter/setter for mBytesDownloaded.
200 virtual PRUint64
GetBytesLoaded();
201 virtual void UpdateBytesDownloaded(PRUint64 aBytes
);
203 // Must be called by the owning object before disposing the decoder.
204 virtual void Shutdown();
207 // Notifies the nsHTMLMediaElement that buffering has started.
208 void BufferingStarted();
210 // Notifies the element that buffering has stopped.
211 void BufferingStopped();
213 // Notifies the element that seeking has started.
214 void SeekingStarted();
216 // Notifies the element that seeking has completed.
217 void SeekingStopped();
219 // Notifies the element that metadata loading has completed. Only fired
220 // if metadata is valid.
221 void MetadataLoaded();
223 // Notifies the element that playback has completed.
224 void PlaybackEnded();
226 // Notifies the element that metadata loading has failed.
227 void MediaErrorDecode();
229 void RegisterShutdownObserver();
230 void UnregisterShutdownObserver();
232 // Length of the current resource, or -1 if not available.
233 PRInt64 mContentLength
;
235 // Total bytes downloaded by mStream so far.
236 PRUint64 mBytesDownloaded
;
238 // Volume that the audio backend will be initialized with.
239 float mInitialVolume
;
241 // URI of the current resource.
242 nsCOMPtr
<nsIURI
> mURI
;
244 // Thread that handles audio playback, including data download.
245 nsCOMPtr
<nsIThread
> mPlaybackThread
;
247 // State machine that runs on mPlaybackThread. Methods on this object are
248 // safe to call from any thread.
249 nsCOMPtr
<nsWaveStateMachine
> mPlaybackStateMachine
;
251 // Threadsafe wrapper around channels that provides seeking based on the
252 // underlying channel type.
253 nsAutoPtr
<nsMediaStream
> mStream
;
255 // Copy of the current time and duration when the state machine was
256 // disposed. Used to respond to time and duration queries with sensible
257 // values after playback has ended.
258 float mEndedCurrentTime
;
259 float mEndedDuration
;
261 // True if we have registered a shutdown observer.
262 PRPackedBool mNotifyOnShutdown
;
264 // True if the media resource is seekable.
265 PRPackedBool mSeekable
;