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/media/audio_renderer_mixer_manager.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "content/renderer/media/audio_device_factory.h"
10#include "media/audio/audio_output_device.h"
11#include "media/base/audio_hardware_config.h"
12#include "media/base/audio_renderer_mixer.h"
13#include "media/base/audio_renderer_mixer_input.h"
14
15namespace content {
16
17AudioRendererMixerManager::AudioRendererMixerManager(
18    media::AudioHardwareConfig* hardware_config)
19    : hardware_config_(hardware_config),
20      sink_for_testing_(NULL) {
21}
22
23AudioRendererMixerManager::~AudioRendererMixerManager() {
24  DCHECK(mixers_.empty());
25}
26
27media::AudioRendererMixerInput* AudioRendererMixerManager::CreateInput(
28    int source_render_view_id, int source_render_frame_id) {
29  return new media::AudioRendererMixerInput(
30      base::Bind(
31          &AudioRendererMixerManager::GetMixer, base::Unretained(this),
32          source_render_view_id,
33          source_render_frame_id),
34      base::Bind(
35          &AudioRendererMixerManager::RemoveMixer, base::Unretained(this),
36          source_render_view_id));
37}
38
39void AudioRendererMixerManager::SetAudioRendererSinkForTesting(
40    media::AudioRendererSink* sink) {
41  sink_for_testing_ = sink;
42}
43
44media::AudioRendererMixer* AudioRendererMixerManager::GetMixer(
45    int source_render_view_id,
46    int source_render_frame_id,
47    const media::AudioParameters& params) {
48  const MixerKey key(source_render_view_id, params);
49  base::AutoLock auto_lock(mixers_lock_);
50
51  AudioRendererMixerMap::iterator it = mixers_.find(key);
52  if (it != mixers_.end()) {
53    it->second.ref_count++;
54    return it->second.mixer;
55  }
56
57  // On ChromeOS and Linux we can rely on the playback device to handle
58  // resampling, so don't waste cycles on it here.
59#if defined(OS_CHROMEOS) || defined(OS_LINUX)
60  int sample_rate = params.sample_rate();
61#else
62  int sample_rate = hardware_config_->GetOutputSampleRate();
63#endif
64
65  // Create output parameters based on the audio hardware configuration for
66  // passing on to the output sink.  Force to 16-bit output for now since we
67  // know that works well for WebAudio and WebRTC.
68  media::AudioParameters output_params(
69      media::AudioParameters::AUDIO_PCM_LOW_LATENCY, params.channel_layout(),
70      sample_rate, 16, hardware_config_->GetHighLatencyBufferSize());
71
72  // If we've created invalid output parameters, simply pass on the input params
73  // and let the browser side handle automatic fallback.
74  if (!output_params.IsValid())
75    output_params = params;
76
77  media::AudioRendererMixer* mixer;
78  if (sink_for_testing_) {
79    mixer = new media::AudioRendererMixer(
80        params, output_params, sink_for_testing_);
81  } else {
82    mixer = new media::AudioRendererMixer(
83        params, output_params, AudioDeviceFactory::NewOutputDevice(
84            source_render_view_id, source_render_frame_id));
85  }
86
87  AudioRendererMixerReference mixer_reference = { mixer, 1 };
88  mixers_[key] = mixer_reference;
89  return mixer;
90}
91
92void AudioRendererMixerManager::RemoveMixer(
93    int source_render_view_id,
94    const media::AudioParameters& params) {
95  const MixerKey key(source_render_view_id, params);
96  base::AutoLock auto_lock(mixers_lock_);
97
98  AudioRendererMixerMap::iterator it = mixers_.find(key);
99  DCHECK(it != mixers_.end());
100
101  // Only remove the mixer if AudioRendererMixerManager is the last owner.
102  it->second.ref_count--;
103  if (it->second.ref_count == 0) {
104    delete it->second.mixer;
105    mixers_.erase(it);
106  }
107}
108
109}  // namespace content
110