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 ae580222c519763e30ebe1715654343a94c4bea8..d3f2090fb524b26a03ecdbdebe9e6ed37ca3a924 100644 |
--- a/content/browser/renderer_host/media/audio_renderer_host.cc |
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc |
@@ -6,17 +6,20 @@ |
#include <stdint.h> |
#include <utility> |
+#if defined(OS_WIN) |
+#include <windows.h> |
+#endif |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/lazy_instance.h" |
#include "base/logging.h" |
-#include "base/memory/shared_memory.h" |
#include "base/metrics/histogram.h" |
#include "base/process/process.h" |
#include "content/browser/bad_message.h" |
#include "content/browser/browser_main_loop.h" |
#include "content/browser/child_process_security_policy_impl.h" |
+#include "content/browser/media/audio_output_impl.h" |
#include "content/browser/media/audio_stream_monitor.h" |
#include "content/browser/media/capture/audio_mirroring_manager.h" |
#include "content/browser/media/media_internals.h" |
@@ -36,6 +39,8 @@ |
#include "media/audio/audio_streams_tracker.h" |
#include "media/base/audio_bus.h" |
#include "media/base/limits.h" |
+#include "mojo/edk/embedder/embedder.h" |
+#include "mojo/public/cpp/system/handle.h" |
using media::AudioBus; |
using media::AudioManager; |
@@ -117,62 +122,6 @@ void MaybeFixAudioParameters(media::AudioParameters* params) { |
} // namespace |
-class AudioRendererHost::AudioEntry |
- : public media::AudioOutputController::EventHandler { |
- public: |
- AudioEntry(AudioRendererHost* host, |
- 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); |
- ~AudioEntry() override; |
- |
- int stream_id() const { |
- return stream_id_; |
- } |
- |
- int render_frame_id() const { return render_frame_id_; } |
- |
- media::AudioOutputController* controller() const { return controller_.get(); } |
- |
- base::SharedMemory* shared_memory() { |
- return shared_memory_.get(); |
- } |
- |
- media::AudioOutputController::SyncReader* reader() const { |
- return reader_.get(); |
- } |
- |
- bool playing() const { return playing_; } |
- void set_playing(bool playing) { playing_ = playing; } |
- |
- private: |
- // media::AudioOutputController::EventHandler implementation. |
- void OnCreated() override; |
- void OnPlaying() override; |
- void OnPaused() override; |
- void OnError() override; |
- |
- AudioRendererHost* const host_; |
- const int stream_id_; |
- |
- // The routing ID of the source RenderFrame. |
- const int render_frame_id_; |
- |
- // Shared memory for transmission of the audio data. Used by |reader_|. |
- const std::unique_ptr<base::SharedMemory> shared_memory_; |
- |
- // The synchronous reader to be used by |controller_|. |
- const std::unique_ptr<media::AudioOutputController::SyncReader> reader_; |
- |
- // The AudioOutputController that manages the audio stream. |
- const scoped_refptr<media::AudioOutputController> controller_; |
- |
- bool playing_; |
-}; |
- |
AudioRendererHost::AudioEntry::AudioEntry( |
AudioRendererHost* host, |
int stream_id, |
@@ -180,7 +129,8 @@ AudioRendererHost::AudioEntry::AudioEntry( |
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, |
+ const mojom::AudioOutput::CreateStreamCallback& callback) |
: host_(host), |
stream_id_(stream_id), |
render_frame_id_(render_frame_id), |
@@ -190,7 +140,8 @@ AudioRendererHost::AudioEntry::AudioEntry( |
this, |
params, |
output_device_id, |
- reader_.get())), |
+ reader_.get(), |
+ callback)), |
playing_(false) { |
DCHECK(controller_.get()); |
} |
@@ -262,11 +213,11 @@ 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_)); |
+void AudioRendererHost::AudioEntry::OnCreated( |
+ const mojom::AudioOutput::CreateStreamCallback& callback) { |
Henrik Grunell
2016/04/19 15:36:09
Can the callback be stored in the AudioEntry inste
rchtara
2016/04/21 09:10:18
it's possible to do that, but we are going to have
Henrik Grunell
2016/04/22 08:23:03
Acknowledged.
|
+ BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
+ base::Bind(&AudioRendererHost::DoCompleteCreation, |
+ host_, stream_id_, callback)); |
} |
void AudioRendererHost::AudioEntry::OnPlaying() { |
@@ -296,29 +247,39 @@ void AudioRendererHost::AudioEntry::OnError() { |
base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_)); |
} |
-void AudioRendererHost::DoCompleteCreation(int stream_id) { |
+void AudioRendererHost::DoCompleteCreation( |
+ int stream_id, |
+ const mojom::AudioOutput::CreateStreamCallback& callback) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
if (!PeerHandle()) { |
DLOG(WARNING) << "Renderer process handle is invalid."; |
- ReportErrorAndClose(stream_id); |
+ ReportErrorAndCloseMojo(stream_id, callback); |
return; |
} |
AudioEntry* const entry = LookupById(stream_id); |
if (!entry) { |
- ReportErrorAndClose(stream_id); |
+ ReportErrorAndCloseMojo(stream_id, callback); |
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()); |
+ scoped_ptr<mojom::AudioOutputStreamPtr> stream_ptr( |
Henrik Grunell
2016/04/19 15:36:09
std::unique_ptr. Here and elsewhere.
rchtara
2016/04/21 09:10:17
Done.
|
+ audio_output_impl_->StreamFactory(stream_id, entry, this)); |
+ |
+ base::SharedMemoryHandle shared_memory_handle = |
+ base::SharedMemory::DuplicateHandle(entry->shared_memory()->handle()); |
+ |
+ MojoHandle mojo_foreign_memory_handle; |
+ |
+ MojoResult shared_buffer_result = mojo::edk::CreateSharedBufferWrapper( |
+ shared_memory_handle, entry->shared_memory()->requested_size(), false, |
+ &mojo_foreign_memory_handle); |
+ |
+ if (shared_buffer_result != MOJO_RESULT_OK) { |
+ DLOG(WARNING) << "Failed to wrap transit descriptor. Closing: " |
+ << shared_buffer_result; |
+ ReportErrorAndCloseMojo(entry->stream_id(), callback); |
return; |
} |
@@ -329,13 +290,59 @@ void AudioRendererHost::DoCompleteCreation(int stream_id) { |
// 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()); |
+ ReportErrorAndCloseMojo(entry->stream_id(), callback); |
+ return; |
+ } |
+ mojo::ScopedSharedBufferHandle shared_buffer_handle = |
+ mojo::ScopedSharedBufferHandle( |
+ mojo::SharedBufferHandle(mojo_foreign_memory_handle)); |
+ |
+ MojoHandle socket_descriptor_handle; |
+ MojoResult platform_handle_result; |
+ |
+ // Mojo is going to close the socket handle when Mojo shutdowns. |
Henrik Grunell
2016/04/19 15:36:08
I'm not sure what Mojo means here. And what "when
rchtara
2016/04/21 09:10:17
Done.
|
+ // This could create a conflict between Mojo and AudioOutputIPCDelegate where |
+ // the socket is going to need to be closed too. |
Henrik Grunell
2016/04/19 15:36:09
This line is hard to parse.
rchtara
2016/04/21 09:10:18
Done.
|
+ // This is why a duplicate of socket handler is going to be created, stored in |
+ // |socket_descriptor_dup| and sent through Mojo to the renderer. |
+ |
+#if defined(OS_WIN) |
Henrik Grunell
2016/04/19 15:36:09
This duplication looks like a good candidate for a
rchtara
2016/04/21 09:10:17
Done.
|
+ base::SyncSocket::TransitDescriptor socket_descriptor_dup = nullptr; |
+ if (::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle |
+ socket_descriptor, |
+ GetCurrentProcess(), // hTargetProcessHandle |
+ &socket_descriptor_dup, |
+ 0, // dwDesiredAccess ignored due to SAME_ACCESS |
+ FALSE, // !bInheritHandle |
+ DUPLICATE_SAME_ACCESS)) { |
+ DLOG(WARNING) << "Failed to duplicate socket"; |
+ return; |
+ } |
+ platform_handle_result = mojo::edk::CreatePlatformHandleWrapper( |
+ mojo::edk::ScopedPlatformHandle( |
+ mojo::edk::PlatformHandle(socket_descriptor_dup)), |
+ &socket_descriptor_handle); |
+ |
+#else |
+ int socket_descriptor_dup = dup(socket_descriptor.fd); |
+ platform_handle_result = mojo::edk::CreatePlatformHandleWrapper( |
+ mojo::edk::ScopedPlatformHandle( |
+ mojo::edk::PlatformHandle(socket_descriptor_dup)), |
+ &socket_descriptor_handle); |
+#endif |
+ |
+ if (platform_handle_result != MOJO_RESULT_OK) { |
+ DLOG(WARNING) << "Failed to wrap platform handle. Closing: " |
+ << platform_handle_result; |
+ ReportErrorAndCloseMojo(stream_id, callback); |
return; |
} |
- Send(new AudioMsg_NotifyStreamCreated( |
- entry->stream_id(), foreign_memory_handle, socket_descriptor, |
- entry->shared_memory()->requested_size())); |
+ mojo::ScopedHandle socket_handle = |
+ mojo::ScopedHandle(mojo::Handle(socket_descriptor_handle)); |
+ callback.Run(std::move(*stream_ptr), stream_id, |
+ std::move(shared_buffer_handle), std::move(socket_handle)); |
+ |
} |
void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, |
@@ -386,7 +393,6 @@ bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { |
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) |
@@ -525,9 +531,11 @@ void AudioRendererHost::OnDeviceIDTranslated( |
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) { |
+void AudioRendererHost::OnCreateStream( |
+ int stream_id, |
+ int render_frame_id, |
+ const media::AudioParameters& params, |
+ const mojom::AudioOutput::CreateStreamCallback& callback) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" |
<< "(stream_id=" << stream_id << ")"; |
@@ -536,19 +544,22 @@ void AudioRendererHost::OnCreateStream(int stream_id, |
// If no previous authorization requested, assume default device |
if (auth_data == authorizations_.end()) { |
- DoCreateStream(stream_id, render_frame_id, params, std::string()); |
+ DoCreateStream(stream_id, render_frame_id, params, std::string(), callback); |
return; |
} |
CHECK(auth_data->second.first); |
- DoCreateStream(stream_id, render_frame_id, params, auth_data->second.second); |
+ DoCreateStream(stream_id, render_frame_id, params, auth_data->second.second, |
+ callback); |
authorizations_.erase(auth_data); |
} |
-void AudioRendererHost::DoCreateStream(int stream_id, |
- int render_frame_id, |
- const media::AudioParameters& params, |
- const std::string& device_unique_id) { |
+void AudioRendererHost::DoCreateStream( |
+ int stream_id, |
+ int render_frame_id, |
+ const media::AudioParameters& params, |
+ const std::string& device_unique_id, |
+ const mojom::AudioOutput::CreateStreamCallback& callback) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |
// media::AudioParameters is validated in the deserializer. |
@@ -560,13 +571,13 @@ void AudioRendererHost::DoCreateStream(int stream_id, |
// Create the shared memory and share with the renderer process. |
uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + |
AudioBus::CalculateMemorySize(params); |
- std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
+ scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
Henrik Grunell
2016/04/19 15:36:09
scoped_ptr is deprecated. Keep std::unique_ptr. (N
rchtara
2016/04/21 09:10:18
Done.
|
if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { |
SendErrorMessage(stream_id); |
return; |
} |
- std::unique_ptr<AudioSyncReader> reader( |
+ scoped_ptr<AudioSyncReader> reader( |
new AudioSyncReader(shared_memory.get(), params)); |
if (!reader->Init()) { |
SendErrorMessage(stream_id); |
@@ -578,9 +589,9 @@ void AudioRendererHost::DoCreateStream(int stream_id, |
if (media_observer) |
media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); |
- std::unique_ptr<AudioEntry> entry( |
+ scoped_ptr<AudioEntry> entry( |
new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id, |
- std::move(shared_memory), std::move(reader))); |
+ std::move(shared_memory), std::move(reader), callback)); |
if (mirroring_manager_) { |
mirroring_manager_->AddDiverter( |
render_process_id_, entry->render_frame_id(), entry->controller()); |
@@ -693,6 +704,28 @@ void AudioRendererHost::ReportErrorAndClose(int stream_id) { |
OnCloseStream(stream_id); |
} |
+void AudioRendererHost::ReportErrorAndCloseMojo( |
Henrik Grunell
2016/04/19 15:36:09
"CloseMojo" sounds like the whole mojo infrastruct
rchtara
2016/04/21 09:10:17
:) yes exactly.
Done.
|
+ int stream_id, |
+ const mojom::AudioOutput::CreateStreamCallback& callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ // Make sure this isn't a stray callback executing after the stream has been |
+ // closed, so error notifications aren't sent after clients believe the stream |
+ // is closed. |
+ if (!LookupById(stream_id)) |
+ return; |
+ mojo::ScopedSharedBufferHandle shared_buffer_handle = |
+ mojo::ScopedSharedBufferHandle(mojo::SharedBufferHandle()); |
+ |
+ mojo::ScopedHandle socket_handle = mojo::ScopedHandle(mojo::Handle()); |
+ |
+ callback.Run(mojom::AudioOutputStreamPtr(), stream_id, |
+ std::move(shared_buffer_handle), std::move(socket_handle)); |
+ |
+ audio_log_->OnError(stream_id); |
+ OnCloseStream(stream_id); |
+} |
+ |
AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { |
DCHECK_CURRENTLY_ON(BrowserThread::IO); |