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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 // NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified | 127 // NOTE(ajm): Don't use hardcoded paths on platforms not explicitly specified |
128 // below. | 128 // below. |
129 #if defined(CHROMEOS) | 129 #if defined(CHROMEOS) |
130 const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump"; | 130 const char kAecDumpByAudioOptionFilename[] = "/tmp/audio.aecdump"; |
131 #elif defined(ANDROID) | 131 #elif defined(ANDROID) |
132 const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; | 132 const char kAecDumpByAudioOptionFilename[] = "/sdcard/audio.aecdump"; |
133 #else | 133 #else |
134 const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; | 134 const char kAecDumpByAudioOptionFilename[] = "audio.aecdump"; |
135 #endif | 135 #endif |
136 | 136 |
| 137 // Constants from voice_engine_defines.h. |
| 138 const int kMinTelephoneEventCode = 0; // RFC4733 (Section 2.3.1) |
| 139 const int kMaxTelephoneEventCode = 255; |
| 140 const int kMinTelephoneEventDuration = 100; |
| 141 const int kMaxTelephoneEventDuration = 60000; // Actual limit is 2^16 |
| 142 |
137 bool ValidateStreamParams(const StreamParams& sp) { | 143 bool ValidateStreamParams(const StreamParams& sp) { |
138 if (sp.ssrcs.empty()) { | 144 if (sp.ssrcs.empty()) { |
139 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); | 145 LOG(LS_ERROR) << "No SSRCs in stream parameters: " << sp.ToString(); |
140 return false; | 146 return false; |
141 } | 147 } |
142 if (sp.ssrcs.size() > 1) { | 148 if (sp.ssrcs.size() > 1) { |
143 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); | 149 LOG(LS_ERROR) << "Multiple SSRCs in stream parameters: " << sp.ToString(); |
144 return false; | 150 return false; |
145 } | 151 } |
146 return true; | 152 return true; |
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
575 if (!SetOptions(GetDefaultEngineOptions())) { | 581 if (!SetOptions(GetDefaultEngineOptions())) { |
576 return false; | 582 return false; |
577 } | 583 } |
578 | 584 |
579 // Print our codec list again for the call diagnostic log | 585 // Print our codec list again for the call diagnostic log |
580 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; | 586 LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; |
581 for (const AudioCodec& codec : codecs_) { | 587 for (const AudioCodec& codec : codecs_) { |
582 LOG(LS_INFO) << ToString(codec); | 588 LOG(LS_INFO) << ToString(codec); |
583 } | 589 } |
584 | 590 |
585 // Disable the DTMF playout when a tone is sent. | |
586 // PlayDtmfTone will be used if local playout is needed. | |
587 if (voe_wrapper_->dtmf()->SetDtmfFeedbackStatus(false) == -1) { | |
588 LOG_RTCERR1(SetDtmfFeedbackStatus, false); | |
589 } | |
590 | |
591 initialized_ = true; | 591 initialized_ = true; |
592 return true; | 592 return true; |
593 } | 593 } |
594 | 594 |
595 void WebRtcVoiceEngine::Terminate() { | 595 void WebRtcVoiceEngine::Terminate() { |
596 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 596 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
597 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; | 597 LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; |
598 initialized_ = false; | 598 initialized_ = false; |
599 | 599 |
600 StopAecDump(); | 600 StopAecDump(); |
(...skipping 650 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1251 if (stream_) { | 1251 if (stream_) { |
1252 call_->DestroyAudioSendStream(stream_); | 1252 call_->DestroyAudioSendStream(stream_); |
1253 stream_ = nullptr; | 1253 stream_ = nullptr; |
1254 } | 1254 } |
1255 config_.rtp.extensions = extensions; | 1255 config_.rtp.extensions = extensions; |
1256 RTC_DCHECK(!stream_); | 1256 RTC_DCHECK(!stream_); |
1257 stream_ = call_->CreateAudioSendStream(config_); | 1257 stream_ = call_->CreateAudioSendStream(config_); |
1258 RTC_CHECK(stream_); | 1258 RTC_CHECK(stream_); |
1259 } | 1259 } |
1260 | 1260 |
| 1261 bool SendTelephoneEvent(int payload_type, uint8_t event, |
| 1262 uint32_t duration_ms) { |
| 1263 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1264 RTC_DCHECK(stream_); |
| 1265 return stream_->SendTelephoneEvent(payload_type, event, duration_ms); |
| 1266 } |
| 1267 |
1261 webrtc::AudioSendStream::Stats GetStats() const { | 1268 webrtc::AudioSendStream::Stats GetStats() const { |
1262 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1269 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
1263 RTC_DCHECK(stream_); | 1270 RTC_DCHECK(stream_); |
1264 return stream_->GetStats(); | 1271 return stream_->GetStats(); |
1265 } | 1272 } |
1266 | 1273 |
1267 // Starts the rendering by setting a sink to the renderer to get data | 1274 // Starts the rendering by setting a sink to the renderer to get data |
1268 // callback. | 1275 // callback. |
1269 // This method is called on the libjingle worker thread. | 1276 // This method is called on the libjingle worker thread. |
1270 // TODO(xians): Make sure Start() is called only once. | 1277 // TODO(xians): Make sure Start() is called only once. |
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1605 | 1612 |
1606 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1613 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
1607 int channel, const std::vector<AudioCodec>& codecs) { | 1614 int channel, const std::vector<AudioCodec>& codecs) { |
1608 // Disable VAD, FEC, and RED unless we know the other side wants them. | 1615 // Disable VAD, FEC, and RED unless we know the other side wants them. |
1609 engine()->voe()->codec()->SetVADStatus(channel, false); | 1616 engine()->voe()->codec()->SetVADStatus(channel, false); |
1610 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); | 1617 engine()->voe()->rtp()->SetNACKStatus(channel, false, 0); |
1611 engine()->voe()->rtp()->SetREDStatus(channel, false); | 1618 engine()->voe()->rtp()->SetREDStatus(channel, false); |
1612 engine()->voe()->codec()->SetFECStatus(channel, false); | 1619 engine()->voe()->codec()->SetFECStatus(channel, false); |
1613 | 1620 |
1614 // Scan through the list to figure out the codec to use for sending, along | 1621 // Scan through the list to figure out the codec to use for sending, along |
1615 // with the proper configuration for VAD and DTMF. | 1622 // with the proper configuration for VAD. |
1616 bool found_send_codec = false; | 1623 bool found_send_codec = false; |
1617 webrtc::CodecInst send_codec; | 1624 webrtc::CodecInst send_codec; |
1618 memset(&send_codec, 0, sizeof(send_codec)); | 1625 memset(&send_codec, 0, sizeof(send_codec)); |
1619 | 1626 |
1620 bool nack_enabled = nack_enabled_; | 1627 bool nack_enabled = nack_enabled_; |
1621 bool enable_codec_fec = false; | 1628 bool enable_codec_fec = false; |
1622 bool enable_opus_dtx = false; | 1629 bool enable_opus_dtx = false; |
1623 int opus_max_playback_rate = 0; | 1630 int opus_max_playback_rate = 0; |
1624 | 1631 |
1625 // Set send codec (the first non-telephone-event/CN codec) | 1632 // Set send codec (the first non-telephone-event/CN codec) |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1734 } | 1741 } |
1735 } | 1742 } |
1736 | 1743 |
1737 // Always update the |send_codec_| to the currently set send codec. | 1744 // Always update the |send_codec_| to the currently set send codec. |
1738 send_codec_.reset(new webrtc::CodecInst(send_codec)); | 1745 send_codec_.reset(new webrtc::CodecInst(send_codec)); |
1739 | 1746 |
1740 if (send_bitrate_setting_) { | 1747 if (send_bitrate_setting_) { |
1741 SetSendBitrateInternal(send_bitrate_bps_); | 1748 SetSendBitrateInternal(send_bitrate_bps_); |
1742 } | 1749 } |
1743 | 1750 |
1744 // Loop through the codecs list again to config the telephone-event/CN codec. | 1751 // Loop through the codecs list again to config the CN codec. |
1745 for (const AudioCodec& codec : codecs) { | 1752 for (const AudioCodec& codec : codecs) { |
1746 // Ignore codecs we don't know about. The negotiation step should prevent | 1753 // Ignore codecs we don't know about. The negotiation step should prevent |
1747 // this, but double-check to be sure. | 1754 // this, but double-check to be sure. |
1748 webrtc::CodecInst voe_codec; | 1755 webrtc::CodecInst voe_codec; |
1749 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { | 1756 if (!WebRtcVoiceEngine::ToCodecInst(codec, &voe_codec)) { |
1750 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | 1757 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
1751 continue; | 1758 continue; |
1752 } | 1759 } |
1753 | 1760 |
1754 // Find the DTMF telephone event "codec" and tell VoiceEngine channels | 1761 if (IsCodec(codec, kCnCodecName)) { |
1755 // about it. | |
1756 if (IsCodec(codec, kDtmfCodecName)) { | |
1757 if (engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType( | |
1758 channel, codec.id) == -1) { | |
1759 LOG_RTCERR2(SetSendTelephoneEventPayloadType, channel, codec.id); | |
1760 return false; | |
1761 } | |
1762 } else if (IsCodec(codec, kCnCodecName)) { | |
1763 // Turn voice activity detection/comfort noise on if supported. | 1762 // Turn voice activity detection/comfort noise on if supported. |
1764 // Set the wideband CN payload type appropriately. | 1763 // Set the wideband CN payload type appropriately. |
1765 // (narrowband always uses the static payload type 13). | 1764 // (narrowband always uses the static payload type 13). |
1766 webrtc::PayloadFrequencies cn_freq; | 1765 webrtc::PayloadFrequencies cn_freq; |
1767 switch (codec.clockrate) { | 1766 switch (codec.clockrate) { |
1768 case 8000: | 1767 case 8000: |
1769 cn_freq = webrtc::kFreq8000Hz; | 1768 cn_freq = webrtc::kFreq8000Hz; |
1770 break; | 1769 break; |
1771 case 16000: | 1770 case 16000: |
1772 cn_freq = webrtc::kFreq16000Hz; | 1771 cn_freq = webrtc::kFreq16000Hz; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1807 } | 1806 } |
1808 } | 1807 } |
1809 } | 1808 } |
1810 } | 1809 } |
1811 return true; | 1810 return true; |
1812 } | 1811 } |
1813 | 1812 |
1814 bool WebRtcVoiceMediaChannel::SetSendCodecs( | 1813 bool WebRtcVoiceMediaChannel::SetSendCodecs( |
1815 const std::vector<AudioCodec>& codecs) { | 1814 const std::vector<AudioCodec>& codecs) { |
1816 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 1815 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
| 1816 // TODO(solenberg): Validate input - that payload types don't overlap, are |
| 1817 // within range, filter out codecs we don't support, |
| 1818 // redundant codecs etc. |
1817 | 1819 |
1818 dtmf_allowed_ = false; | 1820 // Find the DTMF telephone event "codec" payload type. |
| 1821 dtmf_payload_type_ = rtc::Optional<int>(); |
1819 for (const AudioCodec& codec : codecs) { | 1822 for (const AudioCodec& codec : codecs) { |
1820 // Find the DTMF telephone event "codec". | |
1821 if (IsCodec(codec, kDtmfCodecName)) { | 1823 if (IsCodec(codec, kDtmfCodecName)) { |
1822 dtmf_allowed_ = true; | 1824 dtmf_payload_type_ = rtc::Optional<int>(codec.id); |
| 1825 break; |
1823 } | 1826 } |
1824 } | 1827 } |
1825 | 1828 |
1826 // Cache the codecs in order to configure the channel created later. | 1829 // Cache the codecs in order to configure the channel created later. |
1827 send_codecs_ = codecs; | 1830 send_codecs_ = codecs; |
1828 for (const auto& ch : send_streams_) { | 1831 for (const auto& ch : send_streams_) { |
1829 if (!SetSendCodecs(ch.second->channel(), codecs)) { | 1832 if (!SetSendCodecs(ch.second->channel(), codecs)) { |
1830 return false; | 1833 return false; |
1831 } | 1834 } |
1832 } | 1835 } |
(...skipping 442 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2275 volume)) { | 2278 volume)) { |
2276 LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume); | 2279 LOG_RTCERR2(SetChannelOutputVolumeScaling, ch_id, volume); |
2277 return false; | 2280 return false; |
2278 } | 2281 } |
2279 LOG(LS_INFO) << "SetOutputVolume to " << volume | 2282 LOG(LS_INFO) << "SetOutputVolume to " << volume |
2280 << " for channel " << ch_id << " and ssrc " << ssrc; | 2283 << " for channel " << ch_id << " and ssrc " << ssrc; |
2281 return true; | 2284 return true; |
2282 } | 2285 } |
2283 | 2286 |
2284 bool WebRtcVoiceMediaChannel::CanInsertDtmf() { | 2287 bool WebRtcVoiceMediaChannel::CanInsertDtmf() { |
2285 return dtmf_allowed_; | 2288 return dtmf_payload_type_ ? true : false; |
2286 } | 2289 } |
2287 | 2290 |
2288 bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event, | 2291 bool WebRtcVoiceMediaChannel::InsertDtmf(uint32_t ssrc, int event, |
2289 int duration) { | 2292 int duration) { |
2290 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2293 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
2291 if (!dtmf_allowed_) { | 2294 LOG(LS_INFO) << "WebRtcVoiceMediaChannel::InsertDtmf"; |
| 2295 if (!dtmf_payload_type_) { |
2292 return false; | 2296 return false; |
2293 } | 2297 } |
2294 | 2298 |
2295 // Send the event. | 2299 // Figure out which WebRtcAudioSendStream to send the event on. |
2296 int channel = -1; | 2300 auto it = ssrc != 0 ? send_streams_.find(ssrc) : send_streams_.begin(); |
2297 if (ssrc == 0) { | 2301 if (it == send_streams_.end()) { |
2298 if (send_streams_.size() > 0) { | 2302 LOG(LS_WARNING) << "The specified ssrc " << ssrc << " is not in use."; |
2299 channel = send_streams_.begin()->second->channel(); | |
2300 } | |
2301 } else { | |
2302 channel = GetSendChannelId(ssrc); | |
2303 } | |
2304 if (channel == -1) { | |
2305 LOG(LS_WARNING) << "InsertDtmf - The specified ssrc " | |
2306 << ssrc << " is not in use."; | |
2307 return false; | 2303 return false; |
2308 } | 2304 } |
2309 // Send DTMF using out-of-band DTMF. ("true", as 3rd arg) | 2305 if (event < kMinTelephoneEventCode || |
2310 if (engine()->voe()->dtmf()->SendTelephoneEvent( | 2306 event > kMaxTelephoneEventCode) { |
2311 channel, event, true, duration) == -1) { | 2307 LOG(LS_WARNING) << "DTMF event code " << event << " out of range."; |
2312 LOG_RTCERR4(SendTelephoneEvent, channel, event, true, duration); | |
2313 return false; | 2308 return false; |
2314 } | 2309 } |
2315 | 2310 if (duration < kMinTelephoneEventDuration || |
2316 return true; | 2311 duration > kMaxTelephoneEventDuration) { |
| 2312 LOG(LS_WARNING) << "DTMF event duration " << duration << " out of range."; |
| 2313 return false; |
| 2314 } |
| 2315 return it->second->SendTelephoneEvent(*dtmf_payload_type_, event, duration); |
2317 } | 2316 } |
2318 | 2317 |
2319 void WebRtcVoiceMediaChannel::OnPacketReceived( | 2318 void WebRtcVoiceMediaChannel::OnPacketReceived( |
2320 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { | 2319 rtc::Buffer* packet, const rtc::PacketTime& packet_time) { |
2321 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); | 2320 RTC_DCHECK(worker_thread_checker_.CalledOnValidThread()); |
2322 | 2321 |
2323 uint32_t ssrc = 0; | 2322 uint32_t ssrc = 0; |
2324 if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) { | 2323 if (!GetRtpSsrc(packet->data(), packet->size(), &ssrc)) { |
2325 return; | 2324 return; |
2326 } | 2325 } |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2638 } | 2637 } |
2639 } else { | 2638 } else { |
2640 LOG(LS_INFO) << "Stopping playout for channel #" << channel; | 2639 LOG(LS_INFO) << "Stopping playout for channel #" << channel; |
2641 engine()->voe()->base()->StopPlayout(channel); | 2640 engine()->voe()->base()->StopPlayout(channel); |
2642 } | 2641 } |
2643 return true; | 2642 return true; |
2644 } | 2643 } |
2645 } // namespace cricket | 2644 } // namespace cricket |
2646 | 2645 |
2647 #endif // HAVE_WEBRTC_VOICE | 2646 #endif // HAVE_WEBRTC_VOICE |
OLD | NEW |