Commit 90be9e6e authored by Max Morin's avatar Max Morin Committed by Commit Bot

Ensure asynchronous reply from MojoAudioOutputIPC.

AudioOutputDevice currently expects all responses to be asynchronous,
and this change also simplifies the code a bit.

Bug: 816348
Change-Id: I66d51184f2553043578dda17a5cb7aeebb809a20
Reviewed-on: https://chromium-review.googlesource.com/937721
Commit-Queue: Max Morin <maxmorin@chromium.org>
Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#539915}
parent 39ab63b5
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <utility> #include <utility>
#include "base/threading/sequenced_task_runner_handle.h"
#include "media/audio/audio_device_description.h" #include "media/audio/audio_device_description.h"
#include "mojo/public/cpp/bindings/callback_helpers.h" #include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/system/platform_handle.h" #include "mojo/public/cpp/system/platform_handle.h"
...@@ -71,11 +72,9 @@ void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate, ...@@ -71,11 +72,9 @@ void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate,
// No authorization requested yet. Request one for the default device. // No authorization requested yet. Request one for the default device.
// Since the delegate didn't explicitly request authorization, we shouldn't // Since the delegate didn't explicitly request authorization, we shouldn't
// send a callback to it. // send a callback to it.
if (!DoRequestDeviceAuthorization( DoRequestDeviceAuthorization(
0, media::AudioDeviceDescription::kDefaultDeviceId, 0, media::AudioDeviceDescription::kDefaultDeviceId,
base::BindOnce(&TrivialAuthorizedCallback))) { base::BindOnce(&TrivialAuthorizedCallback));
return;
}
} }
DCHECK_EQ(delegate_, delegate); DCHECK_EQ(delegate_, delegate);
...@@ -90,7 +89,7 @@ void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate, ...@@ -90,7 +89,7 @@ void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate,
// Don't set a connection error handler. Either an error has already been // Don't set a connection error handler. Either an error has already been
// signaled through the AudioOutputStreamClient interface, or the connection // signaled through the AudioOutputStreamClient interface, or the connection
// is broken because because the frame owning |this| was destroyed, in which // is broken because the frame owning |this| was destroyed, in which
// case |this| will soon be cleaned up anyways. // case |this| will soon be cleaned up anyways.
} }
...@@ -158,7 +157,7 @@ MojoAudioOutputIPC::MakeProviderRequest() { ...@@ -158,7 +157,7 @@ MojoAudioOutputIPC::MakeProviderRequest() {
return request; return request;
} }
bool MojoAudioOutputIPC::DoRequestDeviceAuthorization( void MojoAudioOutputIPC::DoRequestDeviceAuthorization(
int session_id, int session_id,
const std::string& device_id, const std::string& device_id,
AuthorizationCB callback) { AuthorizationCB callback) {
...@@ -167,20 +166,22 @@ bool MojoAudioOutputIPC::DoRequestDeviceAuthorization( ...@@ -167,20 +166,22 @@ bool MojoAudioOutputIPC::DoRequestDeviceAuthorization(
if (!factory) { if (!factory) {
LOG(ERROR) << "MojoAudioOutputIPC failed to acquire factory"; LOG(ERROR) << "MojoAudioOutputIPC failed to acquire factory";
// Resetting the callback ensures consistent behaviour with when the factory // Create a provider request for consistency with the normal case.
// is destroyed before reply, i.e. calling OnDeviceAuthorized with MakeProviderRequest();
// ERROR_INTERNAL in the normal case. Note that this operation might destroy // Resetting the callback asynchronously ensures consistent behaviour with
// |this|. The AudioOutputIPCDelegate will call CloseStream as necessary. // when the factory is destroyed before reply, i.e. calling
callback.Reset(); // OnDeviceAuthorized with ERROR_INTERNAL in the normal case.
// As |this| may be deleted, no new lines may be added here. // The AudioOutputIPCDelegate will call CloseStream as necessary.
return false; base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce([](AuthorizationCB cb) {}, std::move(callback)));
return;
} }
static_assert(sizeof(int) == sizeof(int32_t), static_assert(sizeof(int) == sizeof(int32_t),
"sizeof(int) == sizeof(int32_t)"); "sizeof(int) == sizeof(int32_t)");
factory->RequestDeviceAuthorization(MakeProviderRequest(), session_id, factory->RequestDeviceAuthorization(MakeProviderRequest(), session_id,
device_id, std::move(callback)); device_id, std::move(callback));
return true;
} }
void MojoAudioOutputIPC::ReceivedDeviceAuthorization( void MojoAudioOutputIPC::ReceivedDeviceAuthorization(
......
...@@ -58,10 +58,10 @@ class CONTENT_EXPORT MojoAudioOutputIPC ...@@ -58,10 +58,10 @@ class CONTENT_EXPORT MojoAudioOutputIPC
bool StreamCreationRequested(); bool StreamCreationRequested();
media::mojom::AudioOutputStreamProviderRequest MakeProviderRequest(); media::mojom::AudioOutputStreamProviderRequest MakeProviderRequest();
// Tries to acquire a RendererAudioOutputStreamFactory, returns true on // Tries to acquire a RendererAudioOutputStreamFactory and requests device
// success. On failure, |this| has been deleted, so returning immediately // authorization. On failure to aquire a factory, |callback| is destructed
// is required. // asynchronously.
bool DoRequestDeviceAuthorization(int session_id, void DoRequestDeviceAuthorization(int session_id,
const std::string& device_id, const std::string& device_id,
AuthorizationCB callback); AuthorizationCB callback);
......
...@@ -207,16 +207,31 @@ TEST(MojoAudioOutputIPC, AuthorizeWithoutFactory_CallsAuthorizedWithError) { ...@@ -207,16 +207,31 @@ TEST(MojoAudioOutputIPC, AuthorizeWithoutFactory_CallsAuthorizedWithError) {
std::unique_ptr<media::AudioOutputIPC> ipc = std::unique_ptr<media::AudioOutputIPC> ipc =
std::make_unique<MojoAudioOutputIPC>(NullAccessor()); std::make_unique<MojoAudioOutputIPC>(NullAccessor());
ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin());
// Don't call OnDeviceAuthorized synchronously, should wait until we run the
// RunLoop.
EXPECT_CALL(delegate, EXPECT_CALL(delegate,
OnDeviceAuthorized(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _, OnDeviceAuthorized(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL, _,
std::string())) std::string()));
.WillOnce(Invoke([&](media::OutputDeviceStatus, base::RunLoop().RunUntilIdle();
const media::AudioParameters&, const std::string&) { ipc->CloseStream();
ipc->CloseStream(); }
ipc.reset();
})); TEST(MojoAudioOutputIPC,
ipc->RequestDeviceAuthorization(&delegate, kSessionId, kDeviceId, Origin()); CreateWithoutAuthorizationWithoutFactory_CallsAuthorizedWithError) {
base::MessageLoopForIO message_loop;
StrictMock<MockDelegate> delegate;
std::unique_ptr<media::AudioOutputIPC> ipc =
std::make_unique<MojoAudioOutputIPC>(NullAccessor());
ipc->CreateStream(&delegate, Params());
// No call to OnDeviceAuthorized since authotization wasn't explicitly
// requested.
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
ipc->CloseStream();
} }
TEST(MojoAudioOutputIPC, DeviceAuthorized_Propagates) { TEST(MojoAudioOutputIPC, DeviceAuthorized_Propagates) {
......
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