Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * libjingle | 2 * libjingle |
| 3 * Copyright 2004 Google Inc. | 3 * Copyright 2004 Google Inc. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
| 9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 197 } | 197 } |
| 198 std::vector<int> payload_types; | 198 std::vector<int> payload_types; |
| 199 for (const AudioCodec& codec : codecs) { | 199 for (const AudioCodec& codec : codecs) { |
| 200 payload_types.push_back(codec.id); | 200 payload_types.push_back(codec.id); |
| 201 } | 201 } |
| 202 std::sort(payload_types.begin(), payload_types.end()); | 202 std::sort(payload_types.begin(), payload_types.end()); |
| 203 auto it = std::unique(payload_types.begin(), payload_types.end()); | 203 auto it = std::unique(payload_types.begin(), payload_types.end()); |
| 204 return it == payload_types.end(); | 204 return it == payload_types.end(); |
| 205 } | 205 } |
| 206 | 206 |
| 207 bool IsNackEnabled(const AudioCodec& codec) { | |
| 208 return codec.HasFeedbackParam(FeedbackParam(kRtcpFbParamNack, | |
| 209 kParamValueEmpty)); | |
| 210 } | |
| 211 | |
| 212 // Return true if codec.params[feature] == "1", false otherwise. | 207 // Return true if codec.params[feature] == "1", false otherwise. |
| 213 bool IsCodecFeatureEnabled(const AudioCodec& codec, const char* feature) { | 208 bool IsCodecFeatureEnabled(const AudioCodec& codec, const char* feature) { |
| 214 int value; | 209 int value; |
| 215 return codec.GetParam(feature, &value) && value == 1; | 210 return codec.GetParam(feature, &value) && value == 1; |
| 216 } | 211 } |
| 217 | 212 |
| 218 // Use params[kCodecParamMaxAverageBitrate] if it is defined, use codec.bitrate | 213 // Use params[kCodecParamMaxAverageBitrate] if it is defined, use codec.bitrate |
| 219 // otherwise. If the value (either from params or codec.bitrate) <=0, use the | 214 // otherwise. If the value (either from params or codec.bitrate) <=0, use the |
| 220 // default configuration. If the value is beyond feasible bit rate of Opus, | 215 // default configuration. If the value is beyond feasible bit rate of Opus, |
| 221 // clamp it. Returns the Opus bit rate for operation. | 216 // clamp it. Returns the Opus bit rate for operation. |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 324 // Only add fmtp parameters that differ from the spec. | 319 // Only add fmtp parameters that differ from the spec. |
| 325 if (kPreferredMinPTime != kOpusDefaultMinPTime) { | 320 if (kPreferredMinPTime != kOpusDefaultMinPTime) { |
| 326 codec.params[kCodecParamMinPTime] = | 321 codec.params[kCodecParamMinPTime] = |
| 327 rtc::ToString(kPreferredMinPTime); | 322 rtc::ToString(kPreferredMinPTime); |
| 328 } | 323 } |
| 329 if (kPreferredMaxPTime != kOpusDefaultMaxPTime) { | 324 if (kPreferredMaxPTime != kOpusDefaultMaxPTime) { |
| 330 codec.params[kCodecParamMaxPTime] = | 325 codec.params[kCodecParamMaxPTime] = |
| 331 rtc::ToString(kPreferredMaxPTime); | 326 rtc::ToString(kPreferredMaxPTime); |
| 332 } | 327 } |
| 333 codec.SetParam(kCodecParamUseInbandFec, 1); | 328 codec.SetParam(kCodecParamUseInbandFec, 1); |
| 329 codec.AddFeedbackParam( | |
| 330 FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty)); | |
| 334 | 331 |
| 335 // TODO(hellner): Add ptime, sprop-stereo, and stereo | 332 // TODO(hellner): Add ptime, sprop-stereo, and stereo |
| 336 // when they can be set to values other than the default. | 333 // when they can be set to values other than the default. |
| 337 } | 334 } |
| 338 result.push_back(codec); | 335 result.push_back(codec); |
| 339 } else { | 336 } else { |
| 340 LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec); | 337 LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec); |
| 341 } | 338 } |
| 342 } | 339 } |
| 343 // Make sure they are in local preference order. | 340 // Make sure they are in local preference order. |
| (...skipping 592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 936 } | 933 } |
| 937 | 934 |
| 938 RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const { | 935 RtpCapabilities WebRtcVoiceEngine::GetCapabilities() const { |
| 939 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); | 936 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); |
| 940 RtpCapabilities capabilities; | 937 RtpCapabilities capabilities; |
| 941 capabilities.header_extensions.push_back(RtpHeaderExtension( | 938 capabilities.header_extensions.push_back(RtpHeaderExtension( |
| 942 kRtpAudioLevelHeaderExtension, kRtpAudioLevelHeaderExtensionDefaultId)); | 939 kRtpAudioLevelHeaderExtension, kRtpAudioLevelHeaderExtensionDefaultId)); |
| 943 capabilities.header_extensions.push_back( | 940 capabilities.header_extensions.push_back( |
| 944 RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, | 941 RtpHeaderExtension(kRtpAbsoluteSenderTimeHeaderExtension, |
| 945 kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); | 942 kRtpAbsoluteSenderTimeHeaderExtensionDefaultId)); |
| 943 if (webrtc::field_trial::FindFullName("WebRTC-Audio-SendSideBwe") == | |
| 944 "Enabled") { | |
| 945 capabilities.header_extensions.push_back(RtpHeaderExtension( | |
| 946 kRtpTransportSequenceNumberHeaderExtension, | |
| 947 kRtpTransportSequenceNumberHeaderExtensionDefaultId)); | |
| 948 } | |
| 946 return capabilities; | 949 return capabilities; |
| 947 } | 950 } |
| 948 | 951 |
| 949 int WebRtcVoiceEngine::GetLastEngineError() { | 952 int WebRtcVoiceEngine::GetLastEngineError() { |
| 950 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 953 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 951 return voe_wrapper_->error(); | 954 return voe_wrapper_->error(); |
| 952 } | 955 } |
| 953 | 956 |
| 954 void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace, | 957 void WebRtcVoiceEngine::Print(webrtc::TraceLevel level, const char* trace, |
| 955 int length) { | 958 int length) { |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1211 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. | 1214 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. |
| 1212 // PeerConnection will make sure invalidating the pointer before the object | 1215 // PeerConnection will make sure invalidating the pointer before the object |
| 1213 // goes away. | 1216 // goes away. |
| 1214 AudioRenderer* renderer_ = nullptr; | 1217 AudioRenderer* renderer_ = nullptr; |
| 1215 | 1218 |
| 1216 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); | 1219 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); |
| 1217 }; | 1220 }; |
| 1218 | 1221 |
| 1219 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { | 1222 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
| 1220 public: | 1223 public: |
| 1221 WebRtcAudioReceiveStream(int ch, uint32_t remote_ssrc, uint32_t local_ssrc, | 1224 WebRtcAudioReceiveStream(int ch, |
| 1222 bool use_combined_bwe, const std::string& sync_group, | 1225 uint32_t remote_ssrc, |
| 1226 uint32_t local_ssrc, | |
| 1227 bool use_transport_cc, | |
| 1228 const std::string& sync_group, | |
| 1223 const std::vector<webrtc::RtpExtension>& extensions, | 1229 const std::vector<webrtc::RtpExtension>& extensions, |
| 1224 webrtc::Call* call) | 1230 webrtc::Call* call) |
| 1225 : call_(call), | 1231 : call_(call), config_() { |
| 1226 config_() { | |
| 1227 RTC_DCHECK_GE(ch, 0); | 1232 RTC_DCHECK_GE(ch, 0); |
| 1228 RTC_DCHECK(call); | 1233 RTC_DCHECK(call); |
| 1229 config_.rtp.remote_ssrc = remote_ssrc; | 1234 config_.rtp.remote_ssrc = remote_ssrc; |
| 1230 config_.rtp.local_ssrc = local_ssrc; | 1235 config_.rtp.local_ssrc = local_ssrc; |
| 1231 config_.voe_channel_id = ch; | 1236 config_.voe_channel_id = ch; |
| 1232 config_.sync_group = sync_group; | 1237 config_.sync_group = sync_group; |
| 1233 RecreateAudioReceiveStream(use_combined_bwe, extensions); | 1238 RecreateAudioReceiveStream(use_transport_cc, extensions); |
| 1234 } | 1239 } |
| 1235 | 1240 |
| 1236 ~WebRtcAudioReceiveStream() { | 1241 ~WebRtcAudioReceiveStream() { |
| 1237 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1242 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1238 call_->DestroyAudioReceiveStream(stream_); | 1243 call_->DestroyAudioReceiveStream(stream_); |
| 1239 } | 1244 } |
| 1240 | 1245 |
| 1246 void RecreateAudioReceiveStream() { | |
|
the sun
2016/01/21 13:26:24
Why do we need to recreate the stream if no config
stefan-webrtc
2016/01/21 15:09:09
I don't really know, but apparently tests are brea
the sun
2016/01/22 10:45:16
Then there is something with how the stream is bei
stefan-webrtc
2016/01/23 16:52:14
You are right, and the problem is that the tests a
| |
| 1247 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | |
| 1248 RecreateAudioReceiveStream(config_.rtp.transport_cc, | |
| 1249 config_.rtp.extensions); | |
| 1250 } | |
| 1241 void RecreateAudioReceiveStream( | 1251 void RecreateAudioReceiveStream( |
| 1242 const std::vector<webrtc::RtpExtension>& extensions) { | 1252 const std::vector<webrtc::RtpExtension>& extensions) { |
| 1243 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1253 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1244 RecreateAudioReceiveStream(config_.combined_audio_video_bwe, extensions); | 1254 RecreateAudioReceiveStream(config_.rtp.transport_cc, extensions); |
| 1245 } | 1255 } |
| 1246 void RecreateAudioReceiveStream(bool use_combined_bwe) { | 1256 void RecreateAudioReceiveStream(bool use_transport_cc) { |
| 1247 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1257 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1248 RecreateAudioReceiveStream(use_combined_bwe, config_.rtp.extensions); | 1258 RecreateAudioReceiveStream(use_transport_cc, config_.rtp.extensions); |
| 1249 } | 1259 } |
| 1250 | 1260 |
| 1251 webrtc::AudioReceiveStream::Stats GetStats() const { | 1261 webrtc::AudioReceiveStream::Stats GetStats() const { |
| 1252 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1262 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1253 RTC_DCHECK(stream_); | 1263 RTC_DCHECK(stream_); |
| 1254 return stream_->GetStats(); | 1264 return stream_->GetStats(); |
| 1255 } | 1265 } |
| 1256 | 1266 |
| 1257 int channel() const { | 1267 int channel() const { |
| 1258 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1268 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1259 return config_.voe_channel_id; | 1269 return config_.voe_channel_id; |
| 1260 } | 1270 } |
| 1261 | 1271 |
| 1262 void SetRawAudioSink(rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) { | 1272 void SetRawAudioSink(rtc::scoped_ptr<webrtc::AudioSinkInterface> sink) { |
| 1263 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1273 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1264 stream_->SetSink(std::move(sink)); | 1274 stream_->SetSink(std::move(sink)); |
| 1265 } | 1275 } |
| 1266 | 1276 |
| 1267 private: | 1277 private: |
| 1268 void RecreateAudioReceiveStream(bool use_combined_bwe, | 1278 void RecreateAudioReceiveStream( |
| 1279 bool use_transport_cc, | |
| 1269 const std::vector<webrtc::RtpExtension>& extensions) { | 1280 const std::vector<webrtc::RtpExtension>& extensions) { |
| 1270 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1281 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1271 if (stream_) { | 1282 if (stream_) { |
| 1272 call_->DestroyAudioReceiveStream(stream_); | 1283 call_->DestroyAudioReceiveStream(stream_); |
| 1273 stream_ = nullptr; | 1284 stream_ = nullptr; |
| 1274 } | 1285 } |
| 1275 config_.rtp.extensions = extensions; | 1286 config_.rtp.extensions = extensions; |
| 1276 config_.combined_audio_video_bwe = use_combined_bwe; | 1287 config_.rtp.transport_cc = use_transport_cc; |
| 1277 RTC_DCHECK(!stream_); | 1288 RTC_DCHECK(!stream_); |
| 1278 stream_ = call_->CreateAudioReceiveStream(config_); | 1289 stream_ = call_->CreateAudioReceiveStream(config_); |
| 1279 RTC_CHECK(stream_); | 1290 RTC_CHECK(stream_); |
| 1280 } | 1291 } |
| 1281 | 1292 |
| 1282 rtc::ThreadChecker worker_thread_checker_; | 1293 rtc::ThreadChecker worker_thread_checker_; |
| 1283 webrtc::Call* call_ = nullptr; | 1294 webrtc::Call* call_ = nullptr; |
| 1284 webrtc::AudioReceiveStream::Config config_; | 1295 webrtc::AudioReceiveStream::Config config_; |
| 1285 // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if | 1296 // The stream is owned by WebRtcAudioReceiveStream and may be reallocated if |
| 1286 // configuration changes. | 1297 // configuration changes. |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1362 } | 1373 } |
| 1363 std::vector<webrtc::RtpExtension> filtered_extensions = | 1374 std::vector<webrtc::RtpExtension> filtered_extensions = |
| 1364 FilterRtpExtensions(params.extensions, | 1375 FilterRtpExtensions(params.extensions, |
| 1365 webrtc::RtpExtension::IsSupportedForAudio, false); | 1376 webrtc::RtpExtension::IsSupportedForAudio, false); |
| 1366 if (recv_rtp_extensions_ != filtered_extensions) { | 1377 if (recv_rtp_extensions_ != filtered_extensions) { |
| 1367 recv_rtp_extensions_.swap(filtered_extensions); | 1378 recv_rtp_extensions_.swap(filtered_extensions); |
| 1368 for (auto& it : recv_streams_) { | 1379 for (auto& it : recv_streams_) { |
| 1369 it.second->RecreateAudioReceiveStream(recv_rtp_extensions_); | 1380 it.second->RecreateAudioReceiveStream(recv_rtp_extensions_); |
| 1370 } | 1381 } |
| 1371 } | 1382 } |
| 1372 | |
| 1373 return true; | 1383 return true; |
| 1374 } | 1384 } |
| 1375 | 1385 |
| 1376 bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { | 1386 bool WebRtcVoiceMediaChannel::SetOptions(const AudioOptions& options) { |
| 1377 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1387 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1378 LOG(LS_INFO) << "Setting voice channel options: " | 1388 LOG(LS_INFO) << "Setting voice channel options: " |
| 1379 << options.ToString(); | 1389 << options.ToString(); |
| 1380 | 1390 |
| 1381 // Check if DSCP value is changed from previous. | 1391 // Check if DSCP value is changed from previous. |
| 1382 bool dscp_option_changed = (options_.dscp != options.dscp); | 1392 bool dscp_option_changed = (options_.dscp != options.dscp); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 1396 if (options_.dscp.value_or(false)) { | 1406 if (options_.dscp.value_or(false)) { |
| 1397 dscp = kAudioDscpValue; | 1407 dscp = kAudioDscpValue; |
| 1398 } | 1408 } |
| 1399 if (MediaChannel::SetDscp(dscp) != 0) { | 1409 if (MediaChannel::SetDscp(dscp) != 0) { |
| 1400 LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel"; | 1410 LOG(LS_WARNING) << "Failed to set DSCP settings for audio channel"; |
| 1401 } | 1411 } |
| 1402 } | 1412 } |
| 1403 | 1413 |
| 1404 // TODO(solenberg): Don't recreate unless options changed. | 1414 // TODO(solenberg): Don't recreate unless options changed. |
| 1405 for (auto& it : recv_streams_) { | 1415 for (auto& it : recv_streams_) { |
| 1406 it.second->RecreateAudioReceiveStream( | 1416 it.second->RecreateAudioReceiveStream(); |
|
the sun
2016/01/21 13:26:24
Not needed anymore. At least not in the current fo
stefan-webrtc
2016/01/21 15:09:09
See above
| |
| 1407 options_.combined_audio_video_bwe.value_or(false)); | |
| 1408 } | 1417 } |
| 1409 | 1418 |
| 1410 LOG(LS_INFO) << "Set voice channel options. Current options: " | 1419 LOG(LS_INFO) << "Set voice channel options. Current options: " |
| 1411 << options_.ToString(); | 1420 << options_.ToString(); |
| 1412 return true; | 1421 return true; |
| 1413 } | 1422 } |
| 1414 | 1423 |
| 1415 bool WebRtcVoiceMediaChannel::SetRecvCodecs( | 1424 bool WebRtcVoiceMediaChannel::SetRecvCodecs( |
| 1416 const std::vector<AudioCodec>& codecs) { | 1425 const std::vector<AudioCodec>& codecs) { |
| 1417 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1426 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1484 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1493 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| 1485 int channel, const std::vector<AudioCodec>& codecs) { | 1494 int channel, const std::vector<AudioCodec>& codecs) { |
| 1486 // Disable VAD, FEC, and RED unless we know the other side wants them. | 1495 // Disable VAD, FEC, and RED unless we know the other side wants them. |
| 1487 engine()->voe()->codec()->SetVADStatus(channel, false); | 1496 engine()->voe()->codec()->SetVADStatus(channel, false); |
| 1488 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); | 1497 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); |
| 1489 engine()->voe()->rtp()->SetREDStatus(channel, false); | 1498 engine()->voe()->rtp()->SetREDStatus(channel, false); |
| 1490 engine()->voe()->codec()->SetFECStatus(channel, false); | 1499 engine()->voe()->codec()->SetFECStatus(channel, false); |
| 1491 | 1500 |
| 1492 // Scan through the list to figure out the codec to use for sending, along | 1501 // Scan through the list to figure out the codec to use for sending, along |
| 1493 // with the proper configuration for VAD. | 1502 // with the proper configuration for VAD. |
| 1494 bool found_send_codec = false; | |
| 1495 webrtc::CodecInst send_codec; | 1503 webrtc::CodecInst send_codec; |
| 1496 memset(&send_codec, 0, sizeof(send_codec)); | 1504 memset(&send_codec, 0, sizeof(send_codec)); |
| 1497 | 1505 |
| 1498 bool nack_enabled = nack_enabled_; | 1506 bool nack_enabled = nack_enabled_; |
| 1499 bool enable_codec_fec = false; | 1507 bool enable_codec_fec = false; |
| 1500 bool enable_opus_dtx = false; | 1508 bool enable_opus_dtx = false; |
| 1501 int opus_max_playback_rate = 0; | 1509 int opus_max_playback_rate = 0; |
| 1510 int red_payload_type = -1; | |
| 1502 | 1511 |
| 1503 // Set send codec (the first non-telephone-event/CN codec) | 1512 // Set send codec (the first non-telephone-event/CN codec) |
| 1504 for (const AudioCodec& codec : codecs) { | 1513 const AudioCodec* codec = |
| 1505 // Ignore codecs we don't know about. The negotiation step should prevent | 1514 GetPreferredCodec(codecs, &send_codec, &red_payload_type); |
| 1506 // this, but double-check to be sure. | 1515 if (codec) { |
| 1507 webrtc::CodecInst voe_codec; | 1516 if (red_payload_type != -1) { |
| 1508 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { | |
| 1509 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | |
| 1510 continue; | |
| 1511 } | |
| 1512 | |
| 1513 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { | |
| 1514 // Skip telephone-event/CN codec, which will be handled later. | |
| 1515 continue; | |
| 1516 } | |
| 1517 | |
| 1518 // We'll use the first codec in the list to actually send audio data. | |
| 1519 // Be sure to use the payload type requested by the remote side. | |
| 1520 // "red", for RED audio, is a special case where the actual codec to be | |
| 1521 // used is specified in params. | |
| 1522 if (IsCodec(codec, kRedCodecName)) { | |
| 1523 // Parse out the RED parameters. If we fail, just ignore RED; | |
| 1524 // we don't support all possible params/usage scenarios. | |
| 1525 if (!GetRedSendCodec(codec, codecs, &send_codec)) { | |
| 1526 continue; | |
| 1527 } | |
| 1528 | |
| 1529 // Enable redundant encoding of the specified codec. Treat any | 1517 // Enable redundant encoding of the specified codec. Treat any |
| 1530 // failure as a fatal internal error. | 1518 // failure as a fatal internal error. |
| 1531 LOG(LS_INFO) << "Enabling RED on channel " << channel; | 1519 LOG(LS_INFO) << "Enabling RED on channel " << channel; |
| 1532 if (engine()->voe()->rtp()->SetREDStatus(channel, true, codec.id) == -1) { | 1520 if (engine()->voe()->rtp()->SetREDStatus(channel, true, |
| 1533 LOG_RTCERR3(SetREDStatus, channel, true, codec.id); | 1521 red_payload_type) == -1) { |
| 1522 LOG_RTCERR3(SetREDStatus, channel, true, red_payload_type); | |
| 1534 return false; | 1523 return false; |
| 1535 } | 1524 } |
| 1536 } else { | 1525 } else { |
| 1537 send_codec = voe_codec; | 1526 nack_enabled = HasNack(*codec); |
| 1538 nack_enabled = IsNackEnabled(codec); | |
| 1539 // For Opus as the send codec, we are to determine inband FEC, maximum | 1527 // For Opus as the send codec, we are to determine inband FEC, maximum |
| 1540 // playback rate, and opus internal dtx. | 1528 // playback rate, and opus internal dtx. |
| 1541 if (IsCodec(codec, kOpusCodecName)) { | 1529 if (IsCodec(*codec, kOpusCodecName)) { |
| 1542 GetOpusConfig(codec, &send_codec, &enable_codec_fec, | 1530 GetOpusConfig(*codec, &send_codec, &enable_codec_fec, |
| 1543 &opus_max_playback_rate, &enable_opus_dtx); | 1531 &opus_max_playback_rate, &enable_opus_dtx); |
| 1544 } | 1532 } |
| 1545 | 1533 |
| 1546 // Set packet size if the AudioCodec param kCodecParamPTime is set. | 1534 // Set packet size if the AudioCodec param kCodecParamPTime is set. |
| 1547 int ptime_ms = 0; | 1535 int ptime_ms = 0; |
| 1548 if (codec.GetParam(kCodecParamPTime, &ptime_ms)) { | 1536 if (codec->GetParam(kCodecParamPTime, &ptime_ms)) { |
| 1549 if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize(&send_codec, ptime_ms)) { | 1537 if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize(&send_codec, ptime_ms)) { |
| 1550 LOG(LS_WARNING) << "Failed to set packet size for codec " | 1538 LOG(LS_WARNING) << "Failed to set packet size for codec " |
| 1551 << send_codec.plname; | 1539 << send_codec.plname; |
| 1552 return false; | 1540 return false; |
| 1553 } | 1541 } |
| 1554 } | 1542 } |
| 1555 } | 1543 } |
| 1556 found_send_codec = true; | |
| 1557 break; | |
| 1558 } | 1544 } |
| 1559 | 1545 |
| 1560 if (nack_enabled_ != nack_enabled) { | 1546 if (nack_enabled_ != nack_enabled) { |
| 1561 SetNack(channel, nack_enabled); | 1547 SetNack(channel, nack_enabled); |
| 1562 nack_enabled_ = nack_enabled; | 1548 nack_enabled_ = nack_enabled; |
| 1563 } | 1549 } |
| 1564 | 1550 if (!codec) { |
| 1565 if (!found_send_codec) { | |
| 1566 LOG(LS_WARNING) << "Received empty list of codecs."; | 1551 LOG(LS_WARNING) << "Received empty list of codecs."; |
| 1567 return false; | 1552 return false; |
| 1568 } | 1553 } |
| 1569 | 1554 |
| 1570 // Set the codec immediately, since SetVADStatus() depends on whether | 1555 // Set the codec immediately, since SetVADStatus() depends on whether |
| 1571 // the current codec is mono or stereo. | 1556 // the current codec is mono or stereo. |
| 1572 if (!SetSendCodec(channel, send_codec)) | 1557 if (!SetSendCodec(channel, send_codec)) |
| 1573 return false; | 1558 return false; |
| 1574 | 1559 |
| 1575 // FEC should be enabled after SetSendCodec. | 1560 // FEC should be enabled after SetSendCodec. |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1674 if (engine()->voe()->codec()->SetVADStatus(channel, true) == -1) { | 1659 if (engine()->voe()->codec()->SetVADStatus(channel, true) == -1) { |
| 1675 LOG_RTCERR2(SetVADStatus, channel, true); | 1660 LOG_RTCERR2(SetVADStatus, channel, true); |
| 1676 return false; | 1661 return false; |
| 1677 } | 1662 } |
| 1678 } | 1663 } |
| 1679 } | 1664 } |
| 1680 } | 1665 } |
| 1681 return true; | 1666 return true; |
| 1682 } | 1667 } |
| 1683 | 1668 |
| 1669 const AudioCodec* WebRtcVoiceMediaChannel::GetPreferredCodec( | |
|
the sun
2016/01/21 13:26:24
IIUC this function and GetRedSendCodec() do not us
stefan-webrtc
2016/01/21 15:09:09
Done.
| |
| 1670 const std::vector<AudioCodec>& codecs, | |
| 1671 webrtc::CodecInst* voe_codec, | |
| 1672 int* red_payload_type) const { | |
| 1673 // Set send codec (the first non-telephone-event/CN codec) | |
| 1674 for (const AudioCodec& codec : codecs) { | |
| 1675 *red_payload_type = -1; | |
| 1676 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { | |
| 1677 // Skip telephone-event/CN codec, which will be handled later. | |
| 1678 continue; | |
| 1679 } | |
| 1680 | |
| 1681 // We'll use the first codec in the list to actually send audio data. | |
| 1682 // Be sure to use the payload type requested by the remote side. | |
| 1683 // "red", for RED audio, is a special case where the actual codec to be | |
| 1684 // used is specified in params. | |
| 1685 const AudioCodec* found_codec = &codec; | |
| 1686 if (IsCodec(*found_codec, kRedCodecName)) { | |
| 1687 // Parse out the RED parameters. If we fail, just ignore RED; | |
| 1688 // we don't support all possible params/usage scenarios. | |
| 1689 *red_payload_type = codec.id; | |
| 1690 found_codec = GetRedSendCodec(*found_codec, codecs); | |
| 1691 if (!found_codec) { | |
| 1692 continue; | |
| 1693 } | |
| 1694 } | |
| 1695 // Ignore codecs we don't know about. The negotiation step should prevent | |
| 1696 // this, but double-check to be sure. | |
| 1697 if (!WebRtcVoiceEngine::ToCodecInst(*found_codec, voe_codec)) { | |
| 1698 LOG(LS_WARNING) << "Unknown codec " << ToString(*found_codec); | |
| 1699 continue; | |
| 1700 } | |
| 1701 return found_codec; | |
| 1702 } | |
| 1703 return nullptr; | |
| 1704 } | |
| 1705 | |
| 1684 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1706 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
| 1685 const std::vector<AudioCodec>& codecs) { | 1707 const std::vector<AudioCodec>& codecs) { |
| 1686 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1708 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1687 // TODO(solenberg): Validate input - that payload types don't overlap, are | 1709 // TODO(solenberg): Validate input - that payload types don't overlap, are |
| 1688 // within range, filter out codecs we don't support, | 1710 // within range, filter out codecs we don't support, |
| 1689 // redundant codecs etc. | 1711 // redundant codecs etc. |
| 1690 | 1712 |
| 1691 // Find the DTMF telephone event "codec" payload type. | 1713 // Find the DTMF telephone event "codec" payload type. |
| 1692 dtmf_payload_type_ = rtc::Optional<int>(); | 1714 dtmf_payload_type_ = rtc::Optional<int>(); |
| 1693 for (const AudioCodec& codec : codecs) { | 1715 for (const AudioCodec& codec : codecs) { |
| 1694 if (IsCodec(codec, kDtmfCodecName)) { | 1716 if (IsCodec(codec, kDtmfCodecName)) { |
| 1695 dtmf_payload_type_ = rtc::Optional<int>(codec.id); | 1717 dtmf_payload_type_ = rtc::Optional<int>(codec.id); |
| 1696 break; | 1718 break; |
| 1697 } | 1719 } |
| 1698 } | 1720 } |
| 1699 | 1721 |
| 1700 // Cache the codecs in order to configure the channel created later. | 1722 // Cache the codecs in order to configure the channel created later. |
| 1701 send_codecs_ = codecs; | 1723 send_codecs_ = codecs; |
| 1702 for (const auto& ch : send_streams_) { | 1724 for (const auto& ch : send_streams_) { |
| 1703 if (!SetSendCodecs(ch.second->channel(), codecs)) { | 1725 if (!SetSendCodecs(ch.second->channel(), codecs)) { |
| 1704 return false; | 1726 return false; |
| 1705 } | 1727 } |
| 1706 } | 1728 } |
| 1707 | 1729 |
| 1708 // Set nack status on receive channels and update |nack_enabled_|. | 1730 // Set nack status on receive channels and update |nack_enabled_|. |
| 1709 for (const auto& ch : recv_streams_) { | 1731 for (const auto& ch : recv_streams_) { |
| 1710 SetNack(ch.second->channel(), nack_enabled_); | 1732 SetNack(ch.second->channel(), nack_enabled_); |
| 1711 } | 1733 } |
| 1712 | 1734 |
| 1735 // Check if the transport cc feedback has changed on the preferred send codec, | |
| 1736 // and in that case reconfigure all receive streams. | |
| 1737 webrtc::CodecInst voe_codec; | |
| 1738 int red_payload_type; | |
| 1739 const AudioCodec* send_codec = | |
| 1740 GetPreferredCodec(send_codecs_, &voe_codec, &red_payload_type); | |
| 1741 if (send_codec) { | |
| 1742 bool transport_cc = HasTransportCc(*send_codec); | |
| 1743 if (transport_cc_enabled_ != transport_cc) { | |
| 1744 LOG(LS_INFO) << "Recreate all the receive streams because the send " | |
| 1745 "codec has changed."; | |
| 1746 transport_cc_enabled_ = transport_cc; | |
| 1747 for (auto& kv : recv_streams_) { | |
| 1748 RTC_DCHECK(kv.second != nullptr); | |
| 1749 kv.second->RecreateAudioReceiveStream(transport_cc_enabled_); | |
| 1750 } | |
| 1751 } | |
| 1752 } | |
| 1753 | |
| 1713 return true; | 1754 return true; |
| 1714 } | 1755 } |
| 1715 | 1756 |
| 1716 void WebRtcVoiceMediaChannel::SetNack(int channel, bool nack_enabled) { | 1757 void WebRtcVoiceMediaChannel::SetNack(int channel, bool nack_enabled) { |
| 1717 if (nack_enabled) { | 1758 if (nack_enabled) { |
| 1718 LOG(LS_INFO) << "Enabling NACK for channel " << channel; | 1759 LOG(LS_INFO) << "Enabling NACK for channel " << channel; |
| 1719 engine()->voe()->rtp()->SetNACKStatus(channel, true, kNackMaxPackets); | 1760 engine()->voe()->rtp()->SetNACKStatus(channel, true, kNackMaxPackets); |
| 1720 } else { | 1761 } else { |
| 1721 LOG(LS_INFO) << "Disabling NACK for channel " << channel; | 1762 LOG(LS_INFO) << "Disabling NACK for channel " << channel; |
| 1722 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); | 1763 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2009 | 2050 |
| 2010 const int send_channel = GetSendChannelId(receiver_reports_ssrc_); | 2051 const int send_channel = GetSendChannelId(receiver_reports_ssrc_); |
| 2011 if (send_channel != -1) { | 2052 if (send_channel != -1) { |
| 2012 // Associate receive channel with first send channel (so the receive channel | 2053 // Associate receive channel with first send channel (so the receive channel |
| 2013 // can obtain RTT from the send channel) | 2054 // can obtain RTT from the send channel) |
| 2014 engine()->voe()->base()->AssociateSendChannel(channel, send_channel); | 2055 engine()->voe()->base()->AssociateSendChannel(channel, send_channel); |
| 2015 LOG(LS_INFO) << "VoiceEngine channel #" << channel | 2056 LOG(LS_INFO) << "VoiceEngine channel #" << channel |
| 2016 << " is associated with channel #" << send_channel << "."; | 2057 << " is associated with channel #" << send_channel << "."; |
| 2017 } | 2058 } |
| 2018 | 2059 |
| 2019 recv_streams_.insert(std::make_pair(ssrc, new WebRtcAudioReceiveStream( | 2060 transport_cc_enabled_ = |
| 2020 channel, ssrc, receiver_reports_ssrc_, | 2061 !send_codecs_.empty() ? HasTransportCc(send_codecs_[0]) : false; |
| 2021 options_.combined_audio_video_bwe.value_or(false), sp.sync_label, | 2062 |
| 2022 recv_rtp_extensions_, call_))); | 2063 recv_streams_.insert(std::make_pair( |
| 2064 ssrc, new WebRtcAudioReceiveStream(channel, ssrc, receiver_reports_ssrc_, | |
| 2065 transport_cc_enabled_, sp.sync_label, | |
| 2066 recv_rtp_extensions_, call_))); | |
| 2023 | 2067 |
| 2024 SetNack(channel, nack_enabled_); | 2068 SetNack(channel, nack_enabled_); |
| 2025 SetPlayout(channel, playout_); | 2069 SetPlayout(channel, playout_); |
| 2026 | 2070 |
| 2027 return true; | 2071 return true; |
| 2028 } | 2072 } |
| 2029 | 2073 |
| 2030 bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) { | 2074 bool WebRtcVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) { |
| 2031 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2075 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 2032 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc; | 2076 LOG(LS_INFO) << "RemoveRecvStream: " << ssrc; |
| (...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2470 | 2514 |
| 2471 int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const { | 2515 int WebRtcVoiceMediaChannel::GetSendChannelId(uint32_t ssrc) const { |
| 2472 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2516 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 2473 const auto it = send_streams_.find(ssrc); | 2517 const auto it = send_streams_.find(ssrc); |
| 2474 if (it != send_streams_.end()) { | 2518 if (it != send_streams_.end()) { |
| 2475 return it->second->channel(); | 2519 return it->second->channel(); |
| 2476 } | 2520 } |
| 2477 return -1; | 2521 return -1; |
| 2478 } | 2522 } |
| 2479 | 2523 |
| 2480 bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec, | 2524 const AudioCodec* WebRtcVoiceMediaChannel::GetRedSendCodec( |
| 2481 const std::vector<AudioCodec>& all_codecs, webrtc::CodecInst* send_codec) { | 2525 const AudioCodec& red_codec, |
| 2526 const std::vector<AudioCodec>& all_codecs) const { | |
| 2482 // Get the RED encodings from the parameter with no name. This may | 2527 // Get the RED encodings from the parameter with no name. This may |
| 2483 // change based on what is discussed on the Jingle list. | 2528 // change based on what is discussed on the Jingle list. |
| 2484 // The encoding parameter is of the form "a/b"; we only support where | 2529 // The encoding parameter is of the form "a/b"; we only support where |
| 2485 // a == b. Verify this and parse out the value into red_pt. | 2530 // a == b. Verify this and parse out the value into red_pt. |
| 2486 // If the parameter value is absent (as it will be until we wire up the | 2531 // If the parameter value is absent (as it will be until we wire up the |
| 2487 // signaling of this message), use the second codec specified (i.e. the | 2532 // signaling of this message), use the second codec specified (i.e. the |
| 2488 // one after "red") as the encoding parameter. | 2533 // one after "red") as the encoding parameter. |
| 2489 int red_pt = -1; | 2534 int red_pt = -1; |
| 2490 std::string red_params; | 2535 std::string red_params; |
| 2491 CodecParameterMap::const_iterator it = red_codec.params.find(""); | 2536 CodecParameterMap::const_iterator it = red_codec.params.find(""); |
| 2492 if (it != red_codec.params.end()) { | 2537 if (it != red_codec.params.end()) { |
| 2493 red_params = it->second; | 2538 red_params = it->second; |
| 2494 std::vector<std::string> red_pts; | 2539 std::vector<std::string> red_pts; |
| 2495 if (rtc::split(red_params, '/', &red_pts) != 2 || | 2540 if (rtc::split(red_params, '/', &red_pts) != 2 || |
| 2496 red_pts[0] != red_pts[1] || | 2541 red_pts[0] != red_pts[1] || |
| 2497 !rtc::FromString(red_pts[0], &red_pt)) { | 2542 !rtc::FromString(red_pts[0], &red_pt)) { |
| 2498 LOG(LS_WARNING) << "RED params " << red_params << " not supported."; | 2543 LOG(LS_WARNING) << "RED params " << red_params << " not supported."; |
| 2499 return false; | 2544 return nullptr; |
| 2500 } | 2545 } |
| 2501 } else if (red_codec.params.empty()) { | 2546 } else if (red_codec.params.empty()) { |
| 2502 LOG(LS_WARNING) << "RED params not present, using defaults"; | 2547 LOG(LS_WARNING) << "RED params not present, using defaults"; |
| 2503 if (all_codecs.size() > 1) { | 2548 if (all_codecs.size() > 1) { |
| 2504 red_pt = all_codecs[1].id; | 2549 red_pt = all_codecs[1].id; |
| 2505 } | 2550 } |
| 2506 } | 2551 } |
| 2507 | 2552 |
| 2508 // Try to find red_pt in |codecs|. | 2553 // Try to find red_pt in |codecs|. |
| 2509 for (const AudioCodec& codec : all_codecs) { | 2554 for (const AudioCodec& codec : all_codecs) { |
| 2510 if (codec.id == red_pt) { | 2555 if (codec.id == red_pt) { |
| 2511 // If we find the right codec, that will be the codec we pass to | 2556 return &codec; |
| 2512 // SetSendCodec, with the desired payload type. | |
| 2513 if (WebRtcVoiceEngine::ToCodecInst(codec, send_codec)) { | |
| 2514 return true; | |
| 2515 } else { | |
| 2516 break; | |
| 2517 } | |
| 2518 } | 2557 } |
| 2519 } | 2558 } |
| 2520 LOG(LS_WARNING) << "RED params " << red_params << " are invalid."; | 2559 LOG(LS_WARNING) << "RED params " << red_params << " are invalid."; |
| 2521 return false; | 2560 return nullptr; |
| 2522 } | 2561 } |
| 2523 | 2562 |
| 2524 bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) { | 2563 bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) { |
| 2525 if (playout) { | 2564 if (playout) { |
| 2526 LOG(LS_INFO) << "Starting playout for channel #" << channel; | 2565 LOG(LS_INFO) << "Starting playout for channel #" << channel; |
| 2527 if (engine()->voe()->base()->StartPlayout(channel) == -1) { | 2566 if (engine()->voe()->base()->StartPlayout(channel) == -1) { |
| 2528 LOG_RTCERR1(StartPlayout, channel); | 2567 LOG_RTCERR1(StartPlayout, channel); |
| 2529 return false; | 2568 return false; |
| 2530 } | 2569 } |
| 2531 } else { | 2570 } else { |
| 2532 LOG(LS_INFO) << "Stopping playout for channel #" << channel; | 2571 LOG(LS_INFO) << "Stopping playout for channel #" << channel; |
| 2533 engine()->voe()->base()->StopPlayout(channel); | 2572 engine()->voe()->base()->StopPlayout(channel); |
| 2534 } | 2573 } |
| 2535 return true; | 2574 return true; |
| 2536 } | 2575 } |
| 2537 } // namespace cricket | 2576 } // namespace cricket |
| 2538 | 2577 |
| 2539 #endif // HAVE_WEBRTC_VOICE | 2578 #endif // HAVE_WEBRTC_VOICE |
| OLD | NEW |