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.
5 #include "content/renderer/pepper/pepper_platform_audio_input.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "build/build_config.h"
11 #include "content/child/child_process.h"
12 #include "content/renderer/media/audio_input_message_filter.h"
13 #include "content/renderer/pepper/pepper_audio_input_host.h"
14 #include "content/renderer/pepper/pepper_media_device_manager.h"
15 #include "content/renderer/render_thread_impl.h"
16 #include "content/renderer/render_view_impl.h"
17 #include "media/audio/audio_manager_base.h"
18 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
24 PepperPlatformAudioInput* PepperPlatformAudioInput::Create(
25 const base::WeakPtr<RenderViewImpl>& render_view,
26 const std::string& device_id,
27 const GURL& document_url,
29 int frames_per_buffer,
30 PepperAudioInputHost* client) {
31 scoped_refptr<PepperPlatformAudioInput> audio_input(
32 new PepperPlatformAudioInput());
33 if (audio_input->Initialize(render_view, device_id, document_url,
34 sample_rate, frames_per_buffer, client)) {
35 // Balanced by Release invoked in
36 // PepperPlatformAudioInput::ShutDownOnIOThread().
37 audio_input->AddRef();
38 return audio_input.get();
43 void PepperPlatformAudioInput::StartCapture() {
44 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
46 io_message_loop_proxy_->PostTask(
48 base::Bind(&PepperPlatformAudioInput::StartCaptureOnIOThread, this));
51 void PepperPlatformAudioInput::StopCapture() {
52 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
54 io_message_loop_proxy_->PostTask(
56 base::Bind(&PepperPlatformAudioInput::StopCaptureOnIOThread, this));
59 void PepperPlatformAudioInput::ShutDown() {
60 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
62 // Make sure we don't call shutdown more than once.
66 // Called on the main thread to stop all audio callbacks. We must only change
67 // the client on the main thread, and the delegates from the I/O thread.
69 io_message_loop_proxy_->PostTask(
71 base::Bind(&PepperPlatformAudioInput::ShutDownOnIOThread, this));
74 void PepperPlatformAudioInput::OnStreamCreated(
75 base::SharedMemoryHandle handle,
76 base::SyncSocket::Handle socket_handle,
81 DCHECK(socket_handle);
83 DCHECK_NE(-1, handle.fd);
84 DCHECK_NE(-1, socket_handle);
87 // TODO(yzshen): Make use of circular buffer scheme. crbug.com/181449.
88 DCHECK_EQ(1, total_segments);
90 if (base::MessageLoopProxy::current().get() !=
91 main_message_loop_proxy_.get()) {
92 // If shutdown has occurred, |client_| will be NULL and the handles will be
93 // cleaned up on the main thread.
94 main_message_loop_proxy_->PostTask(
96 base::Bind(&PepperPlatformAudioInput::OnStreamCreated, this,
97 handle, socket_handle, length, total_segments));
99 // Must dereference the client only on the main thread. Shutdown may have
100 // occurred while the request was in-flight, so we need to NULL check.
102 client_->StreamCreated(handle, length, socket_handle);
104 // Clean up the handles.
105 base::SyncSocket temp_socket(socket_handle);
106 base::SharedMemory temp_shared_memory(handle, false);
111 void PepperPlatformAudioInput::OnVolume(double volume) {}
113 void PepperPlatformAudioInput::OnStateChanged(
114 media::AudioInputIPCDelegate::State state) {
117 void PepperPlatformAudioInput::OnIPCClosed() {
121 PepperPlatformAudioInput::~PepperPlatformAudioInput() {
122 // Make sure we have been shut down. Warning: this may happen on the I/O
124 // Although these members should be accessed on a specific thread (either the
125 // main thread or the I/O thread), it should be fine to examine their value
129 DCHECK(label_.empty());
130 DCHECK(!pending_open_device_);
133 PepperPlatformAudioInput::PepperPlatformAudioInput()
135 main_message_loop_proxy_(base::MessageLoopProxy::current()),
136 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()),
137 create_stream_sent_(false),
138 pending_open_device_(false),
139 pending_open_device_id_(-1) {
142 bool PepperPlatformAudioInput::Initialize(
143 const base::WeakPtr<RenderViewImpl>& render_view,
144 const std::string& device_id,
145 const GURL& document_url,
147 int frames_per_buffer,
148 PepperAudioInputHost* client) {
149 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
151 if (!render_view.get() || !client)
154 ipc_ = RenderThreadImpl::current()->audio_input_message_filter()->
155 CreateAudioInputIPC(render_view->GetRoutingID());
157 render_view_ = render_view;
160 params_.Reset(media::AudioParameters::AUDIO_PCM_LINEAR,
161 media::CHANNEL_LAYOUT_MONO, ppapi::kAudioInputChannels, 0,
162 sample_rate, ppapi::kBitsPerAudioInputSample,
165 // We need to open the device and obtain the label and session ID before
167 pending_open_device_id_ = GetMediaDeviceManager()->OpenDevice(
168 PP_DEVICETYPE_DEV_AUDIOCAPTURE,
169 device_id.empty() ? media::AudioManagerBase::kDefaultDeviceId : device_id,
171 base::Bind(&PepperPlatformAudioInput::OnDeviceOpened, this));
172 pending_open_device_ = true;
177 void PepperPlatformAudioInput::InitializeOnIOThread(int session_id) {
178 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
183 // We will be notified by OnStreamCreated().
184 create_stream_sent_ = true;
185 ipc_->CreateStream(this, session_id, params_, false, 1);
188 void PepperPlatformAudioInput::StartCaptureOnIOThread() {
189 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
192 ipc_->RecordStream();
195 void PepperPlatformAudioInput::StopCaptureOnIOThread() {
196 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
198 // TODO(yzshen): We cannot re-start capturing if the stream is closed.
199 if (ipc_ && create_stream_sent_) {
205 void PepperPlatformAudioInput::ShutDownOnIOThread() {
206 DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
208 StopCaptureOnIOThread();
210 main_message_loop_proxy_->PostTask(
212 base::Bind(&PepperPlatformAudioInput::CloseDevice, this));
214 Release(); // Release for the delegate, balances out the reference taken in
215 // PepperPlatformAudioInput::Create.
218 void PepperPlatformAudioInput::OnDeviceOpened(int request_id,
220 const std::string& label) {
221 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
223 pending_open_device_ = false;
224 pending_open_device_id_ = -1;
226 if (succeeded && render_view_.get()) {
227 DCHECK(!label.empty());
231 int session_id = GetMediaDeviceManager()->GetSessionID(
232 PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
233 io_message_loop_proxy_->PostTask(
235 base::Bind(&PepperPlatformAudioInput::InitializeOnIOThread,
238 // Shutdown has occurred.
242 NotifyStreamCreationFailed();
246 void PepperPlatformAudioInput::CloseDevice() {
247 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
249 if (render_view_.get()) {
250 if (!label_.empty()) {
251 GetMediaDeviceManager()->CloseDevice(label_);
254 if (pending_open_device_) {
255 GetMediaDeviceManager()->CancelOpenDevice(pending_open_device_id_);
256 pending_open_device_ = false;
257 pending_open_device_id_ = -1;
262 void PepperPlatformAudioInput::NotifyStreamCreationFailed() {
263 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
266 client_->StreamCreationFailed();
269 PepperMediaDeviceManager* PepperPlatformAudioInput::GetMediaDeviceManager() {
270 return PepperMediaDeviceManager::GetForRenderView(render_view_.get());
273 } // namespace content