| 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 7e951f12f729e8ee57a182d9c2634c50aa9e7a6d..010da145e06c96800d5c5d886450f6291559d176 100644
 | 
| --- a/content/browser/renderer_host/media/audio_renderer_host.cc
 | 
| +++ b/content/browser/renderer_host/media/audio_renderer_host.cc
 | 
| @@ -6,6 +6,9 @@
 | 
|  
 | 
|  #include <stdint.h>
 | 
|  #include <utility>
 | 
| +#if defined(OS_WIN)
 | 
| +#include <windows.h>
 | 
| +#endif
 | 
|  
 | 
|  #include "base/bind.h"
 | 
|  #include "base/bind_helpers.h"
 | 
| @@ -16,6 +19,7 @@
 | 
|  #include "base/process/process.h"
 | 
|  #include "content/browser/bad_message.h"
 | 
|  #include "content/browser/browser_main_loop.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"
 | 
| @@ -34,6 +38,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;
 | 
| @@ -55,6 +61,28 @@ std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData(
 | 
|                          std::make_pair(authorized, device_unique_id));
 | 
|  }
 | 
|  
 | 
| +base::SyncSocket::TransitDescriptor DuplicateSocket(
 | 
| +    base::SyncSocket::TransitDescriptor socket_descriptor) {
 | 
| +  base::SyncSocket::TransitDescriptor socket_descriptor_dup;
 | 
| +
 | 
| +#if defined(OS_WIN)
 | 
| +  socket_descriptor_dup = 0;
 | 
| +  if (!::DuplicateHandle(GetCurrentProcess(),  // hSourceProcessHandle
 | 
| +                         socket_descriptor,
 | 
| +                         GetCurrentProcess(),  // hTargetProcessHandle
 | 
| +                         &socket_descriptor_dup,
 | 
| +                         0,      // dwDesiredAccess ignored due to SAME_ACCESS
 | 
| +                         FALSE,  // !bInheritHandle
 | 
| +                         DUPLICATE_SAME_ACCESS)) {
 | 
| +    LOG(ERROR) << "Unable to duplicate socket handle.";
 | 
| +  }
 | 
| +
 | 
| +#else
 | 
| +  socket_descriptor_dup.fd = dup(socket_descriptor.fd);
 | 
| +#endif
 | 
| +  return socket_descriptor_dup;
 | 
| +}
 | 
| +
 | 
|  bool IsValidDeviceId(const std::string& device_id) {
 | 
|    static const std::string::size_type kValidLength = 64;
 | 
|  
 | 
| @@ -114,13 +142,16 @@ void MaybeFixAudioParameters(media::AudioParameters* params) {
 | 
|  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(
 | 
| +      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,
 | 
| +      const media::mojom::AudioOutput::CreateStreamCallback&
 | 
| +          create_stream_callback);
 | 
|    ~AudioEntry() override;
 | 
|  
 | 
|    int stream_id() const {
 | 
| @@ -165,6 +196,9 @@ class AudioRendererHost::AudioEntry
 | 
|    const scoped_refptr<media::AudioOutputController> controller_;
 | 
|  
 | 
|    bool playing_;
 | 
| +
 | 
| +  // Callback for media::mojom::AudioOutput::CreateStream.
 | 
| +  media::mojom::AudioOutput::CreateStreamCallback create_stream_callback_;
 | 
|  };
 | 
|  
 | 
|  AudioRendererHost::AudioEntry::AudioEntry(
 | 
| @@ -174,7 +208,9 @@ 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 media::mojom::AudioOutput::CreateStreamCallback&
 | 
| +        create_stream_callback)
 | 
|      : host_(host),
 | 
|        stream_id_(stream_id),
 | 
|        render_frame_id_(render_frame_id),
 | 
| @@ -185,7 +221,8 @@ AudioRendererHost::AudioEntry::AudioEntry(
 | 
|                                                         params,
 | 
|                                                         output_device_id,
 | 
|                                                         reader_.get())),
 | 
| -      playing_(false) {
 | 
| +      playing_(false),
 | 
| +      create_stream_callback_(create_stream_callback) {
 | 
|    DCHECK(controller_.get());
 | 
|  }
 | 
|  
 | 
| @@ -258,9 +295,9 @@ void AudioRendererHost::OnDestruct() const {
 | 
|  
 | 
|  void AudioRendererHost::AudioEntry::OnCreated() {
 | 
|    BrowserThread::PostTask(
 | 
| -      BrowserThread::IO,
 | 
| -      FROM_HERE,
 | 
| -      base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_));
 | 
| +      BrowserThread::IO, FROM_HERE,
 | 
| +      base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_,
 | 
| +                 create_stream_callback_));
 | 
|  }
 | 
|  
 | 
|  void AudioRendererHost::AudioEntry::OnPlaying() {
 | 
| @@ -290,29 +327,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 media::mojom::AudioOutput::CreateStreamCallback& callback) {
 | 
|    DCHECK_CURRENTLY_ON(BrowserThread::IO);
 | 
|  
 | 
|    if (!PeerHandle()) {
 | 
|      DLOG(WARNING) << "Renderer process handle is invalid.";
 | 
| -    ReportErrorAndClose(stream_id);
 | 
| +    ReportErrorAndCloseStream(stream_id, callback);
 | 
|      return;
 | 
|    }
 | 
|  
 | 
|    AudioEntry* const entry = LookupById(stream_id);
 | 
|    if (!entry) {
 | 
| -    ReportErrorAndClose(stream_id);
 | 
| +    ReportErrorAndCloseStream(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());
 | 
| +  media::mojom::AudioOutputStreamPtr stream_ptr =
 | 
| +      (audio_output_impl_->StreamFactory(stream_id, 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;
 | 
| +    ReportErrorAndCloseStream(entry->stream_id(), callback);
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| @@ -323,13 +370,49 @@ 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());
 | 
| +    ReportErrorAndCloseStream(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;
 | 
| +
 | 
| +  // The socket handle is going to be closed when |mojo_application_host_| is
 | 
| +  // reset. AudioOutputIPCDelegate is going to need to close the socket handle
 | 
| +  // too when the steam it controls is closed. This is going to cause an issue
 | 
| +  // because both of them are going to close the same socket handle.
 | 
| +  // This is why a duplicate of the socket handler is going to be created,
 | 
| +  // stored in |socket_descriptor_dup| and sent through Mojo to the renderer so
 | 
| +  // it can be used by AudioOutputIPCDelegate.
 | 
| +
 | 
| +  base::SyncSocket::TransitDescriptor socket_descriptor_dup =
 | 
| +      DuplicateSocket(socket_descriptor);
 | 
| +#if defined(OS_WIN)
 | 
| +  platform_handle_result = mojo::edk::CreatePlatformHandleWrapper(
 | 
| +      mojo::edk::ScopedPlatformHandle(
 | 
| +          mojo::edk::PlatformHandle(socket_descriptor_dup),
 | 
| +      &socket_descriptor_handle);
 | 
| +#else
 | 
| +  platform_handle_result = mojo::edk::CreatePlatformHandleWrapper(
 | 
| +      mojo::edk::ScopedPlatformHandle(
 | 
| +          mojo::edk::PlatformHandle(socket_descriptor_dup.fd)),
 | 
| +      &socket_descriptor_handle);
 | 
| +#endif
 | 
| +
 | 
| +  if (platform_handle_result != MOJO_RESULT_OK) {
 | 
| +    DLOG(WARNING) << "Failed to wrap platform handle. Closing: "
 | 
| +                  << platform_handle_result;
 | 
| +    ReportErrorAndCloseStream(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(stream_id, std::move(stream_ptr),
 | 
| +               std::move(shared_buffer_handle), std::move(socket_handle));
 | 
|  }
 | 
|  
 | 
|  void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id,
 | 
| @@ -380,7 +463,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)
 | 
| @@ -517,30 +599,38 @@ 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::CreateStream(
 | 
| +    int stream_id,
 | 
| +    int render_frame_id,
 | 
| +    const media::AudioParameters& params,
 | 
| +    const media::mojom::AudioOutput::CreateStreamCallback&
 | 
| +        create_stream_callback) {
 | 
|    DCHECK_CURRENTLY_ON(BrowserThread::IO);
 | 
| -  DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream"
 | 
| +  DVLOG(1) << "AudioRendererHost@" << this << "::CreateStream"
 | 
|             << "(stream_id=" << stream_id << ")";
 | 
|  
 | 
|    const auto& auth_data = authorizations_.find(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(),
 | 
| +        create_stream_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,
 | 
| +                 create_stream_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 media::mojom::AudioOutput::CreateStreamCallback&
 | 
| +        create_stream_callback) {
 | 
|    DCHECK_CURRENTLY_ON(BrowserThread::IO);
 | 
|  
 | 
|    // media::AudioParameters is validated in the deserializer.
 | 
| @@ -572,7 +662,8 @@ void AudioRendererHost::DoCreateStream(int stream_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::move(shared_memory), std::move(reader),
 | 
| +                     create_stream_callback));
 | 
|    if (mirroring_manager_) {
 | 
|      mirroring_manager_->AddDiverter(
 | 
|          render_process_id_, entry->render_frame_id(), entry->controller());
 | 
| @@ -685,6 +776,28 @@ void AudioRendererHost::ReportErrorAndClose(int stream_id) {
 | 
|    OnCloseStream(stream_id);
 | 
|  }
 | 
|  
 | 
| +void AudioRendererHost::ReportErrorAndCloseStream(
 | 
| +    int stream_id,
 | 
| +    const media::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(stream_id, media::mojom::AudioOutputStreamPtr(),
 | 
| +               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);
 | 
|  
 | 
| 
 |