Commit 6fc7aad5 authored by Dave Tapuska's avatar Dave Tapuska Committed by Commit Bot

Add ability to pause and resume the audio sink from blink.

Add state to support pausing a web audio device such that it can be
restarted when the frame is returned to be visible.

BUG=907125

Change-Id: I01aef9c19c81e35e68ee1e299e16cd6c9946ebde
Reviewed-on: https://chromium-review.googlesource.com/c/1344265Reviewed-by: default avatarDale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarRick Byers <rbyers@chromium.org>
Reviewed-by: default avatarHongchan Choi <hongchan@chromium.org>
Commit-Queue: Dave Tapuska <dtapuska@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611881}
parent af8067e2
......@@ -188,6 +188,18 @@ void RendererWebAudioDeviceImpl::Start() {
sink_->Play();
}
void RendererWebAudioDeviceImpl::Pause() {
DCHECK(thread_checker_.CalledOnValidThread());
if (sink_)
sink_->Pause();
}
void RendererWebAudioDeviceImpl::Resume() {
DCHECK(thread_checker_.CalledOnValidThread());
if (sink_)
sink_->Play();
}
void RendererWebAudioDeviceImpl::Stop() {
DCHECK(thread_checker_.CalledOnValidThread());
if (sink_) {
......
......@@ -44,6 +44,8 @@ class CONTENT_EXPORT RendererWebAudioDeviceImpl
// blink::WebAudioDevice implementation.
void Start() override;
void Stop() override;
void Pause() override;
void Resume() override;
double SampleRate() override;
int FramesPerBuffer() override;
......
......@@ -58,6 +58,16 @@ class WebAudioDevice {
virtual void Start() = 0;
virtual void Stop() = 0;
// Pause an audio device so that the device doesn't produce
// requests for audio frames. This is used when a web frame is
// frozen. This shouldn't be observable to the web application.
virtual void Pause() = 0;
// Resume an audio device that was previously paused. Used
// for frozen frames.
virtual void Resume() = 0;
virtual double SampleRate() = 0;
virtual int FramesPerBuffer() = 0;
};
......
......@@ -64,6 +64,8 @@ class MockWebAudioDeviceForAutoplayTest : public WebAudioDevice {
void Start() override {}
void Stop() override {}
void Pause() override {}
void Resume() override {}
double SampleRate() override { return sample_rate_; }
int FramesPerBuffer() override { return frames_per_buffer_; }
......
......@@ -27,6 +27,8 @@ class MockWebAudioDeviceForAudioContext : public WebAudioDevice {
void Start() override {}
void Stop() override {}
void Pause() override {}
void Resume() override {}
double SampleRate() override { return sample_rate_; }
int FramesPerBuffer() override { return frames_per_buffer_; }
......
......@@ -64,7 +64,7 @@ AudioDestination::AudioDestination(AudioIOCallback& callback,
unsigned number_of_output_channels,
const WebAudioLatencyHint& latency_hint)
: number_of_output_channels_(number_of_output_channels),
is_playing_(false),
play_state_(PlayState::kStopped),
fifo_(
std::make_unique<PushPullFIFO>(number_of_output_channels, kFIFOSize)),
output_bus_(AudioBus::Create(number_of_output_channels,
......@@ -198,10 +198,10 @@ void AudioDestination::Start() {
DCHECK(IsMainThread());
// Start the "audio device" after the rendering thread is ready.
if (web_audio_device_ && !is_playing_) {
if (web_audio_device_ && play_state_ == PlayState::kStopped) {
TRACE_EVENT0("webaudio", "AudioDestination::Start");
web_audio_device_->Start();
is_playing_ = true;
play_state_ = PlayState::kPlaying;
}
}
......@@ -209,11 +209,11 @@ void AudioDestination::StartWithWorkletTaskRunner(
scoped_refptr<base::SingleThreadTaskRunner> worklet_task_runner) {
DCHECK(IsMainThread());
if (web_audio_device_ && !is_playing_) {
if (web_audio_device_ && play_state_ == PlayState::kStopped) {
TRACE_EVENT0("webaudio", "AudioDestination::Start");
worklet_task_runner_ = std::move(worklet_task_runner);
web_audio_device_->Start();
is_playing_ = true;
play_state_ = PlayState::kPlaying;
}
}
......@@ -222,11 +222,27 @@ void AudioDestination::Stop() {
// This assumes stopping the "audio device" is synchronous and dumping the
// rendering thread is safe after that.
if (web_audio_device_ && is_playing_) {
if (web_audio_device_ && play_state_ != PlayState::kStopped) {
TRACE_EVENT0("webaudio", "AudioDestination::Stop");
web_audio_device_->Stop();
worklet_task_runner_ = nullptr;
is_playing_ = false;
play_state_ = PlayState::kStopped;
}
}
void AudioDestination::Pause() {
DCHECK(IsMainThread());
if (web_audio_device_ && play_state_ == PlayState::kPlaying) {
web_audio_device_->Pause();
play_state_ = PlayState::kPaused;
}
}
void AudioDestination::Resume() {
DCHECK(IsMainThread());
if (web_audio_device_ && play_state_ == PlayState::kPaused) {
web_audio_device_->Resume();
play_state_ = PlayState::kPlaying;
}
}
......@@ -237,7 +253,7 @@ size_t AudioDestination::CallbackBufferSize() const {
bool AudioDestination::IsPlaying() {
DCHECK(IsMainThread());
return is_playing_;
return play_state_ == PlayState::kPlaying;
}
int AudioDestination::FramesPerBuffer() const {
......
......@@ -91,6 +91,8 @@ class PLATFORM_EXPORT AudioDestination
virtual void Start();
virtual void Stop();
virtual void Pause();
virtual void Resume();
// Starts the destination with the AudioWorklet support.
void StartWithWorkletTaskRunner(
......@@ -112,6 +114,8 @@ class PLATFORM_EXPORT AudioDestination
static uint32_t MaxChannelCount();
private:
enum class PlayState { kStopped, kPlaying, kPaused };
// Check if the buffer size chosen by the WebAudioDevice is too large.
bool CheckBufferSize();
......@@ -121,7 +125,7 @@ class PLATFORM_EXPORT AudioDestination
std::unique_ptr<WebAudioDevice> web_audio_device_;
const unsigned number_of_output_channels_;
size_t callback_buffer_size_;
bool is_playing_;
PlayState play_state_;
// The task runner for AudioWorklet operation. This is only valid when
// the AudioWorklet is activated.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment