OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2004 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
377 codec->pacsize = (codec->plfreq / 1000) * packet_size_ms; | 377 codec->pacsize = (codec->plfreq / 1000) * packet_size_ms; |
378 return true; | 378 return true; |
379 } | 379 } |
380 } | 380 } |
381 } | 381 } |
382 return false; | 382 return false; |
383 } | 383 } |
384 | 384 |
385 static const AudioCodec* GetPreferredCodec( | 385 static const AudioCodec* GetPreferredCodec( |
386 const std::vector<AudioCodec>& codecs, | 386 const std::vector<AudioCodec>& codecs, |
387 webrtc::CodecInst* out, | 387 webrtc::CodecInst* out) { |
388 int* red_payload_type) { | |
389 RTC_DCHECK(out); | 388 RTC_DCHECK(out); |
390 RTC_DCHECK(red_payload_type); | |
391 // Select the preferred send codec (the first non-telephone-event/CN codec). | 389 // Select the preferred send codec (the first non-telephone-event/CN codec). |
392 for (const AudioCodec& codec : codecs) { | 390 for (const AudioCodec& codec : codecs) { |
393 *red_payload_type = -1; | |
394 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { | 391 if (IsCodec(codec, kDtmfCodecName) || IsCodec(codec, kCnCodecName)) { |
395 // Skip telephone-event/CN codec, which will be handled later. | 392 // Skip telephone-event/CN codec, which will be handled later. |
396 continue; | 393 continue; |
397 } | 394 } |
398 | 395 |
399 // We'll use the first codec in the list to actually send audio data. | 396 // We'll use the first codec in the list to actually send audio data. |
400 // Be sure to use the payload type requested by the remote side. | 397 // Be sure to use the payload type requested by the remote side. |
401 // "red", for RED audio, is a special case where the actual codec to be | |
402 // used is specified in params. | |
403 const AudioCodec* found_codec = &codec; | |
404 if (IsCodec(*found_codec, kRedCodecName)) { | |
405 // Parse out the RED parameters. If we fail, just ignore RED; | |
406 // we don't support all possible params/usage scenarios. | |
407 *red_payload_type = codec.id; | |
408 found_codec = GetRedSendCodec(*found_codec, codecs); | |
409 if (!found_codec) { | |
410 continue; | |
411 } | |
412 } | |
413 // Ignore codecs we don't know about. The negotiation step should prevent | 398 // Ignore codecs we don't know about. The negotiation step should prevent |
414 // this, but double-check to be sure. | 399 // this, but double-check to be sure. |
415 webrtc::CodecInst voe_codec = {0}; | 400 webrtc::CodecInst voe_codec = {0}; |
416 if (!ToCodecInst(*found_codec, &voe_codec)) { | 401 if (!ToCodecInst(codec, &voe_codec)) { |
417 LOG(LS_WARNING) << "Unknown codec " << ToString(*found_codec); | 402 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
418 continue; | 403 continue; |
419 } | 404 } |
420 *out = voe_codec; | 405 *out = voe_codec; |
421 return found_codec; | 406 return &codec; |
422 } | 407 } |
423 return nullptr; | 408 return nullptr; |
424 } | 409 } |
425 | 410 |
426 private: | 411 private: |
427 static const int kMaxNumPacketSize = 6; | 412 static const int kMaxNumPacketSize = 6; |
428 struct CodecPref { | 413 struct CodecPref { |
429 const char* name; | 414 const char* name; |
430 int clockrate; | 415 int clockrate; |
431 size_t channels; | 416 size_t channels; |
432 int payload_type; | 417 int payload_type; |
433 bool is_multi_rate; | 418 bool is_multi_rate; |
434 int packet_sizes_ms[kMaxNumPacketSize]; | 419 int packet_sizes_ms[kMaxNumPacketSize]; |
435 int max_bitrate_bps; | 420 int max_bitrate_bps; |
436 }; | 421 }; |
437 // Note: keep the supported packet sizes in ascending order. | 422 // Note: keep the supported packet sizes in ascending order. |
438 static const CodecPref kCodecPrefs[12]; | 423 static const CodecPref kCodecPrefs[11]; |
439 | 424 |
440 static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) { | 425 static int SelectPacketSize(const CodecPref& codec_pref, int ptime_ms) { |
441 int selected_packet_size_ms = codec_pref.packet_sizes_ms[0]; | 426 int selected_packet_size_ms = codec_pref.packet_sizes_ms[0]; |
442 for (int packet_size_ms : codec_pref.packet_sizes_ms) { | 427 for (int packet_size_ms : codec_pref.packet_sizes_ms) { |
443 if (packet_size_ms && packet_size_ms <= ptime_ms) { | 428 if (packet_size_ms && packet_size_ms <= ptime_ms) { |
444 selected_packet_size_ms = packet_size_ms; | 429 selected_packet_size_ms = packet_size_ms; |
445 } | 430 } |
446 } | 431 } |
447 return selected_packet_size_ms; | 432 return selected_packet_size_ms; |
448 } | 433 } |
449 | 434 |
450 // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC | 435 // Changes RTP timestamp rate of G722. This is due to the "bug" in the RFC |
451 // which says that G722 should be advertised as 8 kHz although it is a 16 kHz | 436 // which says that G722 should be advertised as 8 kHz although it is a 16 kHz |
452 // codec. | 437 // codec. |
453 static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { | 438 static void MaybeFixupG722(webrtc::CodecInst* voe_codec, int new_plfreq) { |
454 if (IsCodec(*voe_codec, kG722CodecName)) { | 439 if (IsCodec(*voe_codec, kG722CodecName)) { |
455 // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine | 440 // If the ASSERT triggers, the codec definition in WebRTC VoiceEngine |
456 // has changed, and this special case is no longer needed. | 441 // has changed, and this special case is no longer needed. |
457 RTC_DCHECK(voe_codec->plfreq != new_plfreq); | 442 RTC_DCHECK(voe_codec->plfreq != new_plfreq); |
458 voe_codec->plfreq = new_plfreq; | 443 voe_codec->plfreq = new_plfreq; |
459 } | 444 } |
460 } | 445 } |
461 | |
462 static const AudioCodec* GetRedSendCodec( | |
463 const AudioCodec& red_codec, | |
464 const std::vector<AudioCodec>& all_codecs) { | |
465 // Get the RED encodings from the parameter with no name. This may | |
466 // change based on what is discussed on the Jingle list. | |
467 // The encoding parameter is of the form "a/b"; we only support where | |
468 // a == b. Verify this and parse out the value into red_pt. | |
469 // If the parameter value is absent (as it will be until we wire up the | |
470 // signaling of this message), use the second codec specified (i.e. the | |
471 // one after "red") as the encoding parameter. | |
472 int red_pt = -1; | |
473 std::string red_params; | |
474 CodecParameterMap::const_iterator it = red_codec.params.find(""); | |
475 if (it != red_codec.params.end()) { | |
476 red_params = it->second; | |
477 std::vector<std::string> red_pts; | |
478 if (rtc::split(red_params, '/', &red_pts) != 2 || | |
479 red_pts[0] != red_pts[1] || !rtc::FromString(red_pts[0], &red_pt)) { | |
480 LOG(LS_WARNING) << "RED params " << red_params << " not supported."; | |
481 return nullptr; | |
482 } | |
483 } else if (red_codec.params.empty()) { | |
484 LOG(LS_WARNING) << "RED params not present, using defaults"; | |
485 if (all_codecs.size() > 1) { | |
486 red_pt = all_codecs[1].id; | |
487 } | |
488 } | |
489 | |
490 // Try to find red_pt in |codecs|. | |
491 for (const AudioCodec& codec : all_codecs) { | |
492 if (codec.id == red_pt) { | |
493 return &codec; | |
494 } | |
495 } | |
496 LOG(LS_WARNING) << "RED params " << red_params << " are invalid."; | |
497 return nullptr; | |
498 } | |
499 }; | 446 }; |
500 | 447 |
501 const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[12] = { | 448 const WebRtcVoiceCodecs::CodecPref WebRtcVoiceCodecs::kCodecPrefs[11] = { |
502 {kOpusCodecName, 48000, 2, 111, true, {10, 20, 40, 60}, kOpusMaxBitrate}, | 449 {kOpusCodecName, 48000, 2, 111, true, {10, 20, 40, 60}, kOpusMaxBitrate}, |
503 {kIsacCodecName, 16000, 1, 103, true, {30, 60}, kIsacMaxBitrate}, | 450 {kIsacCodecName, 16000, 1, 103, true, {30, 60}, kIsacMaxBitrate}, |
504 {kIsacCodecName, 32000, 1, 104, true, {30}, kIsacMaxBitrate}, | 451 {kIsacCodecName, 32000, 1, 104, true, {30}, kIsacMaxBitrate}, |
505 // G722 should be advertised as 8000 Hz because of the RFC "bug". | 452 // G722 should be advertised as 8000 Hz because of the RFC "bug". |
506 {kG722CodecName, 8000, 1, 9, false, {10, 20, 30, 40, 50, 60}}, | 453 {kG722CodecName, 8000, 1, 9, false, {10, 20, 30, 40, 50, 60}}, |
507 {kIlbcCodecName, 8000, 1, 102, false, {20, 30, 40, 60}}, | 454 {kIlbcCodecName, 8000, 1, 102, false, {20, 30, 40, 60}}, |
508 {kPcmuCodecName, 8000, 1, 0, false, {10, 20, 30, 40, 50, 60}}, | 455 {kPcmuCodecName, 8000, 1, 0, false, {10, 20, 30, 40, 50, 60}}, |
509 {kPcmaCodecName, 8000, 1, 8, false, {10, 20, 30, 40, 50, 60}}, | 456 {kPcmaCodecName, 8000, 1, 8, false, {10, 20, 30, 40, 50, 60}}, |
510 {kCnCodecName, 32000, 1, 106, false, {}}, | 457 {kCnCodecName, 32000, 1, 106, false, {}}, |
511 {kCnCodecName, 16000, 1, 105, false, {}}, | 458 {kCnCodecName, 16000, 1, 105, false, {}}, |
512 {kCnCodecName, 8000, 1, 13, false, {}}, | 459 {kCnCodecName, 8000, 1, 13, false, {}}, |
513 {kRedCodecName, 8000, 1, 127, false, {}}, | 460 {kDtmfCodecName, 8000, 1, 126, false, {}} |
514 {kDtmfCodecName, 8000, 1, 126, false, {}}, | |
515 }; | 461 }; |
516 } // namespace { | 462 } // namespace { |
517 | 463 |
518 bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in, | 464 bool WebRtcVoiceEngine::ToCodecInst(const AudioCodec& in, |
519 webrtc::CodecInst* out) { | 465 webrtc::CodecInst* out) { |
520 return WebRtcVoiceCodecs::ToCodecInst(in, out); | 466 return WebRtcVoiceCodecs::ToCodecInst(in, out); |
521 } | 467 } |
522 | 468 |
523 WebRtcVoiceEngine::WebRtcVoiceEngine(webrtc::AudioDeviceModule* adm) | 469 WebRtcVoiceEngine::WebRtcVoiceEngine(webrtc::AudioDeviceModule* adm) |
524 : WebRtcVoiceEngine(adm, new VoEWrapper()) { | 470 : WebRtcVoiceEngine(adm, new VoEWrapper()) { |
(...skipping 1125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1650 if (IsCodec(codec, kDtmfCodecName)) { | 1596 if (IsCodec(codec, kDtmfCodecName)) { |
1651 if (codec.id < kMinPayloadType || codec.id > kMaxPayloadType) { | 1597 if (codec.id < kMinPayloadType || codec.id > kMaxPayloadType) { |
1652 return false; | 1598 return false; |
1653 } | 1599 } |
1654 dtmf_payload_type_ = rtc::Optional<int>(codec.id); | 1600 dtmf_payload_type_ = rtc::Optional<int>(codec.id); |
1655 break; | 1601 break; |
1656 } | 1602 } |
1657 } | 1603 } |
1658 | 1604 |
1659 // Scan through the list to figure out the codec to use for sending, along | 1605 // Scan through the list to figure out the codec to use for sending, along |
1660 // with the proper configuration for VAD, CNG, RED, NACK and Opus-specific | 1606 // with the proper configuration for VAD, CNG, NACK and Opus-specific |
1661 // parameters. | 1607 // parameters. |
| 1608 // TODO(solenberg): Refactor this logic once we create AudioEncoders here. |
1662 { | 1609 { |
1663 SendCodecSpec send_codec_spec; | 1610 SendCodecSpec send_codec_spec; |
1664 send_codec_spec.nack_enabled = send_codec_spec_.nack_enabled; | 1611 send_codec_spec.nack_enabled = send_codec_spec_.nack_enabled; |
1665 | 1612 |
1666 // Find send codec (the first non-telephone-event/CN codec). | 1613 // Find send codec (the first non-telephone-event/CN codec). |
1667 const AudioCodec* codec = WebRtcVoiceCodecs::GetPreferredCodec( | 1614 const AudioCodec* codec = WebRtcVoiceCodecs::GetPreferredCodec( |
1668 codecs, &send_codec_spec.codec_inst, &send_codec_spec.red_payload_type); | 1615 codecs, &send_codec_spec.codec_inst); |
1669 if (!codec) { | 1616 if (!codec) { |
1670 LOG(LS_WARNING) << "Received empty list of codecs."; | 1617 LOG(LS_WARNING) << "Received empty list of codecs."; |
1671 return false; | 1618 return false; |
1672 } | 1619 } |
1673 | 1620 |
1674 send_codec_spec.transport_cc_enabled = HasTransportCc(*codec); | 1621 send_codec_spec.transport_cc_enabled = HasTransportCc(*codec); |
| 1622 send_codec_spec.nack_enabled = HasNack(*codec); |
1675 | 1623 |
1676 // This condition is apparently here because Opus does not support RED and | 1624 // For Opus as the send codec, we are to determine inband FEC, maximum |
1677 // FEC simultaneously. However, DTX and max playback rate shouldn't have | 1625 // playback rate, and opus internal dtx. |
1678 // such limitations. | 1626 if (IsCodec(*codec, kOpusCodecName)) { |
1679 // TODO(solenberg): Refactor this logic once we create AudioEncoders here. | 1627 GetOpusConfig(*codec, &send_codec_spec.codec_inst, |
1680 if (send_codec_spec.red_payload_type == -1) { | 1628 &send_codec_spec.enable_codec_fec, |
1681 send_codec_spec.nack_enabled = HasNack(*codec); | 1629 &send_codec_spec.opus_max_playback_rate, |
1682 // For Opus as the send codec, we are to determine inband FEC, maximum | 1630 &send_codec_spec.enable_opus_dtx); |
1683 // playback rate, and opus internal dtx. | 1631 } |
1684 if (IsCodec(*codec, kOpusCodecName)) { | |
1685 GetOpusConfig(*codec, &send_codec_spec.codec_inst, | |
1686 &send_codec_spec.enable_codec_fec, | |
1687 &send_codec_spec.opus_max_playback_rate, | |
1688 &send_codec_spec.enable_opus_dtx); | |
1689 } | |
1690 | 1632 |
1691 // Set packet size if the AudioCodec param kCodecParamPTime is set. | 1633 // Set packet size if the AudioCodec param kCodecParamPTime is set. |
1692 int ptime_ms = 0; | 1634 int ptime_ms = 0; |
1693 if (codec->GetParam(kCodecParamPTime, &ptime_ms)) { | 1635 if (codec->GetParam(kCodecParamPTime, &ptime_ms)) { |
1694 if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize( | 1636 if (!WebRtcVoiceCodecs::SetPTimeAsPacketSize( |
1695 &send_codec_spec.codec_inst, ptime_ms)) { | 1637 &send_codec_spec.codec_inst, ptime_ms)) { |
1696 LOG(LS_WARNING) << "Failed to set packet size for codec " | 1638 LOG(LS_WARNING) << "Failed to set packet size for codec " |
1697 << send_codec_spec.codec_inst.plname; | 1639 << send_codec_spec.codec_inst.plname; |
1698 return false; | 1640 return false; |
1699 } | |
1700 } | 1641 } |
1701 } | 1642 } |
1702 | 1643 |
1703 // Loop through the codecs list again to find the CN codec. | 1644 // Loop through the codecs list again to find the CN codec. |
1704 // TODO(solenberg): Break out into a separate function? | 1645 // TODO(solenberg): Break out into a separate function? |
1705 for (const AudioCodec& codec : codecs) { | 1646 for (const AudioCodec& codec : codecs) { |
1706 // Ignore codecs we don't know about. The negotiation step should prevent | 1647 // Ignore codecs we don't know about. The negotiation step should prevent |
1707 // this, but double-check to be sure. | 1648 // this, but double-check to be sure. |
1708 webrtc::CodecInst voe_codec = {0}; | 1649 webrtc::CodecInst voe_codec = {0}; |
1709 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { | 1650 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1761 } | 1702 } |
1762 | 1703 |
1763 send_codecs_ = codecs; | 1704 send_codecs_ = codecs; |
1764 return true; | 1705 return true; |
1765 } | 1706 } |
1766 | 1707 |
1767 // Apply current codec settings to a single voe::Channel used for sending. | 1708 // Apply current codec settings to a single voe::Channel used for sending. |
1768 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1709 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
1769 int channel, | 1710 int channel, |
1770 const webrtc::RtpParameters& rtp_parameters) { | 1711 const webrtc::RtpParameters& rtp_parameters) { |
1771 // Disable VAD, FEC, and RED unless we know the other side wants them. | 1712 // Disable VAD, NACK and FEC unless we know the other side wants them. |
1772 engine()->voe()->codec()->SetVADStatus(channel, false); | 1713 engine()->voe()->codec()->SetVADStatus(channel, false); |
1773 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); | 1714 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); |
1774 engine()->voe()->rtp()->SetREDStatus(channel, false); | |
1775 engine()->voe()->codec()->SetFECStatus(channel, false); | 1715 engine()->voe()->codec()->SetFECStatus(channel, false); |
1776 | 1716 |
1777 if (send_codec_spec_.red_payload_type != -1) { | |
1778 // Enable redundant encoding of the specified codec. Treat any | |
1779 // failure as a fatal internal error. | |
1780 LOG(LS_INFO) << "Enabling RED on channel " << channel; | |
1781 if (engine()->voe()->rtp()->SetREDStatus(channel, true, | |
1782 send_codec_spec_.red_payload_type) == -1) { | |
1783 LOG_RTCERR3(SetREDStatus, channel, true, | |
1784 send_codec_spec_.red_payload_type); | |
1785 return false; | |
1786 } | |
1787 } | |
1788 | |
1789 SetNack(channel, send_codec_spec_.nack_enabled); | 1717 SetNack(channel, send_codec_spec_.nack_enabled); |
1790 | 1718 |
1791 // Set the codec immediately, since SetVADStatus() depends on whether | 1719 // Set the codec immediately, since SetVADStatus() depends on whether |
1792 // the current codec is mono or stereo. | 1720 // the current codec is mono or stereo. |
1793 if (!SetSendCodec(channel, send_codec_spec_.codec_inst)) { | 1721 if (!SetSendCodec(channel, send_codec_spec_.codec_inst)) { |
1794 return false; | 1722 return false; |
1795 } | 1723 } |
1796 | 1724 |
1797 // FEC should be enabled after SetSendCodec. | 1725 // FEC should be enabled after SetSendCodec. |
1798 if (send_codec_spec_.enable_codec_fec) { | 1726 if (send_codec_spec_.enable_codec_fec) { |
(...skipping 829 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2628 } | 2556 } |
2629 } else { | 2557 } else { |
2630 LOG(LS_INFO) << "Stopping playout for channel #" << channel; | 2558 LOG(LS_INFO) << "Stopping playout for channel #" << channel; |
2631 engine()->voe()->base()->StopPlayout(channel); | 2559 engine()->voe()->base()->StopPlayout(channel); |
2632 } | 2560 } |
2633 return true; | 2561 return true; |
2634 } | 2562 } |
2635 } // namespace cricket | 2563 } // namespace cricket |
2636 | 2564 |
2637 #endif // HAVE_WEBRTC_VOICE | 2565 #endif // HAVE_WEBRTC_VOICE |
OLD | NEW |