Skip to content

Commit 38e8f7e

Browse files
committed
Merge M72: "Release sink when AudioSourceProvider::SetClient() is called."
There's currently no way to resume these sinks from html/js so there's no point in restoring the sink state after disconnection. Specifically you can't call MediaElementAudioSourceNode.disconnect() and expect the underlying media element to be able to ever work again. See this demo: http://storage.googleapis.com/dalecurtis/webaudio-test.html Once AudioContext.createMediaElementSource(element) has been called on an element, that element can never be used standalone again. It must always be connected to the AudioContext to be used. In fact it's actually causing unnecessary work when the elements are destructed since removing the client respins the sink and mixer, etc. BUG=905506,910951 TEST=passes cq. R=​hongchan Change-Id: I5ff7fc532545075d62859a30f96d17c83bff9d21 Reviewed-on: https://chromium-review.googlesource.com/c/1359092 Commit-Queue: Dale Curtis <[email protected]> Reviewed-by: Hongchan Choi <[email protected]> Cr-Original-Commit-Position: refs/heads/master@{#613346}(cherry picked from commit 391671c) Reviewed-on: https://chromium-review.googlesource.com/c/1362296 Reviewed-by: Dale Curtis <[email protected]> Cr-Commit-Position: refs/branch-heads/3626@{#50} Cr-Branched-From: d897fb1-refs/heads/master@{#612437}
1 parent 6003b71 commit 38e8f7e

File tree

2 files changed

+27
-51
lines changed

2 files changed

+27
-51
lines changed

media/blink/webaudiosourceprovider_impl.cc

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,14 @@ void WebAudioSourceProviderImpl::SetClient(
130130
base::AutoLock auto_lock(sink_lock_);
131131
if (client) {
132132
// Detach the audio renderer from normal playback.
133-
if (sink_)
133+
if (sink_) {
134134
sink_->Stop();
135135

136+
// It's not possible to resume an element after disconnection, so just
137+
// drop the sink entirely for now.
138+
sink_ = nullptr;
139+
}
140+
136141
// The client will now take control by calling provideInput() periodically.
137142
client_ = client;
138143

@@ -148,15 +153,9 @@ void WebAudioSourceProviderImpl::SetClient(
148153
return;
149154
}
150155

151-
// Restore normal playback.
156+
// Drop client, but normal playback can't be restored. This is okay, the only
157+
// way to disconnect a client is internally at time of destruction.
152158
client_ = nullptr;
153-
if (sink_) {
154-
sink_->SetVolume(volume_);
155-
if (state_ >= kStarted)
156-
sink_->Start();
157-
if (state_ >= kPlaying)
158-
sink_->Play();
159-
}
160159
}
161160

162161
void WebAudioSourceProviderImpl::ProvideInput(
@@ -198,7 +197,8 @@ void WebAudioSourceProviderImpl::Initialize(const AudioParameters& params,
198197

199198
tee_filter_->Initialize(renderer, params.channels(), params.sample_rate());
200199

201-
sink_->Initialize(params, tee_filter_.get());
200+
if (sink_)
201+
sink_->Initialize(params, tee_filter_.get());
202202

203203
if (set_format_cb_)
204204
std::move(set_format_cb_).Run();
@@ -209,30 +209,30 @@ void WebAudioSourceProviderImpl::Start() {
209209
DCHECK(tee_filter_);
210210
DCHECK_EQ(state_, kStopped);
211211
state_ = kStarted;
212-
if (!client_)
212+
if (!client_ && sink_)
213213
sink_->Start();
214214
}
215215

216216
void WebAudioSourceProviderImpl::Stop() {
217217
base::AutoLock auto_lock(sink_lock_);
218218
state_ = kStopped;
219-
if (!client_)
219+
if (!client_ && sink_)
220220
sink_->Stop();
221221
}
222222

223223
void WebAudioSourceProviderImpl::Play() {
224224
base::AutoLock auto_lock(sink_lock_);
225225
DCHECK_EQ(state_, kStarted);
226226
state_ = kPlaying;
227-
if (!client_)
227+
if (!client_ && sink_)
228228
sink_->Play();
229229
}
230230

231231
void WebAudioSourceProviderImpl::Pause() {
232232
base::AutoLock auto_lock(sink_lock_);
233233
DCHECK(state_ == kPlaying || state_ == kStarted);
234234
state_ = kStarted;
235-
if (!client_)
235+
if (!client_ && sink_)
236236
sink_->Pause();
237237
}
238238

@@ -257,10 +257,12 @@ void WebAudioSourceProviderImpl::GetOutputDeviceInfoAsync(
257257
return;
258258
}
259259

260+
// Just return empty hardware parameters. When a |client_| is attached, the
261+
// underlying audio renderer will prefer the media parameters. See
262+
// IsOptimizedForHardwareParameters() for more details.
260263
base::SequencedTaskRunnerHandle::Get()->PostTask(
261-
FROM_HERE,
262-
base::BindOnce(std::move(info_cb),
263-
OutputDeviceInfo(OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND)));
264+
FROM_HERE, base::BindOnce(std::move(info_cb),
265+
OutputDeviceInfo(OUTPUT_DEVICE_STATUS_OK)));
264266
}
265267

266268
bool WebAudioSourceProviderImpl::IsOptimizedForHardwareParameters() {

media/blink/webaudiosourceprovider_impl_unittest.cc

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,17 @@ class WebAudioSourceProviderImplTest
114114
};
115115

116116
TEST_F(WebAudioSourceProviderImplTest, SetClientBeforeInitialize) {
117-
// setClient() with a NULL client should do nothing if no client is set.
118-
wasp_impl_->SetClient(NULL);
117+
// setClient() with a nullptr client should do nothing if no client is set.
118+
wasp_impl_->SetClient(nullptr);
119119

120120
// If |mock_sink_| is not null, it should be stopped during setClient(this).
121121
if (mock_sink_)
122-
EXPECT_CALL(*mock_sink_.get(), Stop()).Times(2);
122+
EXPECT_CALL(*mock_sink_.get(), Stop());
123123

124124
wasp_impl_->SetClient(this);
125125
base::RunLoop().RunUntilIdle();
126126

127-
if (mock_sink_)
128-
EXPECT_CALL(*mock_sink_.get(), SetVolume(1)).Times(1);
129-
wasp_impl_->SetClient(NULL);
127+
wasp_impl_->SetClient(nullptr);
130128
base::RunLoop().RunUntilIdle();
131129

132130
wasp_impl_->SetClient(this);
@@ -155,34 +153,10 @@ TEST_F(WebAudioSourceProviderImplTest, SinkMethods) {
155153
SetClient(this);
156154
CallAllSinkMethodsAndVerify(false);
157155

158-
// Removing the client should cause WASP to revert to the underlying sink.
159-
EXPECT_CALL(*mock_sink_, SetVolume(kTestVolume));
160-
SetClient(NULL);
161-
CallAllSinkMethodsAndVerify(true);
162-
}
163-
164-
// Verify underlying sink state is restored after client removal.
165-
TEST_F(WebAudioSourceProviderImplTest, SinkStateRestored) {
166-
wasp_impl_->Initialize(params_, &fake_callback_);
167-
168-
// Verify state set before the client is set propagates back afterward.
169-
EXPECT_CALL(*mock_sink_, Start());
170-
wasp_impl_->Start();
171-
SetClient(this);
172-
173-
EXPECT_CALL(*mock_sink_, SetVolume(1.0));
174-
EXPECT_CALL(*mock_sink_, Start());
175-
SetClient(NULL);
176-
177-
// Verify state set while the client was attached propagates back afterward.
178-
SetClient(this);
179-
wasp_impl_->Play();
180-
wasp_impl_->SetVolume(kTestVolume);
181-
182-
EXPECT_CALL(*mock_sink_, SetVolume(kTestVolume));
183-
EXPECT_CALL(*mock_sink_, Start());
184-
EXPECT_CALL(*mock_sink_, Play());
185-
SetClient(NULL);
156+
// Removing the client should cause WASP to revert to the underlying sink;
157+
// this shouldn't crash, but shouldn't do anything either.
158+
SetClient(nullptr);
159+
CallAllSinkMethodsAndVerify(false);
186160
}
187161

188162
// Test the AudioRendererSink state machine and its effects on provideInput().

0 commit comments

Comments
 (0)