diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index 8b97b5de51d..2a95df918e0 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -159,8 +159,6 @@ MOZ_MORKREADER = @MOZ_MORKREADER@ MOZ_NO_XPCOM_OBSOLETE = @MOZ_NO_XPCOM_OBSOLETE@ MOZ_NO_FAST_LOAD = @MOZ_NO_FAST_LOAD@ MOZ_OGG = @MOZ_OGG@ -MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@ -MOZ_WAVE = @MOZ_WAVE@ MOZ_MEDIA = @MOZ_MEDIA@ NS_PRINTING = @NS_PRINTING@ MOZ_CRASHREPORTER = @MOZ_CRASHREPORTER@ diff --git a/configure.in b/configure.in index 6d4374ded95..835b165273e 100644 --- a/configure.in +++ b/configure.in @@ -4308,8 +4308,6 @@ MOZ_NO_INSPECTOR_APIS= MOZ_NO_XPCOM_OBSOLETE= MOZ_NO_FAST_LOAD= MOZ_OGG=1 -MOZ_SYDNEYAUDIO= -MOZ_WAVE=1 MOZ_MEDIA= MOZ_OJI=1 MOZ_PERMISSIONS=1 @@ -5282,7 +5280,7 @@ if test -n "$MOZ_NO_FAST_LOAD"; then fi dnl ======================================================== -dnl = Disable Ogg Codecs +dnl = Enable Ogg Codecs dnl ======================================================== MOZ_ARG_DISABLE_BOOL(ogg, [ --disable-ogg Disable Ogg Codec support], @@ -5293,56 +5291,23 @@ AC_SUBST(MOZ_OGG) if test -n "$MOZ_OGG"; then AC_DEFINE(MOZ_OGG) - MOZ_SYDNEYAUDIO=1 MOZ_MEDIA=1 fi -dnl ======================================================== -dnl = Disable Wave decoder support -dnl ======================================================== -MOZ_ARG_ENABLE_BOOL(wave, -[ --disable-wave Disable Wave decoder support], - MOZ_WAVE=, - MOZ_WAVE=1) - -AC_SUBST(MOZ_WAVE) - -if test -n "$MOZ_WAVE"; then - AC_DEFINE(MOZ_WAVE) - MOZ_SYDNEYAUDIO=1 - MOZ_MEDIA=1 -fi - -dnl ======================================================== -dnl = Handle dependent SYDNEYAUDIO and MEDIA defines -dnl ======================================================== - -AC_SUBST(MOZ_SYDNEYAUDIO) - -if test -n "$MOZ_SYDNEYAUDIO"; then - AC_DEFINE(MOZ_SYDNEYAUDIO) -fi - AC_SUBST(MOZ_MEDIA) if test -n "$MOZ_MEDIA"; then AC_DEFINE(MOZ_MEDIA) fi -dnl ======================================================== -dnl = Check alsa availability on Linux if using sydneyaudio -dnl ======================================================== - -dnl If using sydneyaudio with Linux, ensure that the alsa library is available -if test "$COMPILE_ENVIRONMENT"; then -if test -n "$MOZ_SYDNEYAUDIO"; then +dnl If using Ogg with Linux, ensure that the alsa library is available +if test -n "$MOZ_OGG"; then case "$target_os" in linux*) AC_CHECK_LIB(asound, snd_pcm_open,,AC_MSG_ERROR([Ogg support on Linux requires the alsa library])) ;; esac fi -fi dnl ======================================================== dnl Permissions System diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp index 294d4423cfb..7d6a3fc55c4 100644 --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -72,9 +72,6 @@ #ifdef MOZ_OGG #include "nsOggDecoder.h" #endif -#ifdef MOZ_WAVE -#include "nsWaveDecoder.h" -#endif class nsAsyncEventRunner : public nsRunnable { @@ -613,34 +610,12 @@ static PRBool IsOggType(const nsACString& aType) } #endif -#ifdef MOZ_WAVE -static const char gWaveTypes[][16] = { - "audio/x-wav", - "audio/wav", - "audio/wave", - "audio/x-pn-wav" -}; - -static PRBool IsWaveType(const nsACString& aType) -{ - for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gWaveTypes); ++i) { - if (aType.EqualsASCII(gWaveTypes[i])) - return PR_TRUE; - } - return PR_FALSE; -} -#endif - /* static */ PRBool nsHTMLMediaElement::CanHandleMediaType(const char* aMIMEType) { #ifdef MOZ_OGG if (IsOggType(nsDependentCString(aMIMEType))) return PR_TRUE; -#endif -#ifdef MOZ_WAVE - if (IsWaveType(nsDependentCString(aMIMEType))) - return PR_TRUE; #endif return PR_FALSE; } @@ -657,13 +632,6 @@ void nsHTMLMediaElement::InitMediaTypes() "@mozilla.org/content/document-loader-factory;1", PR_FALSE, PR_TRUE, nsnull); } -#endif -#ifdef MOZ_WAVE - for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gWaveTypes); i++) { - catMan->AddCategoryEntry("Gecko-Content-Viewers", gWaveTypes[i], - "@mozilla.org/content/document-loader-factory;1", - PR_FALSE, PR_TRUE, nsnull); - } #endif } } @@ -678,11 +646,6 @@ void nsHTMLMediaElement::ShutdownMediaTypes() for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gOggTypes); i++) { catMan->DeleteCategoryEntry("Gecko-Content-Viewers", gOggTypes[i], PR_FALSE); } -#endif -#ifdef MOZ_WAVE - for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(gWaveTypes); i++) { - catMan->DeleteCategoryEntry("Gecko-Content-Viewers", gWaveTypes[i], PR_FALSE); - } #endif } } @@ -696,14 +659,6 @@ PRBool nsHTMLMediaElement::CreateDecoder(const nsACString& aType) mDecoder = nsnull; } } -#endif -#ifdef MOZ_WAVE - if (IsWaveType(aType)) { - mDecoder = new nsWaveDecoder(); - if (mDecoder && !mDecoder->Init()) { - mDecoder = nsnull; - } - } #endif return mDecoder != nsnull; } diff --git a/content/media/video/public/Makefile.in b/content/media/video/public/Makefile.in index 9a93c4f2387..78198121532 100644 --- a/content/media/video/public/Makefile.in +++ b/content/media/video/public/Makefile.in @@ -47,30 +47,14 @@ EXPORTS = \ nsMediaDecoder.h \ $(NULL) -ifdef MOZ_MEDIA -EXPORTS += \ - nsChannelToPipeListener.h \ - nsMediaStream.h \ - $(NULL) -endif - -ifdef MOZ_SYDNEYAUDIO -EXPORTS += \ - nsAudioStream.h \ - $(NULL) -endif - ifdef MOZ_OGG EXPORTS += \ + nsAudioStream.h \ nsChannelReader.h \ + nsChannelToPipeListener.h \ + nsMediaStream.h \ nsOggDecoder.h \ $(NULL) endif -ifdef MOZ_WAVE -EXPORTS += \ - nsWaveDecoder.h \ - $(NULL) -endif - include $(topsrcdir)/config/rules.mk diff --git a/content/media/video/public/nsAudioStream.h b/content/media/video/public/nsAudioStream.h index 9f8c3245572..5816a80c509 100644 --- a/content/media/video/public/nsAudioStream.h +++ b/content/media/video/public/nsAudioStream.h @@ -35,9 +35,6 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ -#if !defined(nsAudioStream_h_) -#define nsAudioStream_h_ - #include "nscore.h" #include "prlog.h" @@ -67,12 +64,7 @@ class nsAudioStream // Write sound data to the audio hardware. aBuf is an array of floats of // length aCount. aCount should be evenly divisible by the number of // channels in this audio stream. - void Write(const float* aBuf, PRUint32 aCount); - - // Write sound data to the audio hardware. aBuf is an array of shorts in - // signed 16-bit little endian format of length aCount. Acount should be - // evenly divisible by the number of channels in this audio stream. - void Write(const short* aBuf, PRUint32 aCount); + void Write(float* aBuf, PRUint32 count); // Return the number of sound samples that can be written to the audio device // without blocking. @@ -86,29 +78,10 @@ class nsAudioStream // 0 (meaning muted) to 1 (meaning full volume). void SetVolume(float aVolume); - // Block until buffered audio data has been consumed. - void Drain(); - - // Pause sound playback. - void Pause(); - - // Resume sound playback. - void Resume(); - - // Return the position (in seconds) of the audio sample currently being - // played by the audio hardware. - double GetTime(); - private: double mVolume; void* mAudioHandle; int mRate; int mChannels; - - // The byte position in the audio buffer where playback was last paused. - PRInt64 mSavedPauseBytes; - PRInt64 mPauseBytes; - - PRPackedBool mPaused; + PRPackedBool mMute; }; -#endif diff --git a/content/media/video/public/nsMediaDecoder.h b/content/media/video/public/nsMediaDecoder.h index c48af32abba..6d510eec5a0 100644 --- a/content/media/video/public/nsMediaDecoder.h +++ b/content/media/video/public/nsMediaDecoder.h @@ -127,9 +127,6 @@ class nsMediaDecoder : public nsIObserver // Called when the video file has completed downloading. virtual void ResourceLoaded() = 0; - // Called if the media file encounters a network error. - virtual void NetworkError() = 0; - // Call from any thread safely. Return PR_TRUE if we are currently // seeking in the media resource. virtual PRBool IsSeeking() const = 0; diff --git a/content/media/video/public/nsOggDecoder.h b/content/media/video/public/nsOggDecoder.h index c388ac8c0cc..606c0361b1e 100644 --- a/content/media/video/public/nsOggDecoder.h +++ b/content/media/video/public/nsOggDecoder.h @@ -331,10 +331,6 @@ class nsOggDecoder : public nsMediaDecoder // Call on the main thread only. void ResourceLoaded(); - // Called if the media file encounters a network error. - // Call on the main thread only. - void NetworkError(); - // Call from any thread safely. Return PR_TRUE if we are currently // seeking in the media resource. virtual PRBool IsSeeking() const; diff --git a/content/media/video/public/nsWaveDecoder.h b/content/media/video/public/nsWaveDecoder.h deleted file mode 100644 index b9b6baa1bbd..00000000000 --- a/content/media/video/public/nsWaveDecoder.h +++ /dev/null @@ -1,270 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: ML 1.1/GPL 2.0/LGPL 2.1 - * - * 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 Original Code is Mozilla code. - * - * The Initial Developer of the Original Code is the Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Matthew Gregan - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -#if !defined(nsWaveDecoder_h_) -#define nsWaveDecoder_h_ - -#include "nsISupports.h" -#include "nsCOMPtr.h" -#include "nsMediaDecoder.h" -#include "nsMediaStream.h" - -/* - nsWaveDecoder provides an implementation of the abstract nsMediaDecoder - class that supports parsing and playback of Waveform Audio (WAVE) chunks - embedded in Resource Interchange File Format (RIFF) bitstreams as - specified by the Multimedia Programming Interface and Data Specification - 1.0. - - Each decoder instance starts one thread (the playback thread). A single - nsWaveStateMachine event is dispatched to this thread to start the - thread's state machine running. The Run method of the event is a loop - that executes the current state. The state can be changed by the state - machine, or from the main thread via threadsafe methods on the event. - During playback, the playback thread reads data from the network and - writes it to the audio backend, attempting to keep the backend's audio - buffers full. It is also responsible for seeking, buffering, and - pausing/resuming audio. - - The decoder also owns an nsMediaStream instance that provides a threadsafe - blocking interface to read from network channels. The state machine is - the primary user of this stream and holds a weak (raw) pointer to it as - the thread, state machine, and stream's lifetimes are all managed by the - decoder. - - nsWaveStateMachine has the following states: - - LOADING_METADATA - RIFF/WAVE chunks are being read from the stream, the metadata describing - the audio data is parsed. - - BUFFERING - Playback is paused while waiting for additional data. - - PLAYING - If data is available in the stream and the audio backend can consume - more data, it is read from the stream and written to the audio backend. - Sleep until approximately half of the backend's buffers have drained. - - SEEKING - Decoder is seeking to a specified time in the media. - - PAUSED - Pause the audio backend, then wait for a state transition. - - ENDED - Expected PCM data (or stream EOF) reached, wait for the audio backend to - play any buffered data, then wait for shutdown. - - ERROR - Metadata loading/parsing failed, wait for shutdown. - - SHUTDOWN - Close the audio backend and return from the run loop. - - State transitions within the state machine are: - - LOADING_METADATA -> PLAYING - -> PAUSED - -> ERROR - - BUFFERING -> PLAYING - -> PAUSED - - PLAYING -> BUFFERING - -> ENDED - - SEEKING -> PLAYING - -> PAUSED - - PAUSED -> waits for caller to play, seek, or shutdown - - ENDED -> waits for caller to shutdown - - ERROR -> waits for caller to shutdown - - SHUTDOWN -> exits state machine - - In addition, the following methods cause state transitions: - - Shutdown(), Play(), Pause(), Seek(float) - - The decoder implementation is currently limited to Linear PCM encoded - audio data with one or two channels of 16-bit samples at sample rates from - 100 Hz to 96 kHz. The sample size and number of channels (and, to some - extent, the sample format) is limited by what the audio backend - (sydneyaudio via nsAudioStream) currently supports. sydneyaudio's API - suggests support of 8-bit, ยต-Law, and A-Law samples, but this support is - not currently implemented. The supported sample rate is artificially - limited to arbitrarily selected sane values. Support for additional - channels (and other new features) would require extending nsWaveDecoder to - support parsing the newer WAVE_FORMAT_EXTENSIBLE chunk format. - */ - -class nsWaveStateMachine; - -class nsWaveDecoder : public nsMediaDecoder -{ - friend class nsWaveStateMachine; - - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - public: - nsWaveDecoder(); - ~nsWaveDecoder(); - - virtual void GetCurrentURI(nsIURI** aURI); - virtual nsIPrincipal* GetCurrentPrincipal(); - - // Return the current playback position in the media in seconds. - virtual float GetCurrentTime(); - - // Return the total playback length of the media in seconds. - virtual float GetDuration(); - - // Get the current audio playback volume; result in range [0.0, 1.0]. - virtual float GetVolume(); - - // Set the audio playback volume; must be in range [0.0, 1.0]. - virtual void SetVolume(float aVolume); - - virtual nsresult Play(); - virtual void Stop(); - virtual void Pause(); - - // Set the current time of the media to aTime. This may cause mStream to - // create a new channel to fetch data from the appropriate position in the - // stream. - virtual nsresult Seek(float aTime); - - // Report whether the decoder is currently seeking. - virtual PRBool IsSeeking() const; - - // Start downloading the media at the specified URI. The media's metadata - // will be parsed and made available as the load progresses. - virtual nsresult Load(nsIURI* aURI, nsIChannel* aChannel, nsIStreamListener** aStreamListener); - - // Called by mStream (and possibly the nsChannelToPipeListener used - // internally by mStream) when the stream has completed loading. - virtual void ResourceLoaded(); - - // Called by mStream (and possibly the nsChannelToPipeListener used - // internally by mStream) if the stream encounters a network error. - virtual void NetworkError(); - - // Element is notifying us that the requested playback rate has changed. - virtual nsresult PlaybackRateChanged(); - - // Getter/setter for mContentLength. - virtual PRInt64 GetTotalBytes(); - virtual void SetTotalBytes(PRInt64 aBytes); - - // Getter/setter for mSeekable. - virtual void SetSeekable(PRBool aSeekable); - virtual PRBool GetSeekable(); - - // Getter/setter for mBytesDownloaded. - virtual PRUint64 GetBytesLoaded(); - virtual void UpdateBytesDownloaded(PRUint64 aBytes); - - // Must be called by the owning object before disposing the decoder. - virtual void Shutdown(); - -private: - // Notifies the nsHTMLMediaElement that buffering has started. - void BufferingStarted(); - - // Notifies the element that buffering has stopped. - void BufferingStopped(); - - // Notifies the element that seeking has started. - void SeekingStarted(); - - // Notifies the element that seeking has completed. - void SeekingStopped(); - - // Notifies the element that metadata loading has completed. Only fired - // if metadata is valid. - void MetadataLoaded(); - - // Notifies the element that playback has completed. - void PlaybackEnded(); - - // Notifies the element that metadata loading has failed. - void MediaErrorDecode(); - - void RegisterShutdownObserver(); - void UnregisterShutdownObserver(); - - // Length of the current resource, or -1 if not available. - PRInt64 mContentLength; - - // Total bytes downloaded by mStream so far. - PRUint64 mBytesDownloaded; - - // Volume that the audio backend will be initialized with. - float mInitialVolume; - - // URI of the current resource. - nsCOMPtr mURI; - - // Thread that handles audio playback, including data download. - nsCOMPtr mPlaybackThread; - - // State machine that runs on mPlaybackThread. Methods on this object are - // safe to call from any thread. - nsCOMPtr mPlaybackStateMachine; - - // Threadsafe wrapper around channels that provides seeking based on the - // underlying channel type. - nsAutoPtr mStream; - - // Copy of the current time and duration when the state machine was - // disposed. Used to respond to time and duration queries with sensible - // values after playback has ended. - float mEndedCurrentTime; - float mEndedDuration; - - // True if we have registered a shutdown observer. - PRPackedBool mNotifyOnShutdown; - - // True if the media resource is seekable. - PRPackedBool mSeekable; -}; - -#endif diff --git a/content/media/video/src/Makefile.in b/content/media/video/src/Makefile.in index 424dbaedd27..04b521155a3 100644 --- a/content/media/video/src/Makefile.in +++ b/content/media/video/src/Makefile.in @@ -82,32 +82,16 @@ CPPSRCS = \ nsMediaDecoder.cpp \ $(NULL) -ifdef MOZ_MEDIA -CPPSRCS += \ - nsChannelToPipeListener.cpp \ - nsMediaStream.cpp \ - $(NULL) -endif - -ifdef MOZ_SYDNEYAUDIO -CPPSRCS += \ - nsAudioStream.cpp \ - $(NULL) -endif - ifdef MOZ_OGG CPPSRCS += \ + nsAudioStream.cpp \ nsChannelReader.cpp \ + nsChannelToPipeListener.cpp \ + nsMediaStream.cpp \ nsOggDecoder.cpp \ $(NULL) endif -ifdef MOZ_WAVE -CPPSRCS += \ - nsWaveDecoder.cpp \ - $(NULL) -endif - FORCE_STATIC_LIB = 1 include $(topsrcdir)/config/rules.mk diff --git a/content/media/video/src/nsAudioStream.cpp b/content/media/video/src/nsAudioStream.cpp index 398a1d1aa03..628f0feb031 100644 --- a/content/media/video/src/nsAudioStream.cpp +++ b/content/media/video/src/nsAudioStream.cpp @@ -64,10 +64,7 @@ nsAudioStream::nsAudioStream() : mVolume(1.0), mAudioHandle(0), mRate(0), - mChannels(0), - mSavedPauseBytes(0), - mPauseBytes(0), - mPaused(PR_FALSE) + mChannels(0) { } @@ -103,7 +100,7 @@ void nsAudioStream::Shutdown() mAudioHandle = nsnull; } -void nsAudioStream::Write(const float* aBuf, PRUint32 aCount) +void nsAudioStream::Write(float* aBuf, PRUint32 aCount) { if (!mAudioHandle) return; @@ -129,26 +126,7 @@ void nsAudioStream::Write(const float* aBuf, PRUint32 aCount) if (sa_stream_write(reinterpret_cast(mAudioHandle), s_data.get(), aCount * sizeof(short)) != SA_SUCCESS) { PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error")); Shutdown(); - } - } -} - -void nsAudioStream::Write(const short* aBuf, PRUint32 aCount) -{ - if (!mAudioHandle) - return; - - nsAutoArrayPtr s_data(new short[aCount]); - - if (s_data) { - for (PRUint32 i = 0; i < aCount; ++i) { - s_data[i] = aBuf[i] * mVolume; - } - - if (sa_stream_write(reinterpret_cast(mAudioHandle), s_data.get(), aCount * sizeof(short)) != SA_SUCCESS) { - PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error")); - Shutdown(); - } + } } } @@ -171,64 +149,3 @@ void nsAudioStream::SetVolume(float aVolume) { mVolume = aVolume; } - -void nsAudioStream::Drain() -{ - if (!mAudioHandle) - return; - - if (sa_stream_drain(reinterpret_cast(mAudioHandle)) != SA_SUCCESS) { - PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_drain error")); - Shutdown(); - } -} - -void nsAudioStream::Pause() -{ - if (!mAudioHandle) - return; - - if (mPaused) - return; - - mPaused = PR_TRUE; - - int64_t bytes = 0; -#if !defined(WIN32) - sa_stream_get_position(reinterpret_cast(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes); -#endif - mSavedPauseBytes = bytes; - - sa_stream_pause(reinterpret_cast(mAudioHandle)); -} - -void nsAudioStream::Resume() -{ - if (!mAudioHandle) - return; - - if (!mPaused) - return; - - mPaused = PR_FALSE; - - sa_stream_resume(reinterpret_cast(mAudioHandle)); - -#if !defined(WIN32) - mPauseBytes += mSavedPauseBytes; -#endif -} - -double nsAudioStream::GetTime() -{ - if (!mAudioHandle) - return 0.0; - - int64_t bytes = 0; -#if defined(WIN32) - sa_stream_get_position(reinterpret_cast(mAudioHandle), SA_POSITION_WRITE_HARDWARE, &bytes); -#else - sa_stream_get_position(reinterpret_cast(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes); -#endif - return double(bytes + mPauseBytes) / (sizeof(short) * mChannels * mRate); -} diff --git a/content/media/video/src/nsChannelToPipeListener.cpp b/content/media/video/src/nsChannelToPipeListener.cpp index 8c84576bc15..2834402c485 100644 --- a/content/media/video/src/nsChannelToPipeListener.cpp +++ b/content/media/video/src/nsChannelToPipeListener.cpp @@ -135,12 +135,8 @@ nsresult nsChannelToPipeListener::OnStartRequest(nsIRequest* aRequest, nsISuppor nsresult nsChannelToPipeListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus) { mOutput = nsnull; - if (aStatus != NS_BINDING_ABORTED && mDecoder) { - if (NS_SUCCEEDED(aStatus)) { - mDecoder->ResourceLoaded(); - } else { - mDecoder->NetworkError(); - } + if (mDecoder) { + mDecoder->ResourceLoaded(); } return NS_OK; } diff --git a/content/media/video/src/nsMediaStream.cpp b/content/media/video/src/nsMediaStream.cpp index 4982cdc6746..e9b874e3f19 100644 --- a/content/media/video/src/nsMediaStream.cpp +++ b/content/media/video/src/nsMediaStream.cpp @@ -61,8 +61,7 @@ class nsDefaultStreamStrategy : public nsStreamStrategy { public: nsDefaultStreamStrategy(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) : - nsStreamStrategy(aDecoder, aChannel, aURI), - mPosition(0) + nsStreamStrategy(aDecoder, aChannel, aURI) { } @@ -88,10 +87,6 @@ private: // Input stream for the media data currently downloaded // and stored in the pipe. This can be used from any thread. nsCOMPtr mPipeInput; - - // Current seek position. Need to compute this manually because - // the underlying channel may not offer this information. - PRInt64 mPosition; }; nsresult nsDefaultStreamStrategy::Open(nsIStreamListener** aStreamListener) @@ -117,8 +112,6 @@ nsresult nsDefaultStreamStrategy::Open(nsIStreamListener** aStreamListener) rv = mListener->GetInputStream(getter_AddRefs(mPipeInput)); NS_ENSURE_SUCCESS(rv, rv); - mPosition = 0; - return NS_OK; } @@ -144,14 +137,7 @@ nsresult nsDefaultStreamStrategy::Read(char* aBuffer, PRUint32 aCount, PRUint32* // stream. This allows calling from any thread as the pipe is // threadsafe. nsAutoLock lock(mLock); - if (!mPipeInput) - return NS_ERROR_FAILURE; - - nsresult rv = mPipeInput->Read(aBuffer, aCount, aBytes); - NS_ENSURE_SUCCESS(rv, rv); - mPosition += *aBytes; - - return NS_OK; + return mPipeInput ? mPipeInput->Read(aBuffer, aCount, aBytes) : NS_ERROR_FAILURE; } nsresult nsDefaultStreamStrategy::Seek(PRInt32 aWhence, PRInt64 aOffset) @@ -162,7 +148,8 @@ nsresult nsDefaultStreamStrategy::Seek(PRInt32 aWhence, PRInt64 aOffset) PRInt64 nsDefaultStreamStrategy::Tell() { - return mPosition; + // Default streams cannot be seeked + return 0; } PRUint32 nsDefaultStreamStrategy::Available() diff --git a/content/media/video/src/nsOggDecoder.cpp b/content/media/video/src/nsOggDecoder.cpp index 0a69f4a2fe8..3476def63b1 100644 --- a/content/media/video/src/nsOggDecoder.cpp +++ b/content/media/video/src/nsOggDecoder.cpp @@ -966,7 +966,7 @@ nsresult nsOggDecodeStateMachine::Run() mReader->Available() < mBufferingBytes) { LOG(PR_LOG_DEBUG, ("Buffering data until %d bytes available or %d milliseconds", - mBufferingBytes - mReader->Available(), + (long)(mBufferingBytes - mReader->Available()), BUFFERING_WAIT*1000 - (PR_IntervalToMilliseconds(PR_IntervalNow() - mBufferingStart)))); mon.Wait(PR_MillisecondsToInterval(1000)); if (mState == DECODER_STATE_SHUTDOWN) @@ -1336,13 +1336,6 @@ void nsOggDecoder::ResourceLoaded() StopProgress(); } -void nsOggDecoder::NetworkError() -{ - if (mElement) - mElement->NetworkError(); - Stop(); -} - PRBool nsOggDecoder::IsSeeking() const { return mPlayState == PLAY_STATE_SEEKING; diff --git a/content/media/video/src/nsWaveDecoder.cpp b/content/media/video/src/nsWaveDecoder.cpp deleted file mode 100644 index 6d45e9f7191..00000000000 --- a/content/media/video/src/nsWaveDecoder.cpp +++ /dev/null @@ -1,1268 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: ML 1.1/GPL 2.0/LGPL 2.1 - * - * 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 Original Code is Mozilla code. - * - * The Initial Developer of the Original Code is the Mozilla Corporation. - * Portions created by the Initial Developer are Copyright (C) 2008 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Matthew Gregan - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ -#include "limits" -#include "prlog.h" -#include "prmem.h" -#include "nsIDOMHTMLMediaElement.h" -#include "nsIDocument.h" -#include "nsIFrame.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsISeekableStream.h" -#include "nsAudioStream.h" -#include "nsAutoLock.h" -#include "nsHTMLMediaElement.h" -#include "nsNetUtil.h" -#include "nsThreadUtils.h" -#include "nsWaveDecoder.h" - -// Maximum number of seconds to wait when buffering. -#define BUFFERING_TIMEOUT 3 - -// The number of seconds of buffer data before buffering happens -// based on current playback rate. -#define BUFFERING_SECONDS_LOW_WATER_MARK 1 - -// Magic values that identify RIFF chunks we're interested in. -#define RIFF_CHUNK_MAGIC 0x52494646 -#define WAVE_CHUNK_MAGIC 0x57415645 -#define FRMT_CHUNK_MAGIC 0x666d7420 -#define DATA_CHUNK_MAGIC 0x64617461 - -// Size of RIFF chunk header. 4 byte chunk header type and 4 byte size field. -#define RIFF_CHUNK_HEADER_SIZE 8 - -// Size of RIFF header. RIFF chunk and 4 byte RIFF type. -#define RIFF_INITIAL_SIZE (RIFF_CHUNK_HEADER_SIZE + 4) - -// Size of required part of format chunk. Actual format chunks may be -// extended (for non-PCM encodings), but we skip any extended data. -#define WAVE_FORMAT_CHUNK_SIZE 16 - -// Size of format chunk including RIFF chunk header. -#define WAVE_FORMAT_SIZE (RIFF_CHUNK_HEADER_SIZE + WAVE_FORMAT_CHUNK_SIZE) - -// PCM encoding type from format chunk. Linear PCM is the only encoding -// supported by nsAudioStream. -#define WAVE_FORMAT_ENCODING_PCM 1 - -/* - A single nsWaveStateMachine instance is owned by the decoder, created - on-demand at load time. Upon creation, the decoder immediately - dispatches the state machine event to the decode thread to begin - execution. Once running, metadata loading begins immediately. If this - completes successfully, the state machine will move into a paused state - awaiting further commands. The state machine provides a small set of - threadsafe methods enabling the main thread to play, pause, seek, and - query parameters. - - An weak (raw) pointer to the decoder's nsMediaStream is used by the state - machine to read data, seek, and query stream information. The decoder is - responsible for creating and opening the stream, and may also cancel it. - Every other stream operation is performed on the playback thread by the - state machine. A cancel from the main thread will force any in-flight - stream operations to abort. - */ -class nsWaveStateMachine : public nsRunnable -{ -public: - enum State { - STATE_LOADING_METADATA, - STATE_BUFFERING, - STATE_PLAYING, - STATE_SEEKING, - STATE_PAUSED, - STATE_ENDED, - STATE_ERROR, - STATE_SHUTDOWN - }; - - nsWaveStateMachine(nsWaveDecoder* aDecoder, nsMediaStream* aStream, - PRUint32 aBufferWaitTime, float aInitialVolume); - ~nsWaveStateMachine(); - - // Return current audio volume from the audio backend. Result in range - // [0.0, 1.0]. Threadsafe. - float GetVolume(); - - // Set specified volume. aVolume must be in range [0.0, 1.0]. - // Threadsafe. - void SetVolume(float aVolume); - - /* - The following four member functions initiate the appropriate state - transition suggested by the function name. Threadsafe. - */ - void Play(); - void Pause(); - void Seek(float aTime); - void Shutdown(); - - // Returns the playback length of the audio data in seconds, calculated - // from the length extracted from the metadata. Returns NaN if called - // before metadata validation has completed. Threadsafe. - float GetDuration(); - - // Returns the current playback position in the audio stream in seconds. - // Threadsafe. - float GetCurrentTime(); - - // Returns true if the state machine is seeking. Threadsafe. - PRBool IsSeeking(); - - // Called by the decoder to indicate that the media stream has closed. - void StreamEnded(); - - // Main state machine loop. Runs forever, until shutdown state is reached. - NS_IMETHOD Run(); - -private: - // Change the current state and wake the playback thread if it is waiting - // on mMonitor. Used by public member functions called from both threads, - // so must hold mMonitor. Threadsafe. - void ChangeState(State aState); - - // Create and initialize audio stream using current audio parameters. - void OpenAudioStream(); - - // Shut down and dispose audio stream. - void CloseAudioStream(); - - // Read RIFF_INITIAL_SIZE from the beginning of the stream and verify that - // the stream data is a RIFF bitstream containing WAVE data. - PRBool LoadRIFFChunk(); - - // Scan forward in the stream looking for the WAVE format chunk. If - // found, parse and validate required metadata, then use it to set - // mSampleRate, mChannels, and mSampleSize. - PRBool LoadFormatChunk(); - - // Scan forward in the stream looking for the start of the PCM data. If - // found, record the data length and offset in mWaveLength and - // mWavePCMOffset. - PRBool FindDataOffset(); - - // Returns the number of seconds that aBytes represents based on the - // current audio parameters. e.g. 176400 bytes is 1 second at 16-bit - // stereo 44.1kHz. - float BytesToTime(PRUint32 aBytes) const - { - NS_ABORT_IF_FALSE(mMetadataValid, "Requires valid metadata"); - return float(aBytes) / mSampleRate / mSampleSize; - } - - // Returns the number of bytes that aTime represents based on the current - // audio parameters. e.g. 1 second is 176400 bytes at 16-bit stereo - // 44.1kHz. - PRUint32 TimeToBytes(float aTime) const - { - NS_ABORT_IF_FALSE(mMetadataValid, "Requires valid metadata"); - return PRUint32(aTime * mSampleRate * mSampleSize); - } - - // Rounds aBytes down to the nearest complete sample. Assumes beginning - // of byte range is already sample aligned by caller. - PRUint32 RoundDownToSample(PRUint32 aBytes) const - { - NS_ABORT_IF_FALSE(mMetadataValid, "Requires valid metadata"); - return aBytes - (aBytes % mSampleSize); - } - - // Weak (raw) pointer to our decoder instance. The decoder manages the - // lifetime of the state machine object, so it is guaranteed that the - // state machine will not outlive the decoder. The decoder is not - // threadsafe, so this pointer must only be used to create runnable events - // targeted at the main thread. - nsWaveDecoder* mDecoder; - - // Weak (raw) pointer to a media stream. The decoder manages the lifetime - // of the stream, so it is guaranteed that the stream will live as long as - // the state machine. The stream is threadsafe, but is only used on the - // playback thread except for create, open, and cancel, which are called - // from the main thread. - nsMediaStream* mStream; - - // Our audio stream. Created on demand when entering playback state. It - // is destroyed when seeking begins and will not be reinitialized until - // playback resumes, so it is possible for this to be null. - nsAutoPtr mAudioStream; - - // Maximum time in milliseconds to spend waiting for data during buffering. - PRUint32 mBufferingWait; - - // Maximum number of bytes to wait for during buffering. - PRUint32 mBufferingBytes; - - // Machine time that buffering began, used with mBufferingWait to time out - // buffering. - PRIntervalTime mBufferingStart; - - // Maximum number of bytes mAudioStream buffers internally. Used to - // calculate next wakeup time after refilling audio buffers. - PRUint32 mAudioBufferSize; - - /* - Metadata extracted from the WAVE header. Used to initialize the audio - stream, and for byte<->time domain conversions. - */ - - // Number of samples per second. Limited to range [100, 96000] in LoadFormatChunk. - PRUint32 mSampleRate; - - // Number of channels. Limited to range [1, 2] in LoadFormatChunk. - PRUint32 mChannels; - - // Size of a single sample segment, which includes a sample for each - // channel (interleaved). Limited to 2 or 4 due to requirement for 16-bit - // samples and the limit on number of channels. - PRUint32 mSampleSize; - - // Size of PCM data stored in the WAVE as reported by the data chunk in - // the media. - PRUint32 mWaveLength; - - // Start offset of the PCM data in the media stream. Extends mWaveLength - // bytes. - PRUint32 mWavePCMOffset; - - /* - All member variables following this comment are accessed by both - threads and must be synchronized via mMonitor. - */ - PRMonitor* mMonitor; - - // The state to enter when the state machine loop iterates next. - State mState; - - // A queued state transition. This is used to record the next state - // transition when play or pause is requested during seeking or metadata - // loading to ensure a completed metadata load or seek returns to the most - // recently requested state on completion. - State mNextState; - - // Volume that the audio backend will be initialized with. - float mInitialVolume; - - // Time position (in seconds) to offset current time from audio stream. - // Set by calling Seek(float) when seeking, and when the stream is closed - // during shutdown. - float mTimeOffset; - - // Set when StreamEnded has fired to indicate that we should not expect - // any more data from mStream than what is already buffered (i.e. what - // Available() reports). - PRPackedBool mExpectMoreData; - - // True once metadata has been parsed and validated. Users of mSampleRate, - // mChannels, mSampleSize, mWaveLength, mWavePCMOffset must check this - // flag before assuming the values are valid. - PRPackedBool mMetadataValid; -}; - -nsWaveStateMachine::nsWaveStateMachine(nsWaveDecoder* aDecoder, nsMediaStream* aStream, - PRUint32 aBufferWaitTime, float aInitialVolume) - : mDecoder(aDecoder), - mStream(aStream), - mBufferingWait(aBufferWaitTime), - mBufferingBytes(0), - mBufferingStart(0), - mAudioBufferSize(0), - mSampleRate(0), - mChannels(0), - mSampleSize(0), - mWaveLength(0), - mWavePCMOffset(0), - mMonitor(nsnull), - mState(STATE_LOADING_METADATA), - mNextState(STATE_PAUSED), - mInitialVolume(aInitialVolume), - mTimeOffset(0.0), - mExpectMoreData(PR_TRUE), - mMetadataValid(PR_FALSE) -{ - mMonitor = nsAutoMonitor::NewMonitor("nsWaveStateMachine"); -} - -nsWaveStateMachine::~nsWaveStateMachine() -{ - nsAutoMonitor::DestroyMonitor(mMonitor); -} - -void -nsWaveStateMachine::Shutdown() -{ - ChangeState(STATE_SHUTDOWN); -} - -void -nsWaveStateMachine::Play() -{ - nsAutoMonitor monitor(mMonitor); - if (mState == STATE_LOADING_METADATA || mState == STATE_SEEKING) { - mNextState = STATE_PLAYING; - } else { - ChangeState(STATE_PLAYING); - } -} - -float -nsWaveStateMachine::GetVolume() -{ - float volume = mInitialVolume; - if (mAudioStream) { - volume = mAudioStream->GetVolume(); - } - return volume; -} - -void -nsWaveStateMachine::SetVolume(float aVolume) -{ - nsAutoMonitor monitor(mMonitor); - mInitialVolume = aVolume; - if (mAudioStream) { - mAudioStream->SetVolume(aVolume); - } -} - -void -nsWaveStateMachine::Pause() -{ - nsAutoMonitor monitor(mMonitor); - if (mState == STATE_LOADING_METADATA || mState == STATE_SEEKING) { - mNextState = STATE_PAUSED; - } else { - ChangeState(STATE_PAUSED); - } -} - -void -nsWaveStateMachine::Seek(float aTime) -{ - nsAutoMonitor monitor(mMonitor); - mNextState = mState; - mTimeOffset = aTime; - ChangeState(STATE_SEEKING); -} - -float -nsWaveStateMachine::GetDuration() -{ - nsAutoMonitor monitor(mMonitor); - if (mMetadataValid) { - return BytesToTime(mWaveLength); - } - return std::numeric_limits::quiet_NaN(); -} - -float -nsWaveStateMachine::GetCurrentTime() -{ - nsAutoMonitor monitor(mMonitor); - double time = 0.0; - if (mAudioStream) { - time = mAudioStream->GetTime(); - } - return float(time + mTimeOffset); -} - -PRBool -nsWaveStateMachine::IsSeeking() -{ - nsAutoMonitor monitor(mMonitor); - return mState == STATE_SEEKING; -} - -void -nsWaveStateMachine::StreamEnded() -{ - nsAutoMonitor monitor(mMonitor); - mExpectMoreData = PR_FALSE; -} - -NS_IMETHODIMP -nsWaveStateMachine::Run() -{ - // Monitor is held by this thread almost permanently, but must be manually - // dropped during long operations to prevent the main thread from blocking - // when calling methods on the state machine object. - nsAutoMonitor monitor(mMonitor); - - for (;;) { - switch (mState) { - case STATE_LOADING_METADATA: - { - monitor.Exit(); - PRBool loaded = LoadRIFFChunk() && LoadFormatChunk() && FindDataOffset(); - monitor.Enter(); - - if (mState == STATE_LOADING_METADATA) { - nsCOMPtr event; - State newState; - - if (loaded) { - mMetadataValid = PR_TRUE; - event = NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, MetadataLoaded); - newState = mNextState; - } else { - event = NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, MediaErrorDecode); - newState = STATE_ERROR; - } - - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - ChangeState(newState); - } - } - break; - - case STATE_BUFFERING: - if ((PR_IntervalToMilliseconds(PR_IntervalNow() - mBufferingStart) < mBufferingWait) && - mStream->DownloadRate() >= 0 && - mStream->Available() < mBufferingBytes) { - LOG(PR_LOG_DEBUG, ("Buffering data until %d bytes or %d milliseconds (rate %f)\n", - mBufferingBytes - mStream->Available(), - mBufferingWait - (PR_IntervalToMilliseconds(PR_IntervalNow() - mBufferingStart)), - mStream->DownloadRate())); - monitor.Wait(PR_MillisecondsToInterval(1000)); - } else { - ChangeState(mNextState); - nsCOMPtr event = - NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, BufferingStopped); - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - } - - break; - - case STATE_PLAYING: - if (!mAudioStream) { - OpenAudioStream(); - } else { - mAudioStream->Resume(); - } - - if (mStream->DownloadRate() >= 0 && - mStream->Available() < mStream->PlaybackRate() * BUFFERING_SECONDS_LOW_WATER_MARK) { - nsCOMPtr event = - NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, BufferingStarted); - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - - // Buffer until mBufferingWait milliseconds of data is available. - mBufferingBytes = TimeToBytes(float(mBufferingWait) / 1000.0); - mBufferingStart = PR_IntervalNow(); - ChangeState(STATE_BUFFERING); - } - - if (!mExpectMoreData && mStream->Available() < mSampleSize) { - // Media stream has ended and there is less data available than a - // single sample so end playback. - ChangeState(STATE_ENDED); - } else { - // Assuming enough data is available from the network, we aim to - // completely fill the audio backend's buffers with data. This - // allows us plenty of time to wake up and refill the buffers - // without an underrun occurring. - PRUint32 len = RoundDownToSample(NS_MIN(mStream->Available(), - PRUint32(mAudioStream->Available() * sizeof(short)))); - if (len) { - nsAutoArrayPtr buf(new char[len]); - PRUint32 got = 0; - - monitor.Exit(); - if (NS_FAILED(mStream->Read(buf.get(), len, &got))) { - NS_WARNING("Stream read failed"); - } - - if (got == 0) { - ChangeState(STATE_ENDED); - } - - // If we got less data than requested, go ahead and write what we - // got to the audio hardware. It's unlikely that this can happen - // since we never attempt to read more data than what is already - // buffered. - len = RoundDownToSample(got); - - // Calculate difference between the current media stream position - // and the expected end of the PCM data. - PRInt64 endDelta = mWavePCMOffset + mWaveLength - mStream->Tell(); - if (endDelta < 0) { - // Read past the end of PCM data. Adjust len to avoid playing - // back trailing data. - len -= -endDelta; - if (RoundDownToSample(len) != len) { - NS_WARNING("PCM data does not end with complete sample"); - len = RoundDownToSample(len); - } - ChangeState(STATE_ENDED); - } - - mAudioStream->Write(reinterpret_cast(buf.get()), len / sizeof(short)); - monitor.Enter(); - } - - // To avoid waking up too frequently to top up these buffers, - // calculate the duration of the currently buffered data and sleep - // until most of the buffered data has been consumed. We can't - // sleep for the entire duration because we might not wake up in - // time to refill the buffers, causing an underrun. To avoid this, - // wake up when approximately half the buffered data has been - // consumed. This could be made smarter, but at least avoids waking - // up frequently to perform small buffer refills. - float nextWakeup = BytesToTime(mAudioBufferSize - mAudioStream->Available() * sizeof(short)) * 1000.0 / 2.0; - monitor.Wait(PR_MillisecondsToInterval(PRUint32(nextWakeup))); - } - break; - - case STATE_SEEKING: - { - CloseAudioStream(); - - monitor.Exit(); - nsCOMPtr startEvent = - NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, SeekingStarted); - NS_DispatchToMainThread(startEvent, NS_DISPATCH_SYNC); - monitor.Enter(); - - if (mState == STATE_SHUTDOWN) { - break; - } - - PRInt64 position = RoundDownToSample(TimeToBytes(mTimeOffset)) + mWavePCMOffset; - - monitor.Exit(); - nsresult rv = mStream->Seek(nsISeekableStream::NS_SEEK_SET, position); - if (NS_FAILED(rv)) { - NS_WARNING("Seek failed"); - } - monitor.Enter(); - - if (mState == STATE_SHUTDOWN) { - break; - } - - monitor.Exit(); - nsCOMPtr stopEvent = - NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, SeekingStopped); - NS_DispatchToMainThread(stopEvent, NS_DISPATCH_SYNC); - monitor.Enter(); - - if (mState != STATE_SHUTDOWN) { - ChangeState(mNextState); - } - } - break; - - case STATE_PAUSED: - if (mAudioStream) { - mAudioStream->Pause(); - } - monitor.Wait(); - break; - - case STATE_ENDED: - if (mAudioStream) { - monitor.Exit(); - mAudioStream->Drain(); - monitor.Enter(); - } - - if (mState != STATE_SHUTDOWN) { - nsCOMPtr event = - NS_NEW_RUNNABLE_METHOD(nsWaveDecoder, mDecoder, PlaybackEnded); - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - } - - while (mState != STATE_SHUTDOWN) { - monitor.Wait(); - } - break; - - case STATE_ERROR: - monitor.Wait(); - if (mState != STATE_SHUTDOWN) { - NS_WARNING("Invalid state transition"); - ChangeState(STATE_ERROR); - } - break; - - case STATE_SHUTDOWN: - if (mAudioStream) { - mTimeOffset = mAudioStream->GetTime(); - } - CloseAudioStream(); - return NS_OK; - } - } - - return NS_OK; -} - -void -nsWaveStateMachine::ChangeState(State aState) -{ - nsAutoMonitor monitor(mMonitor); - mState = aState; - monitor.NotifyAll(); -} - -void -nsWaveStateMachine::OpenAudioStream() -{ - mAudioStream = new nsAudioStream(); - if (!mAudioStream) { - LOG(PR_LOG_ERROR, ("Could not create audio stream")); - } else { - mAudioStream->Init(mChannels, mSampleRate); - mAudioStream->SetVolume(mInitialVolume); - mAudioBufferSize = mAudioStream->Available() * sizeof(short); - } -} - -void -nsWaveStateMachine::CloseAudioStream() -{ - if (mAudioStream) { - mAudioStream->Shutdown(); - mAudioStream = nsnull; - } -} - -static PRUint32 -ReadUint32BE(const char** aBuffer) -{ - PRUint32 result = - PRUint8((*aBuffer)[0]) << 24 | - PRUint8((*aBuffer)[1]) << 16 | - PRUint8((*aBuffer)[2]) << 8 | - PRUint8((*aBuffer)[3]); - *aBuffer += sizeof(PRUint32); - return result; -} - -static PRUint32 -ReadUint32LE(const char** aBuffer) -{ - PRUint32 result = - PRUint8((*aBuffer)[3]) << 24 | - PRUint8((*aBuffer)[2]) << 16 | - PRUint8((*aBuffer)[1]) << 8 | - PRUint8((*aBuffer)[0]); - *aBuffer += sizeof(PRUint32); - return result; -} - -static PRUint16 -ReadUint16LE(const char** aBuffer) -{ - PRUint16 result = - PRUint8((*aBuffer)[1]) << 8 | - PRUint8((*aBuffer)[0]) << 0; - *aBuffer += sizeof(PRUint16); - return result; -} - -static PRBool -ReadAll(nsMediaStream* aStream, char* aBuf, PRUint32 aSize) -{ - PRUint32 got = 0; - do { - PRUint32 read = 0; - if (NS_FAILED(aStream->Read(aBuf + got, aSize - got, &read))) { - NS_WARNING("Stream read failed"); - return PR_FALSE; - } - got += read; - } while (got != aSize); - return PR_TRUE; -} - -PRBool -nsWaveStateMachine::LoadRIFFChunk() -{ - char riffHeader[RIFF_INITIAL_SIZE]; - const char* p = riffHeader; - - NS_ABORT_IF_FALSE(mStream->Tell() == 0, - "LoadRIFFChunk called when stream in invalid state"); - - if (!ReadAll(mStream, riffHeader, sizeof(riffHeader))) { - return PR_FALSE; - } - - if (ReadUint32BE(&p) != RIFF_CHUNK_MAGIC) { - NS_WARNING("Stream data not in RIFF format"); - return PR_FALSE; - } - - // Skip over RIFF size field. - p += 4; - - if (ReadUint32BE(&p) != WAVE_CHUNK_MAGIC) { - NS_WARNING("Expected WAVE chunk"); - return PR_FALSE; - } - - return PR_TRUE; -} - -PRBool -nsWaveStateMachine::LoadFormatChunk() -{ - PRUint32 rate, channels, sampleSize; - char waveFormat[WAVE_FORMAT_SIZE]; - const char* p = waveFormat; - - // RIFF chunks are always word (two byte) aligned. - NS_ABORT_IF_FALSE(mStream->Tell() % 2 == 0, - "LoadFormatChunk called with unaligned stream"); - - if (!ReadAll(mStream, waveFormat, sizeof(waveFormat))) { - return PR_FALSE; - } - - if (ReadUint32BE(&p) != FRMT_CHUNK_MAGIC) { - NS_WARNING("Expected format chunk"); - return PR_FALSE; - } - - PRUint32 fmtsize = ReadUint32LE(&p); - - if (ReadUint16LE(&p) != WAVE_FORMAT_ENCODING_PCM) { - NS_WARNING("WAVE is not uncompressed PCM, compressed encodings are not supported"); - return PR_FALSE; - } - - channels = ReadUint16LE(&p); - rate = ReadUint32LE(&p); - - // Skip over average bytes per second field. - p += 4; - - sampleSize = ReadUint16LE(&p); - - // We only support 16-bit audio for now, since that's all that the in-tree - // libsydney supports. - if (ReadUint16LE(&p) != 16) { - NS_WARNING("WAVE is not 16-bit, other bit rates are not supported"); - return PR_FALSE; - } - - // PCM encoded WAVEs are not expected to have an extended "format" chunk, - // but I have found WAVEs that have a extended "format" chunk with an - // extension size of 0 bytes. Be polite and handle this rather than - // considering the file invalid. This code skips any extension of the - // "format" chunk. - if (fmtsize > WAVE_FORMAT_CHUNK_SIZE) { - char extLength[2]; - const char* p = extLength; - - if (!ReadAll(mStream, extLength, sizeof(extLength))) { - return PR_FALSE; - } - - PRUint16 extra = ReadUint16LE(&p); - if (fmtsize - WAVE_FORMAT_CHUNK_SIZE + 2 != extra) { - NS_WARNING("Invalid extended format chunk size"); - return PR_FALSE; - } - extra += extra % 2; - - if (extra > 0) { - nsAutoArrayPtr chunkExtension(new char[extra]); - if (!ReadAll(mStream, chunkExtension.get(), extra)) { - return PR_FALSE; - } - } - } - - // RIFF chunks are always word (two byte) aligned. - NS_ABORT_IF_FALSE(mStream->Tell() % 2 == 0, - "LoadFormatChunk left stream unaligned"); - - // Make sure metadata is fairly sane. The rate check is fairly arbitrary, - // but the channels/sampleSize check is intentionally limited to 16-bit - // mono or stereo because that's what the audio backend currently - // supports. - if (rate < 100 || rate > 96000 || - channels < 1 || channels > 2 || - sampleSize < 2 || sampleSize > 4) { - NS_WARNING("Invalid WAVE metadata"); - return PR_FALSE; - } - - nsAutoMonitor monitor(mMonitor); - mSampleRate = rate; - mChannels = channels; - mSampleSize = sampleSize; - return PR_TRUE; -} - -PRBool -nsWaveStateMachine::FindDataOffset() -{ - PRUint32 length; - PRInt64 offset; - - // RIFF chunks are always word (two byte) aligned. - NS_ABORT_IF_FALSE(mStream->Tell() % 2 == 0, - "FindDataOffset called with unaligned stream"); - - // The "data" chunk may not directly follow the "format" chunk, so skip - // over any intermediate chunks. - for (;;) { - char chunkHeader[8]; - const char* p = chunkHeader; - - if (!ReadAll(mStream, chunkHeader, sizeof(chunkHeader))) { - return PR_FALSE; - } - - PRUint32 magic = ReadUint32BE(&p); - - if (magic == DATA_CHUNK_MAGIC) { - length = ReadUint32LE(&p); - break; - } - - if (magic == FRMT_CHUNK_MAGIC) { - LOG(PR_LOG_ERROR, ("Invalid WAVE: expected \"data\" chunk but found \"format\" chunk")); - return PR_FALSE; - } - - PRUint32 size = ReadUint32LE(&p); - size += size % 2; - - nsAutoArrayPtr chunk(new char[size]); - if (!ReadAll(mStream, chunk.get(), size)) { - return PR_FALSE; - } - } - - offset = mStream->Tell(); - if (!offset) { - NS_WARNING("PCM data offset not found"); - return PR_FALSE; - } - - if (offset < 0 || offset > PR_UINT32_MAX) { - NS_WARNING("offset out of range"); - return PR_FALSE; - } - - nsAutoMonitor monitor(mMonitor); - mWaveLength = length; - mWavePCMOffset = PRUint32(offset); - return PR_TRUE; -} - -NS_IMPL_THREADSAFE_ISUPPORTS1(nsWaveDecoder, nsIObserver) - -nsWaveDecoder::nsWaveDecoder() - : mBytesDownloaded(0), - mInitialVolume(1.0), - mStream(nsnull), - mEndedCurrentTime(0.0), - mEndedDuration(std::numeric_limits::quiet_NaN()), - mNotifyOnShutdown(PR_FALSE), - mSeekable(PR_TRUE) -{ - MOZ_COUNT_CTOR(nsWaveDecoder); -} - -nsWaveDecoder::~nsWaveDecoder() -{ - MOZ_COUNT_DTOR(nsWaveDecoder); -} - -void -nsWaveDecoder::GetCurrentURI(nsIURI** aURI) -{ - NS_IF_ADDREF(*aURI = mURI); -} - -nsIPrincipal* -nsWaveDecoder::GetCurrentPrincipal() -{ - if (!mStream) { - return nsnull; - } - return mStream->GetCurrentPrincipal(); -} - -float -nsWaveDecoder::GetCurrentTime() -{ - if (mPlaybackStateMachine) { - return mPlaybackStateMachine->GetCurrentTime(); - } - return mEndedCurrentTime; -} - -nsresult -nsWaveDecoder::Seek(float aTime) -{ - if (mPlaybackStateMachine && aTime >= 0.0) { - mPlaybackStateMachine->Seek(aTime); - return NS_OK; - } - return NS_ERROR_FAILURE; -} - -nsresult -nsWaveDecoder::PlaybackRateChanged() -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -float -nsWaveDecoder::GetDuration() -{ - if (mPlaybackStateMachine) { - return mPlaybackStateMachine->GetDuration(); - } - return mEndedDuration; -} - -void -nsWaveDecoder::Pause() -{ - if (mPlaybackStateMachine) { - mPlaybackStateMachine->Pause(); - } -} - -float -nsWaveDecoder::GetVolume() -{ - if (!mPlaybackStateMachine) { - return mInitialVolume; - } - return mPlaybackStateMachine->GetVolume(); -} - -void -nsWaveDecoder::SetVolume(float aVolume) -{ - mInitialVolume = aVolume; - if (mPlaybackStateMachine) { - mPlaybackStateMachine->SetVolume(aVolume); - } -} - -nsresult -nsWaveDecoder::Play() -{ - if (!mPlaybackStateMachine) { - Load(mURI, nsnull, nsnull); - } - - if (mPlaybackStateMachine) { - mPlaybackStateMachine->Play(); - return NS_OK; - } - - return NS_ERROR_FAILURE; -} - -void -nsWaveDecoder::Stop() -{ - StopProgress(); - - if (mPlaybackStateMachine) { - mPlaybackStateMachine->Shutdown(); - } - - if (mStream) { - mStream->Cancel(); - } - - if (mPlaybackThread) { - mEndedCurrentTime = mPlaybackStateMachine->GetCurrentTime(); - mEndedDuration = mPlaybackStateMachine->GetDuration(); - mPlaybackThread->Shutdown(); - } - - mPlaybackThread = nsnull; - mPlaybackStateMachine = nsnull; - mStream = nsnull; - - UnregisterShutdownObserver(); -} - -nsresult -nsWaveDecoder::Load(nsIURI* aURI, nsIChannel* aChannel, nsIStreamListener** aStreamListener) -{ - if (aStreamListener) { - *aStreamListener = nsnull; - } - - if (aURI) { - NS_ASSERTION(!aStreamListener, "No listener should be requested here"); - mURI = aURI; - } else { - NS_ASSERTION(aChannel, "Either a URI or a channel is required"); - NS_ASSERTION(aStreamListener, "A listener should be requested here"); - - nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(mURI)); - NS_ENSURE_SUCCESS(rv, rv); - } - - StartProgress(); - RegisterShutdownObserver(); - - mStream = new nsMediaStream(); - NS_ENSURE_TRUE(mStream, NS_ERROR_OUT_OF_MEMORY); - - nsresult rv = mStream->Open(this, aURI, aChannel, aStreamListener); - NS_ENSURE_SUCCESS(rv, rv); - - rv = NS_NewThread(getter_AddRefs(mPlaybackThread)); - NS_ENSURE_SUCCESS(rv, rv); - - mPlaybackStateMachine = new nsWaveStateMachine(this, mStream.get(), - BUFFERING_TIMEOUT * 1000, - mInitialVolume); - rv = mPlaybackThread->Dispatch(mPlaybackStateMachine, NS_DISPATCH_NORMAL); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -void -nsWaveDecoder::MetadataLoaded() -{ - if (mElement) { - mElement->MetadataLoaded(); - mElement->FirstFrameLoaded(); - } -} - -void -nsWaveDecoder::PlaybackEnded() -{ - Stop(); - if (mElement) { - mElement->PlaybackEnded(); - } -} - -void -nsWaveDecoder::ResourceLoaded() -{ - if (mElement) { - mElement->ResourceLoaded(); - } - if (mPlaybackStateMachine) { - mPlaybackStateMachine->StreamEnded(); - } - StopProgress(); -} - -void -nsWaveDecoder::NetworkError() -{ - if (mElement) { - mElement->NetworkError(); - } - if (mPlaybackStateMachine) { - mPlaybackStateMachine->StreamEnded(); - } - Stop(); -} - -PRBool -nsWaveDecoder::IsSeeking() const -{ - if (mPlaybackStateMachine) { - return mPlaybackStateMachine->IsSeeking(); - } - return PR_FALSE; -} - -PRUint64 -nsWaveDecoder::GetBytesLoaded() -{ - return mBytesDownloaded; -} - -PRInt64 -nsWaveDecoder::GetTotalBytes() -{ - return mContentLength; -} - -void -nsWaveDecoder::SetTotalBytes(PRInt64 aBytes) -{ - mContentLength = aBytes; -} - -void -nsWaveDecoder::UpdateBytesDownloaded(PRUint64 aBytes) -{ - mBytesDownloaded = aBytes; -} - -// An event that gets posted to the main thread, when the media element is -// being destroyed, to destroy the decoder. Since the decoder shutdown can -// block and post events this cannot be done inside destructor calls. So -// this event is posted asynchronously to the main thread to perform the -// shutdown. It keeps a strong reference to the decoder to ensure it does -// not get deleted when the element is deleted. -class nsWaveDecoderShutdown : public nsRunnable -{ -public: - nsWaveDecoderShutdown(nsWaveDecoder* aDecoder) - : mDecoder(aDecoder) - { - } - - NS_IMETHOD Run() - { - mDecoder->Stop(); - return NS_OK; - } - -private: - nsRefPtr mDecoder; -}; - -void -nsWaveDecoder::Shutdown() -{ - nsMediaDecoder::Shutdown(); - - nsCOMPtr event = new nsWaveDecoderShutdown(this); - NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); -} - -nsresult -nsWaveDecoder::Observe(nsISupports* aSubject, const char* aTopic, const PRUnichar* aData) -{ - if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) { - Shutdown(); - } - return NS_OK; -} - -void -nsWaveDecoder::BufferingStarted() -{ - if (mElement) { - mElement->ChangeReadyState(nsIDOMHTMLMediaElement::DATA_UNAVAILABLE); - } -} - -void -nsWaveDecoder::BufferingStopped() -{ - if (mElement) { - mElement->ChangeReadyState(nsIDOMHTMLMediaElement::CAN_SHOW_CURRENT_FRAME); - } -} - -void -nsWaveDecoder::SeekingStarted() -{ - if (mElement) { - mElement->SeekStarted(); - } -} - -void -nsWaveDecoder::SeekingStopped() -{ - if (mElement) { - mElement->SeekCompleted(); - } -} - -void -nsWaveDecoder::RegisterShutdownObserver() -{ - if (!mNotifyOnShutdown) { - nsCOMPtr observerService = - do_GetService("@mozilla.org/observer-service;1"); - if (observerService) { - mNotifyOnShutdown = - NS_SUCCEEDED(observerService->AddObserver(this, - NS_XPCOM_SHUTDOWN_OBSERVER_ID, - PR_FALSE)); - } else { - NS_WARNING("Could not get an observer service. Audio playback may not shutdown cleanly."); - } - } -} - -void -nsWaveDecoder::UnregisterShutdownObserver() -{ - if (mNotifyOnShutdown) { - nsCOMPtr observerService = - do_GetService("@mozilla.org/observer-service;1"); - if (observerService) { - mNotifyOnShutdown = PR_FALSE; - observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - } - } -} - -void -nsWaveDecoder::MediaErrorDecode() -{ -#if 0 - if (mElement) { - mElement->MediaErrorDecode(); - } -#else - NS_WARNING("MediaErrorDecode fired, but not implemented."); -#endif -} - -void -nsWaveDecoder::SetSeekable(PRBool aSeekable) -{ - mSeekable = aSeekable; -} - -PRBool -nsWaveDecoder::GetSeekable() -{ - return mSeekable; -} diff --git a/content/media/video/test/Makefile.in b/content/media/video/test/Makefile.in index e3e2c969874..bd7141fced7 100644 --- a/content/media/video/test/Makefile.in +++ b/content/media/video/test/Makefile.in @@ -69,11 +69,9 @@ _TEST_FILES = test_autoplay.html \ test_timeupdate2.html \ test_timeupdate3.html \ test_volume.html \ - test_wav_ended1.html \ 320x240.ogg \ bug461281.ogg \ seek.ogg \ - r11025_s16_c1.wav \ # test_bug448534.html \ $(NULL) diff --git a/content/media/video/test/r11025_s16_c1.wav b/content/media/video/test/r11025_s16_c1.wav deleted file mode 100644 index ab2e08befb6..00000000000 Binary files a/content/media/video/test/r11025_s16_c1.wav and /dev/null differ diff --git a/content/media/video/test/test_wav_ended1.html b/content/media/video/test/test_wav_ended1.html deleted file mode 100644 index 8fc2202303c..00000000000 --- a/content/media/video/test/test_wav_ended1.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - Media test: ended - - - - - - -
-
-
- - diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index c3984678359..74d88b1d3fd 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -153,15 +153,10 @@ SHARED_LIBRARY_LIBS += \ $(DEPTH)/media/libogg/src/$(LIB_PREFIX)ogg.$(LIB_SUFFIX) \ $(DEPTH)/media/liboggplay/src/liboggplay/$(LIB_PREFIX)oggplay.$(LIB_SUFFIX) \ $(DEPTH)/media/liboggz/src/liboggz/$(LIB_PREFIX)oggz.$(LIB_SUFFIX) \ + $(DEPTH)/media/libsydneyaudio/src/$(LIB_PREFIX)sydneyaudio.$(LIB_SUFFIX) \ $(DEPTH)/media/libtheora/lib/$(LIB_PREFIX)theora.$(LIB_SUFFIX) \ $(DEPTH)/media/libvorbis/lib/$(LIB_PREFIX)vorbis.$(LIB_SUFFIX) \ $(NULL) -endif - -ifdef MOZ_SYDNEYAUDIO -SHARED_LIBRARY_LIBS += \ - $(DEPTH)/media/libsydneyaudio/src/$(LIB_PREFIX)sydneyaudio.$(LIB_SUFFIX) \ - $(NULL) LOCAL_INCLUDES += -I$(DEPTH)/content/html/content/src endif @@ -263,7 +258,7 @@ ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT))) EXTRA_DSO_LDOPTS += $(XLDFLAGS) $(XLIBS) endif -ifdef MOZ_SYDNEYAUDIO +ifdef MOZ_OGG ifeq ($(OS_ARCH),Darwin) OS_LIBS += -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon endif diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index e1a1df2bef3..e9b81452aa1 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -115,7 +115,7 @@ PRBool NS_SVGEnabled(); #include "nsHTMLMediaElement.h" #endif -#ifdef MOZ_SYDNEYAUDIO +#ifdef MOZ_OGG #include "nsAudioStream.h" #endif @@ -257,7 +257,7 @@ nsLayoutStatics::Initialize() nsHTMLMediaElement::InitMediaTypes(); #endif -#ifdef MOZ_SYDNEYAUDIO +#ifdef MOZ_OGG nsAudioStream::InitLibrary(); #endif @@ -342,7 +342,7 @@ nsLayoutStatics::Shutdown() #ifdef MOZ_MEDIA nsHTMLMediaElement::ShutdownMediaTypes(); #endif -#ifdef MOZ_SYDNEYAUDIO +#ifdef MOZ_OGG nsAudioStream::ShutdownLibrary(); #endif diff --git a/toolkit/library/Makefile.in b/toolkit/library/Makefile.in index c64ddf5cdd2..18df7131179 100644 --- a/toolkit/library/Makefile.in +++ b/toolkit/library/Makefile.in @@ -206,7 +206,7 @@ EXTRA_DSO_LDOPTS += \ $(TK_LIBS) \ $(NULL) -ifdef MOZ_SYDNEYAUDIO +ifdef MOZ_OGG EXTRA_DSO_LDOPTS += \ -framework CoreAudio \ -framework AudioToolbox \ diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 0fb9d4b603d..e1ecca760b7 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -1115,11 +1115,6 @@ if [ "$MOZ_OGG" ]; then $MAKEFILES_libogg $MAKEFILES_libfishsound $MAKEFILES_liboggplay - " -fi - -if [ "$MOZ_SYDNEYAUDIO" ]; then - add_makefiles " $MAKEFILES_libsydneyaudio " fi diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk index efbc641c8be..c8dc7aeb0f9 100644 --- a/toolkit/toolkit-tiers.mk +++ b/toolkit/toolkit-tiers.mk @@ -124,17 +124,12 @@ tier_gecko_dirs += \ media/libogg \ media/liboggplay \ media/liboggz \ + media/libsydneyaudio \ media/libtheora \ media/libvorbis \ $(NULL) endif -ifdef MOZ_SYDNEYAUDIO -tier_gecko_dirs += \ - media/libsydneyaudio \ - $(NULL) -endif - tier_gecko_dirs += \ uriloader \ modules/libimg \ diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 5488d95a227..b8c5726818c 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -537,8 +537,7 @@ static nsExtraMimeTypeEntry extraMimeEntries [] = { TEXT_CSS, "css", "Style Sheet", MAC_TYPE('TEXT'), MAC_TYPE('ttxt') }, { "audio/ogg", "oga", "Ogg Audio", 0, 0 }, { "video/ogg", "ogv", "Ogg Video", 0, 0 }, - { "audio/ogg", "ogg", "Ogg Audio", 0, 0 }, - { "audio/x-wav", "wav", "Waveform Audio", 0, 0 } + { "audio/ogg", "ogg", "Ogg Audio", 0, 0 } }; #undef MAC_TYPE