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_impl.h"
8 #include "base/logging.h"
9 #include "base/message_loop_proxy.h"
10 #include "build/build_config.h"
11 #include "content/common/child_process.h"
12 #include "content/renderer/media/audio_input_message_filter.h"
13 #include "content/renderer/pepper/pepper_plugin_delegate_impl.h"
14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_manager_base.h"
20 PepperPlatformAudioInputImpl
* PepperPlatformAudioInputImpl::Create(
21 const base::WeakPtr
<PepperPluginDelegateImpl
>& plugin_delegate
,
22 const std::string
& device_id
,
24 int frames_per_buffer
,
25 webkit::ppapi::PluginDelegate::PlatformAudioInputClient
* client
) {
26 scoped_refptr
<PepperPlatformAudioInputImpl
> audio_input(
27 new PepperPlatformAudioInputImpl());
28 if (audio_input
->Initialize(plugin_delegate
, device_id
, sample_rate
,
29 frames_per_buffer
, client
)) {
30 // Balanced by Release invoked in
31 // PepperPlatformAudioInputImpl::ShutDownOnIOThread().
32 audio_input
->AddRef();
33 return audio_input
.get();
38 void PepperPlatformAudioInputImpl::StartCapture() {
39 DCHECK(main_message_loop_proxy_
->BelongsToCurrentThread());
41 ChildProcess::current()->io_message_loop()->PostTask(
43 base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread
, this));
46 void PepperPlatformAudioInputImpl::StopCapture() {
47 DCHECK(main_message_loop_proxy_
->BelongsToCurrentThread());
49 ChildProcess::current()->io_message_loop()->PostTask(
51 base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread
, this));
54 void PepperPlatformAudioInputImpl::ShutDown() {
55 DCHECK(main_message_loop_proxy_
->BelongsToCurrentThread());
57 // Make sure we don't call shutdown more than once.
61 // Called on the main thread to stop all audio callbacks. We must only change
62 // the client on the main thread, and the delegates from the I/O thread.
64 ChildProcess::current()->io_message_loop()->PostTask(
66 base::Bind(&PepperPlatformAudioInputImpl::ShutDownOnIOThread
, this));
69 void PepperPlatformAudioInputImpl::OnStreamCreated(
70 base::SharedMemoryHandle handle
,
71 base::SyncSocket::Handle socket_handle
,
76 DCHECK(socket_handle
);
78 DCHECK_NE(-1, handle
.fd
);
79 DCHECK_NE(-1, socket_handle
);
82 // TODO(yzshen): Make use of circular buffer scheme. crbug.com/181449.
83 DCHECK_EQ(1, total_segments
);
85 if (base::MessageLoopProxy::current() != main_message_loop_proxy_
) {
86 // If shutdown has occurred, |client_| will be NULL and the handles will be
87 // cleaned up on the main thread.
88 main_message_loop_proxy_
->PostTask(
90 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated
, this,
91 handle
, socket_handle
, length
, total_segments
));
93 // Must dereference the client only on the main thread. Shutdown may have
94 // occurred while the request was in-flight, so we need to NULL check.
96 client_
->StreamCreated(handle
, length
, socket_handle
);
98 // Clean up the handles.
99 base::SyncSocket
temp_socket(socket_handle
);
100 base::SharedMemory
temp_shared_memory(handle
, false);
105 void PepperPlatformAudioInputImpl::OnVolume(double volume
) {}
107 void PepperPlatformAudioInputImpl::OnStateChanged(
108 media::AudioInputIPCDelegate::State state
) {
111 void PepperPlatformAudioInputImpl::OnIPCClosed() {
115 PepperPlatformAudioInputImpl::~PepperPlatformAudioInputImpl() {
116 // Make sure we have been shut down. Warning: this may happen on the I/O
118 // Although these members should be accessed on a specific thread (either the
119 // main thread or the I/O thread), it should be fine to examine their value
123 DCHECK(label_
.empty());
126 PepperPlatformAudioInputImpl::PepperPlatformAudioInputImpl()
128 main_message_loop_proxy_(base::MessageLoopProxy::current()) {
131 bool PepperPlatformAudioInputImpl::Initialize(
132 const base::WeakPtr
<PepperPluginDelegateImpl
>& plugin_delegate
,
133 const std::string
& device_id
,
135 int frames_per_buffer
,
136 webkit::ppapi::PluginDelegate::PlatformAudioInputClient
* client
) {
137 DCHECK(main_message_loop_proxy_
->BelongsToCurrentThread());
139 if (!plugin_delegate
|| !client
)
142 ipc_
= RenderThreadImpl::current()->audio_input_message_filter()->
143 CreateAudioInputIPC(plugin_delegate
->GetRoutingID());
145 plugin_delegate_
= plugin_delegate
;
148 params_
.Reset(media::AudioParameters::AUDIO_PCM_LINEAR
,
149 media::CHANNEL_LAYOUT_MONO
, 1, 0,
150 sample_rate
, 16, frames_per_buffer
);
152 // We need to open the device and obtain the label and session ID before
154 plugin_delegate_
->OpenDevice(
155 PP_DEVICETYPE_DEV_AUDIOCAPTURE
,
156 device_id
.empty() ? media::AudioManagerBase::kDefaultDeviceId
: device_id
,
157 base::Bind(&PepperPlatformAudioInputImpl::OnDeviceOpened
, this));
162 void PepperPlatformAudioInputImpl::InitializeOnIOThread(int session_id
) {
163 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
164 BelongsToCurrentThread());
169 // We will be notified by OnStreamCreated().
170 ipc_
->CreateStream(this, session_id
, params_
, false, 1);
173 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() {
174 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
175 BelongsToCurrentThread());
178 ipc_
->RecordStream();
181 void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() {
182 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
183 BelongsToCurrentThread());
185 // TODO(yzshen): We cannot re-start capturing if the stream is closed.
192 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() {
193 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
194 BelongsToCurrentThread());
196 StopCaptureOnIOThread();
198 main_message_loop_proxy_
->PostTask(
200 base::Bind(&PepperPlatformAudioInputImpl::CloseDevice
, this));
202 Release(); // Release for the delegate, balances out the reference taken in
203 // PepperPluginDelegateImpl::CreateAudioInput.
206 void PepperPlatformAudioInputImpl::OnDeviceOpened(int request_id
,
208 const std::string
& label
) {
209 DCHECK(main_message_loop_proxy_
->BelongsToCurrentThread());
211 if (succeeded
&& plugin_delegate_
) {
212 DCHECK(!label
.empty());
216 int session_id
= plugin_delegate_
->GetSessionID(
217 PP_DEVICETYPE_DEV_AUDIOCAPTURE
, label
);
218 ChildProcess::current()->io_message_loop()->PostTask(
220 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread
,
223 // Shutdown has occurred.
227 NotifyStreamCreationFailed();
231 void PepperPlatformAudioInputImpl::CloseDevice() {
232 DCHECK(main_message_loop_proxy_
->BelongsToCurrentThread());
234 if (plugin_delegate_
&& !label_
.empty()) {
235 plugin_delegate_
->CloseDevice(label_
);
240 void PepperPlatformAudioInputImpl::NotifyStreamCreationFailed() {
241 DCHECK(main_message_loop_proxy_
->BelongsToCurrentThread());
244 client_
->StreamCreationFailed();
247 } // namespace content