1 // Copyright 2014 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_media_stream_audio_track_host.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/macros.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "ppapi/c/pp_errors.h"
13 #include "ppapi/c/ppb_audio_buffer.h"
14 #include "ppapi/shared_impl/media_stream_buffer.h"
16 using media::AudioParameters;
20 // Max audio buffer duration in milliseconds.
21 const uint32_t kMaxDuration = 10;
23 // TODO(penghuang): make this configurable.
24 const int32_t kNumberOfBuffers = 4;
30 PepperMediaStreamAudioTrackHost::AudioSink::AudioSink(
31 PepperMediaStreamAudioTrackHost* host)
34 main_message_loop_proxy_(base::MessageLoopProxy::current()),
38 PepperMediaStreamAudioTrackHost::AudioSink::~AudioSink() {
39 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
42 void PepperMediaStreamAudioTrackHost::AudioSink::EnqueueBuffer(int32_t index) {
43 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
45 DCHECK_LT(index, host_->buffer_manager()->number_of_buffers());
46 base::AutoLock lock(lock_);
47 buffers_.push_back(index);
50 void PepperMediaStreamAudioTrackHost::AudioSink::InitBuffersOnMainThread(
51 int32_t number_of_buffers, int32_t buffer_size) {
52 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
53 bool result = host_->InitBuffers(number_of_buffers, buffer_size);
54 // TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin.
56 base::AutoLock lock(lock_);
57 for (int32_t i = 0; i < number_of_buffers; ++i) {
58 int32_t index = host_->buffer_manager()->DequeueBuffer();
60 buffers_.push_back(index);
65 PepperMediaStreamAudioTrackHost::AudioSink::
66 SendEnqueueBufferMessageOnMainThread(int32_t index) {
67 DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
68 host_->SendEnqueueBufferMessageToPlugin(index);
71 void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16* audio_data,
73 int number_of_channels,
74 int number_of_frames) {
75 DCHECK(audio_thread_checker_.CalledOnValidThread());
77 DCHECK_EQ(sample_rate, audio_params_.sample_rate());
78 DCHECK_EQ(number_of_channels, audio_params_.channels());
79 DCHECK_EQ(number_of_frames, audio_params_.frames_per_buffer());
82 base::AutoLock lock(lock_);
83 if (!buffers_.empty()) {
84 index = buffers_.front();
90 // TODO(penghuang): support re-sampling, etc.
91 ppapi::MediaStreamBuffer::Audio* buffer =
92 &(host_->buffer_manager()->GetBufferPointer(index)->audio);
93 buffer->header.size = host_->buffer_manager()->buffer_size();
94 buffer->header.type = ppapi::MediaStreamBuffer::TYPE_AUDIO;
95 buffer->timestamp = timestamp_.InMillisecondsF();
96 buffer->sample_rate = static_cast<PP_AudioBuffer_SampleRate>(sample_rate);
97 buffer->number_of_channels = number_of_channels;
98 buffer->number_of_samples = number_of_channels * number_of_frames;
99 buffer->data_size = buffer_data_size_;
100 memcpy(buffer->data, audio_data, buffer_data_size_);
102 main_message_loop_proxy_->PostTask(
104 base::Bind(&AudioSink::SendEnqueueBufferMessageOnMainThread,
105 weak_factory_.GetWeakPtr(), index));
107 timestamp_ += buffer_duration_;
110 void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat(
111 const AudioParameters& params) {
112 DCHECK(params.IsValid());
113 DCHECK_LE(params.GetBufferDuration().InMilliseconds(), kMaxDuration);
114 DCHECK_EQ(params.bits_per_sample(), 16);
115 DCHECK((params.sample_rate() == AudioParameters::kTelephoneSampleRate) ||
116 (params.sample_rate() == AudioParameters::kAudioCDSampleRate));
118 COMPILE_ASSERT(AudioParameters::kTelephoneSampleRate ==
119 static_cast<int32_t>(PP_AUDIOBUFFER_SAMPLERATE_8000),
120 audio_sample_rate_does_not_match);
121 COMPILE_ASSERT(AudioParameters::kAudioCDSampleRate ==
122 static_cast<int32_t>(PP_AUDIOBUFFER_SAMPLERATE_44100),
123 audio_sample_rate_does_not_match);
124 audio_params_ = params;
126 // TODO(penghuang): support setting format more than once.
127 buffer_duration_ = params.GetBufferDuration();
128 buffer_data_size_ = params.GetBytesPerBuffer();
130 if (original_audio_params_.IsValid()) {
131 DCHECK_EQ(params.sample_rate(), original_audio_params_.sample_rate());
132 DCHECK_EQ(params.bits_per_sample(),
133 original_audio_params_.bits_per_sample());
134 DCHECK_EQ(params.channels(), original_audio_params_.channels());
136 audio_thread_checker_.DetachFromThread();
137 original_audio_params_ = params;
138 // The size is slightly bigger than necessary, because 8 extra bytes are
139 // added into the struct. Also see |MediaStreamBuffer|.
140 size_t max_data_size =
141 params.sample_rate() * params.bits_per_sample() / 8 *
142 params.channels() * kMaxDuration / 1000;
143 size_t size = sizeof(ppapi::MediaStreamBuffer::Audio) + max_data_size;
145 main_message_loop_proxy_->PostTask(
147 base::Bind(&AudioSink::InitBuffersOnMainThread,
148 weak_factory_.GetWeakPtr(),
150 static_cast<int32_t>(size)));
154 PepperMediaStreamAudioTrackHost::PepperMediaStreamAudioTrackHost(
155 RendererPpapiHost* host,
156 PP_Instance instance,
157 PP_Resource resource,
158 const blink::WebMediaStreamTrack& track)
159 : PepperMediaStreamTrackHostBase(host, instance, resource),
163 DCHECK(!track_.isNull());
166 PepperMediaStreamAudioTrackHost::~PepperMediaStreamAudioTrackHost() {
170 void PepperMediaStreamAudioTrackHost::OnClose() {
172 MediaStreamAudioSink::RemoveFromAudioTrack(&audio_sink_, track_);
177 void PepperMediaStreamAudioTrackHost::OnNewBufferEnqueued() {
178 int32_t index = buffer_manager()->DequeueBuffer();
180 audio_sink_.EnqueueBuffer(index);
183 void PepperMediaStreamAudioTrackHost::DidConnectPendingHostToResource() {
185 MediaStreamAudioSink::AddToAudioTrack(&audio_sink_, track_);
190 } // namespace content