Bug 1185407. Part 1 - have AudioSink::Init() return a promise. r=kinetik.

This commit is contained in:
JW Wang 2015-07-22 09:54:06 +08:00
parent 309ea5e508
commit 179648e075
4 changed files with 37 additions and 33 deletions

View File

@ -38,26 +38,27 @@ AudioSink::AudioSink(MediaDecoderStateMachine* aStateMachine,
{
}
nsresult
nsRefPtr<GenericPromise>
AudioSink::Init()
{
nsRefPtr<GenericPromise> p = mEndPromise.Ensure(__func__);
nsresult rv = NS_NewNamedThread("Media Audio",
getter_AddRefs(mThread),
nullptr,
MEDIA_THREAD_STACK_SIZE);
if (NS_FAILED(rv)) {
mStateMachine->OnAudioSinkError();
return rv;
mEndPromise.Reject(rv, __func__);
return p;
}
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &AudioSink::AudioLoop);
rv = mThread->Dispatch(event, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv)) {
mStateMachine->OnAudioSinkError();
return rv;
mEndPromise.Reject(rv, __func__);
return p;
}
return NS_OK;
return p;
}
int64_t
@ -142,9 +143,10 @@ AudioSink::AudioLoop()
AssertOnAudioThread();
SINK_LOG("AudioLoop started");
if (NS_FAILED(InitializeAudioStream())) {
nsresult rv = InitializeAudioStream();
if (NS_FAILED(rv)) {
NS_WARNING("Initializing AudioStream failed.");
mStateMachine->DispatchOnAudioSinkError();
mEndPromise.Reject(rv, __func__);
return;
}
@ -235,11 +237,7 @@ AudioSink::Cleanup()
AssertCurrentThreadInMonitor();
nsRefPtr<AudioStream> audioStream;
audioStream.swap(mAudioStream);
// Suppress the callback when the stop is requested by MediaDecoderStateMachine.
// See Bug 115334.
if (!mStopAudioThread) {
mStateMachine->DispatchOnAudioSinkComplete();
}
mEndPromise.Resolve(true, __func__);
ReentrantMonitorAutoExit exit(GetReentrantMonitor());
audioStream->Shutdown();

View File

@ -10,6 +10,7 @@
#include "MediaDecoderReader.h"
#include "mozilla/dom/AudioChannelBinding.h"
#include "mozilla/Atomics.h"
#include "mozilla/MozPromise.h"
namespace mozilla {
@ -23,7 +24,9 @@ public:
AudioSink(MediaDecoderStateMachine* aStateMachine,
int64_t aStartTime, AudioInfo aInfo, dom::AudioChannel aChannel);
nsresult Init();
// Return a promise which will be resolved when AudioSink finishes playing,
// or rejected if any error.
nsRefPtr<GenericPromise> Init();
int64_t GetPosition();
@ -140,6 +143,8 @@ private:
bool mSetPreservesPitch;
bool mPlaying;
MozPromiseHolder<GenericPromise> mEndPromise;
};
} // namespace mozilla

View File

@ -1086,8 +1086,7 @@ void MediaDecoderStateMachine::MaybeStartPlayback()
SetPlayStartTime(TimeStamp::Now());
MOZ_ASSERT(IsPlaying());
nsresult rv = StartAudioThread();
NS_ENSURE_SUCCESS_VOID(rv);
StartAudioThread();
// Tell DecodedStream to start playback with specified start time and media
// info. This is consistent with how we create AudioSink in StartAudioThread().
@ -1481,6 +1480,7 @@ void MediaDecoderStateMachine::StopAudioThread()
}
mAudioSink = nullptr;
}
mAudioSinkPromise.DisconnectIfExists();
}
nsresult
@ -1783,31 +1783,31 @@ MediaDecoderStateMachine::RequestVideoData()
}
}
nsresult
void
MediaDecoderStateMachine::StartAudioThread()
{
MOZ_ASSERT(OnTaskQueue());
AssertCurrentThreadInMonitor();
if (mAudioCaptured) {
MOZ_ASSERT(!mAudioSink);
return NS_OK;
return;
}
if (HasAudio() && !mAudioSink) {
auto audioStartTime = GetMediaTime();
mAudioCompleted = false;
mAudioSink = new AudioSink(this, audioStartTime,
mAudioSink = new AudioSink(this, GetMediaTime(),
mInfo.mAudio, mDecoder->GetAudioChannel());
// OnAudioSinkError() will be called before Init() returns if an error
// occurs during initialization.
nsresult rv = mAudioSink->Init();
NS_ENSURE_SUCCESS(rv, rv);
mAudioSinkPromise.Begin(
mAudioSink->Init()->Then(
OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioSinkComplete,
&MediaDecoderStateMachine::OnAudioSinkError));
mAudioSink->SetVolume(mVolume);
mAudioSink->SetPlaybackRate(mPlaybackRate);
mAudioSink->SetPreservesPitch(mPreservesPitch);
}
return NS_OK;
}
int64_t MediaDecoderStateMachine::AudioDecodedUsecs()
@ -3122,11 +3122,12 @@ void MediaDecoderStateMachine::OnAudioSinkComplete()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
if (mAudioCaptured) {
return;
}
MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio.");
mAudioSinkPromise.Complete();
ResyncAudioClock();
mAudioCompleted = true;
// Kick the decode thread; it may be sleeping waiting for this to finish.
mDecoder->GetReentrantMonitor().NotifyAll();
}
@ -3135,11 +3136,9 @@ void MediaDecoderStateMachine::OnAudioSinkError()
{
MOZ_ASSERT(OnTaskQueue());
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
// AudioSink not used with captured streams, so ignore errors in this case.
if (mAudioCaptured) {
return;
}
MOZ_ASSERT(!mAudioCaptured, "Should be disconnected when capturing audio.");
mAudioSinkPromise.Complete();
ResyncAudioClock();
mAudioCompleted = true;

View File

@ -517,7 +517,7 @@ protected:
// Starts the audio thread. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
nsresult StartAudioThread();
void StartAudioThread();
// Notification method invoked when mPlayState changes.
void PlayStateChanged();
@ -1317,6 +1317,8 @@ private:
// Media data resource from the decoder.
nsRefPtr<MediaResource> mResource;
MozPromiseRequestHolder<GenericPromise> mAudioSinkPromise;
private:
// The buffered range. Mirrored from the decoder thread.
Mirror<media::TimeIntervals> mBuffered;