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(1) << "Received audio ACK "
29 << static_cast<int>(cast_feedback
.ack_frame_id_
);
33 AudioSender
* audio_sender_
;
35 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtcpAudioSenderFeedback
);
38 class LocalRtpSenderStatistics
: public RtpSenderStatistics
{
40 LocalRtpSenderStatistics(
41 transport::CastTransportSender
* const transport_sender
,
43 : transport_sender_(transport_sender
),
47 transport_sender_
->SubscribeAudioRtpStatsCallback(base::Bind(
48 &LocalRtpSenderStatistics::StoreStatistics
, base::Unretained(this)));
51 virtual void GetStatistics(const base::TimeTicks
& now
,
52 transport::RtcpSenderInfo
* sender_info
) OVERRIDE
{
53 // Update and return last stored statistics.
54 uint32 ntp_seconds
= 0;
55 uint32 ntp_fraction
= 0;
56 uint32 rtp_timestamp
= 0;
57 if (rtp_timestamp_
> 0) {
58 base::TimeDelta time_since_last_send
= now
- time_sent_
;
59 rtp_timestamp
= rtp_timestamp_
+ time_since_last_send
.InMilliseconds() *
61 // Update NTP time to current time.
62 ConvertTimeTicksToNtp(now
, &ntp_seconds
, &ntp_fraction
);
64 // Populate sender info.
65 sender_info
->rtp_timestamp
= rtp_timestamp
;
66 sender_info
->ntp_seconds
= sender_info_
.ntp_seconds
;
67 sender_info
->ntp_fraction
= sender_info_
.ntp_fraction
;
68 sender_info
->send_packet_count
= sender_info_
.send_packet_count
;
69 sender_info
->send_octet_count
= sender_info_
.send_octet_count
;
72 void StoreStatistics(transport::RtcpSenderInfo
& sender_info
,
73 base::TimeTicks time_sent
,
74 uint32 rtp_timestamp
) {
75 sender_info_
= sender_info
;
76 time_sent_
= time_sent
;
77 rtp_timestamp_
= rtp_timestamp
;
81 transport::CastTransportSender
* const transport_sender_
;
83 transport::RtcpSenderInfo sender_info_
;
84 base::TimeTicks time_sent_
;
85 uint32 rtp_timestamp_
;
87 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtpSenderStatistics
);
90 // TODO(mikhal): Reduce heap allocation when not needed.
91 AudioSender::AudioSender(scoped_refptr
<CastEnvironment
> cast_environment
,
92 const AudioSenderConfig
& audio_config
,
93 transport::CastTransportSender
* const transport_sender
)
94 : cast_environment_(cast_environment
),
95 transport_sender_(transport_sender
),
96 rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)),
97 rtp_audio_sender_statistics_(
98 new LocalRtpSenderStatistics(transport_sender_
,
99 audio_config
.frequency
)),
100 rtcp_(cast_environment
,
101 rtcp_feedback_
.get(),
103 NULL
, // paced sender.
104 rtp_audio_sender_statistics_
.get(),
106 audio_config
.rtcp_mode
,
107 base::TimeDelta::FromMilliseconds(audio_config
.rtcp_interval
),
108 audio_config
.sender_ssrc
,
109 audio_config
.incoming_feedback_ssrc
,
110 audio_config
.rtcp_c_name
),
111 timers_initialized_(false),
112 initialization_status_(STATUS_INITIALIZED
),
113 weak_factory_(this) {
114 if (!audio_config
.use_external_encoder
) {
116 new AudioEncoder(cast_environment
,
118 base::Bind(&AudioSender::SendEncodedAudioFrame
,
119 weak_factory_
.GetWeakPtr()));
120 initialization_status_
= audio_encoder_
->InitializationResult();
124 AudioSender::~AudioSender() {}
126 void AudioSender::InitializeTimers() {
127 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
128 if (!timers_initialized_
) {
129 timers_initialized_
= true;
130 ScheduleNextRtcpReport();
134 void AudioSender::InsertAudio(const AudioBus
* audio_bus
,
135 const base::TimeTicks
& recorded_time
,
136 const base::Closure
& done_callback
) {
137 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
138 DCHECK(audio_encoder_
.get()) << "Invalid internal state";
140 audio_encoder_
->InsertAudio(audio_bus
, recorded_time
, done_callback
);
143 void AudioSender::SendEncodedAudioFrame(
144 scoped_ptr
<transport::EncodedAudioFrame
> audio_frame
,
145 const base::TimeTicks
& recorded_time
) {
146 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
148 cast_environment_
->PostTask(
149 CastEnvironment::TRANSPORT
,
151 base::Bind(&AudioSender::SendEncodedAudioFrameToTransport
,
152 base::Unretained(this),
153 base::Passed(&audio_frame
),
157 void AudioSender::SendEncodedAudioFrameToTransport(
158 scoped_ptr
<transport::EncodedAudioFrame
> audio_frame
,
159 const base::TimeTicks
& recorded_time
) {
160 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::TRANSPORT
));
161 transport_sender_
->InsertCodedAudioFrame(audio_frame
.get(), recorded_time
);
164 void AudioSender::ResendPackets(
165 const MissingFramesAndPacketsMap
& missing_frames_and_packets
) {
166 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
167 cast_environment_
->PostTask(
168 CastEnvironment::TRANSPORT
,
170 base::Bind(&AudioSender::ResendPacketsOnTransportThread
,
171 base::Unretained(this),
172 missing_frames_and_packets
));
175 void AudioSender::IncomingRtcpPacket(scoped_ptr
<Packet
> packet
) {
176 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
177 rtcp_
.IncomingRtcpPacket(&packet
->front(), packet
->size());
180 void AudioSender::ScheduleNextRtcpReport() {
181 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
182 base::TimeDelta time_to_next
=
183 rtcp_
.TimeToSendNextRtcpReport() - cast_environment_
->Clock()->NowTicks();
185 time_to_next
= std::max(
186 time_to_next
, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs
));
188 cast_environment_
->PostDelayedTask(
189 CastEnvironment::MAIN
,
191 base::Bind(&AudioSender::SendRtcpReport
, weak_factory_
.GetWeakPtr()),
195 void AudioSender::SendRtcpReport() {
196 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
197 // We don't send audio logging messages since all captured audio frames will
199 transport::RtcpSenderLogMessage empty_msg
;
200 rtcp_
.SendRtcpFromRtpSender(empty_msg
);
201 ScheduleNextRtcpReport();
204 void AudioSender::ResendPacketsOnTransportThread(
205 const transport::MissingFramesAndPacketsMap
& missing_packets
) {
206 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::TRANSPORT
));
207 transport_sender_
->ResendPackets(true, missing_packets
);