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

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) {
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 uint32_t sample_rate, 41 uint32_t sample_rate,
33 uint32_t sample_count, 42 uint32_t sample_count,
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, sample_count, client)) { 46 if (audio_input->Initialize(plugin_delegate, device_id, sample_rate,
47 sample_count, 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 uint32_t sample_rate, 85 uint32_t sample_rate,
70 uint32_t sample_count, 86 uint32_t sample_count,
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; 96 params_.format = AudioParameters::AUDIO_PCM_LINEAR;
79 params.format = AudioParameters::AUDIO_PCM_LINEAR; 97 params_.channels = 1;
80 params.channels = 1; 98 params_.sample_rate = sample_rate;
81 params.sample_rate = sample_rate; 99 params_.bits_per_sample = 16;
82 params.bits_per_sample = 16; 100 params_.samples_per_packet = sample_count;
83 params.samples_per_packet = sample_count;
84 101
85 ChildProcess::current()->io_message_loop()->PostTask( 102 if (device_id.empty()) {
86 FROM_HERE, 103 // Use the default device.
87 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread, 104 ChildProcess::current()->io_message_loop()->PostTask(
88 this, params)); 105 FROM_HERE,
106 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
107 this, 0));
108 } else {
109 // We need to open the device and obtain the label and session ID before
110 // initializing.
111 plugin_delegate_->OpenDevice(
112 PP_DEVICETYPE_DEV_AUDIOCAPTURE, device_id,
113 base::Bind(&PepperPlatformAudioInputImpl::OnDeviceOpened, this));
114 }
89 return true; 115 return true;
90 } 116 }
91 117
92 void PepperPlatformAudioInputImpl::InitializeOnIOThread( 118 void PepperPlatformAudioInputImpl::InitializeOnIOThread(int session_id) {
93 const AudioParameters& params) { 119 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
120 BelongsToCurrentThread());
121
122 if (shutdown_called_)
123 return;
124
125 // Make sure we don't call init more than once.
126 DCHECK_EQ(0, stream_id_);
94 stream_id_ = filter_->AddDelegate(this); 127 stream_id_ = filter_->AddDelegate(this);
95 filter_->Send(new AudioInputHostMsg_CreateStream( 128 DCHECK_NE(0, stream_id_);
96 stream_id_, params, AudioManagerBase::kDefaultDeviceId)); 129
130 if (!session_id) {
131 // We will be notified by OnStreamCreated().
132 filter_->Send(new AudioInputHostMsg_CreateStream(
133 stream_id_, params_, AudioManagerBase::kDefaultDeviceId));
134 } else {
135 // We will be notified by OnDeviceReady().
136 filter_->Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id));
137 }
97 } 138 }
98 139
99 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() { 140 void PepperPlatformAudioInputImpl::StartCaptureOnIOThread() {
141 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
142 BelongsToCurrentThread());
143
100 if (stream_id_) 144 if (stream_id_)
101 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_)); 145 filter_->Send(new AudioInputHostMsg_RecordStream(stream_id_));
102 } 146 }
103 147
104 void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() { 148 void PepperPlatformAudioInputImpl::StopCaptureOnIOThread() {
149 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
150 BelongsToCurrentThread());
151
152 // TODO(yzshen): We cannot re-start capturing if the stream is closed.
105 if (stream_id_) 153 if (stream_id_)
106 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 154 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
107 } 155 }
108 156
109 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() { 157 void PepperPlatformAudioInputImpl::ShutDownOnIOThread() {
158 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
159 BelongsToCurrentThread());
160
110 // Make sure we don't call shutdown more than once. 161 // Make sure we don't call shutdown more than once.
111 if (!stream_id_) 162 if (shutdown_called_)
112 return; 163 return;
164 shutdown_called_ = true;
113 165
114 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_)); 166 if (stream_id_) {
115 filter_->RemoveDelegate(stream_id_); 167 filter_->Send(new AudioInputHostMsg_CloseStream(stream_id_));
116 stream_id_ = 0; 168 filter_->RemoveDelegate(stream_id_);
169 stream_id_ = 0;
170 }
171
172 main_message_loop_proxy_->PostTask(
173 FROM_HERE,
174 base::Bind(&PepperPlatformAudioInputImpl::CloseDevice, this));
117 175
118 Release(); // Release for the delegate, balances out the reference taken in 176 Release(); // Release for the delegate, balances out the reference taken in
119 // PepperPluginDelegateImpl::CreateAudioInput. 177 // PepperPluginDelegateImpl::CreateAudioInput.
120 } 178 }
121 179
122 void PepperPlatformAudioInputImpl::OnStreamCreated( 180 void PepperPlatformAudioInputImpl::OnStreamCreated(
123 base::SharedMemoryHandle handle, 181 base::SharedMemoryHandle handle,
124 base::SyncSocket::Handle socket_handle, 182 base::SyncSocket::Handle socket_handle,
125 uint32 length) { 183 uint32 length) {
126 #if defined(OS_WIN) 184 #if defined(OS_WIN)
127 DCHECK(handle); 185 DCHECK(handle);
128 DCHECK(socket_handle); 186 DCHECK(socket_handle);
129 #else 187 #else
130 DCHECK_NE(-1, handle.fd); 188 DCHECK_NE(-1, handle.fd);
131 DCHECK_NE(-1, socket_handle); 189 DCHECK_NE(-1, socket_handle);
132 #endif 190 #endif
133 DCHECK(length); 191 DCHECK(length);
134 192
135 if (base::MessageLoopProxy::current() == main_message_loop_proxy_) { 193 if (base::MessageLoopProxy::current() != main_message_loop_proxy_) {
136 // Must dereference the client only on the main thread. Shutdown may have 194 // 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. 195 // |client_| will be NULL and the handles will be cleaned up on the main
138 if (client_) 196 // thread.
139 client_->StreamCreated(handle, length, socket_handle);
140 } else {
141 main_message_loop_proxy_->PostTask( 197 main_message_loop_proxy_->PostTask(
142 FROM_HERE, 198 FROM_HERE,
143 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this, 199 base::Bind(&PepperPlatformAudioInputImpl::OnStreamCreated, this,
144 handle, socket_handle, length)); 200 handle, socket_handle, length));
201 } else {
202 // Must dereference the client only on the main thread. Shutdown may have
203 // occurred while the request was in-flight, so we need to NULL check.
204 if (client_) {
205 client_->StreamCreated(handle, length, socket_handle);
206 } else {
207 // Clean up the handles.
208 base::SyncSocket temp_socket(socket_handle);
209 base::SharedMemory temp_shared_memory(handle, false);
210 }
145 } 211 }
146 } 212 }
147 213
148 void PepperPlatformAudioInputImpl::OnVolume(double volume) { 214 void PepperPlatformAudioInputImpl::OnVolume(double volume) {
149 } 215 }
150 216
151 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) { 217 void PepperPlatformAudioInputImpl::OnStateChanged(AudioStreamState state) {
152 } 218 }
153 219
154 void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string&) { 220 void PepperPlatformAudioInputImpl::OnDeviceReady(const std::string& device_id) {
221 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
222 BelongsToCurrentThread());
223
224 if (shutdown_called_)
225 return;
226
227 if (device_id.empty()) {
228 main_message_loop_proxy_->PostTask(
229 FROM_HERE,
230 base::Bind(&PepperPlatformAudioInputImpl::NotifyStreamCreationFailed,
231 this));
232 } else {
233 // We will be notified by OnStreamCreated().
234 filter_->Send(new AudioInputHostMsg_CreateStream(stream_id_, params_,
235 device_id));
236 }
155 } 237 }
238
239 void PepperPlatformAudioInputImpl::OnDeviceOpened(int request_id,
240 bool succeeded,
241 const std::string& label) {
242 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
243
244 if (succeeded && plugin_delegate_) {
245 DCHECK(!label.empty());
246 label_ = label;
247
248 if (client_) {
249 int session_id = plugin_delegate_->GetSessionID(
250 PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
251 ChildProcess::current()->io_message_loop()->PostTask(
252 FROM_HERE,
253 base::Bind(&PepperPlatformAudioInputImpl::InitializeOnIOThread,
254 this, session_id));
255 } else {
256 // Shutdown has occurred.
257 CloseDevice();
258 }
259 } else {
260 NotifyStreamCreationFailed();
261 }
262 }
263
264 void PepperPlatformAudioInputImpl::CloseDevice() {
265 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
266
267 if (plugin_delegate_ && !label_.empty()) {
268 plugin_delegate_->CloseDevice(label_);
269 label_.clear();
270 }
271 }
272
273 void PepperPlatformAudioInputImpl::NotifyStreamCreationFailed() {
274 DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
275
276 if (client_)
277 client_->StreamCreationFailed();
278 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698