b=449315 Support WAV format in <audio> element. r+sr=roc

This commit is contained in:
Matthew Gregan 2008-11-07 09:53:20 +13:00
parent 70d7909b47
commit f7e186f1bd
23 changed files with 1920 additions and 30 deletions

View File

@ -159,6 +159,8 @@ 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@

View File

@ -4308,6 +4308,8 @@ 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
@ -5280,7 +5282,7 @@ if test -n "$MOZ_NO_FAST_LOAD"; then
fi
dnl ========================================================
dnl = Enable Ogg Codecs
dnl = Disable Ogg Codecs
dnl ========================================================
MOZ_ARG_DISABLE_BOOL(ogg,
[ --disable-ogg Disable Ogg Codec support],
@ -5291,23 +5293,56 @@ 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 If using Ogg with Linux, ensure that the alsa library is available
if test -n "$MOZ_OGG"; then
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
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

View File

@ -72,6 +72,9 @@
#ifdef MOZ_OGG
#include "nsOggDecoder.h"
#endif
#ifdef MOZ_WAVE
#include "nsWaveDecoder.h"
#endif
class nsAsyncEventRunner : public nsRunnable
{
@ -487,12 +490,34 @@ 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;
}
@ -509,6 +534,13 @@ 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
}
}
@ -523,6 +555,11 @@ 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
}
}
@ -536,6 +573,14 @@ 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;
}

View File

@ -47,14 +47,30 @@ EXPORTS = \
nsMediaDecoder.h \
$(NULL)
ifdef MOZ_OGG
ifdef MOZ_MEDIA
EXPORTS += \
nsAudioStream.h \
nsChannelReader.h \
nsChannelToPipeListener.h \
nsMediaStream.h \
$(NULL)
endif
ifdef MOZ_SYDNEYAUDIO
EXPORTS += \
nsAudioStream.h \
$(NULL)
endif
ifdef MOZ_OGG
EXPORTS += \
nsChannelReader.h \
nsOggDecoder.h \
$(NULL)
endif
ifdef MOZ_WAVE
EXPORTS += \
nsWaveDecoder.h \
$(NULL)
endif
include $(topsrcdir)/config/rules.mk

View File

@ -35,6 +35,9 @@
* 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"
@ -64,7 +67,12 @@ 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(float* aBuf, PRUint32 count);
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);
// Return the number of sound samples that can be written to the audio device
// without blocking.
@ -78,10 +86,33 @@ 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;
PRPackedBool mMute;
// The byte position in the audio buffer where playback was last paused.
PRInt64 mSavedPauseBytes;
PRInt64 mPauseBytes;
float mStartTime;
float mPauseTime;
PRInt64 mSamplesBuffered;
PRPackedBool mPaused;
};
#endif

View File

@ -127,6 +127,9 @@ 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;

View File

@ -331,6 +331,10 @@ 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;

View File

@ -0,0 +1,270 @@
/* -*- 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 <kinetik@flim.org>
*
* 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<nsIURI> mURI;
// Thread that handles audio playback, including data download.
nsCOMPtr<nsIThread> mPlaybackThread;
// State machine that runs on mPlaybackThread. Methods on this object are
// safe to call from any thread.
nsCOMPtr<nsWaveStateMachine> mPlaybackStateMachine;
// Threadsafe wrapper around channels that provides seeking based on the
// underlying channel type.
nsAutoPtr<nsMediaStream> 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

View File

@ -82,16 +82,32 @@ CPPSRCS = \
nsMediaDecoder.cpp \
$(NULL)
ifdef MOZ_OGG
ifdef MOZ_MEDIA
CPPSRCS += \
nsAudioStream.cpp \
nsChannelReader.cpp \
nsChannelToPipeListener.cpp \
nsMediaStream.cpp \
$(NULL)
endif
ifdef MOZ_SYDNEYAUDIO
CPPSRCS += \
nsAudioStream.cpp \
$(NULL)
endif
ifdef MOZ_OGG
CPPSRCS += \
nsChannelReader.cpp \
nsOggDecoder.cpp \
$(NULL)
endif
ifdef MOZ_WAVE
CPPSRCS += \
nsWaveDecoder.cpp \
$(NULL)
endif
FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/rules.mk

View File

@ -49,6 +49,13 @@ extern "C" {
PRLogModuleInfo* gAudioStreamLog = nsnull;
#endif
#define FAKE_BUFFER_SIZE 176400
static float CurrentTimeInSeconds()
{
return PR_IntervalToMilliseconds(PR_IntervalNow()) / 1000.0;
}
void nsAudioStream::InitLibrary()
{
#ifdef PR_LOGGING
@ -64,7 +71,12 @@ nsAudioStream::nsAudioStream() :
mVolume(1.0),
mAudioHandle(0),
mRate(0),
mChannels(0)
mChannels(0),
mSavedPauseBytes(0),
mPauseBytes(0),
mPauseTime(0.0),
mSamplesBuffered(0),
mPaused(PR_FALSE)
{
}
@ -72,6 +84,7 @@ void nsAudioStream::Init(PRInt32 aNumChannels, PRInt32 aRate)
{
mRate = aRate;
mChannels = aNumChannels;
mStartTime = CurrentTimeInSeconds();
if (sa_stream_create_pcm(reinterpret_cast<sa_stream_t**>(&mAudioHandle),
NULL,
SA_MODE_WRONLY,
@ -100,8 +113,10 @@ void nsAudioStream::Shutdown()
mAudioHandle = nsnull;
}
void nsAudioStream::Write(float* aBuf, PRUint32 aCount)
void nsAudioStream::Write(const float* aBuf, PRUint32 aCount)
{
mSamplesBuffered += aCount;
if (!mAudioHandle)
return;
@ -126,14 +141,37 @@ void nsAudioStream::Write(float* aBuf, PRUint32 aCount)
if (sa_stream_write(reinterpret_cast<sa_stream_t*>(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)
{
mSamplesBuffered += aCount;
if (!mAudioHandle)
return;
nsAutoArrayPtr<short> 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<sa_stream_t*>(mAudioHandle), s_data.get(), aCount * sizeof(short)) != SA_SUCCESS) {
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error"));
Shutdown();
}
}
}
PRInt32 nsAudioStream::Available()
{
// If the audio backend failed to open, lie and say we'll accept some
// data.
if (!mAudioHandle)
return 0;
return FAKE_BUFFER_SIZE;
size_t s = 0;
sa_stream_get_write_size(reinterpret_cast<sa_stream_t*>(mAudioHandle), &s);
@ -149,3 +187,77 @@ void nsAudioStream::SetVolume(float aVolume)
{
mVolume = aVolume;
}
void nsAudioStream::Drain()
{
if (!mAudioHandle) {
PRUint32 drainTime = (float(mSamplesBuffered) / mRate / mChannels - GetTime()) * 1000.0;
PR_Sleep(PR_MillisecondsToInterval(drainTime));
return;
}
if (sa_stream_drain(reinterpret_cast<sa_stream_t*>(mAudioHandle)) != SA_SUCCESS) {
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_drain error"));
Shutdown();
}
}
void nsAudioStream::Pause()
{
if (mPaused)
return;
// Save the elapsed playback time. Used to offset the wall-clock time
// when resuming.
mPauseTime = CurrentTimeInSeconds() - mStartTime;
mPaused = PR_TRUE;
if (!mAudioHandle)
return;
int64_t bytes = 0;
#if !defined(WIN32)
sa_stream_get_position(reinterpret_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes);
#endif
mSavedPauseBytes = bytes;
sa_stream_pause(reinterpret_cast<sa_stream_t*>(mAudioHandle));
}
void nsAudioStream::Resume()
{
if (!mPaused)
return;
// Reset the start time to the current time offset backwards by the
// elapsed time saved when the stream paused.
mStartTime = CurrentTimeInSeconds() - mPauseTime;
mPaused = PR_FALSE;
if (!mAudioHandle)
return;
sa_stream_resume(reinterpret_cast<sa_stream_t*>(mAudioHandle));
#if !defined(WIN32)
mPauseBytes += mSavedPauseBytes;
#endif
}
double nsAudioStream::GetTime()
{
// If the audio backend failed to open, emulate the current playback
// position using the system clock.
if (!mAudioHandle)
return mPaused ? mPauseTime : CurrentTimeInSeconds() - mStartTime;
int64_t bytes = 0;
#if defined(WIN32)
sa_stream_get_position(reinterpret_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_HARDWARE, &bytes);
#else
sa_stream_get_position(reinterpret_cast<sa_stream_t*>(mAudioHandle), SA_POSITION_WRITE_SOFTWARE, &bytes);
#endif
return double(bytes + mPauseBytes) / (sizeof(short) * mChannels * mRate);
}

View File

@ -135,8 +135,12 @@ nsresult nsChannelToPipeListener::OnStartRequest(nsIRequest* aRequest, nsISuppor
nsresult nsChannelToPipeListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, nsresult aStatus)
{
mOutput = nsnull;
if (mDecoder) {
mDecoder->ResourceLoaded();
if (aStatus != NS_BINDING_ABORTED && mDecoder) {
if (NS_SUCCEEDED(aStatus)) {
mDecoder->ResourceLoaded();
} else {
mDecoder->NetworkError();
}
}
return NS_OK;
}

View File

@ -61,7 +61,8 @@ class nsDefaultStreamStrategy : public nsStreamStrategy
{
public:
nsDefaultStreamStrategy(nsMediaDecoder* aDecoder, nsIChannel* aChannel, nsIURI* aURI) :
nsStreamStrategy(aDecoder, aChannel, aURI)
nsStreamStrategy(aDecoder, aChannel, aURI),
mPosition(0)
{
}
@ -87,6 +88,10 @@ private:
// Input stream for the media data currently downloaded
// and stored in the pipe. This can be used from any thread.
nsCOMPtr<nsIInputStream> 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)
@ -112,6 +117,8 @@ nsresult nsDefaultStreamStrategy::Open(nsIStreamListener** aStreamListener)
rv = mListener->GetInputStream(getter_AddRefs(mPipeInput));
NS_ENSURE_SUCCESS(rv, rv);
mPosition = 0;
return NS_OK;
}
@ -137,7 +144,14 @@ nsresult nsDefaultStreamStrategy::Read(char* aBuffer, PRUint32 aCount, PRUint32*
// stream. This allows calling from any thread as the pipe is
// threadsafe.
nsAutoLock lock(mLock);
return mPipeInput ? mPipeInput->Read(aBuffer, aCount, aBytes) : NS_ERROR_FAILURE;
if (!mPipeInput)
return NS_ERROR_FAILURE;
nsresult rv = mPipeInput->Read(aBuffer, aCount, aBytes);
NS_ENSURE_SUCCESS(rv, rv);
mPosition += *aBytes;
return NS_OK;
}
nsresult nsDefaultStreamStrategy::Seek(PRInt32 aWhence, PRInt64 aOffset)
@ -148,8 +162,7 @@ nsresult nsDefaultStreamStrategy::Seek(PRInt32 aWhence, PRInt64 aOffset)
PRInt64 nsDefaultStreamStrategy::Tell()
{
// Default streams cannot be seeked
return 0;
return mPosition;
}
PRUint32 nsDefaultStreamStrategy::Available()

View File

@ -966,7 +966,7 @@ nsresult nsOggDecodeStateMachine::Run()
mReader->Available() < mBufferingBytes) {
LOG(PR_LOG_DEBUG,
("Buffering data until %d bytes available or %d milliseconds",
(long)(mBufferingBytes - mReader->Available()),
mBufferingBytes - mReader->Available(),
BUFFERING_WAIT*1000 - (PR_IntervalToMilliseconds(PR_IntervalNow() - mBufferingStart))));
mon.Wait(PR_MillisecondsToInterval(1000));
if (mState == DECODER_STATE_SHUTDOWN)
@ -1336,6 +1336,13 @@ void nsOggDecoder::ResourceLoaded()
StopProgress();
}
void nsOggDecoder::NetworkError()
{
if (mElement)
mElement->NetworkError();
Stop();
}
PRBool nsOggDecoder::IsSeeking() const
{
return mPlayState == PLAY_STATE_SEEKING;

File diff suppressed because it is too large Load Diff

View File

@ -66,9 +66,11 @@ _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)

Binary file not shown.

View File

@ -0,0 +1,46 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Media test: ended</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<audio id='v'
onloadedmetadata='return startTest();'
onended='return playbackEnded();'>
<source type='audio/x-wav' src='r11025_s16_c1.wav'>
</audio>
<pre id="test">
<script class="testbody" type="text/javascript">
// Test if the ended event works correctly.
var v = document.getElementById('v');
var endPassed = false;
var completed = false;
function startTest() {
if (completed)
return false;
v.play();
return false;
}
function playbackEnded() {
if (completed)
return false
completed = true;
ok(v.currentTime >= 0.9 && v.currentTime <= 1.1,
"Checking currentTime at end: " + v.currentTime);
ok(v.ended, "Checking playback has ended");
SimpleTest.finish();
return false;
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
</body>
</html>

View File

@ -153,10 +153,15 @@ 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
@ -258,7 +263,7 @@ ifneq (,$(filter gtk2,$(MOZ_WIDGET_TOOLKIT)))
EXTRA_DSO_LDOPTS += $(XLDFLAGS) $(XLIBS)
endif
ifdef MOZ_OGG
ifdef MOZ_SYDNEYAUDIO
ifeq ($(OS_ARCH),Darwin)
OS_LIBS += -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon
endif

View File

@ -115,7 +115,7 @@ PRBool NS_SVGEnabled();
#include "nsHTMLMediaElement.h"
#endif
#ifdef MOZ_OGG
#ifdef MOZ_SYDNEYAUDIO
#include "nsAudioStream.h"
#endif
@ -257,7 +257,7 @@ nsLayoutStatics::Initialize()
nsHTMLMediaElement::InitMediaTypes();
#endif
#ifdef MOZ_OGG
#ifdef MOZ_SYDNEYAUDIO
nsAudioStream::InitLibrary();
#endif
@ -342,7 +342,7 @@ nsLayoutStatics::Shutdown()
#ifdef MOZ_MEDIA
nsHTMLMediaElement::ShutdownMediaTypes();
#endif
#ifdef MOZ_OGG
#ifdef MOZ_SYDNEYAUDIO
nsAudioStream::ShutdownLibrary();
#endif

View File

@ -206,7 +206,7 @@ EXTRA_DSO_LDOPTS += \
$(TK_LIBS) \
$(NULL)
ifdef MOZ_OGG
ifdef MOZ_SYDNEYAUDIO
EXTRA_DSO_LDOPTS += \
-framework CoreAudio \
-framework AudioToolbox \

View File

@ -1115,6 +1115,11 @@ if [ "$MOZ_OGG" ]; then
$MAKEFILES_libogg
$MAKEFILES_libfishsound
$MAKEFILES_liboggplay
"
fi
if [ "$MOZ_SYDNEYAUDIO" ]; then
add_makefiles "
$MAKEFILES_libsydneyaudio
"
fi

View File

@ -124,12 +124,17 @@ 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 \

View File

@ -537,7 +537,8 @@ 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/ogg", "ogg", "Ogg Audio", 0, 0 },
{ "audio/x-wav", "wav", "Waveform Audio", 0, 0 }
};
#undef MAC_TYPE