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

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: Changes in response to Shijing's suggestions. 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 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 void PepperPlatformAudioInputImpl::StartCapture() {
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;
50 } 58 }
51 59
52 bool PepperPlatformAudioInputImpl::StopCapture() { 60 void PepperPlatformAudioInputImpl::StopCapture() {
61 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
62
53 ChildProcess::current()->io_message_loop()->PostTask( 63 ChildProcess::current()->io_message_loop()->PostTask(
54 FROM_HERE, 64 FROM_HERE,
55 base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this)); 65 base::Bind(&PepperPlatformAudioInputImpl::StopCaptureOnIOThread, this));
56 return true;
57 } 66 }
58 67
59 void PepperPlatformAudioInputImpl::ShutDown() { 68 void PepperPlatformAudioInputImpl::ShutDown() {
69 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
70
60 // Called on the main thread to stop all audio callbacks. We must only change 71 // 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. 72 // the client on the main thread, and the delegates from the I/O thread.
62 client_ = NULL; 73 client_ = NULL;
63 ChildProcess::current()->io_message_loop()->PostTask( 74 ChildProcess::current()->io_message_loop()->PostTask(
64 FROM_HERE, 75 FROM_HERE,
65 base::Bind(&PepperPlatformAudioInputImpl::ShutDownOnIOThread, this)); 76 base::Bind(&PepperPlatformAudioInputImpl::ShutDownOnIOThread, this));
66 } 77 }
67 78
68 bool PepperPlatformAudioInputImpl::Initialize( 79 bool PepperPlatformAudioInputImpl::Initialize(
80 const base::WeakPtr<PepperPluginDelegateImpl>& plugin_delegate,
81 const std::string& device_id,
69 uint32_t sample_rate, 82 uint32_t sample_rate,
70 uint32_t sample_count, 83 uint32_t sample_count,
71 webkit::ppapi::PluginDelegate::PlatformAudioCommonClient* client) { 84 webkit::ppapi::PluginDelegate::PlatformAudioInputClient* client) {
72 DCHECK(client); 85 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
73 // Make sure we don't call init more than once.
74 DCHECK_EQ(0, stream_id_);
75 86
87 if (!plugin_delegate || !client)
88 return false;
89
90 plugin_delegate_ = plugin_delegate;
76 client_ = client; 91 client_ = client;
77 92
78 AudioParameters params; 93 params_.format = AudioParameters::AUDIO_PCM_LINEAR;
79 params.format = AudioParameters::AUDIO_PCM_LINEAR; 94 params_.channels = 1;
80 params.channels = 1; 95 params_.sample_rate = sample_rate;
81 params.sample_rate = sample_rate; 96 params_.bits_per_sample = 16;
82 params.bits_per_sample = 16; 97 params_.samples_per_packet = sample_count;
83 params.samples_per_packet = sample_count;
84 98
85 ChildProcess::current()->io_message_loop()->PostTask( 99 if (device_id.empty()) {
86 FROM_HERE, 100 // Use the default device.
87 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread, 101 ChildProcess::current()->io_message_loop()->PostTask(
88 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 }
89 return true; 112 return true;
90 } 113 }
91 114
92 void PepperPlatformAudioInputImpl::InitializeOnIOThread( 115 void PepperPlatformAudioInputImpl::InitializeOnIOThread(int session_id) {
93 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_);
94 stream_id_ = filter_->AddDelegate(this); 124 stream_id_ = filter_->AddDelegate(this);
95 filter_->Send(new AudioInputHostMsg_CreateStream( 125 DCHECK_NE(0, stream_id_);
96 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 }
97 } 135 }
98 136
99 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() { 137 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() {
138 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
139 BelongsToCurrentThread());
140
100 if (stream_id_) 141 if (stream_id_)
101 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_)); 142 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
102 } 143 }
103 144
104 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.
105 if (stream_id_) 150 if (stream_id_)
106 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 151 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
107 } 152 }
108 153
109 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() { 154 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() {
155 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
156 BelongsToCurrentThread());
157
110 // Make sure we don't call shutdown more than once. 158 // Make sure we don't call shutdown more than once.
111 if (!stream_id_) 159 if (shutdown_called_)
112 return; 160 return;
161 shutdown_called_ = true;
113 162
114 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 163 if (stream_id_) {
115 filter_->RemoveDelegate(stream_id_); 164 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
116 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));
117 172
118 Release(); // Release for the delegate, balances out the reference taken in 173 Release(); // Release for the delegate, balances out the reference taken in
119 // PepperPluginDelegateImpl::CreateAudioInput. 174 // PepperPluginDelegateImpl::CreateAudioInput.
120 } 175 }
121 176
122 void PepperPlatformAudioInputImpl::OnStreamCreated( 177 void PepperPlatformAudioInputImpl::OnStreamCreated(
123 base::SharedMemoryHandle handle, 178 base::SharedMemoryHandle handle,
124 base::SyncSocket::Handle socket_handle, 179 base::SyncSocket::Handle socket_handle,
125 uint32 length) { 180 uint32 length) {
126 #if defined(OS_WIN) 181 #if defined(OS_WIN)
127 DCHECK(handle); 182 DCHECK(handle);
128 DCHECK(socket_handle); 183 DCHECK(socket_handle);
129 #else 184 #else
130 DCHECK_NE(-1, handle.fd); 185 DCHECK_NE(-1, handle.fd);
131 DCHECK_NE(-1, socket_handle); 186 DCHECK_NE(-1, socket_handle);
132 #endif 187 #endif
133 DCHECK(length); 188 DCHECK(length);
134 189
135 if (base::MessageLoopProxy::current() == main_message_loop_proxy_) { 190 if (base::MessageLoopProxy::current() != main_message_loop_proxy_) {
136 // Must dereference the client only on the main thread. Shutdown may have 191 // No need to check |shutdown_called_| here. If shutdown has occurred,
137 // 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
138 if (client_) 193 // thread.
139 client_->StreamCreated(handle, length, socket_handle);
140 } else {
141 main_message_loop_proxy_->PostTask( 194 main_message_loop_proxy_->PostTask(
142 FROM_HERE, 195 FROM_HERE,
143 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this, 196 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this,
144 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 }
145 } 208 }
146 } 209 }
147 210
148 void PepperPlatformAudioInputImpl::OnVolume(double volume) { 211 void PepperPlatformAudioInputImpl::OnVolume(double volume) {
149 } 212 }
150 213
151 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) { 214 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) {
152 } 215 }
153 216
154 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 }
155 } 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 succeeded = succeeded && plugin_delegate_;
242 if (succeeded) {
no longer working on chromium 2012/03/18 00:38:59 it is more clear to be if (succeeded && plugin_del
yzshen1 2012/03/19 21:47:54 Yeah. Thanks for pointing it out. On 2012/03/18 00
243 label_ = label;
244
no longer working on chromium 2012/03/18 00:38:59 add a DCHECK(!label_.empty()) ?
yzshen1 2012/03/19 21:47:54 Done.
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