| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/bind_helpers.h" | 11 #include "base/bind_helpers.h" |
| 12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
| 13 #include "base/memory/shared_memory.h" | 13 #include "base/memory/shared_memory.h" |
| 14 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 15 #include "base/process/process.h" | 15 #include "base/process/process.h" |
| 16 #include "content/browser/bad_message.h" | 16 #include "content/browser/bad_message.h" |
| 17 #include "content/browser/browser_main_loop.h" | 17 #include "content/browser/browser_main_loop.h" |
| 18 #include "content/browser/media/audio_stream_monitor.h" | 18 #include "content/browser/media/audio_stream_monitor.h" |
| 19 #include "content/browser/media/capture/audio_mirroring_manager.h" | 19 #include "content/browser/media/capture/audio_mirroring_manager.h" |
| 20 #include "content/browser/media/media_internals.h" | 20 #include "content/browser/media/media_internals.h" |
| 21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 21 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 22 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 22 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
| 23 #include "content/browser/renderer_host/media/media_stream_manager.h" | 23 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 24 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" | 24 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" |
| 25 #include "content/browser/renderer_host/render_widget_host_impl.h" | 25 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| 26 #include "content/common/media/audio_messages.h" | |
| 27 #include "content/public/browser/content_browser_client.h" | 26 #include "content/public/browser/content_browser_client.h" |
| 28 #include "content/public/browser/media_device_id.h" | 27 #include "content/public/browser/media_device_id.h" |
| 29 #include "content/public/browser/media_observer.h" | 28 #include "content/public/browser/media_observer.h" |
| 30 #include "content/public/browser/render_frame_host.h" | 29 #include "content/public/browser/render_frame_host.h" |
| 31 #include "content/public/common/content_switches.h" | 30 #include "content/public/common/content_switches.h" |
| 32 #include "media/audio/audio_device_description.h" | 31 #include "media/audio/audio_device_description.h" |
| 33 #include "media/audio/audio_streams_tracker.h" | 32 #include "media/audio/audio_streams_tracker.h" |
| 34 #include "media/base/audio_bus.h" | 33 #include "media/base/audio_bus.h" |
| 35 #include "media/base/limits.h" | 34 #include "media/base/limits.h" |
| 35 #include "media/mojo/interfaces/audio_output.mojom-shared.h" |
| 36 #include "media/mojo/interfaces/audio_output.mojom.h" |
| 37 #include "mojo/edk/embedder/embedder.h" |
| 38 #include "mojo/public/cpp/system/handle.h" |
| 39 #include "mojo/public/cpp/system/platform_handle.h" |
| 36 | 40 |
| 37 using media::AudioBus; | 41 using media::AudioBus; |
| 38 using media::AudioManager; | 42 using media::AudioManager; |
| 39 | 43 |
| 40 namespace content { | 44 namespace content { |
| 41 | 45 |
| 42 namespace { | 46 namespace { |
| 43 | 47 |
| 44 // Tracks the maximum number of simultaneous output streams browser-wide. | 48 // Tracks the maximum number of simultaneous output streams browser-wide. |
| 45 // Accessed on IO thread. | 49 // Accessed on IO thread. |
| 46 base::LazyInstance<media::AudioStreamsTracker> g_audio_streams_tracker = | 50 base::LazyInstance<media::AudioStreamsTracker> g_audio_streams_tracker = |
| 47 LAZY_INSTANCE_INITIALIZER; | 51 LAZY_INSTANCE_INITIALIZER; |
| 48 | 52 |
| 49 std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData( | 53 std::pair<int, std::pair<bool, std::string>> MakeAuthorizationData( |
| 50 int stream_id, | 54 int32_t stream_id, |
| 51 bool authorized, | 55 bool authorized, |
| 52 const std::string& device_unique_id) { | 56 const std::string& device_unique_id) { |
| 53 return std::make_pair(stream_id, | 57 return std::make_pair(stream_id, |
| 54 std::make_pair(authorized, device_unique_id)); | 58 std::make_pair(authorized, device_unique_id)); |
| 55 } | 59 } |
| 56 | 60 |
| 57 bool IsValidDeviceId(const std::string& device_id) { | 61 bool IsValidDeviceId(const std::string& device_id) { |
| 58 static const std::string::size_type kValidLength = 64; | 62 static const std::string::size_type kValidLength = 64; |
| 59 | 63 |
| 60 if (device_id.empty() || | 64 if (device_id.empty() || |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 const bool frame_exists = | 129 const bool frame_exists = |
| 126 !!RenderFrameHost::FromID(render_process_id, render_frame_id); | 130 !!RenderFrameHost::FromID(render_process_id, render_frame_id); |
| 127 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 131 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 128 base::Bind(callback, frame_exists)); | 132 base::Bind(callback, frame_exists)); |
| 129 } | 133 } |
| 130 #endif // DCHECK_IS_ON() | 134 #endif // DCHECK_IS_ON() |
| 131 | 135 |
| 132 } // namespace | 136 } // namespace |
| 133 | 137 |
| 134 class AudioRendererHost::AudioEntry | 138 class AudioRendererHost::AudioEntry |
| 135 : public media::AudioOutputController::EventHandler { | 139 : public media::AudioOutputController::EventHandler, |
| 140 private media::mojom::AudioOutputStream { |
| 136 public: | 141 public: |
| 137 AudioEntry(AudioRendererHost* host, | 142 AudioEntry(AudioRendererHost* host, |
| 138 int stream_id, | 143 int32_t stream_id, |
| 139 int render_frame_id, | 144 int render_frame_id, |
| 140 const media::AudioParameters& params, | 145 const media::AudioParameters& params, |
| 141 const std::string& output_device_id, | 146 const std::string& output_device_id, |
| 142 std::unique_ptr<base::SharedMemory> shared_memory, | 147 std::unique_ptr<base::SharedMemory> shared_memory, |
| 143 std::unique_ptr<media::AudioOutputController::SyncReader> reader); | 148 std::unique_ptr<media::AudioOutputController::SyncReader> reader); |
| 144 ~AudioEntry() override; | 149 ~AudioEntry() override; |
| 145 | 150 |
| 146 int stream_id() const { | 151 int32_t stream_id() const { return stream_id_; } |
| 147 return stream_id_; | |
| 148 } | |
| 149 | 152 |
| 150 int render_frame_id() const { return render_frame_id_; } | 153 int render_frame_id() const { return render_frame_id_; } |
| 151 | 154 |
| 152 media::AudioOutputController* controller() const { return controller_.get(); } | 155 media::AudioOutputController* controller() const { return controller_.get(); } |
| 153 | 156 |
| 154 base::SharedMemory* shared_memory() { | 157 base::SharedMemory* shared_memory() { |
| 155 return shared_memory_.get(); | 158 return shared_memory_.get(); |
| 156 } | 159 } |
| 157 | 160 |
| 158 media::AudioOutputController::SyncReader* reader() const { | 161 media::AudioOutputController::SyncReader* reader() const { |
| 159 return reader_.get(); | 162 return reader_.get(); |
| 160 } | 163 } |
| 161 | 164 |
| 162 bool playing() const { return playing_; } | 165 bool playing() const { return playing_; } |
| 163 void set_playing(bool playing) { playing_ = playing; } | 166 void set_playing(bool playing) { playing_ = playing; } |
| 164 | 167 |
| 168 // media::mojom::AudioOutputStream implementation |
| 169 void Play() override; |
| 170 void Pause() override; |
| 171 void SetVolume(double volume) override; |
| 172 |
| 173 void OnConnectionError(); |
| 174 void BindRequest(media::mojom::AudioOutputStreamRequest); |
| 175 |
| 165 private: | 176 private: |
| 166 // media::AudioOutputController::EventHandler implementation. | 177 // media::AudioOutputController::EventHandler implementation. |
| 167 void OnCreated() override; | 178 void OnCreated() override; |
| 168 void OnPlaying() override; | 179 void OnPlaying() override; |
| 169 void OnPaused() override; | 180 void OnPaused() override; |
| 170 void OnError() override; | 181 void OnError() override; |
| 171 | 182 |
| 172 AudioRendererHost* const host_; | 183 AudioRendererHost* const host_; |
| 173 const int stream_id_; | 184 const int32_t stream_id_; |
| 174 | 185 |
| 175 // The routing ID of the source RenderFrame. | 186 // The routing ID of the source RenderFrame. |
| 176 const int render_frame_id_; | 187 const int render_frame_id_; |
| 177 | 188 |
| 178 // Shared memory for transmission of the audio data. Used by |reader_|. | 189 // Shared memory for transmission of the audio data. Used by |reader_|. |
| 179 const std::unique_ptr<base::SharedMemory> shared_memory_; | 190 const std::unique_ptr<base::SharedMemory> shared_memory_; |
| 180 | 191 |
| 181 // The synchronous reader to be used by |controller_|. | 192 // The synchronous reader to be used by |controller_|. |
| 182 const std::unique_ptr<media::AudioOutputController::SyncReader> reader_; | 193 const std::unique_ptr<media::AudioOutputController::SyncReader> reader_; |
| 183 | 194 |
| 184 // The AudioOutputController that manages the audio stream. | 195 // The AudioOutputController that manages the audio stream. |
| 185 const scoped_refptr<media::AudioOutputController> controller_; | 196 const scoped_refptr<media::AudioOutputController> controller_; |
| 186 | 197 |
| 198 // Binds |this| to an AudioOutputStreamPtr that is passed to the |
| 199 // AudioOutputStreamClient (AudioOutputIPC in the renderer process). |
| 200 std::unique_ptr<mojo::Binding<media::mojom::AudioOutputStream>> binding_; |
| 201 |
| 187 bool playing_; | 202 bool playing_; |
| 203 |
| 204 DISALLOW_COPY_AND_ASSIGN(AudioEntry); |
| 188 }; | 205 }; |
| 189 | 206 |
| 190 AudioRendererHost::AudioEntry::AudioEntry( | 207 AudioRendererHost::AudioEntry::AudioEntry( |
| 191 AudioRendererHost* host, | 208 AudioRendererHost* host, |
| 192 int stream_id, | 209 int32_t stream_id, |
| 193 int render_frame_id, | 210 int render_frame_id, |
| 194 const media::AudioParameters& params, | 211 const media::AudioParameters& params, |
| 195 const std::string& output_device_id, | 212 const std::string& output_device_id, |
| 196 std::unique_ptr<base::SharedMemory> shared_memory, | 213 std::unique_ptr<base::SharedMemory> shared_memory, |
| 197 std::unique_ptr<media::AudioOutputController::SyncReader> reader) | 214 std::unique_ptr<media::AudioOutputController::SyncReader> reader) |
| 198 : host_(host), | 215 : host_(host), |
| 199 stream_id_(stream_id), | 216 stream_id_(stream_id), |
| 200 render_frame_id_(render_frame_id), | 217 render_frame_id_(render_frame_id), |
| 201 shared_memory_(std::move(shared_memory)), | 218 shared_memory_(std::move(shared_memory)), |
| 202 reader_(std::move(reader)), | 219 reader_(std::move(reader)), |
| 203 controller_(media::AudioOutputController::Create(host->audio_manager_, | 220 controller_(media::AudioOutputController::Create(host->audio_manager_, |
| 204 this, | 221 this, |
| 205 params, | 222 params, |
| 206 output_device_id, | 223 output_device_id, |
| 207 reader_.get())), | 224 reader_.get())), |
| 225 callback_(callback), |
| 208 playing_(false) { | 226 playing_(false) { |
| 209 DCHECK(controller_.get()); | 227 DCHECK(controller_.get()); |
| 228 |
| 229 BrowserThread::PostTask( |
| 230 BrowserThread::IO, FROM_HERE, |
| 231 base::Bind(&AudioRendererHost::OnCloseStream, host_, stream_id_)); |
| 232 } |
| 233 |
| 234 void AudioRendererHost::AudioEntry::Play() { |
| 235 controller_->Play(); |
| 236 host_->audio_log_->OnStarted(stream_id_); |
| 237 } |
| 238 |
| 239 void AudioRendererHost::AudioEntry::Pause() { |
| 240 controller_->Pause(); |
| 241 host_->audio_log_->OnStopped(stream_id_); |
| 242 } |
| 243 |
| 244 void AudioRendererHost::AudioEntry::SetVolume(double volume) { |
| 245 if (volume < 0 || volume > 1.0) |
| 246 return; |
| 247 |
| 248 controller_->SetVolume(volume); |
| 249 host_->audio_log_->OnSetVolume(stream_id_, volume); |
| 250 } |
| 251 |
| 252 void AudioRendererHost::AudioEntry::OnConnectionError() { |
| 253 binding_.reset(); |
| 254 |
| 255 BrowserThread::PostTask( |
| 256 BrowserThread::IO, FROM_HERE, |
| 257 base::Bind(&AudioRendererHost::CloseStream, host_, stream_id_)); |
| 258 } |
| 259 |
| 260 void AudioRendererHost::AudioEntry::BindRequest( |
| 261 media::mojom::AudioOutputStreamRequest request) { |
| 262 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 263 |
| 264 binding_.reset(new mojo::Binding<media::mojom::AudioOutputStream>( |
| 265 this, std::move(request))); |
| 266 binding_->set_connection_error_handler( |
| 267 base::Bind(&AudioEntry::OnConnectionError, base::Unretained(this))); |
| 210 } | 268 } |
| 211 | 269 |
| 212 AudioRendererHost::AudioEntry::~AudioEntry() {} | 270 AudioRendererHost::AudioEntry::~AudioEntry() {} |
| 213 | 271 |
| 214 /////////////////////////////////////////////////////////////////////////////// | 272 /////////////////////////////////////////////////////////////////////////////// |
| 215 // AudioRendererHost implementations. | 273 // AudioRendererHost implementations. |
| 216 | 274 |
| 217 AudioRendererHost::AudioRendererHost(int render_process_id, | 275 AudioRendererHost::AudioRendererHost(int render_process_id, |
| 218 media::AudioManager* audio_manager, | 276 media::AudioManager* audio_manager, |
| 219 AudioMirroringManager* mirroring_manager, | 277 AudioMirroringManager* mirroring_manager, |
| 220 MediaInternals* media_internals, | 278 MediaInternals* media_internals, |
| 221 MediaStreamManager* media_stream_manager, | 279 MediaStreamManager* media_stream_manager, |
| 222 const std::string& salt) | 280 const std::string& salt) |
| 223 : BrowserMessageFilter(AudioMsgStart), | 281 : render_process_id_(render_process_id), |
| 224 render_process_id_(render_process_id), | |
| 225 audio_manager_(audio_manager), | 282 audio_manager_(audio_manager), |
| 226 mirroring_manager_(mirroring_manager), | 283 mirroring_manager_(mirroring_manager), |
| 227 audio_log_(media_internals->CreateAudioLog( | 284 audio_log_(media_internals->CreateAudioLog( |
| 228 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | 285 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
| 229 media_stream_manager_(media_stream_manager), | 286 media_stream_manager_(media_stream_manager), |
| 230 num_playing_streams_(0), | 287 num_playing_streams_(0), |
| 231 salt_(salt), | 288 salt_(salt), |
| 289 next_stream_id_(0), |
| 232 #if DCHECK_IS_ON() | 290 #if DCHECK_IS_ON() |
| 233 validate_render_frame_id_function_(&ValidateRenderFrameId), | 291 validate_render_frame_id_function_(&ValidateRenderFrameId), |
| 234 #endif // DCHECK_IS_ON() | 292 #endif // DCHECK_IS_ON() |
| 235 max_simultaneous_streams_(0) { | 293 max_simultaneous_streams_(0) { |
| 236 DCHECK(audio_manager_); | 294 DCHECK(audio_manager_); |
| 237 DCHECK(media_stream_manager_); | 295 DCHECK(media_stream_manager_); |
| 238 } | 296 } |
| 239 | 297 |
| 240 AudioRendererHost::~AudioRendererHost() { | 298 AudioRendererHost::~AudioRendererHost() { |
| 241 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 299 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 256 } | 314 } |
| 257 | 315 |
| 258 void AudioRendererHost::GetOutputControllers( | 316 void AudioRendererHost::GetOutputControllers( |
| 259 const RenderProcessHost::GetAudioOutputControllersCallback& | 317 const RenderProcessHost::GetAudioOutputControllersCallback& |
| 260 callback) const { | 318 callback) const { |
| 261 BrowserThread::PostTaskAndReplyWithResult( | 319 BrowserThread::PostTaskAndReplyWithResult( |
| 262 BrowserThread::IO, FROM_HERE, | 320 BrowserThread::IO, FROM_HERE, |
| 263 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); | 321 base::Bind(&AudioRendererHost::DoGetOutputControllers, this), callback); |
| 264 } | 322 } |
| 265 | 323 |
| 266 void AudioRendererHost::OnChannelClosing() { | |
| 267 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 268 // Since the IPC sender is gone, close all requested audio streams. | |
| 269 while (!audio_entries_.empty()) { | |
| 270 // Note: OnCloseStream() removes the entries from audio_entries_. | |
| 271 OnCloseStream(audio_entries_.begin()->first); | |
| 272 } | |
| 273 | |
| 274 // Remove any authorizations for streams that were not yet created | |
| 275 authorizations_.clear(); | |
| 276 } | |
| 277 | |
| 278 void AudioRendererHost::OnDestruct() const { | |
| 279 BrowserThread::DeleteOnIOThread::Destruct(this); | |
| 280 } | |
| 281 | |
| 282 void AudioRendererHost::AudioEntry::OnCreated() { | 324 void AudioRendererHost::AudioEntry::OnCreated() { |
| 283 BrowserThread::PostTask( | 325 // TODO: make sure it's safe to capture |this| in the callback. |
| 284 BrowserThread::IO, | 326 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 285 FROM_HERE, | 327 base::Bind(&AudioRendererHost::DoCompleteCreation, |
| 286 base::Bind(&AudioRendererHost::DoCompleteCreation, host_, stream_id_)); | 328 host_, this, stream_id_, callback_)); |
| 287 } | 329 } |
| 288 | 330 |
| 289 void AudioRendererHost::AudioEntry::OnPlaying() { | 331 void AudioRendererHost::AudioEntry::OnPlaying() { |
| 290 BrowserThread::PostTask( | |
| 291 BrowserThread::IO, | |
| 292 FROM_HERE, | |
| 293 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged, | |
| 294 host_, | |
| 295 stream_id_, | |
| 296 true)); | |
| 297 } | 332 } |
| 298 | 333 |
| 299 void AudioRendererHost::AudioEntry::OnPaused() { | 334 void AudioRendererHost::AudioEntry::OnPaused() { |
| 300 BrowserThread::PostTask( | |
| 301 BrowserThread::IO, | |
| 302 FROM_HERE, | |
| 303 base::Bind(&AudioRendererHost::DoNotifyStreamStateChanged, | |
| 304 host_, | |
| 305 stream_id_, | |
| 306 false)); | |
| 307 } | 335 } |
| 308 | 336 |
| 309 void AudioRendererHost::AudioEntry::OnError() { | 337 void AudioRendererHost::AudioEntry::OnError() { |
| 310 BrowserThread::PostTask( | 338 BrowserThread::PostTask( |
| 311 BrowserThread::IO, | 339 BrowserThread::IO, FROM_HERE, |
| 312 FROM_HERE, | 340 base::Bind(&AudioRendererHost::OnCloseStream, host_, stream_id_)); |
| 313 base::Bind(&AudioRendererHost::ReportErrorAndClose, host_, stream_id_)); | |
| 314 } | 341 } |
| 315 | 342 |
| 316 void AudioRendererHost::DoCompleteCreation(int stream_id) { | 343 void AudioRendererHost::DoCompleteCreation(AudioEntry* entry, |
| 344 int32_t stream_id) { |
| 317 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 345 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 318 | 346 |
| 319 if (!PeerHandle()) { | 347 media::mojom::AudioOutputStreamPtr stream_ptr; |
| 320 DLOG(WARNING) << "Renderer process handle is invalid."; | 348 entry->BindRequest(mojo::GetProxy(&stream_ptr)); |
| 321 ReportErrorAndClose(stream_id); | |
| 322 return; | |
| 323 } | |
| 324 | |
| 325 AudioEntry* const entry = LookupById(stream_id); | |
| 326 if (!entry) { | |
| 327 ReportErrorAndClose(stream_id); | |
| 328 return; | |
| 329 } | |
| 330 | |
| 331 // Once the audio stream is created then complete the creation process by | |
| 332 // mapping shared memory and sharing with the renderer process. | |
| 333 base::SharedMemoryHandle foreign_memory_handle; | |
| 334 if (!entry->shared_memory()->ShareToProcess(PeerHandle(), | |
| 335 &foreign_memory_handle)) { | |
| 336 // If we failed to map and share the shared memory then close the audio | |
| 337 // stream and send an error message. | |
| 338 ReportErrorAndClose(entry->stream_id()); | |
| 339 return; | |
| 340 } | |
| 341 | 349 |
| 342 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader()); | 350 AudioSyncReader* reader = static_cast<AudioSyncReader*>(entry->reader()); |
| 351 base::PlatformFile socket_fd = reader->GetSyncSocket(); |
| 352 mojo::ScopedHandle socket_handle = mojo::WrapPlatformFile(socket_fd); |
| 353 DCHECK(socket_handle.is_valid()); |
| 343 | 354 |
| 344 base::SyncSocket::TransitDescriptor socket_descriptor; | 355 base::SharedMemoryHandle shared_memory_handle = |
| 356 base::SharedMemory::DuplicateHandle(entry->shared_memory()->handle()); |
| 357 if (!base::SharedMemory::IsHandleValid(shared_memory_handle)) { |
| 358 // TODO: When can this happen? |
| 359 LOG(FATAL) << "Invalid shared mem handle"; |
| 360 return ReportErrorAndClose(stream_id); |
| 361 } |
| 362 mojo::ScopedSharedBufferHandle shared_buffer_handle = |
| 363 mojo::WrapSharedMemoryHandle(shared_memory_handle, |
| 364 entry->shared_memory()->requested_size(), |
| 365 false); |
| 366 DCHECK(shared_buffer_handle.is_valid()); |
| 345 | 367 |
| 346 // If we failed to prepare the sync socket for the renderer then we fail | 368 /*mojo::ScopedSharedBufferHandle shared_buffer_handle = |
| 347 // the construction of audio stream. | 369 mojo::WrapSharedMemoryHandle(shared_memory_handle, |
| 348 if (!reader->PrepareForeignSocket(PeerHandle(), &socket_descriptor)) { | 370 entry->shared_memory()->requested_size(), |
| 349 ReportErrorAndClose(entry->stream_id()); | 371 false);*/ |
| 350 return; | |
| 351 } | |
| 352 | 372 |
| 353 Send(new AudioMsg_NotifyStreamCreated( | 373 /* TODO: read comment. |
| 354 entry->stream_id(), foreign_memory_handle, socket_descriptor, | 374 // The socket sent from the browser to the renderer is a ForeignSocket, which |
| 355 entry->shared_memory()->requested_size())); | 375 // is a part of AudioSyncReader that is owned by AudioEntry. The socket handle |
| 376 // is closed when the owning AudioEntry destructs. With mojo, the ownership of |
| 377 // the handle is transferred to the target process. The handle is no longer |
| 378 // valid in the sending process, and cannot be closed there. If the socket |
| 379 // handle is closed when the AudioEntry is deleted, an error occurs. To WAR |
| 380 // this error, duplicate the socket and send the duplicate to the renderer. |
| 381 #if defined(OS_WIN) |
| 382 mojo::ScopedHandle socket_handle = |
| 383 mojo::WrapPlatformFile(socket_descriptor); |
| 384 #else |
| 385 mojo::ScopedHandle socket_handle = |
| 386 mojo::WrapPlatformFile(socket_descriptor.fd); |
| 387 #endif |
| 388 */ |
| 389 |
| 390 callback.Run(std::move(stream_ptr), std::move(shared_buffer_handle), |
| 391 std::move(socket_handle)); |
| 356 } | 392 } |
| 357 | 393 |
| 358 void AudioRendererHost::DoNotifyStreamStateChanged(int stream_id, | 394 /*void AudioRendererHost::DoNotifyStreamStateChanged(int32_t stream_id, |
| 359 bool is_playing) { | 395 bool is_playing) { |
| 360 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 396 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 361 | 397 |
| 362 AudioEntry* const entry = LookupById(stream_id); | 398 AudioEntry* const entry = LookupById(stream_id); |
| 363 if (!entry) | 399 if (!entry) |
| 364 return; | 400 return; |
| 365 | 401 |
| 366 Send(new AudioMsg_NotifyStreamStateChanged( | 402 entry->SendStreamStateResponse( |
| 367 stream_id, | 403 is_playing ? media::mojom::AudioOutputStreamState::PLAYING |
| 368 is_playing ? media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING | 404 : media::mojom::AudioOutputStreamState::PAUSED); |
| 369 : media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED)); | |
| 370 | 405 |
| 371 if (is_playing) { | 406 if (is_playing) { |
| 372 AudioStreamMonitor::StartMonitoringStream( | 407 AudioStreamMonitor::StartMonitoringStream( |
| 373 render_process_id_, | 408 render_process_id_, |
| 374 entry->render_frame_id(), | 409 entry->render_frame_id(), |
| 375 entry->stream_id(), | 410 entry->stream_id(), |
| 376 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, | 411 base::Bind(&media::AudioOutputController::ReadCurrentPowerAndClip, |
| 377 entry->controller())); | 412 entry->controller())); |
| 378 } else { | 413 } else { |
| 379 AudioStreamMonitor::StopMonitoringStream( | 414 AudioStreamMonitor::StopMonitoringStream( |
| 380 render_process_id_, entry->render_frame_id(), entry->stream_id()); | 415 render_process_id_, entry->render_frame_id(), entry->stream_id()); |
| 381 } | 416 } |
| 382 UpdateNumPlayingStreams(entry, is_playing); | 417 UpdateNumPlayingStreams(entry, is_playing); |
| 383 } | 418 }*/ |
| 384 | 419 |
| 385 RenderProcessHost::AudioOutputControllerList | 420 RenderProcessHost::AudioOutputControllerList |
| 386 AudioRendererHost::DoGetOutputControllers() const { | 421 AudioRendererHost::DoGetOutputControllers() const { |
| 387 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 422 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 388 | 423 |
| 389 RenderProcessHost::AudioOutputControllerList controllers; | 424 RenderProcessHost::AudioOutputControllerList controllers; |
| 390 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); | 425 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); |
| 391 it != audio_entries_.end(); | 426 it != audio_entries_.end(); |
| 392 ++it) { | 427 ++it) { |
| 393 controllers.push_back(it->second->controller()); | 428 controllers.push_back(it->second->controller()); |
| 394 } | 429 } |
| 395 | 430 |
| 396 return controllers; | 431 return controllers; |
| 397 } | 432 } |
| 398 | 433 |
| 399 /////////////////////////////////////////////////////////////////////////////// | 434 void AudioRendererHost::OnDeviceAuthorized( |
| 400 // IPC Messages handler | 435 int32_t stream_id, |
| 401 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { | 436 RequestDeviceAuthorizationCallback callback, |
| 402 bool handled = true; | |
| 403 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) | |
| 404 IPC_MESSAGE_HANDLER(AudioHostMsg_RequestDeviceAuthorization, | |
| 405 OnRequestDeviceAuthorization) | |
| 406 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) | |
| 407 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) | |
| 408 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) | |
| 409 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) | |
| 410 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) | |
| 411 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 412 IPC_END_MESSAGE_MAP() | |
| 413 | |
| 414 return handled; | |
| 415 } | |
| 416 | |
| 417 void AudioRendererHost::OnRequestDeviceAuthorization( | |
| 418 int stream_id, | |
| 419 int render_frame_id, | |
| 420 int session_id, | |
| 421 const std::string& device_id, | 437 const std::string& device_id, |
| 422 const url::Origin& security_origin) { | 438 const url::Origin& security_origin, |
| 423 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 439 base::TimeTicks auth_start_time, |
| 424 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); | 440 bool have_access) { |
| 425 | |
| 426 DVLOG(1) << "AudioRendererHost@" << this << "::OnRequestDeviceAuthorization" | |
| 427 << "(stream_id=" << stream_id | |
| 428 << ", render_frame_id=" << render_frame_id | |
| 429 << ", session_id=" << session_id << ", device_id=" << device_id | |
| 430 << ", security_origin=" << security_origin << ")"; | |
| 431 | |
| 432 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) | |
| 433 return; | |
| 434 | |
| 435 if (!IsValidDeviceId(device_id)) { | |
| 436 UMALogDeviceAuthorizationTime(auth_start_time); | |
| 437 Send(new AudioMsg_NotifyDeviceAuthorized( | |
| 438 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, | |
| 439 media::AudioParameters::UnavailableDeviceParams(), std::string())); | |
| 440 return; | |
| 441 } | |
| 442 | |
| 443 // If |session_id should be used for output device selection and such output | |
| 444 // device is found, reuse the input device permissions. | |
| 445 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, | |
| 446 device_id)) { | |
| 447 const StreamDeviceInfo* info = | |
| 448 media_stream_manager_->audio_input_device_manager() | |
| 449 ->GetOpenedDeviceInfoById(session_id); | |
| 450 if (info) { | |
| 451 media::AudioParameters output_params( | |
| 452 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | |
| 453 static_cast<media::ChannelLayout>( | |
| 454 info->device.matched_output.channel_layout), | |
| 455 info->device.matched_output.sample_rate, 16, | |
| 456 info->device.matched_output.frames_per_buffer); | |
| 457 output_params.set_effects(info->device.matched_output.effects); | |
| 458 authorizations_.insert(MakeAuthorizationData( | |
| 459 stream_id, true, info->device.matched_output_device_id)); | |
| 460 MaybeFixAudioParameters(&output_params); | |
| 461 UMALogDeviceAuthorizationTime(auth_start_time); | |
| 462 // Hash matched device id and pass it to the renderer | |
| 463 Send(new AudioMsg_NotifyDeviceAuthorized( | |
| 464 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, | |
| 465 GetHMACForMediaDeviceID(salt_, security_origin, | |
| 466 info->device.matched_output_device_id))); | |
| 467 return; | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 authorizations_.insert( | |
| 472 MakeAuthorizationData(stream_id, false, std::string())); | |
| 473 CheckOutputDeviceAccess( | |
| 474 render_frame_id, device_id, security_origin, | |
| 475 base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id, | |
| 476 device_id, security_origin, auth_start_time)); | |
| 477 } | |
| 478 | |
| 479 void AudioRendererHost::OnDeviceAuthorized(int stream_id, | |
| 480 const std::string& device_id, | |
| 481 const url::Origin& security_origin, | |
| 482 base::TimeTicks auth_start_time, | |
| 483 bool have_access) { | |
| 484 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 441 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 485 const auto& auth_data = authorizations_.find(stream_id); | 442 const auto& auth_data = authorizations_.find(stream_id); |
| 486 | 443 |
| 487 // A close request was received while access check was in progress. | 444 // A close request was received while access check was in progress. |
| 488 if (auth_data == authorizations_.end()) { | 445 if (auth_data == authorizations_.end()) { |
| 489 UMALogDeviceAuthorizationTime(auth_start_time); | 446 UMALogDeviceAuthorizationTime(auth_start_time); |
| 490 return; | 447 return; |
| 491 } | 448 } |
| 492 | 449 |
| 493 if (!have_access) { | 450 if (!have_access) { |
| 494 authorizations_.erase(auth_data); | 451 authorizations_.erase(auth_data); |
| 495 UMALogDeviceAuthorizationTime(auth_start_time); | 452 UMALogDeviceAuthorizationTime(auth_start_time); |
| 496 Send(new AudioMsg_NotifyDeviceAuthorized( | 453 SendAuthorizationMessage( |
| 497 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, | 454 callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_AUTHORIZED, |
| 498 media::AudioParameters::UnavailableDeviceParams(), std::string())); | 455 media::AudioParameters::UnavailableDeviceParams(), std::string()); |
| 499 return; | 456 return; |
| 500 } | 457 } |
| 501 | 458 |
| 502 // If enumerator caching is disabled, avoid the enumeration if the default | 459 // If enumerator caching is disabled, avoid the enumeration if the default |
| 503 // device is requested, since no device ID translation is needed. | 460 // device is requested, since no device ID translation is needed. |
| 504 // If enumerator caching is enabled, it is better to use its cache, even | 461 // If enumerator caching is enabled, it is better to use its cache, even |
| 505 // for the default device. | 462 // for the default device. |
| 506 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) && | 463 if (media::AudioDeviceDescription::IsDefaultDevice(device_id) && |
| 507 !media_stream_manager_->audio_output_device_enumerator() | 464 !media_stream_manager_->audio_output_device_enumerator() |
| 508 ->IsCacheEnabled()) { | 465 ->IsCacheEnabled()) { |
| 509 base::PostTaskAndReplyWithResult( | 466 base::PostTaskAndReplyWithResult( |
| 510 audio_manager_->GetTaskRunner(), FROM_HERE, | 467 audio_manager_->GetTaskRunner(), FROM_HERE, |
| 511 base::Bind(&GetDefaultDeviceInfoOnDeviceThread, audio_manager_), | 468 base::Bind(&GetDefaultDeviceInfoOnDeviceThread, audio_manager_), |
| 512 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id, | 469 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, stream_id, |
| 513 auth_start_time, true)); | 470 auth_start_time, callback, true)); |
| 514 } else { | 471 } else { |
| 515 media_stream_manager_->audio_output_device_enumerator()->Enumerate( | 472 media_stream_manager_->audio_output_device_enumerator()->Enumerate( |
| 516 base::Bind(&AudioRendererHost::TranslateDeviceID, this, device_id, | 473 base::Bind(&AudioRendererHost::TranslateDeviceID, this, device_id, |
| 517 security_origin, | 474 security_origin, |
| 518 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, | 475 base::Bind(&AudioRendererHost::OnDeviceIDTranslated, this, |
| 519 stream_id, auth_start_time))); | 476 stream_id, auth_start_time, callback))); |
| 520 } | 477 } |
| 521 } | 478 } |
| 522 | 479 |
| 523 void AudioRendererHost::OnDeviceIDTranslated( | 480 void AudioRendererHost::OnDeviceIDTranslated( |
| 524 int stream_id, | 481 int32_t stream_id, |
| 525 base::TimeTicks auth_start_time, | 482 base::TimeTicks auth_start_time, |
| 483 RequestDeviceAuthorizationCallback callback, |
| 526 bool device_found, | 484 bool device_found, |
| 527 const AudioOutputDeviceInfo& device_info) { | 485 const AudioOutputDeviceInfo& device_info) { |
| 528 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 486 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 529 const auto& auth_data = authorizations_.find(stream_id); | 487 const auto& auth_data = authorizations_.find(stream_id); |
| 530 | 488 |
| 531 // A close request was received while translation was in progress | 489 // A close request was received while translation was in progress |
| 532 if (auth_data == authorizations_.end()) { | 490 if (auth_data == authorizations_.end()) { |
| 533 UMALogDeviceAuthorizationTime(auth_start_time); | 491 UMALogDeviceAuthorizationTime(auth_start_time); |
| 534 return; | 492 return; |
| 535 } | 493 } |
| 536 | 494 |
| 537 if (!device_found) { | 495 if (!device_found) { |
| 538 authorizations_.erase(auth_data); | 496 authorizations_.erase(auth_data); |
| 539 UMALogDeviceAuthorizationTime(auth_start_time); | 497 UMALogDeviceAuthorizationTime(auth_start_time); |
| 540 Send(new AudioMsg_NotifyDeviceAuthorized( | 498 SendAuthorizationMessage( |
| 541 stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, | 499 callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, |
| 542 media::AudioParameters::UnavailableDeviceParams(), std::string())); | 500 media::AudioParameters::UnavailableDeviceParams(), std::string()); |
| 543 return; | 501 return; |
| 544 } | 502 } |
| 545 | 503 |
| 546 auth_data->second.first = true; | 504 auth_data->second.first = true; |
| 547 auth_data->second.second = device_info.unique_id; | 505 auth_data->second.second = device_info.unique_id; |
| 548 | 506 |
| 549 media::AudioParameters output_params = device_info.output_params; | 507 media::AudioParameters output_params = device_info.output_params; |
| 550 MaybeFixAudioParameters(&output_params); | 508 MaybeFixAudioParameters(&output_params); |
| 551 UMALogDeviceAuthorizationTime(auth_start_time); | 509 UMALogDeviceAuthorizationTime(auth_start_time); |
| 552 Send(new AudioMsg_NotifyDeviceAuthorized( | 510 SendAuthorizationMessage(callback, stream_id, media::OUTPUT_DEVICE_STATUS_OK, |
| 553 stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, std::string())); | 511 output_params, std::string()); |
| 554 } | 512 } |
| 555 | 513 |
| 556 void AudioRendererHost::OnCreateStream(int stream_id, | 514 void AudioRendererHost::DoCreateStream(int32_t stream_id, |
| 557 int render_frame_id, | |
| 558 const media::AudioParameters& params) { | |
| 559 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 560 DVLOG(1) << "AudioRendererHost@" << this << "::OnCreateStream" | |
| 561 << "(stream_id=" << stream_id << ")"; | |
| 562 | |
| 563 // Determine whether to use the device_unique_id from an authorization, or an | |
| 564 // empty string (i.e., when no previous authorization was requested, assume | |
| 565 // default device). | |
| 566 std::string device_unique_id; | |
| 567 const auto& auth_data = authorizations_.find(stream_id); | |
| 568 if (auth_data != authorizations_.end()) { | |
| 569 CHECK(auth_data->second.first); | |
| 570 device_unique_id.swap(auth_data->second.second); | |
| 571 authorizations_.erase(auth_data); | |
| 572 } | |
| 573 | |
| 574 #if DCHECK_IS_ON() | |
| 575 // When DCHECKs are turned on, hop over to the UI thread to validate the | |
| 576 // |render_frame_id|, then continue stream creation on the IO thread. See | |
| 577 // comment at top of DoCreateStream() for further details. | |
| 578 BrowserThread::PostTask( | |
| 579 BrowserThread::UI, FROM_HERE, | |
| 580 base::Bind(validate_render_frame_id_function_, render_process_id_, | |
| 581 render_frame_id, | |
| 582 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id, | |
| 583 render_frame_id, params, device_unique_id))); | |
| 584 #else | |
| 585 DoCreateStream(stream_id, render_frame_id, params, device_unique_id, | |
| 586 render_frame_id > 0); | |
| 587 #endif // DCHECK_IS_ON() | |
| 588 } | |
| 589 | |
| 590 void AudioRendererHost::DoCreateStream(int stream_id, | |
| 591 int render_frame_id, | 515 int render_frame_id, |
| 592 const media::AudioParameters& params, | 516 const media::AudioParameters& params, |
| 593 const std::string& device_unique_id, | 517 const std::string& device_unique_id, |
| 594 bool render_frame_id_is_valid) { | 518 bool render_frame_id_is_valid) { |
| 595 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 519 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 596 | 520 |
| 597 // Fail early if either of two sanity-checks fail: | 521 // Fail early if either of two sanity-checks fail: |
| 598 // 1. There should not yet exist an AudioEntry for the given |stream_id| | 522 // 1. There should not yet exist an AudioEntry for the given |stream_id| |
| 599 // since the renderer may not create two streams with the same ID. | 523 // since the renderer may not create two streams with the same ID. |
| 600 // 2. The render frame ID was either invalid or the render frame host it | 524 // 2. The render frame ID was either invalid or the render frame host it |
| (...skipping 11 matching lines...) Expand all Loading... |
| 612 if (!render_frame_id_is_valid) { | 536 if (!render_frame_id_is_valid) { |
| 613 SendErrorMessage(stream_id); | 537 SendErrorMessage(stream_id); |
| 614 return; | 538 return; |
| 615 } | 539 } |
| 616 | 540 |
| 617 // Create the shared memory and share with the renderer process. | 541 // Create the shared memory and share with the renderer process. |
| 618 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + | 542 uint32_t shared_memory_size = sizeof(media::AudioOutputBufferParameters) + |
| 619 AudioBus::CalculateMemorySize(params); | 543 AudioBus::CalculateMemorySize(params); |
| 620 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); | 544 std::unique_ptr<base::SharedMemory> shared_memory(new base::SharedMemory()); |
| 621 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { | 545 if (!shared_memory->CreateAndMapAnonymous(shared_memory_size)) { |
| 546 // client->OnStreamStateChange(media::mojom::AudioOutputStreamState::ERROR); |
| 622 SendErrorMessage(stream_id); | 547 SendErrorMessage(stream_id); |
| 623 return; | 548 return; |
| 624 } | 549 } |
| 625 | 550 |
| 626 std::unique_ptr<AudioSyncReader> reader( | 551 std::unique_ptr<AudioSyncReader> reader( |
| 627 new AudioSyncReader(shared_memory.get(), params)); | 552 new AudioSyncReader(shared_memory.get(), params)); |
| 628 if (!reader->Init()) { | 553 if (!reader->Init()) { |
| 629 SendErrorMessage(stream_id); | 554 SendErrorMessage(stream_id); |
| 630 return; | 555 return; |
| 631 } | 556 } |
| 632 | 557 |
| 633 MediaObserver* const media_observer = | 558 MediaObserver* const media_observer = |
| 634 GetContentClient()->browser()->GetMediaObserver(); | 559 GetContentClient()->browser()->GetMediaObserver(); |
| 635 if (media_observer) | 560 if (media_observer) |
| 636 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); | 561 media_observer->OnCreatingAudioStream(render_process_id_, render_frame_id); |
| 637 | 562 |
| 638 std::unique_ptr<AudioEntry> entry( | 563 std::unique_ptr<AudioEntry> entry(new AudioEntry( |
| 639 new AudioEntry(this, stream_id, render_frame_id, params, device_unique_id, | 564 this, callback, stream_id, render_frame_id, params, device_unique_id, |
| 640 std::move(shared_memory), std::move(reader))); | 565 std::move(shared_memory), std::move(reader))); |
| 641 if (mirroring_manager_) { | 566 if (mirroring_manager_) { |
| 642 mirroring_manager_->AddDiverter( | 567 mirroring_manager_->AddDiverter( |
| 643 render_process_id_, entry->render_frame_id(), entry->controller()); | 568 render_process_id_, entry->render_frame_id(), entry->controller()); |
| 644 } | 569 } |
| 645 audio_entries_.insert(std::make_pair(stream_id, entry.release())); | 570 audio_entries_.insert(std::make_pair(stream_id, entry.release())); |
| 646 g_audio_streams_tracker.Get().IncreaseStreamCount(); | 571 g_audio_streams_tracker.Get().IncreaseStreamCount(); |
| 647 | 572 |
| 648 audio_log_->OnCreated(stream_id, params, device_unique_id); | 573 audio_log_->OnCreated(stream_id, params, device_unique_id); |
| 649 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( | 574 MediaInternals::GetInstance()->SetWebContentsTitleForAudioLogEntry( |
| 650 stream_id, render_process_id_, render_frame_id, audio_log_.get()); | 575 stream_id, render_process_id_, render_frame_id, audio_log_.get()); |
| 651 | 576 |
| 652 if (audio_entries_.size() > max_simultaneous_streams_) | 577 if (audio_entries_.size() > max_simultaneous_streams_) |
| 653 max_simultaneous_streams_ = audio_entries_.size(); | 578 max_simultaneous_streams_ = audio_entries_.size(); |
| 654 } | 579 } |
| 655 | 580 |
| 656 void AudioRendererHost::OnPlayStream(int stream_id) { | 581 void AudioRendererHost::OnPlayStream(int32_t stream_id) { |
| 657 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 582 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 658 | 583 |
| 659 AudioEntry* entry = LookupById(stream_id); | 584 AudioEntry* entry = LookupById(stream_id); |
| 660 if (!entry) { | 585 if (!entry) { |
| 661 SendErrorMessage(stream_id); | 586 SendErrorMessage(stream_id); |
| 662 return; | 587 return; |
| 663 } | 588 } |
| 664 | 589 |
| 665 entry->controller()->Play(); | 590 entry->controller()->Play(); |
| 666 audio_log_->OnStarted(stream_id); | 591 audio_log_->OnStarted(stream_id); |
| 667 } | 592 } |
| 668 | 593 |
| 669 void AudioRendererHost::OnPauseStream(int stream_id) { | 594 void AudioRendererHost::OnPauseStream(int32_t stream_id) { |
| 670 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 595 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 671 | 596 |
| 672 AudioEntry* entry = LookupById(stream_id); | 597 AudioEntry* entry = LookupById(stream_id); |
| 673 if (!entry) { | 598 if (!entry) { |
| 674 SendErrorMessage(stream_id); | 599 SendErrorMessage(stream_id); |
| 675 return; | 600 return; |
| 676 } | 601 } |
| 677 | 602 |
| 678 entry->controller()->Pause(); | 603 entry->controller()->Pause(); |
| 679 audio_log_->OnStopped(stream_id); | 604 audio_log_->OnStopped(stream_id); |
| 680 } | 605 } |
| 681 | 606 |
| 682 void AudioRendererHost::OnSetVolume(int stream_id, double volume) { | 607 void AudioRendererHost::OnSetVolume(int32_t stream_id, double volume) { |
| 683 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 608 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 684 | 609 |
| 685 AudioEntry* entry = LookupById(stream_id); | 610 AudioEntry* entry = LookupById(stream_id); |
| 686 if (!entry) { | 611 if (!entry) { |
| 687 SendErrorMessage(stream_id); | 612 SendErrorMessage(stream_id); |
| 688 return; | 613 return; |
| 689 } | 614 } |
| 690 | 615 |
| 691 // Make sure the volume is valid. | 616 // Make sure the volume is valid. |
| 692 if (volume < 0 || volume > 1.0) | 617 if (volume < 0 || volume > 1.0) |
| 693 return; | 618 return; |
| 694 entry->controller()->SetVolume(volume); | 619 entry->controller()->SetVolume(volume); |
| 695 audio_log_->OnSetVolume(stream_id, volume); | 620 audio_log_->OnSetVolume(stream_id, volume); |
| 696 } | 621 } |
| 697 | 622 |
| 698 void AudioRendererHost::SendErrorMessage(int stream_id) { | 623 void AudioRendererHost::SendErrorMessage(int32_t stream_id) { |
| 699 Send(new AudioMsg_NotifyStreamStateChanged( | 624 // TODO |
| 700 stream_id, media::AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR)); | |
| 701 } | 625 } |
| 702 | 626 |
| 703 void AudioRendererHost::OnCloseStream(int stream_id) { | 627 void AudioRendererHost::OnCloseStream(int32_t stream_id) { |
| 704 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 628 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 705 authorizations_.erase(stream_id); | 629 authorizations_.erase(stream_id); |
| 706 | 630 |
| 707 // Prevent oustanding callbacks from attempting to close/delete the same | 631 // Prevent oustanding callbacks from attempting to close/delete the same |
| 708 // AudioEntry twice. | 632 // AudioEntry twice. |
| 709 AudioEntryMap::iterator i = audio_entries_.find(stream_id); | 633 AudioEntryMap::iterator i = audio_entries_.find(stream_id); |
| 710 if (i == audio_entries_.end()) | 634 if (i == audio_entries_.end()) |
| 711 return; | 635 return; |
| 712 std::unique_ptr<AudioEntry> entry(i->second); | 636 std::unique_ptr<AudioEntry> entry(i->second); |
| 713 audio_entries_.erase(i); | 637 audio_entries_.erase(i); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 728 // re-start the default AudioOutputStream and cause a brief audio blip to come | 652 // re-start the default AudioOutputStream and cause a brief audio blip to come |
| 729 // out the user's speakers. http://crbug.com/474432 | 653 // out the user's speakers. http://crbug.com/474432 |
| 730 if (mirroring_manager_) | 654 if (mirroring_manager_) |
| 731 mirroring_manager_->RemoveDiverter(entry->controller()); | 655 mirroring_manager_->RemoveDiverter(entry->controller()); |
| 732 | 656 |
| 733 AudioStreamMonitor::StopMonitoringStream( | 657 AudioStreamMonitor::StopMonitoringStream( |
| 734 render_process_id_, entry->render_frame_id(), entry->stream_id()); | 658 render_process_id_, entry->render_frame_id(), entry->stream_id()); |
| 735 UpdateNumPlayingStreams(entry.get(), false); | 659 UpdateNumPlayingStreams(entry.get(), false); |
| 736 } | 660 } |
| 737 | 661 |
| 738 void AudioRendererHost::ReportErrorAndClose(int stream_id) { | 662 void AudioRendererHost::ReportErrorAndClose(int32_t stream_id) { |
| 739 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 663 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 740 | 664 |
| 741 // Make sure this isn't a stray callback executing after the stream has been | 665 // Make sure this isn't a stray callback executing after the stream has been |
| 742 // closed, so error notifications aren't sent after clients believe the stream | 666 // closed, so error notifications aren't sent after clients believe the stream |
| 743 // is closed. | 667 // is closed. |
| 744 if (!LookupById(stream_id)) | 668 if (!LookupById(stream_id)) |
| 745 return; | 669 return; |
| 746 | 670 |
| 747 SendErrorMessage(stream_id); | 671 SendErrorMessage(stream_id); |
| 748 | 672 |
| 749 audio_log_->OnError(stream_id); | 673 audio_log_->OnError(stream_id); |
| 750 OnCloseStream(stream_id); | 674 OnCloseStream(stream_id); |
| 751 } | 675 } |
| 752 | 676 |
| 753 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById(int stream_id) { | 677 AudioRendererHost::AudioEntry* AudioRendererHost::LookupById( |
| 678 int32_t stream_id) { |
| 754 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 679 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 755 | 680 |
| 756 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id); | 681 AudioEntryMap::const_iterator i = audio_entries_.find(stream_id); |
| 757 return i != audio_entries_.end() ? i->second : NULL; | 682 return i != audio_entries_.end() ? i->second : NULL; |
| 758 } | 683 } |
| 759 | 684 |
| 760 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry, | 685 void AudioRendererHost::UpdateNumPlayingStreams(AudioEntry* entry, |
| 761 bool is_playing) { | 686 bool is_playing) { |
| 762 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 687 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 763 if (entry->playing() == is_playing) | 688 if (entry->playing() == is_playing) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 784 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, | 709 base::Bind(&NotifyRenderProcessHostThatAudioStateChanged, |
| 785 render_process_id_)); | 710 render_process_id_)); |
| 786 } | 711 } |
| 787 } | 712 } |
| 788 } | 713 } |
| 789 | 714 |
| 790 bool AudioRendererHost::HasActiveAudio() { | 715 bool AudioRendererHost::HasActiveAudio() { |
| 791 return !base::AtomicRefCountIsZero(&num_playing_streams_); | 716 return !base::AtomicRefCountIsZero(&num_playing_streams_); |
| 792 } | 717 } |
| 793 | 718 |
| 719 void AudioRendererHost::BindRequest(media::mojom::AudioOutputRequest request) { |
| 720 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 721 |
| 722 binding_.reset( |
| 723 new mojo::Binding<media::mojom::AudioOutput>(this, std::move(request))); |
| 724 } |
| 725 |
| 726 // media::mojom::AudioOutput implementation |
| 727 void AudioRendererHost::RequestDeviceAuthorization( |
| 728 int64_t render_frame_id, |
| 729 int64_t session_id, |
| 730 const mojo::String& device_id, |
| 731 const url::Origin& origin, |
| 732 const RequestDeviceAuthorizationCallback& callback) { |
| 733 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 734 const base::TimeTicks auth_start_time = base::TimeTicks::Now(); |
| 735 int32_t stream_id = next_stream_id++; |
| 736 |
| 737 DVLOG(1) << "AudioRendererHost@" << this << "::RequestDeviceAuthorization" |
| 738 << "(stream_id=" << stream_id |
| 739 << ", render_frame_id=" << render_frame_id |
| 740 << ", session_id=" << session_id << ", device_id=" << device_id |
| 741 << ", origin=" << origin << ")"; |
| 742 |
| 743 if (LookupById(stream_id) || IsAuthorizationStarted(stream_id)) |
| 744 return; |
| 745 |
| 746 if (!IsValidDeviceId(device_id)) { |
| 747 UMALogDeviceAuthorizationTime(auth_start_time); |
| 748 SendAuthorizationMessage( |
| 749 callback, stream_id, media::OUTPUT_DEVICE_STATUS_ERROR_NOT_FOUND, |
| 750 media::AudioParameters::UnavailableDeviceParams(), std::string()); |
| 751 return; |
| 752 } |
| 753 |
| 754 // If |session_id should be used for output device selection and such output |
| 755 // device is found, reuse the input device permissions. |
| 756 if (media::AudioDeviceDescription::UseSessionIdToSelectDevice(session_id, |
| 757 device_id)) { |
| 758 const StreamDeviceInfo* info = |
| 759 media_stream_manager_->audio_input_device_manager() |
| 760 ->GetOpenedDeviceInfoById(session_id); |
| 761 if (info) { |
| 762 media::AudioParameters output_params( |
| 763 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 764 static_cast<media::ChannelLayout>( |
| 765 info->device.matched_output.channel_layout), |
| 766 info->device.matched_output.sample_rate, 16, |
| 767 info->device.matched_output.frames_per_buffer); |
| 768 output_params.set_effects(info->device.matched_output.effects); |
| 769 authorizations_.insert(MakeAuthorizationData( |
| 770 stream_id, true, info->device.matched_output_device_id)); |
| 771 MaybeFixAudioParameters(&output_params); |
| 772 UMALogDeviceAuthorizationTime(auth_start_time); |
| 773 // Hash matched device id and pass it to the renderer |
| 774 SendAuthorizationMessage( |
| 775 callback, stream_id, media::OUTPUT_DEVICE_STATUS_OK, output_params, |
| 776 GetHMACForMediaDeviceID(salt_, origin, |
| 777 info->device.matched_output_device_id)); |
| 778 return; |
| 779 } |
| 780 } |
| 781 |
| 782 authorizations_.insert( |
| 783 MakeAuthorizationData(stream_id, false, std::string())); |
| 784 CheckOutputDeviceAccess( |
| 785 render_frame_id, device_id, origin, |
| 786 base::Bind(&AudioRendererHost::OnDeviceAuthorized, this, stream_id, |
| 787 callback, device_id, origin, auth_start_time)); |
| 788 } |
| 789 |
| 790 void AudioRendererHost::CreateStream(int32_t stream_id, |
| 791 int render_frame_id, |
| 792 const media::AudioParameters& params) { |
| 793 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 794 DVLOG(1) << "AudioRendererHost@" << this << "::CreateStream" |
| 795 << "(stream_id=" << stream_id << ")"; |
| 796 |
| 797 // Determine whether to use the device_unique_id from an authorization, or an |
| 798 // empty string (i.e., when no previous authorization was requested, assume |
| 799 // default device). |
| 800 std::string device_unique_id; |
| 801 const auto& auth_data = authorizations_.find(stream_id); |
| 802 if (auth_data != authorizations_.end()) { |
| 803 CHECK(auth_data->second.first); |
| 804 device_unique_id.swap(auth_data->second.second); |
| 805 authorizations_.erase(auth_data); |
| 806 } |
| 807 |
| 808 #if DCHECK_IS_ON() |
| 809 // When DCHECKs are turned on, hop over to the UI thread to validate the |
| 810 // |render_frame_id|, then continue stream creation on the IO thread. See |
| 811 // comment at top of DoCreateStream() for further details. |
| 812 BrowserThread::PostTask( |
| 813 BrowserThread::UI, FROM_HERE, |
| 814 base::Bind(validate_render_frame_id_function_, render_process_id_, |
| 815 render_frame_id, |
| 816 base::Bind(&AudioRendererHost::DoCreateStream, this, stream_id, |
| 817 render_frame_id, params, device_unique_id))); |
| 818 #else |
| 819 DoCreateStream(stream_id, render_frame_id, params, device_unique_id, |
| 820 render_frame_id > 0); |
| 821 #endif // DCHECK_IS_ON() |
| 822 } |
| 823 |
| 824 void AudioRendererHost::CloseStream(int32_t stream_id) { |
| 825 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 826 |
| 827 OnCloseStream(stream_id); |
| 828 } |
| 829 |
| 830 void AudioRendererHost::SendAuthorizationMessage( |
| 831 RequestDeviceAuthorizationCallback callback, |
| 832 int32_t stream_id, |
| 833 media::OutputDeviceStatus status, |
| 834 const media::AudioParameters& params, |
| 835 const std::string& matched_device_id) { |
| 836 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 837 |
| 838 callback.Run(status, params, matched_device_id); |
| 839 } |
| 840 |
| 794 void AudioRendererHost::CheckOutputDeviceAccess( | 841 void AudioRendererHost::CheckOutputDeviceAccess( |
| 795 int render_frame_id, | 842 int render_frame_id, |
| 796 const std::string& device_id, | 843 const std::string& device_id, |
| 797 const url::Origin& security_origin, | 844 const url::Origin& security_origin, |
| 798 const OutputDeviceAccessCB& callback) { | 845 const OutputDeviceAccessCB& callback) { |
| 799 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 846 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 800 | 847 |
| 801 // Check security origin if nondefault device is requested. | 848 // Check security origin if nondefault device is requested. |
| 802 // Ignore check for default device, which is always authorized. | 849 // Ignore check for default device, which is always authorized. |
| 803 if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) && | 850 if (!media::AudioDeviceDescription::IsDefaultDevice(device_id) && |
| 804 !MediaStreamManager::IsOriginAllowed(render_process_id_, | 851 !MediaStreamManager::IsOriginAllowed(render_process_id_, |
| 805 security_origin)) { | 852 security_origin)) { |
| 806 content::bad_message::ReceivedBadMessage(this, | 853 // content::bad_message::ReceivedBadMessage(this, |
| 807 bad_message::ARH_UNAUTHORIZED_URL); | 854 // bad_message::ARH_UNAUTHORIZED_URL); |
| 808 return; | 855 return; |
| 809 } | 856 } |
| 810 | 857 |
| 811 if (device_id.empty()) { | 858 if (device_id.empty()) { |
| 812 callback.Run(true); | 859 callback.Run(true); |
| 813 } else { | 860 } else { |
| 814 // Check that MediaStream device permissions have been granted, | 861 // Check that MediaStream device permissions have been granted, |
| 815 // hence the use of a MediaStreamUIProxy. | 862 // hence the use of a MediaStreamUIProxy. |
| 816 std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create(); | 863 std::unique_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create(); |
| 817 | 864 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 854 return; | 901 return; |
| 855 } | 902 } |
| 856 } | 903 } |
| 857 DCHECK(!device_id.empty()); // Default device must always be found | 904 DCHECK(!device_id.empty()); // Default device must always be found |
| 858 AudioOutputDeviceInfo device_info = { | 905 AudioOutputDeviceInfo device_info = { |
| 859 std::string(), std::string(), | 906 std::string(), std::string(), |
| 860 media::AudioParameters::UnavailableDeviceParams()}; | 907 media::AudioParameters::UnavailableDeviceParams()}; |
| 861 callback.Run(false, device_info); | 908 callback.Run(false, device_info); |
| 862 } | 909 } |
| 863 | 910 |
| 864 bool AudioRendererHost::IsAuthorizationStarted(int stream_id) { | 911 bool AudioRendererHost::IsAuthorizationStarted(int32_t stream_id) { |
| 865 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 912 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 866 const auto& i = authorizations_.find(stream_id); | 913 const auto& i = authorizations_.find(stream_id); |
| 867 return i != authorizations_.end(); | 914 return i != authorizations_.end(); |
| 868 } | 915 } |
| 869 | 916 |
| 870 } // namespace content | 917 } // namespace content |
| OLD | NEW |