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"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/message_loop/message_loop_proxy.h"
14 #include "base/numerics/safe_math.h"
15 #include "ppapi/c/pp_errors.h"
16 #include "ppapi/c/ppb_audio_buffer.h"
17 #include "ppapi/host/dispatch_host_message.h"
18 #include "ppapi/host/host_message_context.h"
19 #include "ppapi/proxy/ppapi_messages.h"
20 #include "ppapi/shared_impl/media_stream_audio_track_shared.h"
21 #include "ppapi/shared_impl/media_stream_buffer.h"
23 using media::AudioParameters
;
24 using ppapi::host::HostMessageContext
;
25 using ppapi::MediaStreamAudioTrackShared
;
29 // Max audio buffer duration in milliseconds.
30 const uint32_t kMaxDuration
= 10;
32 const int32_t kDefaultNumberOfBuffers
= 4;
33 const int32_t kMaxNumberOfBuffers
= 1000; // 10 sec
35 // Returns true if the |sample_rate| is supported in
36 // |PP_AudioBuffer_SampleRate|, otherwise false.
37 PP_AudioBuffer_SampleRate
GetPPSampleRate(int sample_rate
) {
38 switch (sample_rate
) {
40 return PP_AUDIOBUFFER_SAMPLERATE_8000
;
42 return PP_AUDIOBUFFER_SAMPLERATE_16000
;
44 return PP_AUDIOBUFFER_SAMPLERATE_22050
;
46 return PP_AUDIOBUFFER_SAMPLERATE_32000
;
48 return PP_AUDIOBUFFER_SAMPLERATE_44100
;
50 return PP_AUDIOBUFFER_SAMPLERATE_48000
;
52 return PP_AUDIOBUFFER_SAMPLERATE_96000
;
54 return PP_AUDIOBUFFER_SAMPLERATE_192000
;
56 return PP_AUDIOBUFFER_SAMPLERATE_UNKNOWN
;
64 PepperMediaStreamAudioTrackHost::AudioSink::AudioSink(
65 PepperMediaStreamAudioTrackHost
* host
)
68 main_message_loop_proxy_(base::MessageLoopProxy::current()),
70 number_of_buffers_(kDefaultNumberOfBuffers
),
71 bytes_per_second_(0) {}
73 PepperMediaStreamAudioTrackHost::AudioSink::~AudioSink() {
74 DCHECK_EQ(main_message_loop_proxy_
, base::MessageLoopProxy::current());
77 void PepperMediaStreamAudioTrackHost::AudioSink::EnqueueBuffer(int32_t index
) {
78 DCHECK_EQ(main_message_loop_proxy_
, base::MessageLoopProxy::current());
80 DCHECK_LT(index
, host_
->buffer_manager()->number_of_buffers());
81 base::AutoLock
lock(lock_
);
82 buffers_
.push_back(index
);
85 void PepperMediaStreamAudioTrackHost::AudioSink::Configure(
86 int32_t number_of_buffers
) {
87 DCHECK_EQ(main_message_loop_proxy_
, base::MessageLoopProxy::current());
89 if (number_of_buffers
!= number_of_buffers_
)
91 number_of_buffers_
= number_of_buffers
;
93 // Initialize later in OnSetFormat if bytes_per_second_ is not know yet.
94 if (changed
&& bytes_per_second_
> 0)
98 void PepperMediaStreamAudioTrackHost::AudioSink::SetFormatOnMainThread(
99 int bytes_per_second
) {
100 bytes_per_second_
= bytes_per_second
;
104 void PepperMediaStreamAudioTrackHost::AudioSink::InitBuffers() {
105 DCHECK_EQ(main_message_loop_proxy_
, base::MessageLoopProxy::current());
106 // The size is slightly bigger than necessary, because 8 extra bytes are
107 // added into the struct. Also see |MediaStreamBuffer|.
108 base::CheckedNumeric
<int32_t> buffer_size
= bytes_per_second_
;
109 buffer_size
*= kMaxDuration
;
110 buffer_size
/= base::Time::kMillisecondsPerSecond
;
111 buffer_size
+= sizeof(ppapi::MediaStreamBuffer::Audio
);
112 bool result
= host_
->InitBuffers(number_of_buffers_
,
113 buffer_size
.ValueOrDie(),
115 // TODO(penghuang): Send PP_ERROR_NOMEMORY to plugin.
117 base::AutoLock
lock(lock_
);
119 for (int32_t i
= 0; i
< number_of_buffers_
; ++i
) {
120 int32_t index
= host_
->buffer_manager()->DequeueBuffer();
122 buffers_
.push_back(index
);
126 void PepperMediaStreamAudioTrackHost::AudioSink::
127 SendEnqueueBufferMessageOnMainThread(int32_t index
) {
128 DCHECK_EQ(main_message_loop_proxy_
, base::MessageLoopProxy::current());
129 host_
->SendEnqueueBufferMessageToPlugin(index
);
132 void PepperMediaStreamAudioTrackHost::AudioSink::OnData(const int16
* audio_data
,
134 int number_of_channels
,
135 int number_of_frames
) {
136 DCHECK(audio_thread_checker_
.CalledOnValidThread());
138 DCHECK_EQ(sample_rate
, audio_params_
.sample_rate());
139 DCHECK_EQ(number_of_channels
, audio_params_
.channels());
140 DCHECK_EQ(number_of_frames
, audio_params_
.frames_per_buffer());
143 base::AutoLock
lock(lock_
);
144 if (!buffers_
.empty()) {
145 index
= buffers_
.front();
146 buffers_
.pop_front();
151 // TODO(penghuang): support re-sampling, etc.
152 ppapi::MediaStreamBuffer::Audio
* buffer
=
153 &(host_
->buffer_manager()->GetBufferPointer(index
)->audio
);
154 buffer
->header
.size
= host_
->buffer_manager()->buffer_size();
155 buffer
->header
.type
= ppapi::MediaStreamBuffer::TYPE_AUDIO
;
156 buffer
->timestamp
= timestamp_
.InMillisecondsF();
157 buffer
->sample_rate
= static_cast<PP_AudioBuffer_SampleRate
>(sample_rate
);
158 buffer
->number_of_channels
= number_of_channels
;
159 buffer
->number_of_samples
= number_of_channels
* number_of_frames
;
160 buffer
->data_size
= buffer_data_size_
;
161 memcpy(buffer
->data
, audio_data
, buffer_data_size_
);
163 main_message_loop_proxy_
->PostTask(
165 base::Bind(&AudioSink::SendEnqueueBufferMessageOnMainThread
,
166 weak_factory_
.GetWeakPtr(),
169 timestamp_
+= buffer_duration_
;
172 void PepperMediaStreamAudioTrackHost::AudioSink::OnSetFormat(
173 const AudioParameters
& params
) {
174 DCHECK(params
.IsValid());
175 DCHECK_LE(params
.GetBufferDuration().InMilliseconds(), kMaxDuration
);
176 DCHECK_EQ(params
.bits_per_sample(), 16);
177 DCHECK_NE(GetPPSampleRate(params
.sample_rate()),
178 PP_AUDIOBUFFER_SAMPLERATE_UNKNOWN
);
180 audio_params_
= params
;
182 // TODO(penghuang): support setting format more than once.
183 buffer_duration_
= params
.GetBufferDuration();
184 buffer_data_size_
= params
.GetBytesPerBuffer();
186 if (original_audio_params_
.IsValid()) {
187 DCHECK_EQ(params
.sample_rate(), original_audio_params_
.sample_rate());
188 DCHECK_EQ(params
.bits_per_sample(),
189 original_audio_params_
.bits_per_sample());
190 DCHECK_EQ(params
.channels(), original_audio_params_
.channels());
192 audio_thread_checker_
.DetachFromThread();
193 original_audio_params_
= params
;
195 main_message_loop_proxy_
->PostTask(
197 base::Bind(&AudioSink::SetFormatOnMainThread
,
198 weak_factory_
.GetWeakPtr(),
199 params
.GetBytesPerSecond()));
203 PepperMediaStreamAudioTrackHost::PepperMediaStreamAudioTrackHost(
204 RendererPpapiHost
* host
,
205 PP_Instance instance
,
206 PP_Resource resource
,
207 const blink::WebMediaStreamTrack
& track
)
208 : PepperMediaStreamTrackHostBase(host
, instance
, resource
),
212 DCHECK(!track_
.isNull());
215 PepperMediaStreamAudioTrackHost::~PepperMediaStreamAudioTrackHost() {
219 int32_t PepperMediaStreamAudioTrackHost::OnResourceMessageReceived(
220 const IPC::Message
& msg
,
221 HostMessageContext
* context
) {
222 PPAPI_BEGIN_MESSAGE_MAP(PepperMediaStreamAudioTrackHost
, msg
)
223 PPAPI_DISPATCH_HOST_RESOURCE_CALL(
224 PpapiHostMsg_MediaStreamAudioTrack_Configure
, OnHostMsgConfigure
)
225 PPAPI_END_MESSAGE_MAP()
226 return PepperMediaStreamTrackHostBase::OnResourceMessageReceived(msg
,
230 int32_t PepperMediaStreamAudioTrackHost::OnHostMsgConfigure(
231 HostMessageContext
* context
,
232 const MediaStreamAudioTrackShared::Attributes
& attributes
) {
233 if (!MediaStreamAudioTrackShared::VerifyAttributes(attributes
))
234 return PP_ERROR_BADARGUMENT
;
236 int32_t buffers
= attributes
.buffers
237 ? std::min(kMaxNumberOfBuffers
, attributes
.buffers
)
238 : kDefaultNumberOfBuffers
;
239 audio_sink_
.Configure(buffers
);
241 context
->reply_msg
= PpapiPluginMsg_MediaStreamAudioTrack_ConfigureReply();
245 void PepperMediaStreamAudioTrackHost::OnClose() {
247 MediaStreamAudioSink::RemoveFromAudioTrack(&audio_sink_
, track_
);
252 void PepperMediaStreamAudioTrackHost::OnNewBufferEnqueued() {
253 int32_t index
= buffer_manager()->DequeueBuffer();
255 audio_sink_
.EnqueueBuffer(index
);
258 void PepperMediaStreamAudioTrackHost::DidConnectPendingHostToResource() {
260 MediaStreamAudioSink::AddToAudioTrack(&audio_sink_
, track_
);
265 } // namespace content