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_sender/audio_sender.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/cast/audio_sender/audio_encoder.h"
11 #include "media/cast/transport/cast_transport_defines.h"
16 const int64 kMinSchedulingDelayMs
= 1;
18 class LocalRtcpAudioSenderFeedback
: public RtcpSenderFeedback
{
20 explicit LocalRtcpAudioSenderFeedback(AudioSender
* audio_sender
)
21 : audio_sender_(audio_sender
) {}
23 virtual void OnReceivedCastFeedback(const RtcpCastMessage
& cast_feedback
)
25 if (!cast_feedback
.missing_frames_and_packets_
.empty()) {
26 audio_sender_
->ResendPackets(cast_feedback
.missing_frames_and_packets_
);
28 VLOG(2) << "Received audio ACK "
29 << static_cast<int>(cast_feedback
.ack_frame_id_
);
33 AudioSender
* audio_sender_
;
35 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtcpAudioSenderFeedback
);
38 // TODO(mikhal): Reduce heap allocation when not needed.
39 AudioSender::AudioSender(scoped_refptr
<CastEnvironment
> cast_environment
,
40 const AudioSenderConfig
& audio_config
,
41 transport::CastTransportSender
* const transport_sender
)
42 : cast_environment_(cast_environment
),
43 transport_sender_(transport_sender
),
44 rtp_stats_(audio_config
.frequency
),
45 rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)),
46 rtcp_(cast_environment
,
49 NULL
, // paced sender.
51 audio_config
.rtcp_mode
,
52 base::TimeDelta::FromMilliseconds(audio_config
.rtcp_interval
),
53 audio_config
.rtp_config
.ssrc
,
54 audio_config
.incoming_feedback_ssrc
,
55 audio_config
.rtcp_c_name
,
57 timers_initialized_(false),
58 cast_initialization_cb_(STATUS_AUDIO_UNINITIALIZED
),
60 rtcp_
.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize
);
61 if (!audio_config
.use_external_encoder
) {
63 new AudioEncoder(cast_environment
,
65 base::Bind(&AudioSender::SendEncodedAudioFrame
,
66 weak_factory_
.GetWeakPtr())));
67 cast_initialization_cb_
= audio_encoder_
->InitializationResult();
70 media::cast::transport::CastTransportAudioConfig transport_config
;
71 transport_config
.codec
= audio_config
.codec
;
72 transport_config
.rtp
.config
= audio_config
.rtp_config
;
73 transport_config
.frequency
= audio_config
.frequency
;
74 transport_config
.channels
= audio_config
.channels
;
75 transport_config
.rtp
.max_outstanding_frames
=
76 audio_config
.rtp_config
.max_delay_ms
/ 100 + 1;
77 transport_sender_
->InitializeAudio(transport_config
);
79 transport_sender_
->SubscribeAudioRtpStatsCallback(
80 base::Bind(&AudioSender::StoreStatistics
, weak_factory_
.GetWeakPtr()));
83 AudioSender::~AudioSender() {}
85 void AudioSender::InitializeTimers() {
86 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
87 if (!timers_initialized_
) {
88 timers_initialized_
= true;
89 ScheduleNextRtcpReport();
93 void AudioSender::InsertAudio(scoped_ptr
<AudioBus
> audio_bus
,
94 const base::TimeTicks
& recorded_time
) {
95 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
96 DCHECK(audio_encoder_
.get()) << "Invalid internal state";
97 audio_encoder_
->InsertAudio(audio_bus
.Pass(), recorded_time
);
100 void AudioSender::SendEncodedAudioFrame(
101 scoped_ptr
<transport::EncodedAudioFrame
> audio_frame
,
102 const base::TimeTicks
& recorded_time
) {
103 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
105 transport_sender_
->InsertCodedAudioFrame(audio_frame
.get(), recorded_time
);
108 void AudioSender::ResendPackets(
109 const MissingFramesAndPacketsMap
& missing_frames_and_packets
) {
110 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
111 transport_sender_
->ResendPackets(true, missing_frames_and_packets
);
114 void AudioSender::IncomingRtcpPacket(scoped_ptr
<Packet
> packet
) {
115 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
116 rtcp_
.IncomingRtcpPacket(&packet
->front(), packet
->size());
119 void AudioSender::ScheduleNextRtcpReport() {
120 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
121 base::TimeDelta time_to_next
=
122 rtcp_
.TimeToSendNextRtcpReport() - cast_environment_
->Clock()->NowTicks();
124 time_to_next
= std::max(
125 time_to_next
, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs
));
127 cast_environment_
->PostDelayedTask(
128 CastEnvironment::MAIN
,
130 base::Bind(&AudioSender::SendRtcpReport
, weak_factory_
.GetWeakPtr()),
134 void AudioSender::StoreStatistics(
135 const transport::RtcpSenderInfo
& sender_info
,
136 base::TimeTicks time_sent
,
137 uint32 rtp_timestamp
) {
138 rtp_stats_
.Store(sender_info
, time_sent
, rtp_timestamp
);
141 void AudioSender::SendRtcpReport() {
142 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
143 // We don't send audio logging messages since all captured audio frames will
145 transport::RtcpSenderLogMessage empty_msg
;
146 rtp_stats_
.UpdateInfo(cast_environment_
->Clock()->NowTicks());
147 rtcp_
.SendRtcpFromRtpSender(empty_msg
, rtp_stats_
.sender_info());
148 ScheduleNextRtcpReport();