- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / pepper_platform_audio_output.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_output.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/common/media/audio_messages.h"
13 #include "content/renderer/media/audio_message_filter.h"
14 #include "content/renderer/pepper/audio_helper.h"
15 #include "content/renderer/render_thread_impl.h"
16 #include "media/base/audio_hardware_config.h"
17 #include "ppapi/shared_impl/ppb_audio_config_shared.h"
18
19 namespace content {
20
21 // static
22 PepperPlatformAudioOutput* PepperPlatformAudioOutput::Create(
23     int sample_rate,
24     int frames_per_buffer,
25     int source_render_view_id,
26     AudioHelper* client) {
27   scoped_refptr<PepperPlatformAudioOutput> audio_output(
28       new PepperPlatformAudioOutput());
29   if (audio_output->Initialize(sample_rate, frames_per_buffer,
30                                source_render_view_id, client)) {
31     // Balanced by Release invoked in
32     // PepperPlatformAudioOutput::ShutDownOnIOThread().
33     audio_output->AddRef();
34     return audio_output.get();
35   }
36   return NULL;
37 }
38
39 bool PepperPlatformAudioOutput::StartPlayback() {
40   if (ipc_) {
41     io_message_loop_proxy_->PostTask(
42         FROM_HERE,
43         base::Bind(&PepperPlatformAudioOutput::StartPlaybackOnIOThread, this));
44     return true;
45   }
46   return false;
47 }
48
49 bool PepperPlatformAudioOutput::StopPlayback() {
50   if (ipc_) {
51     io_message_loop_proxy_->PostTask(
52         FROM_HERE,
53         base::Bind(&PepperPlatformAudioOutput::StopPlaybackOnIOThread, this));
54     return true;
55   }
56   return false;
57 }
58
59 void PepperPlatformAudioOutput::ShutDown() {
60   // 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.
62   client_ = NULL;
63   io_message_loop_proxy_->PostTask(
64       FROM_HERE,
65       base::Bind(&PepperPlatformAudioOutput::ShutDownOnIOThread, this));
66 }
67
68 void PepperPlatformAudioOutput::OnStateChanged(
69     media::AudioOutputIPCDelegate::State state) {
70 }
71
72 void PepperPlatformAudioOutput::OnStreamCreated(
73     base::SharedMemoryHandle handle,
74     base::SyncSocket::Handle socket_handle,
75     int length) {
76 #if defined(OS_WIN)
77   DCHECK(handle);
78   DCHECK(socket_handle);
79 #else
80   DCHECK_NE(-1, handle.fd);
81   DCHECK_NE(-1, socket_handle);
82 #endif
83   DCHECK(length);
84
85   if (base::MessageLoopProxy::current().get() ==
86           main_message_loop_proxy_.get()) {
87     // Must dereference the client only on the main thread. Shutdown may have
88     // occurred while the request was in-flight, so we need to NULL check.
89     if (client_)
90       client_->StreamCreated(handle, length, socket_handle);
91   } else {
92     main_message_loop_proxy_->PostTask(FROM_HERE,
93         base::Bind(&PepperPlatformAudioOutput::OnStreamCreated, this, handle,
94                    socket_handle, length));
95   }
96 }
97
98 void PepperPlatformAudioOutput::OnIPCClosed() {
99   ipc_.reset();
100 }
101
102 PepperPlatformAudioOutput::~PepperPlatformAudioOutput() {
103   // Make sure we have been shut down. Warning: this will usually happen on
104   // the I/O thread!
105   DCHECK(!ipc_);
106   DCHECK(!client_);
107 }
108
109 PepperPlatformAudioOutput::PepperPlatformAudioOutput()
110     : client_(NULL),
111       main_message_loop_proxy_(base::MessageLoopProxy::current()),
112       io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()) {
113 }
114
115 bool PepperPlatformAudioOutput::Initialize(
116     int sample_rate,
117     int frames_per_buffer,
118     int source_render_view_id,
119     AudioHelper* client) {
120   DCHECK(client);
121   client_ = client;
122
123   RenderThreadImpl* const render_thread = RenderThreadImpl::current();
124   ipc_ = render_thread->audio_message_filter()->
125       CreateAudioOutputIPC(source_render_view_id);
126   CHECK(ipc_);
127
128   media::AudioParameters params(
129       media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
130       media::CHANNEL_LAYOUT_STEREO, sample_rate,
131       ppapi::kBitsPerAudioOutputSample, frames_per_buffer);
132
133   io_message_loop_proxy_->PostTask(
134       FROM_HERE,
135       base::Bind(&PepperPlatformAudioOutput::InitializeOnIOThread, this,
136                  params));
137   return true;
138 }
139
140 void PepperPlatformAudioOutput::InitializeOnIOThread(
141     const media::AudioParameters& params) {
142   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
143   const int kSessionId = 0;
144   if (ipc_)
145     ipc_->CreateStream(this, params, kSessionId);
146 }
147
148 void PepperPlatformAudioOutput::StartPlaybackOnIOThread() {
149   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
150   if (ipc_)
151     ipc_->PlayStream();
152 }
153
154 void PepperPlatformAudioOutput::StopPlaybackOnIOThread() {
155   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
156   if (ipc_)
157     ipc_->PauseStream();
158 }
159
160 void PepperPlatformAudioOutput::ShutDownOnIOThread() {
161   DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
162
163   // Make sure we don't call shutdown more than once.
164   if (!ipc_)
165     return;
166
167   ipc_->CloseStream();
168   ipc_.reset();
169
170   Release();  // Release for the delegate, balances out the reference taken in
171               // PepperPlatformAudioOutput::Create.
172 }
173
174 }  // namespace content