gecko-dev/dom/media/mediasink/AudioSinkWrapper.cpp

218 строки
5.0 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AudioSink.h"
#include "AudioSinkWrapper.h"
namespace mozilla {
namespace media {
AudioSinkWrapper::~AudioSinkWrapper()
{
}
void
AudioSinkWrapper::Shutdown()
{
AssertOwnerThread();
MOZ_ASSERT(!mIsStarted, "Must be called after playback stopped.");
mCreator = nullptr;
}
const MediaSink::PlaybackParams&
AudioSinkWrapper::GetPlaybackParams() const
{
AssertOwnerThread();
return mParams;
}
void
AudioSinkWrapper::SetPlaybackParams(const PlaybackParams& aParams)
{
AssertOwnerThread();
if (mAudioSink) {
mAudioSink->SetVolume(aParams.volume);
mAudioSink->SetPlaybackRate(aParams.playbackRate);
mAudioSink->SetPreservesPitch(aParams.preservesPitch);
}
mParams = aParams;
}
nsRefPtr<GenericPromise>
AudioSinkWrapper::OnEnded(TrackType aType)
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
if (aType == TrackInfo::kAudioTrack) {
return mEndPromise;
}
return nullptr;
}
int64_t
AudioSinkWrapper::GetEndTime(TrackType aType) const
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
if (aType == TrackInfo::kAudioTrack && mAudioSink) {
return mAudioSink->GetEndTime();
}
return -1;
}
int64_t
AudioSinkWrapper::GetVideoPosition(TimeStamp aNow) const
{
AssertOwnerThread();
MOZ_ASSERT(!mPlayStartTime.IsNull());
// Time elapsed since we started playing.
int64_t delta = (aNow - mPlayStartTime).ToMicroseconds();
// Take playback rate into account.
return mPlayDuration + delta * mParams.playbackRate;
}
int64_t
AudioSinkWrapper::GetPosition(TimeStamp* aTimeStamp) const
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "Must be called after playback starts.");
int64_t pos = -1;
TimeStamp t = TimeStamp::Now();
if (mAudioSink) {
// Rely on the audio sink to report playback position when we have one.
pos = mAudioSink->GetPosition();
} else if (!mPlayStartTime.IsNull()) {
// Calculate playback position using system clock if we are still playing.
pos = GetVideoPosition(t);
} else {
// Return how long we've played if we are not playing.
pos = mPlayDuration;
}
if (aTimeStamp) {
*aTimeStamp = t;
}
return pos;
}
bool
AudioSinkWrapper::HasUnplayedFrames(TrackType aType) const
{
AssertOwnerThread();
return mAudioSink ? mAudioSink->HasUnplayedFrames() : false;
}
void
AudioSinkWrapper::SetVolume(double aVolume)
{
AssertOwnerThread();
mParams.volume = aVolume;
if (mAudioSink) {
mAudioSink->SetVolume(aVolume);
}
}
void
AudioSinkWrapper::SetPlaybackRate(double aPlaybackRate)
{
AssertOwnerThread();
mParams.playbackRate = aPlaybackRate;
if (mAudioSink) {
// Pass the playback rate to the audio sink. The underlying AudioStream
// will handle playback rate changes and report correct audio position.
mAudioSink->SetPlaybackRate(aPlaybackRate);
} else if (!mPlayStartTime.IsNull()) {
// Adjust playback duration and start time when we are still playing.
TimeStamp now = TimeStamp::Now();
mPlayDuration = GetVideoPosition(now);
mPlayStartTime = now;
}
// Do nothing when not playing. Changes in playback rate will be taken into
// account by GetVideoPosition().
}
void
AudioSinkWrapper::SetPreservesPitch(bool aPreservesPitch)
{
AssertOwnerThread();
mParams.preservesPitch = aPreservesPitch;
if (mAudioSink) {
mAudioSink->SetPreservesPitch(aPreservesPitch);
}
}
void
AudioSinkWrapper::SetPlaying(bool aPlaying)
{
AssertOwnerThread();
// Resume/pause matters only when playback started.
if (!mIsStarted) {
return;
}
if (mAudioSink) {
mAudioSink->SetPlaying(aPlaying);
}
if (aPlaying) {
MOZ_ASSERT(mPlayStartTime.IsNull());
mPlayStartTime = TimeStamp::Now();
} else {
// Remember how long we've played.
mPlayDuration = GetPosition();
// mPlayStartTime must be updated later since GetPosition()
// depends on the value of mPlayStartTime.
mPlayStartTime = TimeStamp();
}
}
void
AudioSinkWrapper::Start(int64_t aStartTime, const MediaInfo& aInfo)
{
AssertOwnerThread();
MOZ_ASSERT(!mIsStarted, "playback already started.");
mIsStarted = true;
mPlayDuration = aStartTime;
mPlayStartTime = TimeStamp::Now();
if (aInfo.HasAudio()) {
mAudioSink = mCreator->Create();
mEndPromise = mAudioSink->Init();
SetPlaybackParams(mParams);
}
}
void
AudioSinkWrapper::Stop()
{
AssertOwnerThread();
MOZ_ASSERT(mIsStarted, "playback not started.");
mIsStarted = false;
if (mAudioSink) {
mAudioSink->Shutdown();
mAudioSink = nullptr;
mEndPromise = nullptr;
}
}
bool
AudioSinkWrapper::IsStarted() const
{
AssertOwnerThread();
return mIsStarted;
}
} // namespace media
} // namespace mozilla