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 3 // found in the LICENSE file. 4 5 #include "content/renderer/media/renderer_webaudiodevice_impl.h" 6 7 #include "base/command_line.h" 8 #include "base/logging.h" 9 #include "content/renderer/media/audio_device_factory.h" 10 #include "content/renderer/render_view_impl.h" 11 #include "media/audio/audio_output_device.h" 12 #include "media/base/media_switches.h" 13 #include "third_party/WebKit/public/web/WebFrame.h" 14 #include "third_party/WebKit/public/web/WebView.h" 15 16 using blink::WebAudioDevice; 17 using blink::WebFrame; 18 using blink::WebVector; 19 using blink::WebView; 20 21 namespace content { 22 23 RendererWebAudioDeviceImpl::RendererWebAudioDeviceImpl( 24 const media::AudioParameters& params, 25 WebAudioDevice::RenderCallback* callback, 26 int session_id) 27 : params_(params), 28 client_callback_(callback), 29 session_id_(session_id) { 30 DCHECK(client_callback_); 31 } 32 33 RendererWebAudioDeviceImpl::~RendererWebAudioDeviceImpl() { 34 DCHECK(!output_device_.get()); 35 } 36 37 void RendererWebAudioDeviceImpl::start() { 38 DCHECK(thread_checker_.CalledOnValidThread()); 39 40 if (output_device_.get()) 41 return; // Already started. 42 43 // Assumption: This method is being invoked within a V8 call stack. CHECKs 44 // will fail in the call to frameForCurrentContext() otherwise. 45 // 46 // Therefore, we can perform look-ups to determine which RenderView is 47 // starting the audio device. The reason for all this is because the creator 48 // of the WebAudio objects might not be the actual source of the audio (e.g., 49 // an extension creates a object that is passed and used within a page). 50 WebFrame* const web_frame = WebFrame::frameForCurrentContext(); 51 WebView* const web_view = web_frame ? web_frame->view() : NULL; 52 RenderViewImpl* const render_view = 53 web_view ? RenderViewImpl::FromWebView(web_view) : NULL; 54 output_device_ = AudioDeviceFactory::NewOutputDevice( 55 render_view ? render_view->routing_id() : MSG_ROUTING_NONE); 56 output_device_->InitializeUnifiedStream(params_, this, session_id_); 57 output_device_->Start(); 58 // Note: Default behavior is to auto-play on start. 59 } 60 61 void RendererWebAudioDeviceImpl::stop() { 62 DCHECK(thread_checker_.CalledOnValidThread()); 63 64 if (output_device_.get()) { 65 output_device_->Stop(); 66 output_device_ = NULL; 67 } 68 } 69 70 double RendererWebAudioDeviceImpl::sampleRate() { 71 return params_.sample_rate(); 72 } 73 74 int RendererWebAudioDeviceImpl::Render(media::AudioBus* dest, 75 int audio_delay_milliseconds) { 76 RenderIO(NULL, dest, audio_delay_milliseconds); 77 return dest->frames(); 78 } 79 80 void RendererWebAudioDeviceImpl::RenderIO(media::AudioBus* source, 81 media::AudioBus* dest, 82 int audio_delay_milliseconds) { 83 // Make the client callback for an I/O cycle. 84 if (client_callback_) { 85 // Wrap the input pointers using WebVector. 86 size_t source_channels = 87 source ? static_cast<size_t>(source->channels()) : 0; 88 WebVector<float*> web_audio_source_data(source_channels); 89 for (size_t i = 0; i < source_channels; ++i) 90 web_audio_source_data[i] = source->channel(i); 91 92 // Wrap the output pointers using WebVector. 93 WebVector<float*> web_audio_dest_data( 94 static_cast<size_t>(dest->channels())); 95 for (int i = 0; i < dest->channels(); ++i) 96 web_audio_dest_data[i] = dest->channel(i); 97 98 client_callback_->render(web_audio_source_data, 99 web_audio_dest_data, 100 dest->frames()); 101 } 102 } 103 104 void RendererWebAudioDeviceImpl::OnRenderError() { 105 // TODO(crogers): implement error handling. 106 } 107 108 } // namespace content 109