15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "content/renderer/pepper/pepper_platform_audio_output.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "build/build_config.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/child/child_process.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/common/media/audio_messages.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/renderer/media/audio_message_filter.h"
14558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch#include "content/renderer/pepper/audio_helper.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/renderer/render_thread_impl.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/audio_hardware_config.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
21558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochPepperPlatformAudioOutput* PepperPlatformAudioOutput::Create(
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int sample_rate,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int frames_per_buffer,
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int source_render_view_id,
25558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    AudioHelper* client) {
26558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  scoped_refptr<PepperPlatformAudioOutput> audio_output(
27558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      new PepperPlatformAudioOutput());
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (audio_output->Initialize(sample_rate, frames_per_buffer,
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                               source_render_view_id, client)) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Balanced by Release invoked in
31558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    // PepperPlatformAudioOutput::ShutDownOnIOThread().
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    audio_output->AddRef();
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return audio_output.get();
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool PepperPlatformAudioOutput::StartPlayback() {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ipc_) {
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    io_message_loop_proxy_->PostTask(
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
42558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        base::Bind(&PepperPlatformAudioOutput::StartPlaybackOnIOThread, this));
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
48558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool PepperPlatformAudioOutput::StopPlayback() {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (ipc_) {
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    io_message_loop_proxy_->PostTask(
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
52558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        base::Bind(&PepperPlatformAudioOutput::StopPlaybackOnIOThread, this));
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::ShutDown() {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called on the main thread to stop all audio callbacks. We must only change
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the client on the main thread, and the delegates from the I/O thread.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_ = NULL;
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  io_message_loop_proxy_->PostTask(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
64558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      base::Bind(&PepperPlatformAudioOutput::ShutDownOnIOThread, this));
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::OnStateChanged(
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    media::AudioOutputIPCDelegate::State state) {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
71558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::OnStreamCreated(
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SharedMemoryHandle handle,
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::SyncSocket::Handle socket_handle,
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int length) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(handle);
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_handle);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(-1, handle.fd);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_NE(-1, socket_handle);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(length);
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (base::MessageLoopProxy::current().get() ==
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          main_message_loop_proxy_.get()) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Must dereference the client only on the main thread. Shutdown may have
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // occurred while the request was in-flight, so we need to NULL check.
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (client_)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      client_->StreamCreated(handle, length, socket_handle);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    main_message_loop_proxy_->PostTask(FROM_HERE,
92558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        base::Bind(&PepperPlatformAudioOutput::OnStreamCreated, this, handle,
93558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                   socket_handle, length));
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
97558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::OnIPCClosed() {
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ipc_.reset();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
101558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochPepperPlatformAudioOutput::~PepperPlatformAudioOutput() {
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we have been shut down. Warning: this will usually happen on
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the I/O thread!
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!ipc_);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!client_);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
108558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochPepperPlatformAudioOutput::PepperPlatformAudioOutput()
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : client_(NULL),
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      main_message_loop_proxy_(base::MessageLoopProxy::current()),
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()) {
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
114558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochbool PepperPlatformAudioOutput::Initialize(
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int sample_rate,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int frames_per_buffer,
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int source_render_view_id,
118558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    AudioHelper* client) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(client);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  client_ = client;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  RenderThreadImpl* const render_thread = RenderThreadImpl::current();
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ipc_ = render_thread->audio_message_filter()->
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      CreateAudioOutputIPC(source_render_view_id);
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  CHECK(ipc_);
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  media::AudioParameters params(
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      media::CHANNEL_LAYOUT_STEREO, sample_rate, 16, frames_per_buffer);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  io_message_loop_proxy_->PostTask(
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
133558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      base::Bind(&PepperPlatformAudioOutput::InitializeOnIOThread, this,
134558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                 params));
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
138558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::InitializeOnIOThread(
139c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const media::AudioParameters& params) {
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const int kSessionId = 0;
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ipc_)
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ipc_->CreateStream(this, params, kSessionId);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
146558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::StartPlaybackOnIOThread() {
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
148c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ipc_)
149c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ipc_->PlayStream();
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
152558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::StopPlaybackOnIOThread() {
153eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (ipc_)
155c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ipc_->PauseStream();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
158558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PepperPlatformAudioOutput::ShutDownOnIOThread() {
159eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(io_message_loop_proxy_->BelongsToCurrentThread());
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure we don't call shutdown more than once.
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!ipc_)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ipc_->CloseStream();
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ipc_.reset();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Release();  // Release for the delegate, balances out the reference taken in
1693240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch              // PepperPlatformAudioOutput::Create.
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
173