Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(187)

Side by Side Diff: content/renderer/pepper/pepper_platform_audio_input_impl.cc

Issue 9705056: PepperPlatformAudioInputImpl: support audio input device selection. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sync&resolve again Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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/renderer/pepper/pepper_platform_audio_input_impl.h" 5 #include "content/renderer/pepper/pepper_platform_audio_input_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/message_loop_proxy.h" 9 #include "base/message_loop_proxy.h"
10 #include "build/build_config.h" 10 #include "build/build_config.h"
11 #include "content/common/child_process.h" 11 #include "content/common/child_process.h"
12 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
13 #include "content/renderer/pepper/pepper_plugin_delegate_impl.h"
13 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
14 #include "media/audio/audio_manager_base.h" 15 #include "media/audio/audio_manager_base.h"
15 16
16 PepperPlatformAudioInputImpl::PepperPlatformAudioInputImpl() 17 PepperPlatformAudioInputImpl::PepperPlatformAudioInputImpl()
17 : client_(NULL), 18 : client_(NULL),
18 stream_id_(0), 19 stream_id_(0),
19 main_message_loop_proxy_(base::MessageLoopProxy::current()) { 20 main_message_loop_proxy_(base::MessageLoopProxy::current()),
21 shutdown_called_(false) {
20 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 22 filter_ = RenderThreadImpl::current()->audio_input_message_filter();
21 } 23 }
22 24
23 PepperPlatformAudioInputImpl::~PepperPlatformAudioInputImpl() { 25 PepperPlatformAudioInputImpl::~PepperPlatformAudioInputImpl() {
24 // Make sure we have been shut down. Warning: this will usually happen on 26 // Make sure we have been shut down. Warning: this may happen on the I/O
25 // the I/O thread! 27 // thread!
28 // Although these members should be accessed on a specific thread (either the
29 // main thread or the I/O thread), it should be fine to examine their value
30 // here.
26 DCHECK_EQ(0, stream_id_); 31 DCHECK_EQ(0, stream_id_);
27 DCHECK(!client_); 32 DCHECK(!client_);
33 DCHECK(label_.empty());
34 DCHECK(shutdown_called_);
28 } 35 }
29 36
30 // static 37 // static
31 PepperPlatformAudioInputImpl* PepperPlatformAudioInputImpl::Create( 38 PepperPlatformAudioInputImpl* PepperPlatformAudioInputImpl::Create(
39 const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate,
40 const std::string& device_id,
32 int sample_rate, 41 int sample_rate,
33 int frames_per_buffer, 42 int frames_per_buffer,
34 webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { 43 webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) {
35 scoped_refptr<PepperPlatformAudioInputImpl> audio_input( 44 scoped_refptr<PepperPlatformAudioInputImpl> audio_input(
36 new PepperPlatformAudioInputImpl); 45 new PepperPlatformAudioInputImpl);
37 if (audio_input->Initialize(sample_rate, frames_per_buffer, client)) { 46 if (audio_input->Initialize(plugin_delegate, device_id, sample_rate,
47 frames_per_buffer, client)) {
38 // Balanced by Release invoked in 48 // Balanced by Release invoked in
39 // PepperPlatformAudioInputImpl::ShutDownOnIOThread(). 49 // PepperPlatformAudioInputImpl::ShutDownOnIOThread().
40 return audio_input.release(); 50 return audio_input.release();
41 } 51 }
42 return NULL; 52 return NULL;
43 } 53 }
44 54
45 bool PepperPlatformAudioInputImpl::StartCapture() { 55 void PepperPlatformAudioInputImpl::StartCapture() {
56 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
57
46 ChildProcess::current()->io_message_loop()->PostTask( 58 ChildProcess::current()->io_message_loop()->PostTask(
47 FROM_HERE, 59 FROM_HERE,
48 base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this)); 60 base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this));
49 return true;
50 } 61 }
51 62
52 bool PepperPlatformAudioInputImpl::StopCapture() { 63 void PepperPlatformAudioInputImpl::StopCapture() {
64 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
65
53 ChildProcess::current()->io_message_loop()->PostTask( 66 ChildProcess::current()->io_message_loop()->PostTask(
54 FROM_HERE, 67 FROM_HERE,
55 base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this)); 68 base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this));
56 return true;
57 } 69 }
58 70
59 void PepperPlatformAudioInputImpl::ShutDown() { 71 void PepperPlatformAudioInputImpl::ShutDown() {
72 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
73
60 // Called on the main thread to stop all audio callbacks. We must only change 74 // Called on the main thread to stop all audio callbacks. We must only change
61 // the client on the main thread, and the delegates from the I/O thread. 75 // the client on the main thread, and the delegates from the I/O thread.
62 client_ = NULL; 76 client_ = NULL;
63 ChildProcess::current()->io_message_loop()->PostTask( 77 ChildProcess::current()->io_message_loop()->PostTask(
64 FROM_HERE, 78 FROM_HERE,
65 base::Bind(&PepperPlatformAudioInputImpl::ShutDownOnIOThread, this)); 79 base::Bind(&PepperPlatformAudioInputImpl::ShutDownOnIOThread, this));
66 } 80 }
67 81
68 bool PepperPlatformAudioInputImpl::Initialize( 82 bool PepperPlatformAudioInputImpl::Initialize(
83 const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate,
84 const std::string& device_id,
69 int sample_rate, 85 int sample_rate,
70 int frames_per_buffer, 86 int frames_per_buffer,
71 webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { 87 webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) {
72 DCHECK(client); 88 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
73 // Make sure we don't call init more than once.
74 DCHECK_EQ(0, stream_id_);
75 89
90 if (!plugin_delegate || !client)
91 return false;
92
93 plugin_delegate_ = plugin_delegate;
76 client_ = client; 94 client_ = client;
77 95
78 AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, 96 params_.Reset(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO,
79 CHANNEL_LAYOUT_MONO, 97 sample_rate, 16, frames_per_buffer);
80 sample_rate, 16, frames_per_buffer);
81 98
82 ChildProcess::current()->io_message_loop()->PostTask( 99 if (device_id.empty()) {
83 FROM_HERE, 100 // Use the default device.
84 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread, 101 ChildProcess::current()->io_message_loop()->PostTask(
85 this, params)); 102 FROM_HERE,
103 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
104 this, 0));
105 } else {
106 // We need to open the device and obtain the label and session ID before
107 // initializing.
108 plugin_delegate_->OpenDevice(
109 PP_DEVICETYPE_DEV_AUDIOCAPTURE, device_id,
110 base::Bind(&PepperPlatformAudioInputImpl::OnDeviceOpened, this));
111 }
86 return true; 112 return true;
87 } 113 }
88 114
89 void PepperPlatformAudioInputImpl::InitializeOnIOThread( 115 void PepperPlatformAudioInputImpl::InitializeOnIOThread(int session_id) {
90 const AudioParameters& params) { 116 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
117 BelongsToCurrentThread());
118
119 if (shutdown_called_)
120 return;
121
122 // Make sure we don't call init more than once.
123 DCHECK_EQ(0, stream_id_);
91 stream_id_ = filter_->AddDelegate(this); 124 stream_id_ = filter_->AddDelegate(this);
92 filter_->Send(new AudioInputHostMsg_CreateStream( 125 DCHECK_NE(0, stream_id_);
93 stream_id_, params, AudioManagerBase::kDefaultDeviceId)); 126
127 if (!session_id) {
128 // We will be notified by OnStreamCreated().
129 filter_->Send(new AudioInputHostMsg_CreateStream(
130 stream_id_, params_, AudioManagerBase::kDefaultDeviceId));
131 } else {
132 // We will be notified by OnDeviceReady().
133 filter_->Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id));
134 }
94 } 135 }
95 136
96 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() { 137 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() {
138 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
139 BelongsToCurrentThread());
140
97 if (stream_id_) 141 if (stream_id_)
98 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_)); 142 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
99 } 143 }
100 144
101 void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() { 145 void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() {
146 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
147 BelongsToCurrentThread());
148
149 // TODO(yzshen): We cannot re-start capturing if the stream is closed.
102 if (stream_id_) 150 if (stream_id_)
103 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 151 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
104 } 152 }
105 153
106 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() { 154 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() {
155 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
156 BelongsToCurrentThread());
157
107 // Make sure we don't call shutdown more than once. 158 // Make sure we don't call shutdown more than once.
108 if (!stream_id_) 159 if (shutdown_called_)
109 return; 160 return;
161 shutdown_called_ = true;
110 162
111 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 163 if (stream_id_) {
112 filter_->RemoveDelegate(stream_id_); 164 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
113 stream_id_ = 0; 165 filter_->RemoveDelegate(stream_id_);
166 stream_id_ = 0;
167 }
168
169 main_message_loop_proxy_->PostTask(
170 FROM_HERE,
171 base::Bind(&PepperPlatformAudioInputImpl::CloseDevice, this));
114 172
115 Release(); // Release for the delegate, balances out the reference taken in 173 Release(); // Release for the delegate, balances out the reference taken in
116 // PepperPluginDelegateImpl::CreateAudioInput. 174 // PepperPluginDelegateImpl::CreateAudioInput.
117 } 175 }
118 176
119 void PepperPlatformAudioInputImpl::OnStreamCreated( 177 void PepperPlatformAudioInputImpl::OnStreamCreated(
120 base::SharedMemoryHandle handle, 178 base::SharedMemoryHandle handle,
121 base::SyncSocket::Handle socket_handle, 179 base::SyncSocket::Handle socket_handle,
122 uint32 length) { 180 uint32 length) {
123 #if defined(OS_WIN) 181 #if defined(OS_WIN)
124 DCHECK(handle); 182 DCHECK(handle);
125 DCHECK(socket_handle); 183 DCHECK(socket_handle);
126 #else 184 #else
127 DCHECK_NE(-1, handle.fd); 185 DCHECK_NE(-1, handle.fd);
128 DCHECK_NE(-1, socket_handle); 186 DCHECK_NE(-1, socket_handle);
129 #endif 187 #endif
130 DCHECK(length); 188 DCHECK(length);
131 189
132 if (base::MessageLoopProxy::current() == main_message_loop_proxy_) { 190 if (base::MessageLoopProxy::current() != main_message_loop_proxy_) {
133 // Must dereference the client only on the main thread. Shutdown may have 191 // No need to check |shutdown_called_| here. If shutdown has occurred,
134 // occurred while the request was in-flight, so we need to NULL check. 192 // |client_| will be NULL and the handles will be cleaned up on the main
135 if (client_) 193 // thread.
136 client_->StreamCreated(handle, length, socket_handle);
137 } else {
138 main_message_loop_proxy_->PostTask( 194 main_message_loop_proxy_->PostTask(
139 FROM_HERE, 195 FROM_HERE,
140 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this, 196 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this,
141 handle, socket_handle, length)); 197 handle, socket_handle, length));
198 } else {
199 // Must dereference the client only on the main thread. Shutdown may have
200 // occurred while the request was in-flight, so we need to NULL check.
201 if (client_) {
202 client_->StreamCreated(handle, length, socket_handle);
203 } else {
204 // Clean up the handles.
205 base::SyncSocket temp_socket(socket_handle);
206 base::SharedMemory temp_shared_memory(handle, false);
207 }
142 } 208 }
143 } 209 }
144 210
145 void PepperPlatformAudioInputImpl::OnVolume(double volume) { 211 void PepperPlatformAudioInputImpl::OnVolume(double volume) {
146 } 212 }
147 213
148 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) { 214 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) {
149 } 215 }
150 216
151 void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string&) { 217 void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string& device_id) {
218 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
219 BelongsToCurrentThread());
220
221 if (shutdown_called_)
222 return;
223
224 if (device_id.empty()) {
225 main_message_loop_proxy_->PostTask(
226 FROM_HERE,
227 base::Bind(&PepperPlatformAudioInputImpl::NotifyStreamCreationFailed,
228 this));
229 } else {
230 // We will be notified by OnStreamCreated().
231 filter_->Send(new AudioInputHostMsg_CreateStream(stream_id_, params_,
232 device_id));
233 }
152 } 234 }
235
236 void PepperPlatformAudioInputImpl::OnDeviceOpened(int request_id,
237 bool succeeded,
238 const std::string& label) {
239 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
240
241 if (succeeded && plugin_delegate_) {
242 DCHECK(!label.empty());
243 label_ = label;
244
245 if (client_) {
246 int session_id = plugin_delegate_->GetSessionID(
247 PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
248 ChildProcess::current()->io_message_loop()->PostTask(
249 FROM_HERE,
250 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
251 this, session_id));
252 } else {
253 // Shutdown has occurred.
254 CloseDevice();
255 }
256 } else {
257 NotifyStreamCreationFailed();
258 }
259 }
260
261 void PepperPlatformAudioInputImpl::CloseDevice() {
262 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
263
264 if (plugin_delegate_ && !label_.empty()) {
265 plugin_delegate_->CloseDevice(label_);
266 label_.clear();
267 }
268 }
269
270 void PepperPlatformAudioInputImpl::NotifyStreamCreationFailed() {
271 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
272
273 if (client_)
274 client_->StreamCreationFailed();
275 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698