• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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.
4 
5 #include "cast/standalone_sender/streaming_opus_encoder.h"
6 
7 #include <opus/opus.h>
8 
9 #include <algorithm>
10 #include <chrono>
11 
12 #include "util/chrono_helpers.h"
13 
14 namespace openscreen {
15 namespace cast {
16 
17 using openscreen::operator<<;  // To pretty-print chrono values.
18 
19 namespace {
20 
21 // The bitrate at which virtually all stereo audio can be encoded and decoded
22 // without human-perceivable artifacts. Source:
23 // https://wiki.hydrogenaud.io/index.php?title=Opus#Bitrate_performance
24 constexpr opus_int32 kTransparentBitrate = 160000;
25 
26 // The maximum number of Cast audio frames the encoder may fall behind by before
27 // skipping-ahead the RTP timestamps to compensate.
28 constexpr int kMaxCastFramesBeforeSkip = 3;
29 
30 }  // namespace
31 
StreamingOpusEncoder(int num_channels,int cast_frames_per_second,Sender * sender)32 StreamingOpusEncoder::StreamingOpusEncoder(int num_channels,
33                                            int cast_frames_per_second,
34                                            Sender* sender)
35     : num_channels_(num_channels),
36       sender_(sender),
37       samples_per_cast_frame_(sample_rate() / cast_frames_per_second),
38       approximate_cast_frame_duration_(Clock::to_duration(seconds(1)) /
39                                        cast_frames_per_second),
40       encoder_storage_(new uint8_t[opus_encoder_get_size(num_channels_)]),
41       input_(new float[num_channels_ * samples_per_cast_frame_]),
42       output_(new uint8_t[kOpusMaxPayloadSize]) {
43   OSP_CHECK_GT(cast_frames_per_second, 0);
44   OSP_DCHECK(sender_);
45   OSP_CHECK_GT(samples_per_cast_frame_, 0);
46   OSP_CHECK_EQ(sample_rate() % cast_frames_per_second, 0);
47   OSP_CHECK(approximate_cast_frame_duration_ > Clock::duration::zero());
48 
49   frame_.dependency = EncodedFrame::KEY_FRAME;
50 
51   const auto init_result = opus_encoder_init(
52       encoder(), sample_rate(), num_channels_, OPUS_APPLICATION_AUDIO);
53   OSP_CHECK_EQ(init_result, OPUS_OK);
54 
55   UseStandardQuality();
56 }
57 
58 StreamingOpusEncoder::~StreamingOpusEncoder() = default;
59 
GetBitrate() const60 int StreamingOpusEncoder::GetBitrate() const {
61   opus_int32 bitrate;
62   const auto ctl_result =
63       opus_encoder_ctl(encoder(), OPUS_GET_BITRATE(&bitrate));
64   OSP_CHECK_EQ(ctl_result, OPUS_OK);
65   return bitrate;
66 }
67 
UseStandardQuality()68 void StreamingOpusEncoder::UseStandardQuality() {
69   const auto ctl_result =
70       opus_encoder_ctl(encoder(), OPUS_SET_BITRATE(OPUS_AUTO));
71   OSP_CHECK_EQ(ctl_result, OPUS_OK);
72   UpdateCodecDelay();
73 }
74 
UseHighQuality()75 void StreamingOpusEncoder::UseHighQuality() {
76   // kTransparentBitrate assumes stereo audio. Scale it by the actual number of
77   // channels.
78   const opus_int32 bitrate = kTransparentBitrate * num_channels_ / 2;
79   const auto ctl_result =
80       opus_encoder_ctl(encoder(), OPUS_SET_BITRATE(bitrate));
81   OSP_CHECK_EQ(ctl_result, OPUS_OK);
82   UpdateCodecDelay();
83 }
84 
EncodeAndSend(const float * interleaved_samples,int num_samples,Clock::time_point reference_time)85 void StreamingOpusEncoder::EncodeAndSend(const float* interleaved_samples,
86                                          int num_samples,
87                                          Clock::time_point reference_time) {
88   OSP_DCHECK(interleaved_samples);
89   OSP_DCHECK_GT(num_samples, 0);
90 
91   ResolveTimestampsAndMaybeSkip(reference_time);
92 
93   while (num_samples > 0) {
94     const int samples_copied =
95         FillInputBuffer(interleaved_samples, num_samples);
96     num_samples -= samples_copied;
97     interleaved_samples += num_channels_ * samples_copied;
98 
99     if (num_samples_queued_ < samples_per_cast_frame_) {
100       return;  // Not enough yet for a full Cast audio frame.
101     }
102 
103     const opus_int32 packet_size_or_error =
104         opus_encode_float(encoder(), input_.get(), num_samples_queued_,
105                           output_.get(), kOpusMaxPayloadSize);
106     num_samples_queued_ = 0;
107     if (packet_size_or_error < 0) {
108       OSP_LOG_FATAL << "AUDIO[" << sender_->ssrc()
109                     << "] Error code from opus_encode_float(): "
110                     << packet_size_or_error;
111       return;
112     }
113 
114     frame_.frame_id = sender_->GetNextFrameId();
115     frame_.referenced_frame_id = frame_.frame_id;
116     // Note: It's possible for Opus to encode a zero byte packet. Send a Cast
117     // audio frame anyway, to represent the passage of silence and to send other
118     // stream metadata.
119     frame_.data = absl::Span<uint8_t>(output_.get(), packet_size_or_error);
120     last_sent_frame_reference_time_ = frame_.reference_time;
121     switch (sender_->EnqueueFrame(frame_)) {
122       case Sender::OK:
123         break;
124       case Sender::PAYLOAD_TOO_LARGE:
125         OSP_NOTREACHED();  // The Opus packet cannot possibly be too large.
126         break;
127       case Sender::REACHED_ID_SPAN_LIMIT:
128         OSP_LOG_WARN << "AUDIO[" << sender_->ssrc()
129                      << "] Dropping: FrameId span limit reached.";
130         break;
131       case Sender::MAX_DURATION_IN_FLIGHT:
132         OSP_LOG_INFO << "AUDIO[" << sender_->ssrc()
133                      << "] Dropping: In-flight duration would be too high.";
134         break;
135     }
136 
137     frame_.rtp_timestamp += RtpTimeDelta::FromTicks(samples_per_cast_frame_);
138     frame_.reference_time += approximate_cast_frame_duration_;
139   }
140 }
141 
UpdateCodecDelay()142 void StreamingOpusEncoder::UpdateCodecDelay() {
143   opus_int32 lookahead = 0;
144   const auto ctl_result =
145       opus_encoder_ctl(encoder(), OPUS_GET_LOOKAHEAD(&lookahead));
146   OSP_CHECK_EQ(ctl_result, OPUS_OK);
147   codec_delay_ = RtpTimeDelta::FromTicks(lookahead).ToDuration<Clock::duration>(
148       sample_rate());
149 }
150 
ResolveTimestampsAndMaybeSkip(Clock::time_point reference_time)151 void StreamingOpusEncoder::ResolveTimestampsAndMaybeSkip(
152     Clock::time_point reference_time) {
153   // Back-track the reference time to account for the audio delay introduced by
154   // the codec.
155   reference_time -= codec_delay_;
156 
157   // Special case: Nothing special for the first frame's timestamps.
158   if (start_time_ == Clock::time_point::min()) {
159     frame_.rtp_timestamp = RtpTimeTicks();
160     frame_.reference_time = start_time_ = reference_time;
161     last_sent_frame_reference_time_ =
162         reference_time - approximate_cast_frame_duration_;
163     return;
164   }
165 
166   const RtpTimeTicks current_position =
167       frame_.rtp_timestamp + RtpTimeDelta::FromTicks(num_samples_queued_);
168   const RtpTimeTicks reference_position = RtpTimeTicks::FromTimeSinceOrigin(
169       reference_time - start_time_, sample_rate());
170   const RtpTimeDelta rtp_advancement = reference_position - current_position;
171   const RtpTimeDelta skip_threshold =
172       RtpTimeDelta::FromTicks(samples_per_cast_frame_) *
173       kMaxCastFramesBeforeSkip;
174   if (rtp_advancement > skip_threshold) {
175     OSP_LOG_WARN << "Detected audio gap "
176                  << rtp_advancement.ToDuration<microseconds>(sample_rate())
177                  << ", skipping ahead...";
178     num_samples_queued_ = 0;
179     frame_.rtp_timestamp = reference_position;
180   }
181 
182   // Further back-track the reference time to account for the already-queued
183   // samples.
184   reference_time -= RtpTimeDelta::FromTicks(num_samples_queued_)
185                         .ToDuration<Clock::duration>(sample_rate());
186 
187   // Frame reference times must be monotonically increasing. A little noise in
188   // the negative direction is okay to cap-off. Log a warning if there's a
189   // bigger problem (at the source).
190   const Clock::time_point lower_bound =
191       last_sent_frame_reference_time_ +
192       RtpTimeDelta::FromTicks(1).ToDuration<Clock::duration>(sample_rate());
193   if (reference_time < lower_bound) {
194     const Clock::duration backwards_amount =
195         last_sent_frame_reference_time_ - reference_time;
196     OSP_LOG_IF(WARN, backwards_amount >= approximate_cast_frame_duration_)
197         << "Reference time went *backwards* too much (" << backwards_amount
198         << " in wrong direction). A/V sync may suffer at the Receiver!";
199     reference_time = lower_bound;
200   }
201 
202   frame_.reference_time = reference_time;
203 }
204 
FillInputBuffer(const float * interleaved_samples,int num_samples)205 int StreamingOpusEncoder::FillInputBuffer(const float* interleaved_samples,
206                                           int num_samples) {
207   const int samples_needed = samples_per_cast_frame_ - num_samples_queued_;
208   const int samples_to_copy = std::min(num_samples, samples_needed);
209   std::copy(interleaved_samples,
210             interleaved_samples + num_channels_ * samples_to_copy,
211             input_.get() + num_channels_ * num_samples_queued_);
212   num_samples_queued_ += samples_to_copy;
213   return samples_to_copy;
214 }
215 
216 // static
217 constexpr int StreamingOpusEncoder::kDefaultCastAudioFramesPerSecond;
218 // static
219 constexpr int StreamingOpusEncoder::kOpusMaxPayloadSize;
220 
221 }  // namespace cast
222 }  // namespace openscreen
223