Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(368)

Unified Diff: webrtc/audio/audio_send_stream.cc

Issue 2405183002: Moving WebRtcVoiceMediaChannel::SendSetCodec to AudioSendStream. (Closed)
Patch Set: working version Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/audio/audio_send_stream.cc
diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc
index ee84b96aaa3700a8e7d937e0cf3d4ec1dfd0990d..00827a27cca54a42a9176c07ebfd3875ef6354b6 100644
--- a/webrtc/audio/audio_send_stream.cc
+++ b/webrtc/audio/audio_send_stream.cc
@@ -10,6 +10,7 @@
#include "webrtc/audio/audio_send_stream.h"
+#include <algorithm>
#include <string>
#include "webrtc/audio/audio_state.h"
@@ -30,6 +31,84 @@
#include "webrtc/voice_engine/voice_engine_impl.h"
namespace webrtc {
+
+namespace {
+// TODO(minyue): these are all copied from corresponding cricket. Find good
+// place for them.
+
+const char kOpusCodecName[] = "opus";
+const char kIsacCodecName[] = "isac";
+const char kG722CodecName[] = "g722";
+const char kIlbcCodecName[] = "ilbc";
+const char kPcmuCodecName[] = "pcmu";
+const char kPcmaCodecName[] = "pcma";
+const char kCnCodecName[] = "cn";
+const char kDtmfCodecName[] = "telephone-event";
+const int kOpusMaxBitrate = 510000;
+const int kIsacMaxBitrate = 56000;
+
+static const int kMaxNumPacketSize = 6;
+struct CodecPref {
+ const char* name;
+ int clockrate;
+ size_t channels;
+ int payload_type;
+ bool is_multi_rate;
+ int packet_sizes_ms[kMaxNumPacketSize];
+ int max_bitrate_bps;
+};
+
+const CodecPref kCodecPrefs[11] = {
+ {kOpusCodecName, 48000, 2, 111, true, {10, 20, 40, 60}, kOpusMaxBitrate},
+ {kIsacCodecName, 16000, 1, 103, true, {30, 60}, kIsacMaxBitrate},
+ {kIsacCodecName, 32000, 1, 104, true, {30}, kIsacMaxBitrate},
+ // G722 should be advertised as 8000 Hz because of the RFC "bug".
+ {kG722CodecName, 8000, 1, 9, false, {10, 20, 30, 40, 50, 60}},
+ {kIlbcCodecName, 8000, 1, 102, false, {20, 30, 40, 60}},
+ {kPcmuCodecName, 8000, 1, 0, false, {10, 20, 30, 40, 50, 60}},
+ {kPcmaCodecName, 8000, 1, 8, false, {10, 20, 30, 40, 50, 60}},
+ {kCnCodecName, 32000, 1, 106, false, {}},
+ {kCnCodecName, 16000, 1, 105, false, {}},
+ {kCnCodecName, 8000, 1, 13, false, {}},
+ {kDtmfCodecName, 8000, 1, 126, false, {}}};
+
+bool IsCodec(const webrtc::CodecInst& codec, const char* ref_name) {
+ return (_stricmp(codec.plname, ref_name) == 0);
+}
+
+bool IsCodecMultiRate(const webrtc::CodecInst& codec) {
+ for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) {
+ if (IsCodec(codec, kCodecPrefs[i].name) &&
+ kCodecPrefs[i].clockrate == codec.plfreq) {
+ return kCodecPrefs[i].is_multi_rate;
+ }
+ }
+ return false;
+}
+
+int MaxBitrateBps(const webrtc::CodecInst& codec) {
+ for (size_t i = 0; i < arraysize(kCodecPrefs); ++i) {
+ if (IsCodec(codec, kCodecPrefs[i].name) &&
+ kCodecPrefs[i].clockrate == codec.plfreq) {
+ return kCodecPrefs[i].max_bitrate_bps;
+ }
+ }
+ return 0;
+}
+
+template <typename T>
+static T MinPositive(T a, T b) {
+ if (a <= 0) {
+ return b;
+ }
+ if (b <= 0) {
+ return a;
+ }
+ return std::min(a, b);
+}
+
+} // namespace
+
std::string AudioSendStream::Config::Rtp::ToString() const {
std::stringstream ss;
ss << "{ssrc: " << ssrc;
@@ -102,6 +181,7 @@ AudioSendStream::AudioSendStream(
RTC_NOTREACHED() << "Registering unsupported RTP extension.";
}
}
+ SetSendCodecs();
}
AudioSendStream::~AudioSendStream() {
@@ -285,5 +365,193 @@ VoiceEngine* AudioSendStream::voice_engine() const {
RTC_DCHECK(voice_engine);
return voice_engine;
}
+
+// Apply current codec settings to a single voe::Channel used for sending.
+bool AudioSendStream::SetSendCodecs() {
+ ScopedVoEInterface<VoECodec> codec(voice_engine());
+ const int channel = config_.voe_channel_id;
+
+ // Disable VAD and FEC unless we know the other side wants them.
+ codec->SetVADStatus(channel, false);
+ codec->SetFECStatus(channel, false);
+
+ // Set the codec immediately, since SetVADStatus() depends on whether
+ // the current codec is mono or stereo.
+ if (!SetSendCodec(config_.send_codec_spec.codec_inst)) {
+ return false;
+ }
+
+ // FEC should be enabled after SetSendCodec.
+ if (config_.send_codec_spec.enable_codec_fec) {
+ LOG(LS_INFO) << "Attempt to enable codec internal FEC on channel "
+ << channel;
+ if (codec->SetFECStatus(channel, true) == -1) {
+ // Enable codec internal FEC. Treat any failure as fatal internal error.
+ // TODO(minyue): use normal logging.
+ // LOG_RTCERR2(SetFECStatus, channel, true);
+ return false;
+ }
+ }
+
+ if (IsCodec(config_.send_codec_spec.codec_inst, kOpusCodecName)) {
+ // DTX and maxplaybackrate should be set after SetSendCodec. Because current
+ // send codec has to be Opus.
+
+ // Set Opus internal DTX.
+ LOG(LS_INFO) << "Attempt to "
+ << (config_.send_codec_spec.enable_opus_dtx ? "enable"
+ : "disable")
+ << " Opus DTX on channel " << channel;
+ if (codec->SetOpusDtx(channel, config_.send_codec_spec.enable_opus_dtx)) {
+ // TODO(minyue): use normal logging.
+ // LOG_RTCERR2(SetOpusDtx, channel,
+ // config_.send_codec_spec.enable_opus_dtx);
+ return false;
+ }
+
+ // If opus_max_playback_rate <= 0, the default maximum playback rate
+ // (48 kHz) will be used.
+ if (config_.send_codec_spec.opus_max_playback_rate > 0) {
+ LOG(LS_INFO) << "Attempt to set maximum playback rate to "
+ << config_.send_codec_spec.opus_max_playback_rate
+ << " Hz on channel " << channel;
+ if (codec->SetOpusMaxPlaybackRate(
+ channel, config_.send_codec_spec.opus_max_playback_rate) == -1) {
+ // TODO(minyue): use normal logging.
+ // LOG_RTCERR2(SetOpusMaxPlaybackRate, channel,
+ // config_.send_codec_spec.opus_max_playback_rate);
+ return false;
+ }
+ }
+ }
+ // TODO(solenberg): ApplyMaxSendBitrate() yields another call to
+ // SetSendCodec(). Check if it is possible to fuse with the previous call
+ // in this function.
+ ApplyMaxSendBitrate();
+
+ // Set the CN payloadtype and the VAD status.
+ if (config_.send_codec_spec.cng_payload_type != -1) {
+ // The CN payload type for 8000 Hz clockrate is fixed at 13.
+ if (config_.send_codec_spec.cng_plfreq != 8000) {
+ webrtc::PayloadFrequencies cn_freq;
+ switch (config_.send_codec_spec.cng_plfreq) {
+ case 16000:
+ cn_freq = webrtc::kFreq16000Hz;
+ break;
+ case 32000:
+ cn_freq = webrtc::kFreq32000Hz;
+ break;
+ default:
+ RTC_NOTREACHED();
+ return false;
+ }
+ if (codec->SetSendCNPayloadType(channel,
+ config_.send_codec_spec.cng_payload_type,
+ cn_freq) == -1) {
+ // TODO(minyue): use normal logging.
+ // LOG_RTCERR3(SetSendCNPayloadType, channel,
+ // config_.send_codec_spec.cng_payload_type, cn_freq);
+
+ // TODO(ajm): This failure condition will be removed from VoE.
+ // Restore the return here when we update to a new enough webrtc.
+ //
+ // Not returning false because the SetSendCNPayloadType will fail if
+ // the channel is already sending.
+ // This can happen if the remote description is applied twice, for
+ // example in the case of ROAP on top of JSEP, where both side will
+ // send the offer.
+ }
+ }
+
+ // Only turn on VAD if we have a CN payload type that matches the
+ // clockrate for the codec we are going to use.
+ if (config_.send_codec_spec.cng_plfreq ==
+ config_.send_codec_spec.codec_inst.plfreq &&
+ config_.send_codec_spec.codec_inst.channels == 1) {
+ // TODO(minyue): If CN frequency == 48000 Hz is allowed, consider the
+ // interaction between VAD and Opus FEC.
+ LOG(LS_INFO) << "Enabling VAD";
+ if (codec->SetVADStatus(channel, true) == -1) {
+ // TODO(minyue): use normal logging.
+ // LOG_RTCERR2(SetVADStatus, channel, true);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool AudioSendStream::SetSendCodec(const webrtc::CodecInst& send_codec) {
+ // TODO(minyue): avoid ToString
+ // LOG(LS_INFO) << "Send channel " << channel << " selected voice codec "
+ // << ToString(send_codec) << ", bitrate=" << send_codec.rate;
+
+ ScopedVoEInterface<VoECodec> codec(voice_engine());
+ int channel = config_.voe_channel_id;
+
+ webrtc::CodecInst current_codec = {0};
+ if (codec->GetSendCodec(channel, current_codec) == 0 &&
+ (send_codec == current_codec)) {
+ // Codec is already configured, we can return without setting it again.
+ return true;
+ }
+
+ if (codec->SetSendCodec(channel, send_codec) == -1) {
+ // TODO(minyue): use normal logging.
+ // LOG_RTCERR2(SetSendCodec, channel, ToString(send_codec));
+ return false;
+ }
+ return true;
+}
+
+bool AudioSendStream::ApplyMaxSendBitrate() {
+ int bps = config_.max_send_bitrate_bps;
+
+ // Bitrate is auto by default.
+ // TODO(bemasc): Fix this so that if SetMaxSendBandwidth(50) is followed by
+ // SetMaxSendBandwith(0), the second call removes the previous limit.
+ if (bps <= 0) {
+ return true;
+ }
+
+ if (!HasSendCodec()) {
+ LOG(LS_INFO) << "The send codec has not been set up yet. "
+ << "The send bitrate setting will be applied later.";
+ return true;
+ }
+
+ webrtc::CodecInst codec = config_.send_codec_spec.codec_inst;
+ bool is_multi_rate = IsCodecMultiRate(codec);
+
+ if (is_multi_rate) {
+ // If codec is multi-rate then just set the bitrate.
+ int max_bitrate_bps = MaxBitrateBps(codec);
+ codec.rate = std::min(bps, max_bitrate_bps);
+ LOG(LS_INFO) << "Setting codec " << codec.plname << " to bitrate " << bps
+ << " bps.";
+ if (!SetSendCodec(codec)) {
+ LOG(LS_ERROR) << "Failed to set codec " << codec.plname << " to bitrate "
+ << bps << " bps.";
+ return false;
+ }
+ return true;
+ } else {
+ // If codec is not multi-rate and |bps| is less than the fixed bitrate
+ // then fail. If codec is not multi-rate and |bps| exceeds or equal the
+ // fixed bitrate then ignore.
+ if (bps < codec.rate) {
+ LOG(LS_ERROR) << "Failed to set codec " << codec.plname << " to bitrate "
+ << bps << " bps"
+ << ", requires at least " << codec.rate << " bps.";
+ return false;
+ }
+ return true;
+ }
+}
+
+bool AudioSendStream::HasSendCodec() const {
+ return config_.send_codec_spec.codec_inst.pltype != -1;
the sun 2016/10/12 15:15:17 Think we can do without this function.
minyue-webrtc 2016/10/12 18:59:21 sure.
+}
+
} // namespace internal
} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698