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(); |