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/media/audio_device.h"
7 #include "base/debug/trace_event.h"
8 #include "base/message_loop.h"
9 #include "base/threading/thread_restrictions.h"
10 #include "base/time.h"
11 #include "content/common/child_process.h"
12 #include "content/common/media/audio_messages.h"
13 #include "content/common/view_messages.h"
14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_output_controller.h"
16 #include "media/audio/audio_util.h"
18 using media::AudioRendererSink
;
20 // Takes care of invoking the render callback on the audio thread.
21 // An instance of this class is created for each capture stream in
23 class AudioDevice::AudioThreadCallback
24 : public AudioDeviceThread::Callback
{
26 AudioThreadCallback(const media::AudioParameters
& audio_parameters
,
27 base::SharedMemoryHandle memory
,
29 AudioRendererSink::RenderCallback
* render_callback
);
30 virtual ~AudioThreadCallback();
32 virtual void MapSharedMemory() OVERRIDE
;
34 // Called whenever we receive notifications about pending data.
35 virtual void Process(int pending_data
) OVERRIDE
;
38 AudioRendererSink::RenderCallback
* render_callback_
;
39 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback
);
42 AudioDevice::AudioDevice()
43 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()),
49 filter_
= RenderThreadImpl::current()->audio_message_filter();
52 AudioDevice::AudioDevice(const media::AudioParameters
& params
,
53 RenderCallback
* callback
)
54 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()),
55 audio_parameters_(params
),
61 filter_
= RenderThreadImpl::current()->audio_message_filter();
64 void AudioDevice::Initialize(const media::AudioParameters
& params
,
65 RenderCallback
* callback
) {
66 CHECK_EQ(0, stream_id_
) <<
67 "AudioDevice::Initialize() must be called before Start()";
69 CHECK(!callback_
); // Calling Initialize() twice?
71 audio_parameters_
= params
;
72 // TODO(xians): We have to hard code the sample format to 16 since the
73 // current audio path does not support sample formats rather than 16bits per
74 // channel. Remove it if the problem is fixed.
75 audio_parameters_
.Reset(
77 params
.channel_layout(), params
.sample_rate(), 16,
78 params
.frames_per_buffer());
82 AudioDevice::~AudioDevice() {
83 // The current design requires that the user calls Stop() before deleting
85 CHECK_EQ(0, stream_id_
);
88 void AudioDevice::Start() {
89 DCHECK(callback_
) << "Initialize hasn't been called";
90 message_loop()->PostTask(FROM_HERE
,
91 base::Bind(&AudioDevice::InitializeOnIOThread
, this, audio_parameters_
));
94 void AudioDevice::Stop() {
96 base::AutoLock
auto_lock(audio_thread_lock_
);
97 audio_thread_
.Stop(MessageLoop::current());
100 message_loop()->PostTask(FROM_HERE
,
101 base::Bind(&AudioDevice::ShutDownOnIOThread
, this));
104 void AudioDevice::Play() {
105 message_loop()->PostTask(FROM_HERE
,
106 base::Bind(&AudioDevice::PlayOnIOThread
, this));
109 void AudioDevice::Pause(bool flush
) {
110 message_loop()->PostTask(FROM_HERE
,
111 base::Bind(&AudioDevice::PauseOnIOThread
, this, flush
));
114 bool AudioDevice::SetVolume(double volume
) {
115 if (volume
< 0 || volume
> 1.0)
118 if (!message_loop()->PostTask(FROM_HERE
,
119 base::Bind(&AudioDevice::SetVolumeOnIOThread
, this, volume
))) {
128 void AudioDevice::GetVolume(double* volume
) {
129 // Return a locally cached version of the current scaling factor.
133 void AudioDevice::InitializeOnIOThread(const media::AudioParameters
& params
) {
134 DCHECK(message_loop()->BelongsToCurrentThread());
135 // Make sure we don't create the stream more than once.
136 DCHECK_EQ(0, stream_id_
);
140 stream_id_
= filter_
->AddDelegate(this);
141 Send(new AudioHostMsg_CreateStream(stream_id_
, params
));
144 void AudioDevice::PlayOnIOThread() {
145 DCHECK(message_loop()->BelongsToCurrentThread());
146 if (stream_id_
&& is_started_
)
147 Send(new AudioHostMsg_PlayStream(stream_id_
));
149 play_on_start_
= true;
152 void AudioDevice::PauseOnIOThread(bool flush
) {
153 DCHECK(message_loop()->BelongsToCurrentThread());
154 if (stream_id_
&& is_started_
) {
155 Send(new AudioHostMsg_PauseStream(stream_id_
));
157 Send(new AudioHostMsg_FlushStream(stream_id_
));
159 // Note that |flush| isn't relevant here since this is the case where
160 // the stream is first starting.
161 play_on_start_
= false;
165 void AudioDevice::ShutDownOnIOThread() {
166 DCHECK(message_loop()->BelongsToCurrentThread());
168 // Make sure we don't call shutdown more than once.
172 filter_
->RemoveDelegate(stream_id_
);
173 Send(new AudioHostMsg_CloseStream(stream_id_
));
177 // We can run into an issue where ShutDownOnIOThread is called right after
178 // OnStreamCreated is called in cases where Start/Stop are called before we
179 // get the OnStreamCreated callback. To handle that corner case, we call
180 // Stop(). In most cases, the thread will already be stopped.
181 // Another situation is when the IO thread goes away before Stop() is called
182 // in which case, we cannot use the message loop to close the thread handle
183 // and can't not rely on the main thread existing either.
184 base::ThreadRestrictions::ScopedAllowIO allow_io
;
185 audio_thread_
.Stop(NULL
);
186 audio_callback_
.reset();
189 void AudioDevice::SetVolumeOnIOThread(double volume
) {
190 DCHECK(message_loop()->BelongsToCurrentThread());
192 Send(new AudioHostMsg_SetVolume(stream_id_
, volume
));
195 void AudioDevice::OnStateChanged(AudioStreamState state
) {
196 DCHECK(message_loop()->BelongsToCurrentThread());
198 // Do nothing if the stream has been closed.
202 if (state
== kAudioStreamError
) {
203 DLOG(WARNING
) << "AudioDevice::OnStateChanged(kError)";
204 // Don't dereference the callback object if the audio thread
205 // is stopped or stopping. That could mean that the callback
206 // object has been deleted.
207 // TODO(tommi): Add an explicit contract for clearing the callback
208 // object. Possibly require calling Initialize again or provide
209 // a callback object via Start() and clear it in Stop().
210 if (!audio_thread_
.IsStopped())
211 callback_
->OnRenderError();
215 void AudioDevice::OnStreamCreated(
216 base::SharedMemoryHandle handle
,
217 base::SyncSocket::Handle socket_handle
,
219 DCHECK(message_loop()->BelongsToCurrentThread());
221 audio_parameters_
.frames_per_buffer() * sizeof(int16
) *
222 audio_parameters_
.channels());
225 DCHECK(socket_handle
);
227 DCHECK_GE(handle
.fd
, 0);
228 DCHECK_GE(socket_handle
, 0);
231 base::AutoLock
auto_lock(audio_thread_lock_
);
233 // Takes care of the case when Stop() is called before OnStreamCreated().
235 base::SharedMemory::CloseHandle(handle
);
236 // Close the socket handler.
237 base::SyncSocket
socket(socket_handle
);
241 DCHECK(audio_thread_
.IsStopped());
242 audio_callback_
.reset(new AudioDevice::AudioThreadCallback(audio_parameters_
,
243 handle
, length
, callback_
));
244 audio_thread_
.Start(audio_callback_
.get(), socket_handle
, "AudioDevice");
246 // We handle the case where Play() and/or Pause() may have been called
247 // multiple times before OnStreamCreated() gets called.
253 void AudioDevice::Send(IPC::Message
* message
) {
254 filter_
->Send(message
);
257 void AudioDevice::WillDestroyCurrentMessageLoop() {
258 LOG(ERROR
) << "IO loop going away before the audio device has been stopped";
259 ShutDownOnIOThread();
262 // AudioDevice::AudioThreadCallback
264 AudioDevice::AudioThreadCallback::AudioThreadCallback(
265 const media::AudioParameters
& audio_parameters
,
266 base::SharedMemoryHandle memory
,
268 media::AudioRendererSink::RenderCallback
* render_callback
)
269 : AudioDeviceThread::Callback(audio_parameters
, memory
, memory_length
),
270 render_callback_(render_callback
) {
273 AudioDevice::AudioThreadCallback::~AudioThreadCallback() {
276 void AudioDevice::AudioThreadCallback::MapSharedMemory() {
277 shared_memory_
.Map(media::TotalSharedMemorySizeInBytes(memory_length_
));
280 // Called whenever we receive notifications about pending data.
281 void AudioDevice::AudioThreadCallback::Process(int pending_data
) {
282 if (pending_data
== media::AudioOutputController::kPauseMark
) {
283 memset(shared_memory_
.memory(), 0, memory_length_
);
284 media::SetActualDataSizeInBytes(&shared_memory_
, memory_length_
, 0);
288 // Convert the number of pending bytes in the render buffer
289 // into milliseconds.
290 int audio_delay_milliseconds
= pending_data
/ bytes_per_ms_
;
292 TRACE_EVENT0("audio", "AudioDevice::FireRenderCallback");
294 // Update the audio-delay measurement then ask client to render audio.
295 size_t num_frames
= render_callback_
->Render(audio_data_
,
296 audio_parameters_
.frames_per_buffer(), audio_delay_milliseconds
);
298 // Interleave, scale, and clip to int16.
299 // TODO(crogers): avoid converting to integer here, and pass the data
300 // to the browser process as float, so we don't lose precision for
301 // audio hardware which has better than 16bit precision.
302 int16
* data
= reinterpret_cast<int16
*>(shared_memory_
.memory());
303 media::InterleaveFloatToInt16(audio_data_
, data
,
304 audio_parameters_
.frames_per_buffer());
306 // Let the host know we are done.
307 media::SetActualDataSizeInBytes(&shared_memory_
, memory_length_
,
308 num_frames
* audio_parameters_
.channels() * sizeof(data
[0]));