1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/cast/sender/audio_sender.h"
#include <utility>
#include "base/bind.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "media/cast/common/rtp_time.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/sender/audio_encoder.h"
namespace media {
namespace cast {
AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
const AudioSenderConfig& audio_config,
const StatusChangeCallback& status_change_cb,
CastTransportSender* const transport_sender)
: FrameSender(cast_environment,
true,
transport_sender,
audio_config.frequency,
audio_config.ssrc,
0, // |max_frame_rate_| is set after encoder initialization.
audio_config.min_playout_delay,
audio_config.max_playout_delay,
audio_config.animated_playout_delay,
NewFixedCongestionControl(audio_config.bitrate)),
samples_in_encoder_(0),
weak_factory_(this) {
if (!audio_config.use_external_encoder) {
audio_encoder_.reset(
new AudioEncoder(cast_environment,
audio_config.channels,
audio_config.frequency,
audio_config.bitrate,
audio_config.codec,
base::Bind(&AudioSender::OnEncodedAudioFrame,
weak_factory_.GetWeakPtr(),
audio_config.bitrate)));
}
// AudioEncoder provides no operational status changes during normal use.
// Post a task now with its initialization result status to allow the client
// to start sending frames.
cast_environment_->PostTask(
CastEnvironment::MAIN,
FROM_HERE,
base::Bind(status_change_cb,
audio_encoder_ ? audio_encoder_->InitializationResult() :
STATUS_INVALID_CONFIGURATION));
// The number of samples per encoded audio frame depends on the codec and its
// initialization parameters. Now that we have an encoder, we can calculate
// the maximum frame rate.
max_frame_rate_ =
audio_config.frequency / audio_encoder_->GetSamplesPerFrame();
media::cast::CastTransportRtpConfig transport_config;
transport_config.ssrc = audio_config.ssrc;
transport_config.feedback_ssrc = audio_config.receiver_ssrc;
transport_config.rtp_payload_type = audio_config.rtp_payload_type;
transport_config.aes_key = audio_config.aes_key;
transport_config.aes_iv_mask = audio_config.aes_iv_mask;
transport_sender->InitializeAudio(
transport_config,
base::Bind(&AudioSender::OnReceivedCastFeedback,
weak_factory_.GetWeakPtr()),
base::Bind(&AudioSender::OnMeasuredRoundTripTime,
weak_factory_.GetWeakPtr()));
}
AudioSender::~AudioSender() {}
void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus,
const base::TimeTicks& recorded_time) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
if (!audio_encoder_) {
NOTREACHED();
return;
}
const base::TimeDelta next_frame_duration =
RtpTimeDelta::FromTicks(audio_bus->frames()).ToTimeDelta(rtp_timebase());
if (ShouldDropNextFrame(next_frame_duration))
return;
samples_in_encoder_ += audio_bus->frames();
audio_encoder_->InsertAudio(std::move(audio_bus), recorded_time);
}
int AudioSender::GetNumberOfFramesInEncoder() const {
// Note: It's possible for a partial frame to be in the encoder, but returning
// the floor() is good enough for the "design limit" check in FrameSender.
return samples_in_encoder_ / audio_encoder_->GetSamplesPerFrame();
}
base::TimeDelta AudioSender::GetInFlightMediaDuration() const {
const int samples_in_flight = samples_in_encoder_ +
GetUnacknowledgedFrameCount() * audio_encoder_->GetSamplesPerFrame();
return RtpTimeDelta::FromTicks(samples_in_flight).ToTimeDelta(rtp_timebase());
}
void AudioSender::OnEncodedAudioFrame(
int encoder_bitrate,
scoped_ptr<SenderEncodedFrame> encoded_frame,
int samples_skipped) {
DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
samples_in_encoder_ -= audio_encoder_->GetSamplesPerFrame() + samples_skipped;
DCHECK_GE(samples_in_encoder_, 0);
SendEncodedFrame(encoder_bitrate, std::move(encoded_frame));
}
} // namespace cast
} // namespace media
|