| 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 a3ca23926826d8df32370f319ff0b3309dfe1617..baeb46edcd55bf27a1f2af29d70e6b0209385470 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;
|
| @@ -47,7 +51,7 @@ base::LazyInstance<media::AudioStreamsTracker> g_audio_streams_tracker =
|
| LAZY_INSTANCE_INITIALIZER;
|
|
|
| std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData(
|
| - int stream_id,
|
| + int32_t stream_id,
|
| bool authorized,
|
| const std::string& device_unique_id) {
|
| return std::make_pair(stream_id,
|
| @@ -132,10 +136,11 @@ void ValidateRenderFrameId(int render_process_id,
|
| } // namespace
|
|
|
| class AudioRendererHost::AudioEntry
|
| - : public media::AudioOutputController::EventHandler {
|
| + : public media::AudioOutputController::EventHandler,
|
| + private media::mojom::AudioOutputStream {
|
| public:
|
| AudioEntry(AudioRendererHost* host,
|
| - int stream_id,
|
| + int32_t stream_id,
|
| int render_frame_id,
|
| const media::AudioParameters& params,
|
| const std::string& output_device_id,
|
| @@ -143,9 +148,7 @@ class AudioRendererHost::AudioEntry
|
| std::unique_ptr<media::AudioOutputController::SyncReader> reader);
|
| ~AudioEntry() override;
|
|
|
| - int stream_id() const {
|
| - return stream_id_;
|
| - }
|
| + int32_t stream_id() const { return stream_id_; }
|
|
|
| int render_frame_id() const { return render_frame_id_; }
|
|
|
| @@ -162,6 +165,14 @@ 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();
|
| + void BindRequest(media::mojom::AudioOutputStreamRequest);
|
| +
|
| private:
|
| // media::AudioOutputController::EventHandler implementation.
|
| void OnCreated() override;
|
| @@ -170,7 +181,7 @@ class AudioRendererHost::AudioEntry
|
| void OnError() override;
|
|
|
| AudioRendererHost* const host_;
|
| - const int stream_id_;
|
| + const int32_t stream_id_;
|
|
|
| // The routing ID of the source RenderFrame.
|
| const int render_frame_id_;
|
| @@ -184,12 +195,18 @@ class AudioRendererHost::AudioEntry
|
| // The AudioOutputController that manages the audio stream.
|
| const scoped_refptr<media::AudioOutputController> controller_;
|
|
|
| + // 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_;
|
| +
|
| bool playing_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(AudioEntry);
|
| };
|
|
|
| AudioRendererHost::AudioEntry::AudioEntry(
|
| AudioRendererHost* host,
|
| - int stream_id,
|
| + int32_t stream_id,
|
| int render_frame_id,
|
| const media::AudioParameters& params,
|
| const std::string& output_device_id,
|
| @@ -205,8 +222,49 @@ AudioRendererHost::AudioEntry::AudioEntry(
|
| params,
|
| output_device_id,
|
| reader_.get())),
|
| + callback_(callback),
|
| playing_(false) {
|
| DCHECK(controller_.get());
|
| +
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioRendererHost::OnCloseStream, host_, stream_id_));
|
| +}
|
| +
|
| +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();
|
| +
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioRendererHost::CloseStream, host_, stream_id_));
|
| +}
|
| +
|
| +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 +278,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(
|
| @@ -229,6 +286,7 @@ AudioRendererHost::AudioRendererHost(int render_process_id,
|
| media_stream_manager_(media_stream_manager),
|
| num_playing_streams_(0),
|
| salt_(salt),
|
| + next_stream_id_(0),
|
| #if DCHECK_IS_ON()
|
| validate_render_frame_id_function_(&ValidateRenderFrameId),
|
| #endif // DCHECK_IS_ON()
|
| @@ -263,99 +321,77 @@ 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_));
|
| + // TODO: make sure it's safe to capture |this| in the callback.
|
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&AudioRendererHost::DoCompleteCreation,
|
| + host_, this, stream_id_, callback_));
|
| }
|
|
|
| void AudioRendererHost::AudioEntry::OnPlaying() {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
|
| - host_,
|
| - stream_id_,
|
| - true));
|
| }
|
|
|
| void AudioRendererHost::AudioEntry::OnPaused() {
|
| - BrowserThread::PostTask(
|
| - BrowserThread::IO,
|
| - FROM_HERE,
|
| - base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged,
|
| - host_,
|
| - stream_id_,
|
| - false));
|
| }
|
|
|
| void AudioRendererHost::AudioEntry::OnError() {
|
| 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(AudioEntry* entry,
|
| + int32_t stream_id) {
|
| 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()));
|
| -}
|
| -
|
| -void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
|
| + base::PlatformFile socket_fd = reader->GetSyncSocket();
|
| + mojo::ScopedHandle socket_handle = mojo::WrapPlatformFile(socket_fd);
|
| + DCHECK(socket_handle.is_valid());
|
| +
|
| + base::SharedMemoryHandle shared_memory_handle =
|
| + base::SharedMemory::DuplicateHandle(entry->shared_memory()->handle());
|
| + if (!base::SharedMemory::IsHandleValid(shared_memory_handle)) {
|
| + // TODO: When can this happen?
|
| + LOG(FATAL) << "Invalid shared mem handle";
|
| + return ReportErrorAndClose(stream_id);
|
| + }
|
| + mojo::ScopedSharedBufferHandle shared_buffer_handle =
|
| + mojo::WrapSharedMemoryHandle(shared_memory_handle,
|
| + entry->shared_memory()->requested_size(),
|
| + false);
|
| + DCHECK(shared_buffer_handle.is_valid());
|
| +
|
| + /*mojo::ScopedSharedBufferHandle shared_buffer_handle =
|
| + mojo::WrapSharedMemoryHandle(shared_memory_handle,
|
| + entry->shared_memory()->requested_size(),
|
| + false);*/
|
| +
|
| + /* TODO: read 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(int32_t stream_id,
|
| bool is_playing) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| @@ -363,10 +399,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(
|
| @@ -380,7 +415,7 @@ void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
|
| render_process_id_, entry->render_frame_id(), entry->stream_id());
|
| }
|
| UpdateNumPlayingStreams(entry, is_playing);
|
| -}
|
| +}*/
|
|
|
| RenderProcessHost::AudioOutputControllerList
|
| AudioRendererHost::DoGetOutputControllers() const {
|
| @@ -396,91 +431,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(
|
| - int stream_id,
|
| - int render_frame_id,
|
| - int session_id,
|
| +void AudioRendererHost::OnDeviceAuthorized(
|
| + int32_t stream_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 +450,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 +467,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,
|
| + int32_t stream_id,
|
| base::TimeTicks auth_start_time,
|
| + RequestDeviceAuthorizationCallback callback,
|
| bool device_found,
|
| const AudioOutputDeviceInfo& device_info) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| @@ -537,9 +495,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,45 +507,11 @@ 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,
|
| +void AudioRendererHost::DoCreateStream(int32_t stream_id,
|
| int render_frame_id,
|
| const media::AudioParameters& params,
|
| const std::string& device_unique_id,
|
| @@ -619,6 +543,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 +560,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)));
|
| if (mirroring_manager_) {
|
| mirroring_manager_->AddDiverter(
|
| render_process_id_, entry->render_frame_id(), entry->controller());
|
| @@ -653,7 +578,7 @@ void AudioRendererHost::DoCreateStream(int stream_id,
|
| max_simultaneous_streams_ = audio_entries_.size();
|
| }
|
|
|
| -void AudioRendererHost::OnPlayStream(int stream_id) {
|
| +void AudioRendererHost::OnPlayStream(int32_t stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| AudioEntry* entry = LookupById(stream_id);
|
| @@ -666,7 +591,7 @@ void AudioRendererHost::OnPlayStream(int stream_id) {
|
| audio_log_->OnStarted(stream_id);
|
| }
|
|
|
| -void AudioRendererHost::OnPauseStream(int stream_id) {
|
| +void AudioRendererHost::OnPauseStream(int32_t stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| AudioEntry* entry = LookupById(stream_id);
|
| @@ -679,7 +604,7 @@ void AudioRendererHost::OnPauseStream(int stream_id) {
|
| audio_log_->OnStopped(stream_id);
|
| }
|
|
|
| -void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
|
| +void AudioRendererHost::OnSetVolume(int32_t stream_id, double volume) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| AudioEntry* entry = LookupById(stream_id);
|
| @@ -695,12 +620,11 @@ void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
|
| audio_log_->OnSetVolume(stream_id, volume);
|
| }
|
|
|
| -void AudioRendererHost::SendErrorMessage(int stream_id) {
|
| - Send(new AudioMsg_NotifyStreamStateChanged(
|
| - stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR));
|
| +void AudioRendererHost::SendErrorMessage(int32_t stream_id) {
|
| + // TODO
|
| }
|
|
|
| -void AudioRendererHost::OnCloseStream(int stream_id) {
|
| +void AudioRendererHost::OnCloseStream(int32_t stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| authorizations_.erase(stream_id);
|
|
|
| @@ -735,7 +659,7 @@ void AudioRendererHost::DeleteEntry(std::unique_ptr<AudioEntry> entry) {
|
| UpdateNumPlayingStreams(entry.get(), false);
|
| }
|
|
|
| -void AudioRendererHost::ReportErrorAndClose(int stream_id) {
|
| +void AudioRendererHost::ReportErrorAndClose(int32_t stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| // Make sure this isn't a stray callback executing after the stream has been
|
| @@ -750,7 +674,8 @@ void AudioRendererHost::ReportErrorAndClose(int stream_id) {
|
| OnCloseStream(stream_id);
|
| }
|
|
|
| -AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) {
|
| +AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(
|
| + int32_t stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
| AudioEntryMap::const_iterator i = audio_entries_.find(stream_id);
|
| @@ -791,6 +716,128 @@ 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(
|
| + int64_t render_frame_id,
|
| + int64_t 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();
|
| + int32_t stream_id = next_stream_id++;
|
| +
|
| + 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(int32_t stream_id,
|
| + int render_frame_id,
|
| + const media::AudioParameters& params) {
|
| + 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(
|
| + 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()
|
| +}
|
| +
|
| +void AudioRendererHost::CloseStream(int32_t stream_id) {
|
| + DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| +
|
| + OnCloseStream(stream_id);
|
| +}
|
| +
|
| +void AudioRendererHost::SendAuthorizationMessage(
|
| + RequestDeviceAuthorizationCallback callback,
|
| + int32_t 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 +850,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;
|
| }
|
|
|
| @@ -861,7 +908,7 @@ void AudioRendererHost::TranslateDeviceID(
|
| callback.Run(false, device_info);
|
| }
|
|
|
| -bool AudioRendererHost::IsAuthorizationStarted(int stream_id) {
|
| +bool AudioRendererHost::IsAuthorizationStarted(int32_t stream_id) {
|
| DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
| const auto& i = authorizations_.find(stream_id);
|
| return i != authorizations_.end();
|
|
|