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

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: 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) {
no longer working on chromium 2012/03/16 14:33:23 why do we need a new shutdown_called flag? can we
yzshen1 2012/03/17 09:32:56 ShutDown() may be called before stream_id_ is set
no longer working on chromium 2012/03/18 00:38:59 Do I miss something here? It looks to me they all
yzshen1 2012/03/19 21:47:54 OpenDevice() and OnDeviceOpened() happens on the m
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 will usually happen on
25 // the I/O thread! 27 // the I/O thread!
26 DCHECK_EQ(0, stream_id_); 28 DCHECK_EQ(0, stream_id_);
27 DCHECK(!client_); 29 DCHECK(!client_);
30 DCHECK(label_.empty());
31 DCHECK(shutdown_called_);
28 } 32 }
29 33
30 // static 34 // static
31 PepperPlatformAudioInputImpl* PepperPlatformAudioInputImpl::Create( 35 PepperPlatformAudioInputImpl* PepperPlatformAudioInputImpl::Create(
36 const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate,
37 const std::string& device_id,
32 uint32_t sample_rate, 38 uint32_t sample_rate,
33 uint32_t sample_count, 39 uint32_t sample_count,
34 webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { 40 webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) {
35 scoped_refptr<PepperPlatformAudioInputImpl> audio_input( 41 scoped_refptr<PepperPlatformAudioInputImpl> audio_input(
36 new PepperPlatformAudioInputImpl); 42 new PepperPlatformAudioInputImpl);
37 if (audio_input->Initialize(sample_rate, sample_count, client)) { 43 if (audio_input->Initialize(plugin_delegate, device_id, sample_rate,
44 sample_count, client)) {
38 // Balanced by Release invoked in 45 // Balanced by Release invoked in
39 // PepperPlatformAudioInputImpl::ShutDownOnIOThread(). 46 // PepperPlatformAudioInputImpl::ShutDownOnIOThread().
40 return audio_input.release(); 47 return audio_input.release();
41 } 48 }
42 return NULL; 49 return NULL;
43 } 50 }
44 51
45 bool PepperPlatformAudioInputImpl::StartCapture() { 52 bool PepperPlatformAudioInputImpl::StartCapture() {
no longer working on chromium 2012/03/16 14:33:23 It looks like this function has no way to return f
yzshen1 2012/03/17 09:32:56 Done.
53 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
54
46 ChildProcess::current()->io_message_loop()->PostTask( 55 ChildProcess::current()->io_message_loop()->PostTask(
47 FROM_HERE, 56 FROM_HERE,
48 base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this)); 57 base::Bind(&PepperPlatformAudioInputImpl::StartCaptureOnIOThread, this));
49 return true; 58 return true;
50 } 59 }
51 60
52 bool PepperPlatformAudioInputImpl::StopCapture() { 61 bool PepperPlatformAudioInputImpl::StopCapture() {
no longer working on chromium 2012/03/16 14:33:23 void?
yzshen1 2012/03/17 09:32:56 Done.
62 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
63
53 ChildProcess::current()->io_message_loop()->PostTask( 64 ChildProcess::current()->io_message_loop()->PostTask(
54 FROM_HERE, 65 FROM_HERE,
55 base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this)); 66 base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this));
56 return true; 67 return true;
57 } 68 }
58 69
59 void PepperPlatformAudioInputImpl::ShutDown() { 70 void PepperPlatformAudioInputImpl::ShutDown() {
71 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
72
60 // Called on the main thread to stop all audio callbacks. We must only change 73 // 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. 74 // the client on the main thread, and the delegates from the I/O thread.
62 client_ = NULL; 75 client_ = NULL;
63 ChildProcess::current()->io_message_loop()->PostTask( 76 ChildProcess::current()->io_message_loop()->PostTask(
64 FROM_HERE, 77 FROM_HERE,
65 base::Bind(&PepperPlatformAudioInputImpl::ShutDownOnIOThread, this)); 78 base::Bind(&PepperPlatformAudioInputImpl::ShutDownOnIOThread, this));
66 } 79 }
67 80
68 bool PepperPlatformAudioInputImpl::Initialize( 81 bool PepperPlatformAudioInputImpl::Initialize(
no longer working on chromium 2012/03/16 14:33:23 void?
yzshen1 2012/03/17 09:32:56 I changed two DCHECKs to input parameter validatio
82 const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate,
83 const std::string& device_id,
69 uint32_t sample_rate, 84 uint32_t sample_rate,
70 uint32_t sample_count, 85 uint32_t sample_count,
71 webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { 86 webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) {
87 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
88
89 DCHECK(plugin_delegate);
72 DCHECK(client); 90 DCHECK(client);
73 // Make sure we don't call init more than once.
74 DCHECK_EQ(0, stream_id_);
75 91
92 plugin_delegate_ = plugin_delegate;
76 client_ = client; 93 client_ = client;
77 94
78 AudioParameters params; 95 params_.format = AudioParameters::AUDIO_PCM_LINEAR;
79 params.format = AudioParameters::AUDIO_PCM_LINEAR; 96 params_.channels = 1;
80 params.channels = 1; 97 params_.sample_rate = sample_rate;
81 params.sample_rate = sample_rate; 98 params_.bits_per_sample = 16;
82 params.bits_per_sample = 16; 99 params_.samples_per_packet = sample_count;
83 params.samples_per_packet = sample_count;
84 100
85 ChildProcess::current()->io_message_loop()->PostTask( 101 if (device_id.empty()) {
86 FROM_HERE, 102 // Use the default device.
87 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread, 103 ChildProcess::current()->io_message_loop()->PostTask(
88 this, params)); 104 FROM_HERE,
105 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
106 this, 0));
107 } else {
108 // We need to open the device and obtain the label and session ID before
109 // initializing.
110 plugin_delegate_->OpenDevice(
111 PP_DEVICETYPE_DEV_AUDIOCAPTURE, device_id,
112 base::Bind(&PepperPlatformAudioInputImpl::OnDeviceOpened, this));
113 }
89 return true; 114 return true;
90 } 115 }
91 116
92 void PepperPlatformAudioInputImpl::InitializeOnIOThread( 117 void PepperPlatformAudioInputImpl::InitializeOnIOThread(int session_id) {
93 const AudioParameters& params) { 118 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
119 BelongsToCurrentThread());
120
121 if (shutdown_called_)
122 return;
123
124 // Make sure we don't call init more than once.
125 DCHECK_EQ(0, stream_id_);
94 stream_id_ = filter_->AddDelegate(this); 126 stream_id_ = filter_->AddDelegate(this);
95 filter_->Send(new AudioInputHostMsg_CreateStream( 127 DCHECK_NE(0, stream_id_);
96 stream_id_, params, AudioManagerBase::kDefaultDeviceId)); 128
129 if (!session_id) {
130 // We will be notified by OnStreamCreated().
131 filter_->Send(new AudioInputHostMsg_CreateStream(
132 stream_id_, params_, AudioManagerBase::kDefaultDeviceId));
133 } else {
134 // We will be notified by OnDeviceReady().
135 filter_->Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id));
136 }
97 } 137 }
98 138
99 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() { 139 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() {
140 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
141 BelongsToCurrentThread());
142
100 if (stream_id_) 143 if (stream_id_)
101 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_)); 144 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
no longer working on chromium 2012/03/16 14:33:23 What happens if we are in the middle of starting t
yzshen1 2012/03/17 09:32:56 Thanks for pointing this out! This class doesn't
no longer working on chromium 2012/03/18 00:38:59 Thanks for clarification.
102 } 145 }
103 146
104 void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() { 147 void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() {
148 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
149 BelongsToCurrentThread());
150
151 // TODO(yzshen): We cannot re-start capturing if the stream is closed.
105 if (stream_id_) 152 if (stream_id_)
106 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 153 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
no longer working on chromium 2012/03/16 14:33:23 same situation here, we need to do similar things
yzshen1 2012/03/17 09:32:56 Please see my comment above. On 2012/03/16 14:33:2
107 } 154 }
108 155
109 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() { 156 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() {
157 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
158 BelongsToCurrentThread());
159
110 // Make sure we don't call shutdown more than once. 160 // Make sure we don't call shutdown more than once.
111 if (!stream_id_) 161 if (shutdown_called_)
112 return; 162 return;
163 shutdown_called_ = true;
113 164
114 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 165 if (stream_id_) {
115 filter_->RemoveDelegate(stream_id_); 166 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
116 stream_id_ = 0; 167 filter_->RemoveDelegate(stream_id_);
168 stream_id_ = 0;
169 }
170
171 main_message_loop_proxy_->PostTask(
172 FROM_HERE,
173 base::Bind(&PepperPlatformAudioInputImpl::CloseDevice, this));
117 174
118 Release(); // Release for the delegate, balances out the reference taken in 175 Release(); // Release for the delegate, balances out the reference taken in
no longer working on chromium 2012/03/16 14:33:23 What does this Release() do? We execute CloseDevic
yzshen1 2012/03/17 09:32:56 This is a ref-counted object, Release() decreases
no longer working on chromium 2012/03/18 00:38:59 True, I know it is safe due to PepperPlatformAudio
yzshen1 2012/03/19 21:47:54 I try to maintain the following order: open device
119 // PepperPluginDelegateImpl::CreateAudioInput. 176 // PepperPluginDelegateImpl::CreateAudioInput.
120 } 177 }
121 178
122 void PepperPlatformAudioInputImpl::OnStreamCreated( 179 void PepperPlatformAudioInputImpl::OnStreamCreated(
123 base::SharedMemoryHandle handle, 180 base::SharedMemoryHandle handle,
124 base::SyncSocket::Handle socket_handle, 181 base::SyncSocket::Handle socket_handle,
125 uint32 length) { 182 uint32 length) {
126 #if defined(OS_WIN) 183 #if defined(OS_WIN)
127 DCHECK(handle); 184 DCHECK(handle);
128 DCHECK(socket_handle); 185 DCHECK(socket_handle);
129 #else 186 #else
130 DCHECK_NE(-1, handle.fd); 187 DCHECK_NE(-1, handle.fd);
131 DCHECK_NE(-1, socket_handle); 188 DCHECK_NE(-1, socket_handle);
132 #endif 189 #endif
133 DCHECK(length); 190 DCHECK(length);
134 191
no longer working on chromium 2012/03/16 14:33:23 Which thread does this OnStreamCreated() happen? I
yzshen1 2012/03/17 09:32:56 Yes. And then we will post a task (using the same
135 if (base::MessageLoopProxy::current() == main_message_loop_proxy_) { 192 if (base::MessageLoopProxy::current() == main_message_loop_proxy_) {
136 // Must dereference the client only on the main thread. Shutdown may have 193 // Must dereference the client only on the main thread. Shutdown may have
137 // occurred while the request was in-flight, so we need to NULL check. 194 // occurred while the request was in-flight, so we need to NULL check.
138 if (client_) 195 if (client_) {
139 client_->StreamCreated(handle, length, socket_handle); 196 client_->StreamCreated(handle, length, socket_handle);
197 } else {
198 // Clean up the handles.
199 base::SyncSocket temp_socket(socket_handle);
200 base::SharedMemory temp_shared_memory(handle, false);
201 }
140 } else { 202 } else {
203 // No need to check |shutdown_called_| here. If shutdown has occurred,
204 // |client_| will be NULL and the handles will be cleaned up on the main
205 // thread.
141 main_message_loop_proxy_->PostTask( 206 main_message_loop_proxy_->PostTask(
142 FROM_HERE, 207 FROM_HERE,
143 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this, 208 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this,
144 handle, socket_handle, length)); 209 handle, socket_handle, length));
145 } 210 }
146 } 211 }
147 212
148 void PepperPlatformAudioInputImpl::OnVolume(double volume) { 213 void PepperPlatformAudioInputImpl::OnVolume(double volume) {
149 } 214 }
150 215
151 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) { 216 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) {
152 } 217 }
153 218
154 void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string&) { 219 void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string& device_id) {
220 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
221 BelongsToCurrentThread());
222
223 if (shutdown_called_)
224 return;
225
226 if (device_id.empty()) {
227 main_message_loop_proxy_->PostTask(
228 FROM_HERE,
229 base::Bind(&PepperPlatformAudioInputImpl::NotifyStreamCreationFailed,
230 this));
231 } else {
232 // We will be notified by OnStreamCreated().
233 filter_->Send(new AudioInputHostMsg_CreateStream(stream_id_, params_,
234 device_id));
235 }
155 } 236 }
237
238 void PepperPlatformAudioInputImpl::OnDeviceOpened(int request_id,
239 bool succeeded,
240 const std::string& label) {
241 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
242
243 succeeded = succeeded && plugin_delegate_;
244 if (succeeded) {
245 label_ = label;
246
247 if (client_) {
248 int session_id = plugin_delegate_->GetSessionID(
249 PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
250 ChildProcess::current()->io_message_loop()->PostTask(
251 FROM_HERE,
252 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
253 this, session_id));
254 } else {
255 // Shutdown has occurred.
256 CloseDevice();
257 }
258 } else {
259 NotifyStreamCreationFailed();
no longer working on chromium 2012/03/16 14:33:23 shall we still send the notification when plugin_d
yzshen1 2012/03/17 09:32:56 As long as client_ is not NULL, I think it makes s
260 }
261 }
262
263 void PepperPlatformAudioInputImpl::CloseDevice() {
264 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
265
266 if (plugin_delegate_ && !label_.empty()) {
267 plugin_delegate_->CloseDevice(label_);
268 label_.clear();
269 }
270 }
271
272 void PepperPlatformAudioInputImpl::NotifyStreamCreationFailed() {
273 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
274
275 if (client_)
276 client_->StreamCreationFailed();
277 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698