1 // Copyright 2013 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 "media/cast/audio_receiver/audio_receiver.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/cast/audio_receiver/audio_decoder.h"
11 #include "media/cast/framer/framer.h"
12 #include "media/cast/rtcp/rtcp.h"
13 #include "media/cast/rtp_receiver/rtp_receiver.h"
15 // Max time we wait until an audio frame is due to be played out is released.
16 static const int64 kMaxAudioFrameWaitMs
= 20;
17 static const int64 kMinSchedulingDelayMs
= 1;
23 // Local implementation of RtpData (defined in rtp_rtcp_defines.h).
24 // Used to pass payload data into the audio receiver.
25 class LocalRtpAudioData
: public RtpData
{
27 LocalRtpAudioData(AudioReceiver
* audio_receiver
, base::TickClock
* clock
)
28 : audio_receiver_(audio_receiver
),
29 time_first_incoming_packet_(),
30 first_incoming_rtp_timestamp_(0),
33 virtual void OnReceivedPayloadData(
34 const uint8
* payload_data
,
36 const RtpCastHeader
* rtp_header
) OVERRIDE
{
37 // TODO(pwestin): update this as video to refresh over time.
38 if (time_first_incoming_packet_
.is_null()) {
39 first_incoming_rtp_timestamp_
= rtp_header
->webrtc
.header
.timestamp
;
40 time_first_incoming_packet_
= clock_
->NowTicks();
42 audio_receiver_
->IncomingParsedRtpPacket(payload_data
, payload_size
,
46 void GetFirstPacketInformation(base::TimeTicks
* time_incoming_packet
,
47 uint32
* incoming_rtp_timestamp
) {
48 *time_incoming_packet
= time_first_incoming_packet_
;
49 *incoming_rtp_timestamp
= first_incoming_rtp_timestamp_
;
53 AudioReceiver
* audio_receiver_
;
54 base::TimeTicks time_first_incoming_packet_
;
55 uint32 first_incoming_rtp_timestamp_
;
56 base::TickClock
* clock_
;
59 // Local implementation of RtpPayloadFeedback (defined in rtp_defines.h)
60 // Used to convey cast-specific feedback from receiver to sender.
61 class LocalRtpAudioFeedback
: public RtpPayloadFeedback
{
63 explicit LocalRtpAudioFeedback(AudioReceiver
* audio_receiver
)
64 : audio_receiver_(audio_receiver
) {
67 virtual void CastFeedback(const RtcpCastMessage
& cast_message
) OVERRIDE
{
68 audio_receiver_
->CastFeedback(cast_message
);
72 AudioReceiver
* audio_receiver_
;
75 class LocalRtpReceiverStatistics
: public RtpReceiverStatistics
{
77 explicit LocalRtpReceiverStatistics(RtpReceiver
* rtp_receiver
)
78 : rtp_receiver_(rtp_receiver
) {
81 virtual void GetStatistics(uint8
* fraction_lost
,
82 uint32
* cumulative_lost
, // 24 bits valid.
83 uint32
* extended_high_sequence_number
,
84 uint32
* jitter
) OVERRIDE
{
85 rtp_receiver_
->GetStatistics(fraction_lost
,
87 extended_high_sequence_number
,
92 RtpReceiver
* rtp_receiver_
;
95 AudioReceiver::AudioReceiver(scoped_refptr
<CastEnvironment
> cast_environment
,
96 const AudioReceiverConfig
& audio_config
,
97 PacedPacketSender
* const packet_sender
)
98 : cast_environment_(cast_environment
),
99 codec_(audio_config
.codec
),
100 incoming_ssrc_(audio_config
.incoming_ssrc
),
101 frequency_(audio_config
.frequency
),
105 weak_factory_(this) {
106 target_delay_delta_
=
107 base::TimeDelta::FromMilliseconds(audio_config
.rtp_max_delay_ms
);
108 incoming_payload_callback_
.reset(
109 new LocalRtpAudioData(this, cast_environment
->Clock()));
110 incoming_payload_feedback_
.reset(new LocalRtpAudioFeedback(this));
111 if (audio_config
.use_external_decoder
) {
112 audio_buffer_
.reset(new Framer(cast_environment
->Clock(),
113 incoming_payload_feedback_
.get(),
114 audio_config
.incoming_ssrc
,
118 audio_decoder_
= new AudioDecoder(audio_config
);
120 rtp_receiver_
.reset(new RtpReceiver(cast_environment
->Clock(),
123 incoming_payload_callback_
.get()));
124 rtp_audio_receiver_statistics_
.reset(
125 new LocalRtpReceiverStatistics(rtp_receiver_
.get()));
126 base::TimeDelta rtcp_interval_delta
=
127 base::TimeDelta::FromMilliseconds(audio_config
.rtcp_interval
);
128 rtcp_
.reset(new Rtcp(cast_environment
->Clock(),
132 rtp_audio_receiver_statistics_
.get(),
133 audio_config
.rtcp_mode
,
136 audio_config
.feedback_ssrc
,
137 audio_config
.rtcp_c_name
));
138 rtcp_
->SetRemoteSSRC(audio_config
.incoming_ssrc
);
139 ScheduleNextRtcpReport();
142 AudioReceiver::~AudioReceiver() {}
144 void AudioReceiver::IncomingParsedRtpPacket(const uint8
* payload_data
,
146 const RtpCastHeader
& rtp_header
) {
147 if (audio_decoder_
) {
148 DCHECK(!audio_buffer_
) << "Invalid internal state";
149 audio_decoder_
->IncomingParsedRtpPacket(payload_data
, payload_size
,
153 DCHECK(audio_buffer_
) << "Invalid internal state";
154 DCHECK(!audio_decoder_
) << "Invalid internal state";
155 bool complete
= audio_buffer_
->InsertPacket(payload_data
, payload_size
,
157 if (!complete
) return; // Audio frame not complete; wait for more packets.
158 if (queued_encoded_callbacks_
.empty()) return; // No pending callback.
160 AudioFrameEncodedCallback callback
= queued_encoded_callbacks_
.front();
161 queued_encoded_callbacks_
.pop_front();
162 cast_environment_
->PostTask(CastEnvironment::MAIN
, FROM_HERE
,
163 base::Bind(&AudioReceiver::GetEncodedAudioFrame
,
164 weak_factory_
.GetWeakPtr(), callback
));
167 void AudioReceiver::GetRawAudioFrame(int number_of_10ms_blocks
,
168 int desired_frequency
, const AudioFrameDecodedCallback
& callback
) {
169 DCHECK(audio_decoder_
) << "Invalid function call in this configuration";
171 cast_environment_
->PostTask(CastEnvironment::AUDIO_DECODER
, FROM_HERE
,
172 base::Bind(&AudioReceiver::DecodeAudioFrameThread
,
173 weak_factory_
.GetWeakPtr(),
174 number_of_10ms_blocks
,
179 void AudioReceiver::DecodeAudioFrameThread(
180 int number_of_10ms_blocks
,
181 int desired_frequency
,
182 const AudioFrameDecodedCallback callback
) {
183 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::AUDIO_DECODER
));
184 // TODO(mikhal): Allow the application to allocate this memory.
185 scoped_ptr
<PcmAudioFrame
> audio_frame(new PcmAudioFrame());
187 uint32 rtp_timestamp
= 0;
188 if (!audio_decoder_
->GetRawAudioFrame(number_of_10ms_blocks
,
194 base::TimeTicks now
= cast_environment_
->Clock()->NowTicks();
195 base::TimeTicks playout_time
;
196 playout_time
= GetPlayoutTime(now
, rtp_timestamp
);
198 // Frame is ready - Send back to the main thread.
199 cast_environment_
->PostTask(CastEnvironment::MAIN
, FROM_HERE
,
201 base::Passed(&audio_frame
), playout_time
));
204 void AudioReceiver::PlayoutTimeout() {
205 if (queued_encoded_callbacks_
.empty()) {
206 // Already released by incoming packet.
209 AudioFrameEncodedCallback callback
= queued_encoded_callbacks_
.front();
210 queued_encoded_callbacks_
.pop_front();
212 uint32 rtp_timestamp
= 0;
213 bool next_frame
= false;
214 scoped_ptr
<EncodedAudioFrame
> encoded_frame(new EncodedAudioFrame());
216 if (!audio_buffer_
->GetEncodedAudioFrame(encoded_frame
.get(),
217 &rtp_timestamp
, &next_frame
)) {
218 // We have no audio frames. Wait for new packet(s).
220 queued_encoded_callbacks_
.push_front(callback
);
223 // Put the callback back first in the queue on a wait event.
224 PostEncodedAudioFrame(true, callback
, rtp_timestamp
, next_frame
,
228 void AudioReceiver::GetEncodedAudioFrame(
229 const AudioFrameEncodedCallback
& callback
) {
230 DCHECK(audio_buffer_
) << "Invalid function call in this configuration";
232 uint32 rtp_timestamp
= 0;
233 bool next_frame
= false;
234 scoped_ptr
<EncodedAudioFrame
> encoded_frame(new EncodedAudioFrame());
236 if (!audio_buffer_
->GetEncodedAudioFrame(encoded_frame
.get(),
237 &rtp_timestamp
, &next_frame
)) {
238 // We have no audio frames. Wait for new packet(s).
239 VLOG(1) << "Wait for more audio packets in frame";
240 queued_encoded_callbacks_
.push_back(callback
);
243 PostEncodedAudioFrame(false, callback
, rtp_timestamp
, next_frame
,
247 void AudioReceiver::PostEncodedAudioFrame(
248 bool on_wait_event_put_first_in_queue
,
249 const AudioFrameEncodedCallback
& callback
,
250 uint32 rtp_timestamp
,
252 scoped_ptr
<EncodedAudioFrame
>* encoded_frame
) {
253 base::TimeTicks now
= cast_environment_
->Clock()->NowTicks();
254 base::TimeTicks playout_time
= GetPlayoutTime(now
, rtp_timestamp
);
255 base::TimeDelta time_until_playout
= playout_time
- now
;
256 base::TimeDelta min_wait_delta
=
257 base::TimeDelta::FromMilliseconds(kMaxAudioFrameWaitMs
);
259 if (!next_frame
&& (time_until_playout
> min_wait_delta
)) {
260 // We have an audio frame; however we are missing packets and we have time
261 // to wait for new packet(s).
262 if (on_wait_event_put_first_in_queue
) {
263 queued_encoded_callbacks_
.push_front(callback
);
265 queued_encoded_callbacks_
.push_back(callback
);
268 base::TimeDelta time_until_release
= time_until_playout
- min_wait_delta
;
269 cast_environment_
->PostDelayedTask(CastEnvironment::MAIN
, FROM_HERE
,
270 base::Bind(&AudioReceiver::PlayoutTimeout
, weak_factory_
.GetWeakPtr()),
272 VLOG(1) << "Wait until time to playout:"
273 << time_until_release
.InMilliseconds();
276 (*encoded_frame
)->codec
= codec_
;
277 audio_buffer_
->ReleaseFrame((*encoded_frame
)->frame_id
);
279 cast_environment_
->PostTask(CastEnvironment::MAIN
, FROM_HERE
,
280 base::Bind(callback
, base::Passed(encoded_frame
), playout_time
));
283 void AudioReceiver::IncomingPacket(const uint8
* packet
, size_t length
,
284 const base::Closure callback
) {
285 bool rtcp_packet
= Rtcp::IsRtcpPacket(packet
, length
);
287 rtp_receiver_
->ReceivedPacket(packet
, length
);
289 rtcp_
->IncomingRtcpPacket(packet
, length
);
291 cast_environment_
->PostTask(CastEnvironment::MAIN
, FROM_HERE
, callback
);
294 void AudioReceiver::CastFeedback(const RtcpCastMessage
& cast_message
) {
295 rtcp_
->SendRtcpCast(cast_message
);
298 base::TimeTicks
AudioReceiver::GetPlayoutTime(base::TimeTicks now
,
299 uint32 rtp_timestamp
) {
300 // Senders time in ms when this frame was recorded.
301 // Note: the senders clock and our local clock might not be synced.
302 base::TimeTicks rtp_timestamp_in_ticks
;
303 if (time_offset_
== base::TimeDelta()) {
304 base::TimeTicks time_first_incoming_packet
;
305 uint32 first_incoming_rtp_timestamp
;
307 incoming_payload_callback_
->GetFirstPacketInformation(
308 &time_first_incoming_packet
, &first_incoming_rtp_timestamp
);
310 if (rtcp_
->RtpTimestampInSenderTime(frequency_
,
311 first_incoming_rtp_timestamp
,
312 &rtp_timestamp_in_ticks
)) {
313 time_offset_
= time_first_incoming_packet
- rtp_timestamp_in_ticks
;
315 // We have not received any RTCP to sync the stream play it out as soon as
317 uint32 rtp_timestamp_diff
=
318 rtp_timestamp
- first_incoming_rtp_timestamp
;
320 int frequency_khz
= frequency_
/ 1000;
321 base::TimeDelta rtp_time_diff_delta
=
322 base::TimeDelta::FromMilliseconds(rtp_timestamp_diff
/ frequency_khz
);
323 base::TimeDelta time_diff_delta
= now
- time_first_incoming_packet
;
325 return now
+ std::max(rtp_time_diff_delta
- time_diff_delta
,
329 // This can fail if we have not received any RTCP packets in a long time.
330 return rtcp_
->RtpTimestampInSenderTime(frequency_
, rtp_timestamp
,
331 &rtp_timestamp_in_ticks
) ?
332 rtp_timestamp_in_ticks
+ time_offset_
+ target_delay_delta_
:
336 void AudioReceiver::ScheduleNextRtcpReport() {
337 base::TimeDelta time_to_send
= rtcp_
->TimeToSendNextRtcpReport() -
338 cast_environment_
->Clock()->NowTicks();
340 time_to_send
= std::max(time_to_send
,
341 base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs
));
343 cast_environment_
->PostDelayedTask(CastEnvironment::MAIN
, FROM_HERE
,
344 base::Bind(&AudioReceiver::SendNextRtcpReport
,
345 weak_factory_
.GetWeakPtr()), time_to_send
);
348 void AudioReceiver::SendNextRtcpReport() {
349 rtcp_
->SendRtcpReport(incoming_ssrc_
);
350 ScheduleNextRtcpReport();