| 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 |