Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / renderer / pepper / pepper_platform_audio_input.cc
blobd1aaf53b95513e73f95159777afddaaa42602a19
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"
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "build/build_config.h"
13 #include "content/child/child_process.h"
14 #include "content/renderer/media/audio_input_message_filter.h"
15 #include "content/renderer/pepper/pepper_audio_input_host.h"
16 #include "content/renderer/pepper/pepper_media_device_manager.h"
17 #include "content/renderer/render_frame_impl.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "content/renderer/render_view_impl.h"
20 #include "media/audio/audio_manager_base.h"
21 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
22 #include "url/gurl.h"
24 namespace content {
26 // static
27 PepperPlatformAudioInput* PepperPlatformAudioInput::Create(
28 int render_frame_id,
29 const std::string& device_id,
30 const GURL& document_url,
31 int sample_rate,
32 int frames_per_buffer,
33 PepperAudioInputHost* client) {
34 scoped_refptr<PepperPlatformAudioInput> audio_input(
35 new PepperPlatformAudioInput());
36 if (audio_input->Initialize(render_frame_id,
37 device_id,
38 document_url,
39 sample_rate,
40 frames_per_buffer,
41 client)) {
42 // Balanced by Release invoked in
43 // PepperPlatformAudioInput::ShutDownOnIOThread().
44 audio_input->AddRef();
45 return audio_input.get();
47 return NULL;
50 void PepperPlatformAudioInput::StartCapture() {
51 DCHECK(main_task_runner_->BelongsToCurrentThread());
53 io_task_runner_->PostTask(
54 FROM_HERE,
55 base::Bind(&PepperPlatformAudioInput::StartCaptureOnIOThread, this));
58 void PepperPlatformAudioInput::StopCapture() {
59 DCHECK(main_task_runner_->BelongsToCurrentThread());
61 io_task_runner_->PostTask(
62 FROM_HERE,
63 base::Bind(&PepperPlatformAudioInput::StopCaptureOnIOThread, this));
66 void PepperPlatformAudioInput::ShutDown() {
67 DCHECK(main_task_runner_->BelongsToCurrentThread());
69 // Make sure we don't call shutdown more than once.
70 if (!client_)
71 return;
73 // Called on the main thread to stop all audio callbacks. We must only change
74 // the client on the main thread, and the delegates from the I/O thread.
75 client_ = NULL;
76 io_task_runner_->PostTask(
77 FROM_HERE,
78 base::Bind(&PepperPlatformAudioInput::ShutDownOnIOThread, this));
81 void PepperPlatformAudioInput::OnStreamCreated(
82 base::SharedMemoryHandle handle,
83 base::SyncSocket::Handle socket_handle,
84 int length,
85 int total_segments) {
86 #if defined(OS_WIN)
87 DCHECK(handle);
88 DCHECK(socket_handle);
89 #else
90 DCHECK(base::SharedMemory::IsHandleValid(handle));
91 DCHECK_NE(-1, socket_handle);
92 #endif
93 DCHECK(length);
94 // TODO(yzshen): Make use of circular buffer scheme. crbug.com/181449.
95 DCHECK_EQ(1, total_segments);
97 if (base::ThreadTaskRunnerHandle::Get().get() != main_task_runner_.get()) {
98 // If shutdown has occurred, |client_| will be NULL and the handles will be
99 // cleaned up on the main thread.
100 main_task_runner_->PostTask(
101 FROM_HERE, base::Bind(&PepperPlatformAudioInput::OnStreamCreated, this,
102 handle, socket_handle, length, total_segments));
103 } else {
104 // Must dereference the client only on the main thread. Shutdown may have
105 // occurred while the request was in-flight, so we need to NULL check.
106 if (client_) {
107 client_->StreamCreated(handle, length, socket_handle);
108 } else {
109 // Clean up the handles.
110 base::SyncSocket temp_socket(socket_handle);
111 base::SharedMemory temp_shared_memory(handle, false);
116 void PepperPlatformAudioInput::OnVolume(double volume) {}
118 void PepperPlatformAudioInput::OnStateChanged(
119 media::AudioInputIPCDelegateState state) {}
121 void PepperPlatformAudioInput::OnIPCClosed() { ipc_.reset(); }
123 PepperPlatformAudioInput::~PepperPlatformAudioInput() {
124 // Make sure we have been shut down. Warning: this may happen on the I/O
125 // thread!
126 // Although these members should be accessed on a specific thread (either the
127 // main thread or the I/O thread), it should be fine to examine their value
128 // here.
129 DCHECK(!ipc_);
130 DCHECK(!client_);
131 DCHECK(label_.empty());
132 DCHECK(!pending_open_device_);
135 PepperPlatformAudioInput::PepperPlatformAudioInput()
136 : client_(NULL),
137 main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
138 io_task_runner_(ChildProcess::current()->io_task_runner()),
139 render_frame_id_(MSG_ROUTING_NONE),
140 create_stream_sent_(false),
141 pending_open_device_(false),
142 pending_open_device_id_(-1) {
145 bool PepperPlatformAudioInput::Initialize(
146 int render_frame_id,
147 const std::string& device_id,
148 const GURL& document_url,
149 int sample_rate,
150 int frames_per_buffer,
151 PepperAudioInputHost* client) {
152 DCHECK(main_task_runner_->BelongsToCurrentThread());
154 RenderFrameImpl* const render_frame =
155 RenderFrameImpl::FromRoutingID(render_frame_id);
156 if (!render_frame || !client)
157 return false;
159 render_frame_id_ = render_frame_id;
160 client_ = client;
162 if (!GetMediaDeviceManager())
163 return false;
165 ipc_ = RenderThreadImpl::current()
166 ->audio_input_message_filter()
167 ->CreateAudioInputIPC(render_frame_id);
169 params_.Reset(media::AudioParameters::AUDIO_PCM_LINEAR,
170 media::CHANNEL_LAYOUT_MONO,
171 ppapi::kAudioInputChannels,
172 sample_rate,
173 ppapi::kBitsPerAudioInputSample,
174 frames_per_buffer);
176 // We need to open the device and obtain the label and session ID before
177 // initializing.
178 pending_open_device_id_ = GetMediaDeviceManager()->OpenDevice(
179 PP_DEVICETYPE_DEV_AUDIOCAPTURE,
180 device_id.empty() ? media::AudioManagerBase::kDefaultDeviceId : device_id,
181 document_url,
182 base::Bind(&PepperPlatformAudioInput::OnDeviceOpened, this));
183 pending_open_device_ = true;
185 return true;
188 void PepperPlatformAudioInput::InitializeOnIOThread(int session_id) {
189 DCHECK(io_task_runner_->BelongsToCurrentThread());
191 if (!ipc_)
192 return;
194 // We will be notified by OnStreamCreated().
195 create_stream_sent_ = true;
196 ipc_->CreateStream(this, session_id, params_, false, 1);
199 void PepperPlatformAudioInput::StartCaptureOnIOThread() {
200 DCHECK(io_task_runner_->BelongsToCurrentThread());
202 if (ipc_)
203 ipc_->RecordStream();
206 void PepperPlatformAudioInput::StopCaptureOnIOThread() {
207 DCHECK(io_task_runner_->BelongsToCurrentThread());
209 // TODO(yzshen): We cannot re-start capturing if the stream is closed.
210 if (ipc_ && create_stream_sent_) {
211 ipc_->CloseStream();
213 ipc_.reset();
216 void PepperPlatformAudioInput::ShutDownOnIOThread() {
217 DCHECK(io_task_runner_->BelongsToCurrentThread());
219 StopCaptureOnIOThread();
221 main_task_runner_->PostTask(
222 FROM_HERE, base::Bind(&PepperPlatformAudioInput::CloseDevice, this));
224 Release(); // Release for the delegate, balances out the reference taken in
225 // PepperPlatformAudioInput::Create.
228 void PepperPlatformAudioInput::OnDeviceOpened(int request_id,
229 bool succeeded,
230 const std::string& label) {
231 DCHECK(main_task_runner_->BelongsToCurrentThread());
233 pending_open_device_ = false;
234 pending_open_device_id_ = -1;
236 PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
237 if (succeeded && device_manager) {
238 DCHECK(!label.empty());
239 label_ = label;
241 if (client_) {
242 int session_id = device_manager->GetSessionID(
243 PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
244 io_task_runner_->PostTask(
245 FROM_HERE, base::Bind(&PepperPlatformAudioInput::InitializeOnIOThread,
246 this, session_id));
247 } else {
248 // Shutdown has occurred.
249 CloseDevice();
251 } else {
252 NotifyStreamCreationFailed();
256 void PepperPlatformAudioInput::CloseDevice() {
257 DCHECK(main_task_runner_->BelongsToCurrentThread());
259 if (!label_.empty()) {
260 PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
261 if (device_manager)
262 device_manager->CloseDevice(label_);
263 label_.clear();
265 if (pending_open_device_) {
266 PepperMediaDeviceManager* const device_manager = GetMediaDeviceManager();
267 if (device_manager)
268 device_manager->CancelOpenDevice(pending_open_device_id_);
269 pending_open_device_ = false;
270 pending_open_device_id_ = -1;
274 void PepperPlatformAudioInput::NotifyStreamCreationFailed() {
275 DCHECK(main_task_runner_->BelongsToCurrentThread());
277 if (client_)
278 client_->StreamCreationFailed();
281 PepperMediaDeviceManager* PepperPlatformAudioInput::GetMediaDeviceManager() {
282 DCHECK(main_task_runner_->BelongsToCurrentThread());
284 RenderFrameImpl* const render_frame =
285 RenderFrameImpl::FromRoutingID(render_frame_id_);
286 return render_frame ?
287 PepperMediaDeviceManager::GetForRenderFrame(render_frame).get() : NULL;
290 } // namespace content