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 "media/cast/sender/audio_sender.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "media/cast/cast_defines.h"
11 #include "media/cast/net/cast_transport_config.h"
12 #include "media/cast/sender/audio_encoder.h"
18 // TODO(miu): This should be specified in AudioSenderConfig, but currently it is
19 // fixed to 100 FPS (i.e., 10 ms per frame), and AudioEncoder assumes this as
21 const int kAudioFrameRate
= 100;
25 AudioSender::AudioSender(scoped_refptr
<CastEnvironment
> cast_environment
,
26 const AudioSenderConfig
& audio_config
,
27 CastTransportSender
* const transport_sender
)
32 base::TimeDelta::FromMilliseconds(audio_config
.rtcp_interval
),
33 audio_config
.frequency
,
35 kAudioFrameRate
* 2.0, // We lie to increase max outstanding frames.
36 audio_config
.min_playout_delay
,
37 audio_config
.max_playout_delay
,
38 NewFixedCongestionControl(audio_config
.bitrate
)),
39 samples_in_encoder_(0),
41 cast_initialization_status_
= STATUS_AUDIO_UNINITIALIZED
;
42 VLOG(1) << "max_unacked_frames " << max_unacked_frames_
;
43 DCHECK_GT(max_unacked_frames_
, 0);
45 if (!audio_config
.use_external_encoder
) {
47 new AudioEncoder(cast_environment
,
48 audio_config
.channels
,
49 audio_config
.frequency
,
52 base::Bind(&AudioSender::OnEncodedAudioFrame
,
53 weak_factory_
.GetWeakPtr(),
54 audio_config
.bitrate
)));
55 cast_initialization_status_
= audio_encoder_
->InitializationResult();
57 NOTREACHED(); // No support for external audio encoding.
58 cast_initialization_status_
= STATUS_AUDIO_UNINITIALIZED
;
61 media::cast::CastTransportRtpConfig transport_config
;
62 transport_config
.ssrc
= audio_config
.ssrc
;
63 transport_config
.feedback_ssrc
= audio_config
.incoming_feedback_ssrc
;
64 transport_config
.rtp_payload_type
= audio_config
.rtp_payload_type
;
65 transport_config
.stored_frames
=
66 std::min(kMaxUnackedFrames
,
67 1 + static_cast<int>(max_playout_delay_
*
69 base::TimeDelta::FromSeconds(1)));
70 transport_config
.aes_key
= audio_config
.aes_key
;
71 transport_config
.aes_iv_mask
= audio_config
.aes_iv_mask
;
73 transport_sender
->InitializeAudio(
75 base::Bind(&AudioSender::OnReceivedCastFeedback
,
76 weak_factory_
.GetWeakPtr()),
77 base::Bind(&AudioSender::OnMeasuredRoundTripTime
,
78 weak_factory_
.GetWeakPtr()));
81 AudioSender::~AudioSender() {}
83 void AudioSender::InsertAudio(scoped_ptr
<AudioBus
> audio_bus
,
84 const base::TimeTicks
& recorded_time
) {
85 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
86 if (cast_initialization_status_
!= STATUS_AUDIO_INITIALIZED
) {
90 DCHECK(audio_encoder_
.get()) << "Invalid internal state";
92 // TODO(miu): An |audio_bus| that represents more duration than a single
93 // frame's duration can defeat our logic here, causing too much data to become
94 // enqueued. This will be addressed in a soon-upcoming change.
95 if (ShouldDropNextFrame(recorded_time
)) {
96 VLOG(1) << "Dropping frame due to too many frames currently in-flight.";
100 samples_in_encoder_
+= audio_bus
->frames();
102 audio_encoder_
->InsertAudio(audio_bus
.Pass(), recorded_time
);
105 int AudioSender::GetNumberOfFramesInEncoder() const {
106 // Note: It's possible for a partial frame to be in the encoder, but returning
107 // the floor() is good enough for the "design limit" check in FrameSender.
108 return samples_in_encoder_
/ audio_encoder_
->GetSamplesPerFrame();
111 void AudioSender::OnAck(uint32 frame_id
) {
114 void AudioSender::OnEncodedAudioFrame(
116 scoped_ptr
<EncodedFrame
> encoded_frame
,
117 int samples_skipped
) {
118 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
120 samples_in_encoder_
-= audio_encoder_
->GetSamplesPerFrame() + samples_skipped
;
121 DCHECK_GE(samples_in_encoder_
, 0);
123 SendEncodedFrame(encoder_bitrate
, encoded_frame
.Pass());