| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 
|  | 2 // Use of this source code is governed by a BSD-style license that can be | 
|  | 3 // found in the LICENSE file. | 
|  | 4 | 
|  | 5 #if defined(OS_WIN) | 
|  | 6 #include <windows.h> | 
|  | 7 #endif | 
|  | 8 | 
|  | 9 #include "base/memory/shared_memory.h" | 
|  | 10 #include "content/browser/frame_host/render_frame_host_impl.h" | 
|  | 11 #include "content/browser/media/audio_output_impl.h" | 
|  | 12 #include "content/browser/media/audio_output_stream_impl.h" | 
|  | 13 #include "content/browser/renderer_host/render_process_host_impl.h" | 
|  | 14 #include "content/public/browser/render_frame_host.h" | 
|  | 15 #include "mojo/edk/embedder/embedder.h" | 
|  | 16 #include "mojo/public/cpp/system/handle.h" | 
|  | 17 #include "mojo/public/cpp/system/platform_handle.h" | 
|  | 18 | 
|  | 19 namespace content { | 
|  | 20 | 
|  | 21 namespace { | 
|  | 22 | 
|  | 23 base::SyncSocket::TransitDescriptor DuplicateSocket( | 
|  | 24     base::SyncSocket::TransitDescriptor socket_descriptor) { | 
|  | 25   base::SyncSocket::TransitDescriptor socket_descriptor_dup; | 
|  | 26 | 
|  | 27 #if defined(OS_WIN) | 
|  | 28   socket_descriptor_dup = 0; | 
|  | 29   if (!::DuplicateHandle(GetCurrentProcess(),  // hSourceProcessHandle | 
|  | 30                          socket_descriptor, | 
|  | 31                          GetCurrentProcess(),  // hTargetProcessHandle | 
|  | 32                          &socket_descriptor_dup, | 
|  | 33                          0,      // dwDesiredAccess ignored due to SAME_ACCESS | 
|  | 34                          FALSE,  // !bInheritHandle | 
|  | 35                          DUPLICATE_SAME_ACCESS)) { | 
|  | 36     LOG(ERROR) << "Unable to duplicate socket handle."; | 
|  | 37   } | 
|  | 38 | 
|  | 39 #else | 
|  | 40   socket_descriptor_dup.fd = dup(socket_descriptor.fd); | 
|  | 41 #endif | 
|  | 42   return socket_descriptor_dup; | 
|  | 43 } | 
|  | 44 | 
|  | 45 }  // namespace | 
|  | 46 | 
|  | 47 AudioOutputImpl::AudioOutputImpl(RenderFrameHostImpl* frame, | 
|  | 48                                  media::mojom::AudioOutputRequest request) | 
|  | 49     : frame_(frame) { | 
|  | 50   binding_.reset( | 
|  | 51       new mojo::Binding<media::mojom::AudioOutput>(this, std::move(request))); | 
|  | 52 | 
|  | 53 } | 
|  | 54 | 
|  | 55 AudioOutputImpl::~AudioOutputImpl() { | 
|  | 56   auto audio_renderer_host = audio_renderer_host_.get(); | 
|  | 57 | 
|  | 58   if (audio_renderer_host) | 
|  | 59     audio_renderer_host->CleanAudioOutputImpl(this); | 
|  | 60 | 
|  | 61   for (auto it = create_stream_callbacks_.begin(); | 
|  | 62        it != create_stream_callbacks_.end(); ++it) { | 
|  | 63     it->second.reset(); | 
|  | 64   } | 
|  | 65   create_stream_callbacks_.clear(); | 
|  | 66 } | 
|  | 67 | 
|  | 68 // static | 
|  | 69 void AudioOutputImpl::CreateService(RenderFrameHostImpl* frame, | 
|  | 70                                     media::mojom::AudioOutputRequest request) { | 
|  | 71   DCHECK_CURRENTLY_ON(BrowserThread::UI); | 
|  | 72 | 
|  | 73   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 
|  | 74                           base::Bind(&AudioOutputImpl::CreateServiceOnIOThread, | 
|  | 75                                      frame, base::Passed(&request))); | 
|  | 76 } | 
|  | 77 | 
|  | 78 void AudioOutputImpl::Reset() { | 
|  | 79 | 
|  | 80   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) | 
|  | 81     BrowserThread::PostTask( | 
|  | 82         BrowserThread::IO, FROM_HERE, | 
|  | 83         base::Bind(&AudioOutputImpl::Reset, base::Unretained(this))); | 
|  | 84   else | 
|  | 85     delete this; | 
|  | 86 } | 
|  | 87 | 
|  | 88 // static | 
|  | 89 void AudioOutputImpl::CreateServiceOnIOThread( | 
|  | 90     RenderFrameHostImpl* frame, | 
|  | 91     media::mojom::AudioOutputRequest request) { | 
|  | 92   DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
|  | 93   frame->set_audio_output_impl(new AudioOutputImpl(frame, std::move(request))); | 
|  | 94 } | 
|  | 95 | 
|  | 96 void AudioOutputImpl::CreateStream(int stream_id, | 
|  | 97                                    const media::AudioParameters& params, | 
|  | 98                                    const CreateStreamCallback& callback) { | 
|  | 99   DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
|  | 100 | 
|  | 101   create_stream_callbacks_.insert(std::make_pair(stream_id, callback)); | 
|  | 102   InitAudioRendererHost(); | 
|  | 103   if (audio_renderer_host_) | 
|  | 104     audio_renderer_host_->CreateStream(stream_id, frame_->GetRoutingID(), | 
|  | 105                                        params, this); | 
|  | 106 } | 
|  | 107 | 
|  | 108 void AudioOutputImpl::CreateStreamFactory( | 
|  | 109     int stream_id, | 
|  | 110     base::SharedMemory* shared_memory, | 
|  | 111     base::SyncSocket::TransitDescriptor socket_descriptor) { | 
|  | 112   DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
|  | 113 | 
|  | 114   auto callback = create_stream_callbacks_.find(stream_id); | 
|  | 115   if (callback == create_stream_callbacks_.end()) { | 
|  | 116     ReportErrorAndCloseStream(stream_id); | 
|  | 117     return; | 
|  | 118   } | 
|  | 119 | 
|  | 120   media::mojom::AudioOutputStreamPtr stream_ptr = | 
|  | 121       media::mojom::AudioOutputStreamPtr(); | 
|  | 122   std::unique_ptr<AudioOutputStreamImpl> stream( | 
|  | 123       new AudioOutputStreamImpl(stream_id, this, mojo::GetProxy(&stream_ptr))); | 
|  | 124   stream_impls_.insert(std::make_pair(stream_id, std::move(stream))); | 
|  | 125 | 
|  | 126   base::SharedMemoryHandle shared_memory_handle = | 
|  | 127       base::SharedMemory::DuplicateHandle(shared_memory->handle()); | 
|  | 128   if (!base::SharedMemory::IsHandleValid(shared_memory_handle)) { | 
|  | 129     ReportErrorAndCloseStream(stream_id); | 
|  | 130     return; | 
|  | 131   } | 
|  | 132   mojo::ScopedSharedBufferHandle shared_buffer_handle = | 
|  | 133       mojo::WrapSharedMemoryHandle(shared_memory_handle, | 
|  | 134                                    shared_memory->requested_size(), false); | 
|  | 135   // The socket that we will send from the browser to the renderer is a | 
|  | 136   // |foreign_socket_| which is a part AudioSyncReader that is owned by | 
|  | 137   // AudioEntry. The socket handle will be closed when the AudioEntry it | 
|  | 138   // belongs to will be closed. However, with mojo and unlike IPC, the | 
|  | 139   // ownership of the handle is transferred to the target process. It's no | 
|  | 140   // longer a valid handle in the sending process and it is an error to try | 
|  | 141   // closing it there. So, if the socket handle is closed when the AudioEntry | 
|  | 142   // is deleted, we will have an error. To fix this error we could just | 
|  | 143   // duplicate the socket and send the duplicate to the renderer. Thus, we | 
|  | 144   // will avoid having an problem when closing the socket. | 
|  | 145   // See https://goo.gl/ACwSfa. | 
|  | 146   base::SyncSocket::TransitDescriptor socket_descriptor_dup = | 
|  | 147       DuplicateSocket(socket_descriptor); | 
|  | 148 #if defined(OS_WIN) | 
|  | 149   mojo::ScopedHandle socket_handle = | 
|  | 150       mojo::WrapPlatformFile(socket_descriptor_dup); | 
|  | 151 #else | 
|  | 152   mojo::ScopedHandle socket_handle = | 
|  | 153       mojo::WrapPlatformFile(socket_descriptor_dup.fd); | 
|  | 154 #endif | 
|  | 155 | 
|  | 156   callback->second.Run(stream_id, std::move(stream_ptr), | 
|  | 157                        std::move(shared_buffer_handle), | 
|  | 158                        std::move(socket_handle)); | 
|  | 159   callback->second.reset(); | 
|  | 160   create_stream_callbacks_.erase(stream_id); | 
|  | 161 } | 
|  | 162 | 
|  | 163 bool AudioOutputImpl::CloseStream(int stream_id) { | 
|  | 164   if (audio_renderer_host_.get()) | 
|  | 165     audio_renderer_host_->CloseStream(stream_id); | 
|  | 166 | 
|  | 167   if (stream_impls_.erase(stream_id) == 0) | 
|  | 168     return false; | 
|  | 169 | 
|  | 170   auto callback = create_stream_callbacks_.find(stream_id); | 
|  | 171 | 
|  | 172   if (callback != create_stream_callbacks_.end()) { | 
|  | 173     callback->second.reset(); | 
|  | 174     create_stream_callbacks_.erase(stream_id); | 
|  | 175   } | 
|  | 176   return true; | 
|  | 177 } | 
|  | 178 | 
|  | 179 void AudioOutputImpl::ReportErrorAndCloseStream(int stream_id) { | 
|  | 180   DCHECK_CURRENTLY_ON(BrowserThread::IO); | 
|  | 181 | 
|  | 182   // Make sure this isn't a stray callback executing after the stream has been | 
|  | 183   // closed, so error notifications aren't sent after clients believe the stream | 
|  | 184   // is closed. | 
|  | 185   auto callback = create_stream_callbacks_.find(stream_id); | 
|  | 186 | 
|  | 187   mojo::ScopedSharedBufferHandle shared_buffer_handle = | 
|  | 188       mojo::ScopedSharedBufferHandle(mojo::SharedBufferHandle()); | 
|  | 189 | 
|  | 190   mojo::ScopedHandle socket_handle = mojo::ScopedHandle(mojo::Handle()); | 
|  | 191 | 
|  | 192   callback->second.Run(stream_id, media::mojom::AudioOutputStreamPtr(), | 
|  | 193                        std::move(shared_buffer_handle), | 
|  | 194                        std::move(socket_handle)); | 
|  | 195 | 
|  | 196   if (audio_renderer_host_) | 
|  | 197     audio_renderer_host_->get_audio_log()->OnError(stream_id); | 
|  | 198   CloseStream(stream_id); | 
|  | 199 } | 
|  | 200 | 
|  | 201 void AudioOutputImpl::InitAudioRendererHost() { | 
|  | 202   RenderProcessHost* process = frame_->GetProcess(); | 
|  | 203   // It's safe to use static casting of the |process| to RenderProcessHostImpl | 
|  | 204   // outside the tests: there is just RenderProcessHostImpl and | 
|  | 205   // MockRenderProcessHost that inherit from RenderProcessHost and | 
|  | 206   // MockRenderProcessHost is used in just some tests that doesn't involve | 
|  | 207   // AudioOutputImpl. It's also a common practice used in many places to access | 
|  | 208   // RenderProcessHostImpl hidden methods  from RenderProcessHost. | 
|  | 209   // See https://goo.gl/tkKvkd. | 
|  | 210 | 
|  | 211   auto host = | 
|  | 212       static_cast<RenderProcessHostImpl*>(process)->audio_renderer_host(); | 
|  | 213   if (host.get()) | 
|  | 214     audio_renderer_host_ = host; | 
|  | 215 } | 
|  | 216 | 
|  | 217 }  // namespace content | 
| OLD | NEW | 
|---|