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.
5 #include "content/renderer/pepper/pepper_platform_audio_output_impl.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/message_loop_proxy.h"
11 #include "build/build_config.h"
12 #include "content/common/child_process.h"
13 #include "content/common/media/audio_messages.h"
14 #include "content/renderer/media/audio_message_filter.h"
15 #include "content/renderer/render_thread_impl.h"
16 #include "media/base/audio_hardware_config.h"
17 #include "media/base/media_switches.h"
22 PepperPlatformAudioOutputImpl
* PepperPlatformAudioOutputImpl::Create(
24 int frames_per_buffer
,
25 int source_render_view_id
,
26 webkit::ppapi::PluginDelegate::PlatformAudioOutputClient
* client
) {
27 scoped_refptr
<PepperPlatformAudioOutputImpl
> audio_output(
28 new PepperPlatformAudioOutputImpl());
29 if (audio_output
->Initialize(sample_rate
, frames_per_buffer
,
30 source_render_view_id
, client
)) {
31 // Balanced by Release invoked in
32 // PepperPlatformAudioOutputImpl::ShutDownOnIOThread().
33 audio_output
->AddRef();
34 return audio_output
.get();
39 bool PepperPlatformAudioOutputImpl::StartPlayback() {
41 ChildProcess::current()->io_message_loop()->PostTask(
43 base::Bind(&PepperPlatformAudioOutputImpl::StartPlaybackOnIOThread
,
50 bool PepperPlatformAudioOutputImpl::StopPlayback() {
52 ChildProcess::current()->io_message_loop()->PostTask(
54 base::Bind(&PepperPlatformAudioOutputImpl::StopPlaybackOnIOThread
,
61 void PepperPlatformAudioOutputImpl::ShutDown() {
62 // Called on the main thread to stop all audio callbacks. We must only change
63 // the client on the main thread, and the delegates from the I/O thread.
65 ChildProcess::current()->io_message_loop()->PostTask(
67 base::Bind(&PepperPlatformAudioOutputImpl::ShutDownOnIOThread
, this));
70 void PepperPlatformAudioOutputImpl::OnStateChanged(
71 media::AudioOutputIPCDelegate::State state
) {
74 void PepperPlatformAudioOutputImpl::OnStreamCreated(
75 base::SharedMemoryHandle handle
,
76 base::SyncSocket::Handle socket_handle
,
80 DCHECK(socket_handle
);
82 DCHECK_NE(-1, handle
.fd
);
83 DCHECK_NE(-1, socket_handle
);
87 if (base::MessageLoopProxy::current() == main_message_loop_proxy_
) {
88 // Must dereference the client only on the main thread. Shutdown may have
89 // occurred while the request was in-flight, so we need to NULL check.
91 client_
->StreamCreated(handle
, length
, socket_handle
);
93 main_message_loop_proxy_
->PostTask(FROM_HERE
,
94 base::Bind(&PepperPlatformAudioOutputImpl::OnStreamCreated
, this,
95 handle
, socket_handle
, length
));
99 void PepperPlatformAudioOutputImpl::OnIPCClosed() {
103 PepperPlatformAudioOutputImpl::~PepperPlatformAudioOutputImpl() {
104 // Make sure we have been shut down. Warning: this will usually happen on
110 PepperPlatformAudioOutputImpl::PepperPlatformAudioOutputImpl()
112 main_message_loop_proxy_(base::MessageLoopProxy::current()) {
115 bool PepperPlatformAudioOutputImpl::Initialize(
117 int frames_per_buffer
,
118 int source_render_view_id
,
119 webkit::ppapi::PluginDelegate::PlatformAudioOutputClient
* client
) {
123 RenderThreadImpl
* const render_thread
= RenderThreadImpl::current();
124 ipc_
= render_thread
->audio_message_filter()->
125 CreateAudioOutputIPC(source_render_view_id
);
128 media::AudioParameters::Format format
;
129 const int kMaxFramesForLowLatency
= 2047;
131 media::AudioHardwareConfig
* hardware_config
=
132 render_thread
->GetAudioHardwareConfig();
134 const CommandLine
* cmd_line
= CommandLine::ForCurrentProcess();
135 if (!cmd_line
->HasSwitch(switches::kDisableAudioOutputResampler
)) {
136 // Rely on AudioOutputResampler to handle any inconsistencies between the
137 // hardware params required for low latency and the requested params.
138 format
= media::AudioParameters::AUDIO_PCM_LOW_LATENCY
;
139 } else if (sample_rate
== hardware_config
->GetOutputSampleRate() &&
140 frames_per_buffer
<= kMaxFramesForLowLatency
&&
141 frames_per_buffer
% hardware_config
->GetOutputBufferSize() == 0) {
142 // Use the low latency back end if the client request is compatible, and
143 // the sample count is low enough to justify using AUDIO_PCM_LOW_LATENCY.
144 format
= media::AudioParameters::AUDIO_PCM_LOW_LATENCY
;
146 format
= media::AudioParameters::AUDIO_PCM_LINEAR
;
149 media::AudioParameters
params(format
, media::CHANNEL_LAYOUT_STEREO
,
150 sample_rate
, 16, frames_per_buffer
);
152 ChildProcess::current()->io_message_loop()->PostTask(
154 base::Bind(&PepperPlatformAudioOutputImpl::InitializeOnIOThread
,
159 void PepperPlatformAudioOutputImpl::InitializeOnIOThread(
160 const media::AudioParameters
& params
) {
161 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
162 BelongsToCurrentThread());
164 ipc_
->CreateStream(this, params
);
167 void PepperPlatformAudioOutputImpl::StartPlaybackOnIOThread() {
168 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
169 BelongsToCurrentThread());
174 void PepperPlatformAudioOutputImpl::StopPlaybackOnIOThread() {
175 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
176 BelongsToCurrentThread());
181 void PepperPlatformAudioOutputImpl::ShutDownOnIOThread() {
182 DCHECK(ChildProcess::current()->io_message_loop_proxy()->
183 BelongsToCurrentThread());
185 // Make sure we don't call shutdown more than once.
192 Release(); // Release for the delegate, balances out the reference taken in
193 // PepperPluginDelegateImpl::CreateAudio.
196 } // namespace content