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(ch >= 0); |
1324 RTC_DCHECK(call); | 1325 RTC_DCHECK(call); |
1325 webrtc::AudioSendStream::Config config(nullptr); | 1326 webrtc::AudioSendStream::Config config(nullptr); |
1326 config.voe_channel_id = channel_; | 1327 config.voe_channel_id = channel_; |
1327 config.rtp.ssrc = ssrc; | 1328 config.rtp.ssrc = ssrc; |
1328 stream_ = call_->CreateAudioSendStream(config); | 1329 stream_ = call_->CreateAudioSendStream(config); |
1329 RTC_DCHECK(stream_); | 1330 RTC_DCHECK(stream_); |
1330 } | 1331 } |
1331 ~WebRtcAudioSendStream() override { | 1332 ~WebRtcAudioSendStream() override { |
| 1333 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
1332 Stop(); | 1334 Stop(); |
1333 call_->DestroyAudioSendStream(stream_); | 1335 call_->DestroyAudioSendStream(stream_); |
1334 } | 1336 } |
1335 | 1337 |
1336 // Starts the rendering by setting a sink to the renderer to get data | 1338 // Starts the rendering by setting a sink to the renderer to get data |
1337 // callback. | 1339 // callback. |
1338 // This method is called on the libjingle worker thread. | 1340 // This method is called on the libjingle worker thread. |
1339 // TODO(xians): Make sure Start() is called only once. | 1341 // TODO(xians): Make sure Start() is called only once. |
1340 void Start(AudioRenderer* renderer) { | 1342 void Start(AudioRenderer* renderer) { |
1341 rtc::CritScope lock(&lock_); | 1343 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
1342 RTC_DCHECK(renderer); | 1344 RTC_DCHECK(renderer); |
1343 if (renderer_) { | 1345 if (renderer_) { |
1344 RTC_DCHECK(renderer_ == renderer); | 1346 RTC_DCHECK(renderer_ == renderer); |
1345 return; | 1347 return; |
1346 } | 1348 } |
1347 renderer->SetSink(this); | 1349 renderer->SetSink(this); |
1348 renderer_ = renderer; | 1350 renderer_ = renderer; |
1349 } | 1351 } |
1350 | 1352 |
| 1353 webrtc::AudioSendStream::Stats GetStats() const { |
| 1354 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 1355 return stream_->GetStats(); |
| 1356 } |
| 1357 |
1351 // Stops rendering by setting the sink of the renderer to nullptr. No data | 1358 // Stops rendering by setting the sink of the renderer to nullptr. No data |
1352 // callback will be received after this method. | 1359 // callback will be received after this method. |
1353 // This method is called on the libjingle worker thread. | 1360 // This method is called on the libjingle worker thread. |
1354 void Stop() { | 1361 void Stop() { |
1355 rtc::CritScope lock(&lock_); | 1362 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
1356 if (renderer_) { | 1363 if (renderer_) { |
1357 renderer_->SetSink(nullptr); | 1364 renderer_->SetSink(nullptr); |
1358 renderer_ = nullptr; | 1365 renderer_ = nullptr; |
1359 } | 1366 } |
1360 } | 1367 } |
1361 | 1368 |
1362 // AudioRenderer::Sink implementation. | 1369 // AudioRenderer::Sink implementation. |
1363 // This method is called on the audio thread. | 1370 // This method is called on the audio thread. |
1364 void OnData(const void* audio_data, | 1371 void OnData(const void* audio_data, |
1365 int bits_per_sample, | 1372 int bits_per_sample, |
1366 int sample_rate, | 1373 int sample_rate, |
1367 int number_of_channels, | 1374 int number_of_channels, |
1368 size_t number_of_frames) override { | 1375 size_t number_of_frames) override { |
| 1376 RTC_DCHECK(!thread_checker_.CalledOnValidThread()); |
| 1377 // TODO(solenberg): Move to c-tor once we're not using FakeWebRtcVoiceEngine |
| 1378 // anymore. |
1369 RTC_DCHECK(voe_audio_transport_); | 1379 RTC_DCHECK(voe_audio_transport_); |
1370 voe_audio_transport_->OnData(channel_, | 1380 voe_audio_transport_->OnData(channel_, |
1371 audio_data, | 1381 audio_data, |
1372 bits_per_sample, | 1382 bits_per_sample, |
1373 sample_rate, | 1383 sample_rate, |
1374 number_of_channels, | 1384 number_of_channels, |
1375 number_of_frames); | 1385 number_of_frames); |
1376 } | 1386 } |
1377 | 1387 |
1378 // Callback from the |renderer_| when it is going away. In case Start() has | 1388 // Callback from the |renderer_| when it is going away. In case Start() has |
1379 // never been called, this callback won't be triggered. | 1389 // never been called, this callback won't be triggered. |
1380 void OnClose() override { | 1390 void OnClose() override { |
1381 rtc::CritScope lock(&lock_); | 1391 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
1382 // Set |renderer_| to nullptr to make sure no more callback will get into | 1392 // Set |renderer_| to nullptr to make sure no more callback will get into |
1383 // the renderer. | 1393 // the renderer. |
1384 renderer_ = nullptr; | 1394 renderer_ = nullptr; |
1385 } | 1395 } |
1386 | 1396 |
1387 // Accessor to the VoE channel ID. | 1397 // Accessor to the VoE channel ID. |
1388 int channel() const { return channel_; } | 1398 int channel() const { |
| 1399 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 1400 return channel_; |
| 1401 } |
1389 | 1402 |
1390 private: | 1403 private: |
| 1404 rtc::ThreadChecker thread_checker_; |
1391 const int channel_ = -1; | 1405 const int channel_ = -1; |
1392 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; | 1406 webrtc::AudioTransport* const voe_audio_transport_ = nullptr; |
1393 webrtc::Call* call_ = nullptr; | 1407 webrtc::Call* call_ = nullptr; |
1394 webrtc::AudioSendStream* stream_ = nullptr; | 1408 webrtc::AudioSendStream* stream_ = nullptr; |
1395 | 1409 |
1396 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. | 1410 // Raw pointer to AudioRenderer owned by LocalAudioTrackHandler. |
1397 // PeerConnection will make sure invalidating the pointer before the object | 1411 // PeerConnection will make sure invalidating the pointer before the object |
1398 // goes away. | 1412 // goes away. |
1399 AudioRenderer* renderer_ = nullptr; | 1413 AudioRenderer* renderer_ = nullptr; |
1400 | 1414 |
1401 // Protects |renderer_| in Start(), Stop() and OnClose(). | |
1402 rtc::CriticalSection lock_; | |
1403 | |
1404 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); | 1415 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WebRtcAudioSendStream); |
1405 }; | 1416 }; |
1406 | 1417 |
1407 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { | 1418 class WebRtcVoiceMediaChannel::WebRtcAudioReceiveStream { |
1408 public: | 1419 public: |
1409 explicit WebRtcAudioReceiveStream(int voe_channel_id) | 1420 explicit WebRtcAudioReceiveStream(int voe_channel_id) |
1410 : channel_(voe_channel_id) {} | 1421 : channel_(voe_channel_id) {} |
1411 | 1422 |
1412 int channel() { return channel_; } | 1423 int channel() { return channel_; } |
1413 | 1424 |
(...skipping 12 matching lines...) Expand all Loading... |
1426 send_bitrate_bps_(0), | 1437 send_bitrate_bps_(0), |
1427 options_(), | 1438 options_(), |
1428 dtmf_allowed_(false), | 1439 dtmf_allowed_(false), |
1429 desired_playout_(false), | 1440 desired_playout_(false), |
1430 nack_enabled_(false), | 1441 nack_enabled_(false), |
1431 playout_(false), | 1442 playout_(false), |
1432 typing_noise_detected_(false), | 1443 typing_noise_detected_(false), |
1433 desired_send_(SEND_NOTHING), | 1444 desired_send_(SEND_NOTHING), |
1434 send_(SEND_NOTHING), | 1445 send_(SEND_NOTHING), |
1435 call_(call) { | 1446 call_(call) { |
1436 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | |
1437 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel"; | 1447 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel"; |
1438 RTC_DCHECK(nullptr != call); | 1448 RTC_DCHECK(nullptr != call); |
1439 engine->RegisterChannel(this); | 1449 engine->RegisterChannel(this); |
1440 SetOptions(options); | 1450 SetOptions(options); |
1441 } | 1451 } |
1442 | 1452 |
1443 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { | 1453 WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { |
1444 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 1454 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
1445 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel"; | 1455 LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel"; |
1446 | 1456 |
(...skipping 1164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2611 << " to bitrate " << bps << " bps" | 2621 << " to bitrate " << bps << " bps" |
2612 << ", requires at least " << codec.rate << " bps."; | 2622 << ", requires at least " << codec.rate << " bps."; |
2613 return false; | 2623 return false; |
2614 } | 2624 } |
2615 return true; | 2625 return true; |
2616 } | 2626 } |
2617 } | 2627 } |
2618 | 2628 |
2619 bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { | 2629 bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { |
2620 RTC_DCHECK(thread_checker_.CalledOnValidThread()); | 2630 RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
| 2631 RTC_DCHECK(info); |
2621 | 2632 |
2622 bool echo_metrics_on = false; | 2633 // Get SSRC and stats for each sender. |
2623 // These can take on valid negative values, so use the lowest possible level | 2634 RTC_DCHECK(info->senders.size() == 0); |
2624 // as default rather than -1. | 2635 for (const auto& stream : send_streams_) { |
2625 int echo_return_loss = -100; | 2636 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; | 2637 VoiceSenderInfo sinfo; |
2658 | 2638 sinfo.add_ssrc(stats.local_ssrc); |
2659 webrtc::CallStatistics cs = {0}; | 2639 sinfo.bytes_sent = stats.bytes_sent; |
2660 unsigned int ssrc = 0; | 2640 sinfo.packets_sent = stats.packets_sent; |
2661 if (engine()->voe()->rtp()->GetRTCPStatistics(channel, cs) == -1 || | 2641 sinfo.packets_lost = stats.packets_lost; |
2662 engine()->voe()->rtp()->GetLocalSSRC(channel, ssrc) == -1) { | 2642 sinfo.fraction_lost = stats.fraction_lost; |
2663 continue; | 2643 sinfo.codec_name = stats.codec_name; |
2664 } | 2644 sinfo.ext_seqnum = stats.ext_seqnum; |
2665 | 2645 sinfo.jitter_ms = stats.jitter_ms; |
2666 sinfo.add_ssrc(ssrc); | 2646 sinfo.rtt_ms = stats.rtt_ms; |
2667 sinfo.codec_name = send_codec_.get() ? send_codec_->plname : ""; | 2647 sinfo.audio_level = stats.audio_level; |
2668 sinfo.bytes_sent = cs.bytesSent; | 2648 sinfo.aec_quality_min = stats.aec_quality_min; |
2669 sinfo.packets_sent = cs.packetsSent; | 2649 sinfo.echo_delay_median_ms = stats.echo_delay_median_ms; |
2670 // RTT isn't known until a RTCP report is received. Until then, VoiceEngine | 2650 sinfo.echo_delay_std_ms = stats.echo_delay_std_ms; |
2671 // returns 0 to indicate an error value. | 2651 sinfo.echo_return_loss = stats.echo_return_loss; |
2672 sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1; | 2652 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_; | 2653 sinfo.typing_noise_detected = typing_noise_detected_; |
2718 | 2654 // TODO(solenberg): Move to AudioSendStream. |
| 2655 // sinfo.typing_noise_detected = stats.typing_noise_detected; |
2719 info->senders.push_back(sinfo); | 2656 info->senders.push_back(sinfo); |
2720 } | 2657 } |
2721 | 2658 |
2722 // Get the SSRC and stats for each receiver. | 2659 // Get SSRC and stats for each receiver. |
2723 info->receivers.clear(); | 2660 RTC_DCHECK(info->receivers.size() == 0); |
2724 for (const auto& stream : receive_streams_) { | 2661 for (const auto& stream : receive_streams_) { |
2725 webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); | 2662 webrtc::AudioReceiveStream::Stats stats = stream.second->GetStats(); |
2726 VoiceReceiverInfo rinfo; | 2663 VoiceReceiverInfo rinfo; |
2727 rinfo.add_ssrc(stats.remote_ssrc); | 2664 rinfo.add_ssrc(stats.remote_ssrc); |
2728 rinfo.bytes_rcvd = stats.bytes_rcvd; | 2665 rinfo.bytes_rcvd = stats.bytes_rcvd; |
2729 rinfo.packets_rcvd = stats.packets_rcvd; | 2666 rinfo.packets_rcvd = stats.packets_rcvd; |
2730 rinfo.packets_lost = stats.packets_lost; | 2667 rinfo.packets_lost = stats.packets_lost; |
2731 rinfo.fraction_lost = stats.fraction_lost; | 2668 rinfo.fraction_lost = stats.fraction_lost; |
2732 rinfo.codec_name = stats.codec_name; | 2669 rinfo.codec_name = stats.codec_name; |
2733 rinfo.ext_seqnum = stats.ext_seqnum; | 2670 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); | 2891 LOG(LS_WARNING) << "Unknown codec " << ToString(codec); |
2955 return false; | 2892 return false; |
2956 } | 2893 } |
2957 } | 2894 } |
2958 return true; | 2895 return true; |
2959 } | 2896 } |
2960 | 2897 |
2961 } // namespace cricket | 2898 } // namespace cricket |
2962 | 2899 |
2963 #endif // HAVE_WEBRTC_VOICE | 2900 #endif // HAVE_WEBRTC_VOICE |
OLD | NEW |