Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / pepper_platform_audio_input.cc
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.
4
5 #include "content/renderer/pepper/pepper_platform_audio_input.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop_proxy.h"
10 #include "build/build_config.h"
11 #include "content/child/child_process.h"
12 #include "content/renderer/media/audio_input_message_filter.h"
13 #include "content/renderer/pepper/pepper_audio_input_host.h"
14 #include "content/renderer/pepper/pepper_media_device_manager.h"
15 #include "content/renderer/render_thread_impl.h"
16 #include "content/renderer/render_view_impl.h"
17 #include "media/audio/audio_manager_base.h"
18 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
19 #include "url/gurl.h"
20
21 namespace content {
22
23 // static
24 PepperPlatformAudioInput* PepperPlatformAudioInput::Create(
25     const base::WeakPtr<RenderViewImpl>& render_view,
26     const std::string& device_id,
27     const GURL& document_url,
28     int sample_rate,
29     int frames_per_buffer,
30     PepperAudioInputHost* client) {
31   scoped_refptr<PepperPlatformAudioInput> audio_input(
32       new PepperPlatformAudioInput());
33   if (audio_input->Initialize(render_view,
34                               device_id,
35                               document_url,
36                               sample_rate,
37                               frames_per_buffer,
38                               client)) {
39     // Balanced by Release invoked in
40     // PepperPlatformAudioInput::ShutDownOnIOThread().
41     audio_input->AddRef();
42     return audio_input.get();
43   }
44   return NULL;
45 }
46
47 void PepperPlatformAudioInput::StartCapture() {
48   DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
49
50   io_message_loop_proxy_->PostTask(
51       FROM_HERE,
52       base::Bind(&PepperPlatformAudioInput::StartCaptureOnIOThread, this));
53 }
54
55 void PepperPlatformAudioInput::StopCapture() {
56   DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
57
58   io_message_loop_proxy_->PostTask(
59       FROM_HERE,
60       base::Bind(&PepperPlatformAudioInput::StopCaptureOnIOThread, this));
61 }
62
63 void PepperPlatformAudioInput::ShutDown() {
64   DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
65
66   // Make sure we don't call shutdown more than once.
67   if (!client_)
68     return;
69
70   // Called on the main thread to stop all audio callbacks. We must only change
71   // the client on the main thread, and the delegates from the I/O thread.
72   client_ = NULL;
73   io_message_loop_proxy_->PostTask(
74       FROM_HERE,
75       base::Bind(&PepperPlatformAudioInput::ShutDownOnIOThread, this));
76 }
77
78 void PepperPlatformAudioInput::OnStreamCreated(
79     base::SharedMemoryHandle handle,
80     base::SyncSocket::Handle socket_handle,
81     int length,
82     int total_segments) {
83 #if defined(OS_WIN)
84   DCHECK(handle);
85   DCHECK(socket_handle);
86 #else
87   DCHECK_NE(-1, handle.fd);
88   DCHECK_NE(-1, socket_handle);
89 #endif
90   DCHECK(length);
91   // TODO(yzshen): Make use of circular buffer scheme. crbug.com/181449.
92   DCHECK_EQ(1, total_segments);
93
94   if (base::MessageLoopProxy::current().get() !=
95       main_message_loop_proxy_.get()) {
96     // If shutdown has occurred, |client_| will be NULL and the handles will be
97     // cleaned up on the main thread.
98     main_message_loop_proxy_->PostTask(
99         FROM_HERE,
100         base::Bind(&PepperPlatformAudioInput::OnStreamCreated,
101                    this,
102                    handle,
103                    socket_handle,
104                    length,
105                    total_segments));
106   } else {
107     // Must dereference the client only on the main thread. Shutdown may have
108     // occurred while the request was in-flight, so we need to NULL check.
109     if (client_) {
110       client_->StreamCreated(handle, length, socket_handle);
111     } else {
112       // Clean up the handles.
113       base::SyncSocket temp_socket(socket_handle);
114       base::SharedMemory temp_shared_memory(handle, false);
115     }
116   }
117 }
118
119 void PepperPlatformAudioInput::OnVolume(double volume) {}
120
121 void PepperPlatformAudioInput::OnStateChanged(
122     media::AudioInputIPCDelegate::State state) {}
123
124 void PepperPlatformAudioInput::OnIPCClosed() { ipc_.reset(); }
125
126 PepperPlatformAudioInput::~PepperPlatformAudioInput() {
127   // Make sure we have been shut down. Warning: this may happen on the I/O
128   // thread!
129   // Although these members should be accessed on a specific thread (either the
130   // main thread or the I/O thread), it should be fine to examine their value
131   // here.
132   DCHECK(!ipc_);
133   DCHECK(!client_);
134   DCHECK(label_.empty());
135   DCHECK(!pending_open_device_);
136 }
137
138 PepperPlatformAudioInput::PepperPlatformAudioInput()
139     : client_(NULL),
140       main_message_loop_proxy_(base::MessageLoopProxy::current()),
141       io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()),
142       create_stream_sent_(false),
143       pending_open_device_(false),
144       pending_open_device_id_(-1) {}
145
146 bool PepperPlatformAudioInput::Initialize(
147     const base::WeakPtr<RenderViewImpl>& render_view,
148     const std::string& device_id,
149     const GURL& document_url,
150     int sample_rate,
151     int frames_per_buffer,
152     PepperAudioInputHost* client) {
153   DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
154
155   if (!render_view.get() || !client)
156     return false;
157
158   ipc_ = RenderThreadImpl::current()
159              ->audio_input_message_filter()
160              ->CreateAudioInputIPC(render_view->GetRoutingID());
161
162   render_view_ = render_view;
163   client_ = client;
164
165   params_.Reset(media::AudioParameters::AUDIO_PCM_LINEAR,
166                 media::CHANNEL_LAYOUT_MONO,
167                 ppapi::kAudioInputChannels,
168                 0,
169                 sample_rate,
170                 ppapi::kBitsPerAudioInputSample,
171                 frames_per_buffer);
172
173   // We need to open the device and obtain the label and session ID before
174   // initializing.
175   pending_open_device_id_ = GetMediaDeviceManager()->OpenDevice(
176       PP_DEVICETYPE_DEV_AUDIOCAPTURE,
177       device_id.empty() ? media::AudioManagerBase::kDefaultDeviceId : device_id,
178       document_url,
179       base::Bind(&PepperPlatformAudioInput::OnDeviceOpened, this));
180   pending_open_device_ = true;
181
182   return true;
183 }
184
185 void PepperPlatformAudioInput::InitializeOnIOThread(int session_id) {
186   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
187
188   if (!ipc_)
189     return;
190
191   // We will be notified by OnStreamCreated().
192   create_stream_sent_ = true;
193   ipc_->CreateStream(this, session_id, params_, false, 1);
194 }
195
196 void PepperPlatformAudioInput::StartCaptureOnIOThread() {
197   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
198
199   if (ipc_)
200     ipc_->RecordStream();
201 }
202
203 void PepperPlatformAudioInput::StopCaptureOnIOThread() {
204   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
205
206   // TODO(yzshen): We cannot re-start capturing if the stream is closed.
207   if (ipc_ && create_stream_sent_) {
208     ipc_->CloseStream();
209   }
210   ipc_.reset();
211 }
212
213 void PepperPlatformAudioInput::ShutDownOnIOThread() {
214   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
215
216   StopCaptureOnIOThread();
217
218   main_message_loop_proxy_->PostTask(
219       FROM_HERE, base::Bind(&PepperPlatformAudioInput::CloseDevice, this));
220
221   Release();  // Release for the delegate, balances out the reference taken in
222               // PepperPlatformAudioInput::Create.
223 }
224
225 void PepperPlatformAudioInput::OnDeviceOpened(int request_id,
226                                               bool succeeded,
227                                               const std::string& label) {
228   DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
229
230   pending_open_device_ = false;
231   pending_open_device_id_ = -1;
232
233   if (succeeded && render_view_.get()) {
234     DCHECK(!label.empty());
235     label_ = label;
236
237     if (client_) {
238       int session_id = GetMediaDeviceManager()->GetSessionID(
239           PP_DEVICETYPE_DEV_AUDIOCAPTURE, label);
240       io_message_loop_proxy_->PostTask(
241           FROM_HERE,
242           base::Bind(&PepperPlatformAudioInput::InitializeOnIOThread,
243                      this,
244                      session_id));
245     } else {
246       // Shutdown has occurred.
247       CloseDevice();
248     }
249   } else {
250     NotifyStreamCreationFailed();
251   }
252 }
253
254 void PepperPlatformAudioInput::CloseDevice() {
255   DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
256
257   if (render_view_.get()) {
258     if (!label_.empty()) {
259       GetMediaDeviceManager()->CloseDevice(label_);
260       label_.clear();
261     }
262     if (pending_open_device_) {
263       GetMediaDeviceManager()->CancelOpenDevice(pending_open_device_id_);
264       pending_open_device_ = false;
265       pending_open_device_id_ = -1;
266     }
267   }
268 }
269
270 void PepperPlatformAudioInput::NotifyStreamCreationFailed() {
271   DCHECK(main_message_loop_proxy_->BelongsToCurrentThread());
272
273   if (client_)
274     client_->StreamCreationFailed();
275 }
276
277 PepperMediaDeviceManager* PepperPlatformAudioInput::GetMediaDeviceManager() {
278   return PepperMediaDeviceManager::GetForRenderView(render_view_.get());
279 }
280
281 }  // namespace content