Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / pepper_media_stream_audio_track_host.cc
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.
4
5 #include "content/renderer/pepper/pepper_media_stream_audio_track_host.h"
6
7 #include "base/bind.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"
15
16 using media::AudioParameters;
17
18 namespace {
19
20 // Max audio buffer duration in milliseconds.
21 const uint32_t kMaxDuration = 10;
22
23 // TODO(penghuang): make this configurable.
24 const int32_t kNumberOfBuffers = 4;
25
26 }  // namespace
27
28 namespace content {
29
30 PepperMediaStreamAudioTrackHost::AudioSink::AudioSink(
31     PepperMediaStreamAudioTrackHost* host)
32     : host_(host),
33       buffer_data_size_(0),
34       main_message_loop_proxy_(base::MessageLoopProxy::current()),
35       weak_factory_(this) {
36 }
37
38 PepperMediaStreamAudioTrackHost::AudioSink::~AudioSink() {
39   DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
40 }
41
42 void PepperMediaStreamAudioTrackHost::AudioSink::EnqueueBuffer(int32_t index) {
43   DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
44   DCHECK_GE(index, 0);
45   DCHECK_LT(index, host_->buffer_manager()->number_of_buffers());
46   base::AutoLock lock(lock_);
47   buffers_.push_back(index);
48 }
49
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.
55   CHECK(result);
56   base::AutoLock lock(lock_);
57   for (int32_t i = 0; i < number_of_buffers; ++i) {
58     int32_t index = host_->buffer_manager()->DequeueBuffer();
59     DCHECK_GE(index, 0);
60     buffers_.push_back(index);
61   }
62 }
63
64 void
65 PepperMediaStreamAudioTrackHost::AudioSink::
66     SendEnqueueBufferMessageOnMainThread(int32_t index) {
67   DCHECK_EQ(main_message_loop_proxy_, base::MessageLoopProxy::current());
68   host_->SendEnqueueBufferMessageToPlugin(index);
69 }
70
71 void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16* audio_data,
72                                                         int sample_rate,
73                                                         int number_of_channels,
74                                                         int number_of_frames) {
75   DCHECK(audio_thread_checker_.CalledOnValidThread());
76   DCHECK(audio_data);
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());
80   int32_t index = -1;
81   {
82     base::AutoLock lock(lock_);
83     if (!buffers_.empty()) {
84       index = buffers_.front();
85       buffers_.pop_front();
86     }
87   }
88
89   if (index != -1) {
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_);
101
102     main_message_loop_proxy_->PostTask(
103         FROM_HERE,
104         base::Bind(&AudioSink::SendEnqueueBufferMessageOnMainThread,
105                    weak_factory_.GetWeakPtr(), index));
106   }
107   timestamp_ += buffer_duration_;
108 }
109
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));
117
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;
125
126   // TODO(penghuang): support setting format more than once.
127   buffer_duration_ = params.GetBufferDuration();
128   buffer_data_size_ = params.GetBytesPerBuffer();
129
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());
135   } else {
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;
144
145     main_message_loop_proxy_->PostTask(
146         FROM_HERE,
147         base::Bind(&AudioSink::InitBuffersOnMainThread,
148                    weak_factory_.GetWeakPtr(),
149                    kNumberOfBuffers,
150                    static_cast<int32_t>(size)));
151   }
152 }
153
154 PepperMediaStreamAudioTrackHost::PepperMediaStreamAudioTrackHost(
155     RendererPpapiHost* host,
156     PP_Instance instance,
157     PP_Resource resource,
158     const blink::WebMediaStreamTrack& track)
159     : PepperMediaStreamTrackHostBase(host, instance, resource),
160       track_(track),
161       connected_(false),
162       audio_sink_(this) {
163   DCHECK(!track_.isNull());
164 }
165
166 PepperMediaStreamAudioTrackHost::~PepperMediaStreamAudioTrackHost() {
167   OnClose();
168 }
169
170 void PepperMediaStreamAudioTrackHost::OnClose() {
171   if (connected_) {
172     MediaStreamAudioSink::RemoveFromAudioTrack(&audio_sink_, track_);
173     connected_ = false;
174   }
175 }
176
177 void PepperMediaStreamAudioTrackHost::OnNewBufferEnqueued() {
178   int32_t index = buffer_manager()->DequeueBuffer();
179   DCHECK_GE(index, 0);
180   audio_sink_.EnqueueBuffer(index);
181 }
182
183 void PepperMediaStreamAudioTrackHost::DidConnectPendingHostToResource() {
184   if (!connected_) {
185     MediaStreamAudioSink::AddToAudioTrack(&audio_sink_, track_);
186     connected_ = true;
187   }
188 }
189
190 }  // namespace content