| 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 1303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 } | 1314 } |
| 1315 | 1315 |
| 1316 class WebRtcVoiceMediaChannel::WebRtcAudioSendStream | 1316 class WebRtcVoiceMediaChannel::WebRtcAudioSendStream |
| 1317 : public AudioRenderer::Sink { | 1317 : public AudioRenderer::Sink { |
| 1318 public: | 1318 public: |
| 1319 WebRtcAudioSendStream(int ch, webrtc::AudioTransport* voe_audio_transport, | 1319 WebRtcAudioSendStream(int ch, webrtc::AudioTransport* voe_audio_transport, |
| 1320 uint32_t ssrc, webrtc::Call* call) | 1320 uint32_t ssrc, webrtc::Call* call) |
| 1321 : channel_(ch), | 1321 : channel_(ch), |
| 1322 voe_audio_transport_(voe_audio_transport), | 1322 voe_audio_transport_(voe_audio_transport), |
| 1323 call_(call) { | 1323 call_(call) { |
| 1324 RTC_DCHECK_GE(ch, 0); |
| 1325 // TODO(solenberg): Once we're not using FakeWebRtcVoiceEngine anymore: |
| 1326 // RTC_DCHECK(voe_audio_transport); |
| 1324 RTC_DCHECK(call); | 1327 RTC_DCHECK(call); |
| 1328 audio_capture_thread_checker_.DetachFromThread(); |
| 1325 webrtc::AudioSendStream::Config config(nullptr); | 1329 webrtc::AudioSendStream::Config config(nullptr); |
| 1326 config.voe_channel_id = channel_; | 1330 config.voe_channel_id = channel_; |
| 1327 config.rtp.ssrc = ssrc; | 1331 config.rtp.ssrc = ssrc; |
| 1328 stream_ = call_->CreateAudioSendStream(config); | 1332 stream_ = call_->CreateAudioSendStream(config); |
| 1329 RTC_DCHECK(stream_); | 1333 RTC_DCHECK(stream_); |
| 1330 } | 1334 } |
| 1331 ~WebRtcAudioSendStream() override { | 1335 ~WebRtcAudioSendStream() override { |
| 1336 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); |
| 1332 Stop(); | 1337 Stop(); |
| 1333 call_->DestroyAudioSendStream(stream_); | 1338 call_->DestroyAudioSendStream(stream_); |
| 1334 } | 1339 } |
| 1335 | 1340 |
| 1336 // Starts the rendering by setting a sink to the renderer to get data | 1341 // Starts the rendering by setting a sink to the renderer to get data |
| 1337 // callback. | 1342 // callback. |
| 1338 // This method is called on the libjingle worker thread. | 1343 // This method is called on the libjingle worker thread. |
| 1339 // TODO(xians): Make sure Start() is called only once. | 1344 // TODO(xians): Make sure Start() is called only once. |
| 1340 void Start(AudioRenderer* renderer) { | 1345 void Start(AudioRenderer* renderer) { |
| 1341 rtc::CritScope lock(&lock_); | 1346 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); |
| 1342 RTC_DCHECK(renderer); | 1347 RTC_DCHECK(renderer); |
| 1343 if (renderer_) { | 1348 if (renderer_) { |
| 1344 RTC_DCHECK(renderer_ == renderer); | 1349 RTC_DCHECK(renderer_ == renderer); |
| 1345 return; | 1350 return; |
| 1346 } | 1351 } |
| 1347 renderer->SetSink(this); | 1352 renderer->SetSink(this); |
| 1348 renderer_ = renderer; | 1353 renderer_ = renderer; |
| 1349 } | 1354 } |
| 1350 | 1355 |
| 1356 webrtc::AudioSendStream::Stats GetStats() const { |
| 1357 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); |
| 1358 return stream_->GetStats(); |
| 1359 } |
| 1360 |
| 1351 // Stops rendering by setting the sink of the renderer to nullptr. No data | 1361 // Stops rendering by setting the sink of the renderer to nullptr. No data |
| 1352 // callback will be received after this method. | 1362 // callback will be received after this method. |
| 1353 // This method is called on the libjingle worker thread. | 1363 // This method is called on the libjingle worker thread. |
| 1354 void Stop() { | 1364 void Stop() { |
| 1355 rtc::CritScope lock(&lock_); | 1365 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); |
| 1356 if (renderer_) { | 1366 if (renderer_) { |
| 1357 renderer_->SetSink(nullptr); | 1367 renderer_->SetSink(nullptr); |
| 1358 renderer_ = nullptr; | 1368 renderer_ = nullptr; |
| 1359 } | 1369 } |
| 1360 } | 1370 } |
| 1361 | 1371 |
| 1362 // AudioRenderer::Sink implementation. | 1372 // AudioRenderer::Sink implementation. |
| 1363 // This method is called on the audio thread. | 1373 // This method is called on the audio thread. |
| 1364 void OnData(const void* audio_data, | 1374 void OnData(const void* audio_data, |
| 1365 int bits_per_sample, | 1375 int bits_per_sample, |
| 1366 int sample_rate, | 1376 int sample_rate, |
| 1367 int number_of_channels, | 1377 int number_of_channels, |
| 1368 size_t number_of_frames) override { | 1378 size_t number_of_frames) override { |
| 1379 RTC_DCHECK(audio_capture_thread_checker_.CalledOnValidThread()); |
| 1369 RTC_DCHECK(voe_audio_transport_); | 1380 RTC_DCHECK(voe_audio_transport_); |
| 1370 voe_audio_transport_->OnData(channel_, | 1381 voe_audio_transport_->OnData(channel_, |
| 1371 audio_data, | 1382 audio_data, |
| 1372 bits_per_sample, | 1383 bits_per_sample, |
| 1373 sample_rate, | 1384 sample_rate, |
| 1374 number_of_channels, | 1385 number_of_channels, |
| 1375 number_of_frames); | 1386 number_of_frames); |
| 1376 } | 1387 } |
| 1377 | 1388 |
| 1378 // Callback from the |renderer_| when it is going away. In case Start() has | 1389 // Callback from the |renderer_| when it is going away. In case Start() has |
| 1379 // never been called, this callback won't be triggered. | 1390 // never been called, this callback won't be triggered. |
| 1380 void OnClose() override { | 1391 void OnClose() override { |
| 1381 rtc::CritScope lock(&lock_); | 1392 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); |
| 1382 // Set |renderer_| to nullptr to make sure no more callback will get into | 1393 // Set |renderer_| to nullptr to make sure no more callback will get into |
| 1383 // the renderer. | 1394 // the renderer. |
| 1384 renderer_ = nullptr; | 1395 renderer_ = nullptr; |
| 1385 } | 1396 } |
| 1386 | 1397 |
| 1387 // Accessor to the VoE channel ID. | 1398 // Accessor to the VoE channel ID. |
| 1388 int channel() const { return channel_; } | 1399 int channel() const { |
| 1400 RTC_DCHECK(signal_thread_checker_.CalledOnValidThread()); |
| 1401 return channel_; |
| 1402 } |
| 1389 | 1403 |
| 1390 private: | 1404 private: |
| 1405 rtc::ThreadChecker signal_thread_checker_; |
| 1406 rtc::ThreadChecker audio_capture_thread_checker_; |
| 1391 const int channel_ = -1; | 1407 const int channel_ = -1; |
| 1392 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; | 1408 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; |
| 1393 webrtc::Call* call_ = nullptr; | 1409 webrtc::Call* call_ = nullptr; |
| 1394 webrtc::AudioSendStream* stream_ = nullptr; | 1410 webrtc::AudioSendStream* stream_ = nullptr; |
| 1395 | 1411 |
| 1396 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. | 1412 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. |
| 1397 // PeerConnection will make sure invalidating the pointer before the object | 1413 // PeerConnection will make sure invalidating the pointer before the object |
| 1398 // goes away. | 1414 // goes away. |
| 1399 AudioRenderer* renderer_ = nullptr; | 1415 AudioRenderer* renderer_ = nullptr; |
| 1400 | 1416 |
| 1401 // Protects |renderer_| in Start(), Stop() and OnClose(). | |
| 1402 rtc::CriticalSection lock_; | |
| 1403 | |
| 1404 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); | 1417 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); |
| 1405 }; | 1418 }; |
| 1406 | 1419 |
| 1407 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { | 1420 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
| 1408 public: | 1421 public: |
| 1409 explicit WebRtcAudioReceiveStream(int voe_channel_id) | 1422 explicit WebRtcAudioReceiveStream(int voe_channel_id) |
| 1410 : channel_(voe_channel_id) {} | 1423 : channel_(voe_channel_id) {} |
| 1411 | 1424 |
| 1412 int channel() { return channel_; } | 1425 int channel() { return channel_; } |
| 1413 | 1426 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1426 send_bitrate_bps_(0), | 1439 send_bitrate_bps_(0), |
| 1427 options_(), | 1440 options_(), |
| 1428 dtmf_allowed_(false), | 1441 dtmf_allowed_(false), |
| 1429 desired_playout_(false), | 1442 desired_playout_(false), |
| 1430 nack_enabled_(false), | 1443 nack_enabled_(false), |
| 1431 playout_(false), | 1444 playout_(false), |
| 1432 typing_noise_detected_(false), | 1445 typing_noise_detected_(false), |
| 1433 desired_send_(SEND_NOTHING), | 1446 desired_send_(SEND_NOTHING), |
| 1434 send_(SEND_NOTHING), | 1447 send_(SEND_NOTHING), |
| 1435 call_(call) { | 1448 call_(call) { |
| 1436 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
| 1437 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel"; | 1449 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel"; |
| 1438 RTC_DCHECK(nullptr != call); | 1450 RTC_DCHECK(nullptr != call); |
| 1439 engine->RegisterChannel(this); | 1451 engine->RegisterChannel(this); |
| 1440 SetOptions(options); | 1452 SetOptions(options); |
| 1441 } | 1453 } |
| 1442 | 1454 |
| 1443 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { | 1455 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { |
| 1444 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 1456 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 1445 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel"; | 1457 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel"; |
| 1446 | 1458 |
| (...skipping 1164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2611 << " to bitrate " << bps << " bps" | 2623 << " to bitrate " << bps << " bps" |
| 2612 << ", requires at least " << codec.rate << " bps."; | 2624 << ", requires at least " << codec.rate << " bps."; |
| 2613 return false; | 2625 return false; |
| 2614 } | 2626 } |
| 2615 return true; | 2627 return true; |
| 2616 } | 2628 } |
| 2617 } | 2629 } |
| 2618 | 2630 |
| 2619 bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { | 2631 bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { |
| 2620 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 2632 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 2633 RTC_DCHECK(info); |
| 2621 | 2634 |
| 2622 bool echo_metrics_on = false; | 2635 // Get SSRC and stats for each sender. |
| 2623 // These can take on valid negative values, so use the lowest possible level | 2636 RTC_DCHECK(info->senders.size() == 0); |
| 2624 // as default rather than -1. | 2637 for (const auto& stream : send_streams_) { |
| 2625 int echo_return_loss = -100; | 2638 webrtc::AudioSendStream::Stats stats = stream.second->GetStats(); |
| 2626 int echo_return_loss_enhancement = -100; | |
| 2627 // These can also be negative, but in practice -1 is only used to signal | |
| 2628 // insufficient data, since the resolution is limited to multiples of 4 ms. | |
| 2629 int echo_delay_median_ms = -1; | |
| 2630 int echo_delay_std_ms = -1; | |
| 2631 if (engine()->voe()->processing()->GetEcMetricsStatus( | |
| 2632 echo_metrics_on) != -1 && echo_metrics_on) { | |
| 2633 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary | |
| 2634 // here, but it appears to be unsuitable currently. Revisit after this is | |
| 2635 // investigated: http://b/issue?id=5666755 | |
| 2636 int erl, erle, rerl, anlp; | |
| 2637 if (engine()->voe()->processing()->GetEchoMetrics( | |
| 2638 erl, erle, rerl, anlp) != -1) { | |
| 2639 echo_return_loss = erl; | |
| 2640 echo_return_loss_enhancement = erle; | |
| 2641 } | |
| 2642 | |
| 2643 int median, std; | |
| 2644 float dummy; | |
| 2645 if (engine()->voe()->processing()->GetEcDelayMetrics( | |
| 2646 median, std, dummy) != -1) { | |
| 2647 echo_delay_median_ms = median; | |
| 2648 echo_delay_std_ms = std; | |
| 2649 } | |
| 2650 } | |
| 2651 | |
| 2652 for (const auto& ch : send_streams_) { | |
| 2653 const int channel = ch.second->channel(); | |
| 2654 | |
| 2655 // Fill in the sender info, based on what we know, and what the | |
| 2656 // remote side told us it got from its RTCP report. | |
| 2657 VoiceSenderInfo sinfo; | 2639 VoiceSenderInfo sinfo; |
| 2658 | 2640 sinfo.add_ssrc(stats.local_ssrc); |
| 2659 webrtc::CallStatistics cs = {0}; | 2641 sinfo.bytes_sent = stats.bytes_sent; |
| 2660 unsigned int ssrc = 0; | 2642 sinfo.packets_sent = stats.packets_sent; |
| 2661 if (engine()->voe()->rtp()->GetRTCPStatistics(channel, cs) == -1 || | 2643 sinfo.packets_lost = stats.packets_lost; |
| 2662 engine()->voe()->rtp()->GetLocalSSRC(channel, ssrc) == -1) { | 2644 sinfo.fraction_lost = stats.fraction_lost; |
| 2663 continue; | 2645 sinfo.codec_name = stats.codec_name; |
| 2664 } | 2646 sinfo.ext_seqnum = stats.ext_seqnum; |
| 2665 | 2647 sinfo.jitter_ms = stats.jitter_ms; |
| 2666 sinfo.add_ssrc(ssrc); | 2648 sinfo.rtt_ms = stats.rtt_ms; |
| 2667 sinfo.codec_name = send_codec_.get() ? send_codec_->plname : ""; | 2649 sinfo.audio_level = stats.audio_level; |
| 2668 sinfo.bytes_sent = cs.bytesSent; | 2650 sinfo.aec_quality_min = stats.aec_quality_min; |
| 2669 sinfo.packets_sent = cs.packetsSent; | 2651 sinfo.echo_delay_median_ms = stats.echo_delay_median_ms; |
| 2670 // RTT isn't known until a RTCP report is received. Until then, VoiceEngine | 2652 sinfo.echo_delay_std_ms = stats.echo_delay_std_ms; |
| 2671 // returns 0 to indicate an error value. | 2653 sinfo.echo_return_loss = stats.echo_return_loss; |
| 2672 sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1; | 2654 sinfo.echo_return_loss_enhancement = stats.echo_return_loss_enhancement; |
| 2673 | |
| 2674 // Get data from the last remote RTCP report. Use default values if no data | |
| 2675 // available. | |
| 2676 sinfo.fraction_lost = -1.0; | |
| 2677 sinfo.jitter_ms = -1; | |
| 2678 sinfo.packets_lost = -1; | |
| 2679 sinfo.ext_seqnum = -1; | |
| 2680 std::vector<webrtc::ReportBlock> receive_blocks; | |
| 2681 webrtc::CodecInst codec = {0}; | |
| 2682 if (engine()->voe()->rtp()->GetRemoteRTCPReportBlocks( | |
| 2683 channel, &receive_blocks) != -1 && | |
| 2684 engine()->voe()->codec()->GetSendCodec(channel, codec) != -1) { | |
| 2685 for (const webrtc::ReportBlock& block : receive_blocks) { | |
| 2686 // Lookup report for send ssrc only. | |
| 2687 if (block.source_SSRC == sinfo.ssrc()) { | |
| 2688 // Convert Q8 to floating point. | |
| 2689 sinfo.fraction_lost = static_cast<float>(block.fraction_lost) / 256; | |
| 2690 // Convert samples to milliseconds. | |
| 2691 if (codec.plfreq / 1000 > 0) { | |
| 2692 sinfo.jitter_ms = block.interarrival_jitter / (codec.plfreq / 1000); | |
| 2693 } | |
| 2694 sinfo.packets_lost = block.cumulative_num_packets_lost; | |
| 2695 sinfo.ext_seqnum = block.extended_highest_sequence_number; | |
| 2696 break; | |
| 2697 } | |
| 2698 } | |
| 2699 } | |
| 2700 | |
| 2701 // Local speech level. | |
| 2702 unsigned int level = 0; | |
| 2703 sinfo.audio_level = (engine()->voe()->volume()-> | |
| 2704 GetSpeechInputLevelFullRange(level) != -1) ? level : -1; | |
| 2705 | |
| 2706 // TODO(xians): We are injecting the same APM logging to all the send | |
| 2707 // channels here because there is no good way to know which send channel | |
| 2708 // is using the APM. The correct fix is to allow the send channels to have | |
| 2709 // their own APM so that we can feed the correct APM logging to different | |
| 2710 // send channels. See issue crbug/264611 . | |
| 2711 sinfo.echo_return_loss = echo_return_loss; | |
| 2712 sinfo.echo_return_loss_enhancement = echo_return_loss_enhancement; | |
| 2713 sinfo.echo_delay_median_ms = echo_delay_median_ms; | |
| 2714 sinfo.echo_delay_std_ms = echo_delay_std_ms; | |
| 2715 // TODO(ajm): Re-enable this metric once we have a reliable implementation. | |
| 2716 sinfo.aec_quality_min = -1; | |
| 2717 sinfo.typing_noise_detected = typing_noise_detected_; | 2655 sinfo.typing_noise_detected = typing_noise_detected_; |
| 2718 | 2656 // TODO(solenberg): Move to AudioSendStream. |
| 2657 // sinfo.typing_noise_detected = stats.typing_noise_detected; |
| 2719 info->senders.push_back(sinfo); | 2658 info->senders.push_back(sinfo); |
| 2720 } | 2659 } |
| 2721 | 2660 |
| 2722 // Get the SSRC and stats for each receiver. | 2661 // Get SSRC and stats for each receiver. |
| 2723 info->receivers.clear(); | 2662 RTC_DCHECK(info->receivers.size() == 0); |
| 2724 for (const auto& stream : receive_streams_) { | 2663 for (const auto& stream : receive_streams_) { |
| 2725 webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); | 2664 webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); |
| 2726 VoiceReceiverInfo rinfo; | 2665 VoiceReceiverInfo rinfo; |
| 2727 rinfo.add_ssrc(stats.remote_ssrc); | 2666 rinfo.add_ssrc(stats.remote_ssrc); |
| 2728 rinfo.bytes_rcvd = stats.bytes_rcvd; | 2667 rinfo.bytes_rcvd = stats.bytes_rcvd; |
| 2729 rinfo.packets_rcvd = stats.packets_rcvd; | 2668 rinfo.packets_rcvd = stats.packets_rcvd; |
| 2730 rinfo.packets_lost = stats.packets_lost; | 2669 rinfo.packets_lost = stats.packets_lost; |
| 2731 rinfo.fraction_lost = stats.fraction_lost; | 2670 rinfo.fraction_lost = stats.fraction_lost; |
| 2732 rinfo.codec_name = stats.codec_name; | 2671 rinfo.codec_name = stats.codec_name; |
| 2733 rinfo.ext_seqnum = stats.ext_seqnum; | 2672 rinfo.ext_seqnum = stats.ext_seqnum; |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2954 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); | 2893 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
| 2955 return false; | 2894 return false; |
| 2956 } | 2895 } |
| 2957 } | 2896 } |
| 2958 return true; | 2897 return true; |
| 2959 } | 2898 } |
| 2960 | 2899 |
| 2961 } // namespace cricket | 2900 } // namespace cricket |
| 2962 | 2901 |
| 2963 #endif // HAVE_WEBRTC_VOICE | 2902 #endif // HAVE_WEBRTC_VOICE |
| OLD | NEW |