Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(356)

Unified Diff: content/browser/renderer_host/media/audio_renderer_host.cc

Issue 2289543003: IPC->mojo of audio_renderer_host (Closed)
Patch Set: It builds \o/. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/media/audio_renderer_host.cc
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
index 4ee8318b52146df977496b4cea5b4c97d6235944..7a2fbbc1489ab9552ee9539e4a10d7513c6d2a75 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -23,7 +23,6 @@
#include "content/browser/renderer_host/media/media_stream_manager.h"
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "content/common/media/audio_messages.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/media_device_id.h"
#include "content/public/browser/media_observer.h"
@@ -33,6 +32,11 @@
#include "media/audio/audio_streams_tracker.h"
#include "media/base/audio_bus.h"
#include "media/base/limits.h"
+#include "media/mojo/interfaces/audio_output.mojom-shared.h"
+#include "media/mojo/interfaces/audio_output.mojom.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/platform_handle.h"
using media::AudioBus;
using media::AudioManager;
@@ -132,15 +136,18 @@ void ValidateRenderFrameId(int render_process_id,
} // namespace
class AudioRendererHost::AudioEntry
Henrik Grunell 2016/09/01 15:09:07 Maybe this should be renamed, but let's settle the
- : public media::AudioOutputController::EventHandler {
+ : public media::AudioOutputController::EventHandler,
+ private media::mojom::AudioOutputStream {
public:
AudioEntry(AudioRendererHost* host,
+ CreateStreamCallback callback,
int stream_id,
int render_frame_id,
const media::AudioParameters& params,
const std::string& output_device_id,
std::unique_ptr<base::SharedMemory> shared_memory,
- std::unique_ptr<media::AudioOutputController::SyncReader> reader);
+ std::unique_ptr<media::AudioOutputController::SyncReader> reader,
+ media::mojom::AudioOutputStreamClientPtr output_stream_client);
~AudioEntry() override;
int stream_id() const {
@@ -162,6 +169,15 @@ class AudioRendererHost::AudioEntry
bool playing() const { return playing_; }
void set_playing(bool playing) { playing_ = playing; }
+ // media::mojom::AudioOutputStream implementation
+ void Play() override;
+ void Pause() override;
+ void SetVolume(double volume) override;
+
+ void OnConnectionError();
+ bool SendStreamStateResponse(media::mojom::AudioOutputStreamState state);
+ void BindRequest(media::mojom::AudioOutputStreamRequest);
+
private:
// media::AudioOutputController::EventHandler implementation.
void OnCreated() override;
@@ -184,17 +200,30 @@ class AudioRendererHost::AudioEntry
// The AudioOutputController that manages the audio stream.
const scoped_refptr<media::AudioOutputController> controller_;
+ // Used for communication with the bound AudioOutputStreamClient.
+ media::mojom::AudioOutputStreamClientPtr output_stream_client;
o1ka 2016/09/02 07:31:46 output_stream_client_
+
+ // Binds |this| to an AudioOutputStreamPtr that is passed to the
+ // AudioOutputStreamClient (AudioOutputIPC in the renderer process).
+ std::unique_ptr<mojo::Binding<media::mojom::AudioOutputStream>> binding_;
+
+ CreateStreamCallback callback_;
+
bool playing_;
+
+ DISALLOW_COPY_AND_ASSIGN(AudioEntry);
};
AudioRendererHost::AudioEntry::AudioEntry(
AudioRendererHost* host,
+ CreateStreamCallback callback,
o1ka 2016/09/02 07:31:46 const &
int stream_id,
int render_frame_id,
const media::AudioParameters& params,
const std::string& output_device_id,
std::unique_ptr<base::SharedMemory> shared_memory,
- std::unique_ptr<media::AudioOutputController::SyncReader> reader)
+ std::unique_ptr<media::AudioOutputController::SyncReader> reader,
+ media::mojom::AudioOutputStreamClientPtr output_stream_client)
: host_(host),
stream_id_(stream_id),
render_frame_id_(render_frame_id),
@@ -205,8 +234,64 @@ AudioRendererHost::AudioEntry::AudioEntry(
params,
output_device_id,
reader_.get())),
+ output_stream_client(std::move(output_stream_client)),
+ callback_(callback),
playing_(false) {
DCHECK(controller_.get());
+
+ if (output_stream_client.is_bound())
+ output_stream_client.set_connection_error_handler(
+ base::Bind(&AudioEntry::OnConnectionError, base::Unretained(this)));
+ else
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioRendererHost::OnCloseStream, host_, stream_id_));
o1ka 2016/09/02 07:31:46 |host_| is a raw pointer which AudioEntry does not
+}
+
+void AudioRendererHost::AudioEntry::Play() {
+ controller_->Play();
+ host_->audio_log_->OnStarted(stream_id_);
+}
+
+void AudioRendererHost::AudioEntry::Pause() {
+ controller_->Pause();
+ host_->audio_log_->OnStopped(stream_id_);
+}
+
+void AudioRendererHost::AudioEntry::SetVolume(double volume) {
+ if (volume < 0 || volume > 1.0)
+ return;
+
+ controller_->SetVolume(volume);
+ host_->audio_log_->OnSetVolume(stream_id_, volume);
+}
+
+void AudioRendererHost::AudioEntry::OnConnectionError() {
+ binding_.reset();
+ output_stream_client.reset();
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioRendererHost::CloseStream, host_, stream_id_));
o1ka 2016/09/02 07:31:46 Same as above. AudioRendererHost should probably h
+}
+
+bool AudioRendererHost::AudioEntry::SendStreamStateResponse(
+ media::mojom::AudioOutputStreamState state) {
+ if (!output_stream_client.is_bound())
+ return false;
+
+ output_stream_client->OnStreamStateChange(state);
+ return true;
+}
+
+void AudioRendererHost::AudioEntry::BindRequest(
+ media::mojom::AudioOutputStreamRequest request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ binding_.reset(new mojo::Binding<media::mojom::AudioOutputStream>(
+ this, std::move(request)));
+ binding_->set_connection_error_handler(
+ base::Bind(&AudioEntry::OnConnectionError, base::Unretained(this)));
}
AudioRendererHost::AudioEntry::~AudioEntry() {}
@@ -220,8 +305,7 @@ AudioRendererHost::AudioRendererHost(int render_process_id,
MediaInternals* media_internals,
MediaStreamManager* media_stream_manager,
const std::string& salt)
- : BrowserMessageFilter(AudioMsgStart),
- render_process_id_(render_process_id),
+ : render_process_id_(render_process_id),
audio_manager_(audio_manager),
mirroring_manager_(mirroring_manager),
audio_log_(media_internals->CreateAudioLog(
@@ -263,96 +347,76 @@ void AudioRendererHost::GetOutputControllers(
base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback);
}
-void AudioRendererHost::OnChannelClosing() {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Since the IPC sender is gone, close all requested audio streams.
- while (!audio_entries_.empty()) {
- // Note: OnCloseStream() removes the entries from audio_entries_.
- OnCloseStream(audio_entries_.begin()->first);
- }
-
- // Remove any authorizations for streams that were not yet created
- authorizations_.clear();
-}
-
-void AudioRendererHost::OnDestruct() const {
- BrowserThread::DeleteOnIOThread::Destruct(this);
-}
-
void AudioRendererHost::AudioEntry::OnCreated() {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioRendererHost::DoCompleteCreation,
+ host_, stream_id_, callback_));
o1ka 2016/09/02 07:31:46 same as above
}
void AudioRendererHost::AudioEntry::OnPlaying() {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
- host_,
- stream_id_,
- true));
+ output_stream_client->OnStreamStateChange(
+ ::media::mojom::AudioOutputStreamState::PLAYING);
}
void AudioRendererHost::AudioEntry::OnPaused() {
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
- host_,
- stream_id_,
- false));
+ output_stream_client->OnStreamStateChange(
+ ::media::mojom::AudioOutputStreamState::PAUSED);
}
void AudioRendererHost::AudioEntry::OnError() {
+ output_stream_client->OnStreamStateChange(
+ ::media::mojom::AudioOutputStreamState::ERROR);
BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_));
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioRendererHost::OnCloseStream, host_, stream_id_));
}
-void AudioRendererHost::DoCompleteCreation(int stream_id) {
+void AudioRendererHost::DoCompleteCreation(int stream_id,
+ CreateStreamCallback callback) {
o1ka 2016/09/02 07:31:46 const &
Max Morin 2016/09/02 10:27:07 mojo gets upset if I do this. This inefficiency is
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- if (!PeerHandle()) {
- DLOG(WARNING) << "Renderer process handle is invalid.";
- ReportErrorAndClose(stream_id);
- return;
- }
-
AudioEntry* const entry = LookupById(stream_id);
if (!entry) {
ReportErrorAndClose(stream_id);
return;
}
- // Once the audio stream is created then complete the creation process by
- // mapping shared memory and sharing with the renderer process.
- base::SharedMemoryHandle foreign_memory_handle;
- if (!entry->shared_memory()->ShareToProcess(PeerHandle(),
- &foreign_memory_handle)) {
- // If we failed to map and share the shared memory then close the audio
- // stream and send an error message.
- ReportErrorAndClose(entry->stream_id());
- return;
- }
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ entry->BindRequest(mojo::GetProxy(&stream_ptr));
AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader());
-
- base::SyncSocket::TransitDescriptor socket_descriptor;
-
- // If we failed to prepare the sync socket for the renderer then we fail
- // the construction of audio stream.
- if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) {
- ReportErrorAndClose(entry->stream_id());
- return;
- }
-
- Send(new AudioMsg_NotifyStreamCreated(
- entry->stream_id(), foreign_memory_handle, socket_descriptor,
- entry->shared_memory()->requested_size()));
+ mojo::ScopedHandle socket_handle =
+ mojo::WrapPlatformFile(reader->GetSyncSocket());
+
+ base::SharedMemoryHandle shared_memory_handle =
+ base::SharedMemory::DuplicateHandle(entry->shared_memory()->handle());
+ if (!base::SharedMemory::IsHandleValid(shared_memory_handle))
+ return ReportErrorAndClose(stream_id);
+
+ mojo::ScopedSharedBufferHandle shared_buffer_handle =
+ mojo::WrapSharedMemoryHandle(shared_memory_handle,
+ entry->shared_memory()->requested_size(),
+ false);
+
+ /* TODO: investigate comment.
+ // The socket sent from the browser to the renderer is a ForeignSocket, which
+ // is a part of AudioSyncReader that is owned by AudioEntry. The socket handle
+ // is closed when the owning AudioEntry destructs. With mojo, the ownership of
+ // the handle is transferred to the target process. The handle is no longer
+ // valid in the sending process, and cannot be closed there. If the socket
+ // handle is closed when the AudioEntry is deleted, an error occurs. To WAR
+ // this error, duplicate the socket and send the duplicate to the renderer.
+ #if defined(OS_WIN)
+ mojo::ScopedHandle socket_handle =
+ mojo::WrapPlatformFile(socket_descriptor);
+ #else
+ mojo::ScopedHandle socket_handle =
+ mojo::WrapPlatformFile(socket_descriptor.fd);
+ #endif
+ */
+
+ callback.Run(std::move(stream_ptr), std::move(shared_buffer_handle),
+ std::move(socket_handle));
}
void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
@@ -363,10 +427,9 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
if (!entry)
return;
- Send(new AudioMsg_NotifyStreamStateChanged(
- stream_id,
- is_playing ? media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING
- : media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED));
+ entry->SendStreamStateResponse(
+ is_playing ? media::mojom::AudioOutputStreamState::PLAYING
+ : media::mojom::AudioOutputStreamState::PAUSED);
if (is_playing) {
AudioStreamMonitor::StartMonitoringStream(
@@ -396,91 +459,13 @@ AudioRendererHost::DoGetOutputControllers() const {
return controllers;
}
-///////////////////////////////////////////////////////////////////////////////
-// IPC Messages handler
-bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
- IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization,
- OnRequestDeviceAuthorization)
- IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
- IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
- IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
- IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
- IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-void AudioRendererHost::OnRequestDeviceAuthorization(
+void AudioRendererHost::OnDeviceAuthorized(
int stream_id,
- int render_frame_id,
- int session_id,
+ RequestDeviceAuthorizationCallback callback,
const std::string& device_id,
- const url::Origin& security_origin) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- const base::TimeTicks auth_start_time = base::TimeTicks::Now();
-
- DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization"
- << "(stream_id=" << stream_id
- << ", render_frame_id=" << render_frame_id
- << ", session_id=" << session_id << ", device_id=" << device_id
- << ", security_origin=" << security_origin << ")";
-
- if (LookupById(stream_id) || IsAuthorizationStarted(stream_id))
- return;
-
- if (!IsValidDeviceId(device_id)) {
- UMALogDeviceAuthorizationTime(auth_start_time);
- Send(new AudioMsg_NotifyDeviceAuthorized(
- stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
- media::AudioParameters::UnavailableDeviceParams(), std::string()));
- return;
- }
-
- // If |session_id should be used for output device selection and such output
- // device is found, reuse the input device permissions.
- if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id,
- device_id)) {
- const StreamDeviceInfo* info =
- media_stream_manager_->audio_input_device_manager()
- ->GetOpenedDeviceInfoById(session_id);
- if (info) {
- media::AudioParameters output_params(
- media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
- static_cast<media::ChannelLayout>(
- info->device.matched_output.channel_layout),
- info->device.matched_output.sample_rate, 16,
- info->device.matched_output.frames_per_buffer);
- output_params.set_effects(info->device.matched_output.effects);
- authorizations_.insert(MakeAuthorizationData(
- stream_id, true, info->device.matched_output_device_id));
- MaybeFixAudioParameters(&output_params);
- UMALogDeviceAuthorizationTime(auth_start_time);
- // Hash matched device id and pass it to the renderer
- Send(new AudioMsg_NotifyDeviceAuthorized(
- stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params,
- GetHMACForMediaDeviceID(salt_, security_origin,
- info->device.matched_output_device_id)));
- return;
- }
- }
-
- authorizations_.insert(
- MakeAuthorizationData(stream_id, false, std::string()));
- CheckOutputDeviceAccess(
- render_frame_id, device_id, security_origin,
- base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id,
- device_id, security_origin, auth_start_time));
-}
-
-void AudioRendererHost::OnDeviceAuthorized(int stream_id,
- const std::string& device_id,
- const url::Origin& security_origin,
- base::TimeTicks auth_start_time,
- bool have_access) {
+ const url::Origin& security_origin,
+ base::TimeTicks auth_start_time,
+ bool have_access) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
const auto& auth_data = authorizations_.find(stream_id);
@@ -493,9 +478,9 @@ void AudioRendererHost::OnDeviceAuthorized(int stream_id,
if (!have_access) {
authorizations_.erase(auth_data);
UMALogDeviceAuthorizationTime(auth_start_time);
- Send(new AudioMsg_NotifyDeviceAuthorized(
- stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
- media::AudioParameters::UnavailableDeviceParams(), std::string()));
+ SendAuthorizationMessage(
+ callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED,
+ media::AudioParameters::UnavailableDeviceParams(), std::string());
return;
}
@@ -510,19 +495,20 @@ void AudioRendererHost::OnDeviceAuthorized(int stream_id,
audio_manager_->GetTaskRunner(), FROM_HERE,
base::Bind(&GetDefaultDeviceInfoOnDeviceThread, audio_manager_),
base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id,
- auth_start_time, true));
+ auth_start_time, callback, true));
} else {
media_stream_manager_->audio_output_device_enumerator()->Enumerate(
base::Bind(&AudioRendererHost::TranslateDeviceID, this, device_id,
security_origin,
base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this,
- stream_id, auth_start_time)));
+ stream_id, auth_start_time, callback)));
}
}
void AudioRendererHost::OnDeviceIDTranslated(
int stream_id,
base::TimeTicks auth_start_time,
+ RequestDeviceAuthorizationCallback callback,
bool device_found,
const AudioOutputDeviceInfo& device_info) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -537,9 +523,9 @@ void AudioRendererHost::OnDeviceIDTranslated(
if (!device_found) {
authorizations_.erase(auth_data);
UMALogDeviceAuthorizationTime(auth_start_time);
- Send(new AudioMsg_NotifyDeviceAuthorized(
- stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
- media::AudioParameters::UnavailableDeviceParams(), std::string()));
+ SendAuthorizationMessage(
+ callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
+ media::AudioParameters::UnavailableDeviceParams(), std::string());
return;
}
@@ -549,49 +535,18 @@ void AudioRendererHost::OnDeviceIDTranslated(
media::AudioParameters output_params = device_info.output_params;
MaybeFixAudioParameters(&output_params);
UMALogDeviceAuthorizationTime(auth_start_time);
- Send(new AudioMsg_NotifyDeviceAuthorized(
- stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string()));
-}
-
-void AudioRendererHost::OnCreateStream(int stream_id,
- int render_frame_id,
- const media::AudioParameters& params) {
- DCHECK_CURRENTLY_ON(BrowserThread::IO);
- DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream"
- << "(stream_id=" << stream_id << ")";
-
- // Determine whether to use the device_unique_id from an authorization, or an
- // empty string (i.e., when no previous authorization was requested, assume
- // default device).
- std::string device_unique_id;
- const auto& auth_data = authorizations_.find(stream_id);
- if (auth_data != authorizations_.end()) {
- CHECK(auth_data->second.first);
- device_unique_id.swap(auth_data->second.second);
- authorizations_.erase(auth_data);
- }
-
-#if DCHECK_IS_ON()
- // When DCHECKs are turned on, hop over to the UI thread to validate the
- // |render_frame_id|, then continue stream creation on the IO thread. See
- // comment at top of DoCreateStream() for further details.
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(validate_render_frame_id_function_, render_process_id_,
- render_frame_id,
- base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id,
- render_frame_id, params, device_unique_id)));
-#else
- DoCreateStream(stream_id, render_frame_id, params, device_unique_id,
- render_frame_id > 0);
-#endif // DCHECK_IS_ON()
+ SendAuthorizationMessage(callback, stream_id, media::OUTPUT_DEVICE_STATUS_OK,
+ output_params, std::string());
}
-void AudioRendererHost::DoCreateStream(int stream_id,
- int render_frame_id,
- const media::AudioParameters& params,
- const std::string& device_unique_id,
- bool render_frame_id_is_valid) {
+void AudioRendererHost::DoCreateStream(
+ int stream_id,
+ int render_frame_id,
+ const media::AudioParameters& params,
+ const std::string& device_unique_id,
+ media::mojom::AudioOutputStreamClientPtr client,
+ CreateStreamCallback callback,
+ bool render_frame_id_is_valid) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// Fail early if either of two sanity-checks fail:
@@ -619,6 +574,7 @@ void AudioRendererHost::DoCreateStream(int stream_id,
AudioBus::CalculateMemorySize(params);
std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) {
+ client->OnStreamStateChange(media::mojom::AudioOutputStreamState::ERROR);
SendErrorMessage(stream_id);
return;
}
@@ -635,9 +591,9 @@ void AudioRendererHost::DoCreateStream(int stream_id,
if (media_observer)
media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id);
- std::unique_ptr<AudioEntry> entry(
- new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id,
- std::move(shared_memory), std::move(reader)));
+ std::unique_ptr<AudioEntry> entry(new AudioEntry(
+ this, callback, stream_id, render_frame_id, params, device_unique_id,
+ std::move(shared_memory), std::move(reader), std::move(client)));
if (mirroring_manager_) {
mirroring_manager_->AddDiverter(
render_process_id_, entry->render_frame_id(), entry->controller());
@@ -696,8 +652,9 @@ void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
}
void AudioRendererHost::SendErrorMessage(int stream_id) {
- Send(new AudioMsg_NotifyStreamStateChanged(
- stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR));
+ AudioEntry* entry = LookupById(stream_id);
o1ka 2016/09/02 07:31:46 I suspect it's safe to do on IO thread only.
+ if (entry)
+ entry->SendStreamStateResponse(media::mojom::AudioOutputStreamState::ERROR);
}
void AudioRendererHost::OnCloseStream(int stream_id) {
@@ -791,6 +748,132 @@ bool AudioRendererHost::HasActiveAudio() {
return !base::AtomicRefCountIsZero(&num_playing_streams_);
}
+void AudioRendererHost::BindRequest(media::mojom::AudioOutputRequest request) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ binding_.reset(
+ new mojo::Binding<media::mojom::AudioOutput>(this, std::move(request)));
+}
+
+// media::mojom::AudioOutput implementation
+void AudioRendererHost::RequestDeviceAuthorization(
+ int stream_id,
+ int render_frame_id,
+ int session_id,
+ const mojo::String& device_id,
+ const url::Origin& origin,
+ const RequestDeviceAuthorizationCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ const base::TimeTicks auth_start_time = base::TimeTicks::Now();
+
+ DVLOG(1) << "AudioRendererHost@" << this << "::RequestDeviceAuthorization"
+ << "(stream_id=" << stream_id
+ << ", render_frame_id=" << render_frame_id
+ << ", session_id=" << session_id << ", device_id=" << device_id
+ << ", origin=" << origin << ")";
+
+ if (LookupById(stream_id) || IsAuthorizationStarted(stream_id))
+ return;
+
+ if (!IsValidDeviceId(device_id)) {
+ UMALogDeviceAuthorizationTime(auth_start_time);
+ SendAuthorizationMessage(
+ callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND,
+ media::AudioParameters::UnavailableDeviceParams(), std::string());
+ return;
+ }
+
+ // If |session_id should be used for output device selection and such output
+ // device is found, reuse the input device permissions.
+ if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id,
+ device_id)) {
+ const StreamDeviceInfo* info =
+ media_stream_manager_->audio_input_device_manager()
+ ->GetOpenedDeviceInfoById(session_id);
+ if (info) {
+ media::AudioParameters output_params(
+ media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
+ static_cast<media::ChannelLayout>(
+ info->device.matched_output.channel_layout),
+ info->device.matched_output.sample_rate, 16,
+ info->device.matched_output.frames_per_buffer);
+ output_params.set_effects(info->device.matched_output.effects);
+ authorizations_.insert(MakeAuthorizationData(
+ stream_id, true, info->device.matched_output_device_id));
+ MaybeFixAudioParameters(&output_params);
+ UMALogDeviceAuthorizationTime(auth_start_time);
+ // Hash matched device id and pass it to the renderer
+ SendAuthorizationMessage(
+ callback, stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params,
+ GetHMACForMediaDeviceID(salt_, origin,
+ info->device.matched_output_device_id));
+ return;
+ }
+ }
+
+ authorizations_.insert(
+ MakeAuthorizationData(stream_id, false, std::string()));
+ CheckOutputDeviceAccess(
+ render_frame_id, device_id, origin,
+ base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id,
+ callback, device_id, origin, auth_start_time));
+}
+
+void AudioRendererHost::CreateStream(
+ int stream_id,
+ int render_frame_id,
+ media::mojom::AudioOutputStreamClientPtr client,
+ const media::AudioParameters& params,
+ const CreateStreamCallback& callback) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DVLOG(1) << "AudioRendererHost@" << this << "::CreateStream"
+ << "(stream_id=" << stream_id << ")";
+
+ // Determine whether to use the device_unique_id from an authorization, or an
+ // empty string (i.e., when no previous authorization was requested, assume
+ // default device).
+ std::string device_unique_id;
+ const auto& auth_data = authorizations_.find(stream_id);
+ if (auth_data != authorizations_.end()) {
+ CHECK(auth_data->second.first);
+ device_unique_id.swap(auth_data->second.second);
+ authorizations_.erase(auth_data);
+ }
+
+#if DCHECK_IS_ON()
+ // When DCHECKs are turned on, hop over to the UI thread to validate the
+ // |render_frame_id|, then continue stream creation on the IO thread. See
+ // comment at top of DoCreateStream() for further details.
+ BrowserThread::PostTask(
o1ka 2016/09/02 11:30:55 Beware of this bug https://bugs.chromium.org/p/chr
Max Morin 2016/09/02 11:37:30 Thanks for the heads up. Maybe we can eliminate Lo
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(validate_render_frame_id_function_, render_process_id_,
+ render_frame_id,
+ base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id,
+ render_frame_id, params, device_unique_id,
+ base::Passed(&client), callback)));
+#else
+ DoCreateStream(stream_id, render_frame_id, params, device_unique_id,
+ std::move(client), callback, render_frame_id > 0);
+#endif // DCHECK_IS_ON()
+}
+
+void AudioRendererHost::CloseStream(int stream_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ OnCloseStream(stream_id);
+}
+
+void AudioRendererHost::SendAuthorizationMessage(
+ RequestDeviceAuthorizationCallback callback,
+ int stream_id,
+ media::OutputDeviceStatus status,
+ const media::AudioParameters& params,
+ const std::string& matched_device_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+ callback.Run(status, params, matched_device_id);
+}
+
void AudioRendererHost::CheckOutputDeviceAccess(
int render_frame_id,
const std::string& device_id,
@@ -803,8 +886,8 @@ void AudioRendererHost::CheckOutputDeviceAccess(
if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) &&
!MediaStreamManager::IsOriginAllowed(render_process_id_,
security_origin)) {
- content::bad_message::ReceivedBadMessage(this,
- bad_message::ARH_UNAUTHORIZED_URL);
+ // content::bad_message::ReceivedBadMessage(this,
+ // bad_message::ARH_UNAUTHORIZED_URL);
return;
}

Powered by Google App Engine
This is Rietveld 408576698