From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- third_party/libwebrtc/moz-patch-stack/0001.patch | 1950 ++++++++++++++++++++++ 1 file changed, 1950 insertions(+) create mode 100644 third_party/libwebrtc/moz-patch-stack/0001.patch (limited to 'third_party/libwebrtc/moz-patch-stack/0001.patch') diff --git a/third_party/libwebrtc/moz-patch-stack/0001.patch b/third_party/libwebrtc/moz-patch-stack/0001.patch new file mode 100644 index 0000000000..19eea5558b --- /dev/null +++ b/third_party/libwebrtc/moz-patch-stack/0001.patch @@ -0,0 +1,1950 @@ +From: Dan Minor +Date: Mon, 22 Jan 2018 13:31:00 -0500 +Subject: Bug 1376873 - Rollup of local modifications; r=ng + +MozReview-Commit-ID: 2euYzBEvuNb + +Differential Revision: https://phabricator.services.mozilla.com/D7425 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/28b57e3ba51de982a4663801a3935580114b5477 + +Bug 1376873 - Rollup conflict fixes for audio/video code; r=pehrsons + +MozReview-Commit-ID: 1T8mgqdkzq3 + +Differential Revision: https://phabricator.services.mozilla.com/D7427 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/93eec571640ee0810da8475ee37e417b88045574 + +Bug 1376873 - Rollup conflict fixes for rtp_rtcp module; r=ng + +MozReview-Commit-ID: D09534DOVLj + +Differential Revision: https://phabricator.services.mozilla.com/D7428 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/50f89f4e45b0af87fd6aa45aed60f02f3e69b951 + +Bug 1497552 - Remove support for 44100 Hz in dtmf_tone_generator; r=padenot + +Assertions in NetEqImpl::SetSampleRateAndChannels prevent us from requesting +tones at 44100 Hz, so this code can be safely removed. + +Differential Revision: https://phabricator.services.mozilla.com/D12982 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/8ea04ec01e9905d4714aa01ade891d552c56a3a6 + +Bug 1497577 - Remove code to detect zero size windows; r=ng + +This code was added by Bug 1196542 to fix a permanently failing test on our +Windows test machines. After this landed, upstream added a check for empty +windows in window_captuer_win.cc, so this should no longer be a problem on +Windows. As far as I know, this was never a problem on the other platforms, +so this code can be safely removed. + +Differential Revision: https://phabricator.services.mozilla.com/D13448 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/647ade4da0fba74a268aab079677cb47f20f036e + +Bug 1509994 - Move video_engine from webrtc to systemservices; r=pehrsons + +Historically this code was part of webrtc.org but has since been removed +from upstream. Rather than maintaining it as a local diff against upstream, +we should just move it to where it is used. + +Differential Revision: https://phabricator.services.mozilla.com/D13092 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/0fd399c6caabff60ac0fe53b920b7d26a9806750 + +Bug 1497606 - Remove disable_composition_ in screen_capturer_win_gdi; r=ng + +This removes disable_composition_ and instead uses the value of +composition_func_ to determine whether or not composition is +disabled. This is what is done by upstream webrtc.org. + +We call options.set_disable_effects(false) in desktop_capture_impl.cc. + +Differential Revision: https://phabricator.services.mozilla.com/D13839 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/b3f5cca4be44c01024b1ef7b5d4951c7297a112a + +Bug 1497974 - Remove local changes to jitter_buffer.cc; r=pehrsons + +These modifications are made to code which we do not use and so +can be removed. + +Differential Revision: https://phabricator.services.mozilla.com/D13989 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/2fb1dd0d8344ef24e2e0fca94725bbfaf59aa257 + +Bug 1512459 - Remove webrtc sndio audio device; r=padenot + +This code is unused and can be removed. + +Differential Revision: https://phabricator.services.mozilla.com/D13929 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/fa0a179388e96b1a47eeef2fda9676812c244d3b + +Bug 1497650 - Remove 100 bytes added to CalcBufferSize in vp8_impl.cc; r=ng + +In Bug 919979 we added 100 bytes to the size returned by CalcBufferSize +to work around an error with the calculated buffer size with small +resolutions. I verified that this extra buffer is no longer required with +a modified mochitest. Given the age of the bug this was working around, +I don't think a permanent test is required to prevent regressions from +upstream. + +Differential Revision: https://phabricator.services.mozilla.com/D14076 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/b20329b1ec0565b3b94db73e13a9c49e43c418c3 + +Bug 1368816 - Enable VideoCaptureExternalTest Rotation gtest; r=ng + +This test started failing after the 57 update and started passing +again after the 64 update, so we might as well enable it. + +Differential Revision: https://phabricator.services.mozilla.com/D13803 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/65a44b43b7b69c066abcb864076003252abc475e + +Bug 1497573 - Remove DesktopCapturer::Stop; r=ng + +Differential Revision: https://phabricator.services.mozilla.com/D14066 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/0d9c607f26195b7f63cca847224bcd137f73720d + +Bug 1497619 - Restore thread check in process_thread_impl.cc; r=ng + +Not not really needed. + +Differential Revision: https://phabricator.services.mozilla.com/D14097 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/923373fdf5e50d44c895141dc1db74709d6610fe + +Bug 1497992 - Remove VideoReceiver::Reset; r=pehrsons + +This ends up calling VCMReceiver::Reset() which resets the +state of the VCMJitterBuffer. We no longer use VCMJitterBuffer, +which is the old jitter buffer implementation, so this code +no longer has any effect and can be removed. + +Differential Revision: https://phabricator.services.mozilla.com/D14185 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/9e526b3093ee60791cf9c436ea06b6665eb5ef74 + +Bug 1497610 - Remove IsNewerOrSameTimestamp; r=bwc + +The affected functions are only used by VCMJitterBuffer, which is the older +jitter buffer that is no longer in use. We can safely remove these +modifications. + +Differential Revision: https://phabricator.services.mozilla.com/D14485 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/5ed0ed11b23d82ee026244a9a48e522fe38335e2 + +Bug 1498253 - Remove mozAvSyncDelay and mozJitterBufferDelay; r=ng + +The value for mozAvSyncDelay has been broken since the branch 57 update +(Bug 1341285). We added SetCurrentSyncOffset() but never called it from +anywhere. + +In the future we should be getting stats from AudioReceiveStream rather than +modifying the channel code, the delay_estimate_ms field provides almost the +same information. + +Since we're attempting to get rid of moz prefixed stats, it makes sense to just +remove this code rather than fix it. The associated telemetry code has been +broken since Bug 1341285 as well so I think it is safe to remove. + +Differential Revision: https://phabricator.services.mozilla.com/D14462 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/80e86c169d202e724cda74bbd9535b2d5236305b + +Bug 1498205 - Move PlatformUIThread from rtc_base to video_engine; r=pehrsons + +PlatformUIThread is only used by the video_engine code, so it makes sense to +move it there rather than maintain it as a diff against upstream webrtc.org. + +Differential Revision: https://phabricator.services.mozilla.com/D13531 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/65bf3e37a4409f3ca0350366d7be19368adfa21b + +Bug 1497602 - Enable DirectX screen capturer on Windows; r=pehrsons + +This enables support for the DirectX screen capturer. We use the default +DesktopCaptureOptions which do not set the option to use the DirectX screen +capturer so this change will have no effect with the current code. + +For what it's worth, I tested enabling the DirectX option and it worked fine on my +system, but I don't see any reason to not follow the defaults provided by +webrtc.org in this case. + +Differential Revision: https://phabricator.services.mozilla.com/D13303 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/eb07312cfbe868780ebed84fc83e5a5470e81fb4 + +Bug 1439997 - Remove old mac video capture code; r=jib + +This code is no longer used and has been removed upstream. We can remove +it as well. + +Differential Revision: https://phabricator.services.mozilla.com/D15196 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/e79251fa381cfc9f3425f6a746ac8d8c22046d6b + +Bug 1376873 - Updates to Android video capture; r=pehrsons + +Differential Revision: https://phabricator.services.mozilla.com/D7452 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/1e6d72de0587d24c20fefc142591d8b47c363f89 + +Bug 1578073 - Move android video capture code to dom/media/systemservices; r=jib + +Although originally part of webrtc.org, this code has subsequently been +removed by upstream. Moving it to under dom/media should make it clearer that +this is code that we are maintaining and simplify future upstream merges. + +Differential Revision: https://phabricator.services.mozilla.com/D61850 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/46c21affcbc14da30abb03b10573076aee6341c0 + +Bug 1652552 - Remove remaining application capture code; r=jib + +Differential Revision: https://phabricator.services.mozilla.com/D83491 +Mercurial Revision: https://hg.mozilla.org/mozilla-central/rev/26eee332d844bd3f9479d1db92d2f000255664c1 +--- + api/rtp_headers.cc | 3 +- + api/rtp_headers.h | 17 +- + api/rtp_parameters.cc | 3 +- + call/BUILD.gn | 4 +- + call/video_receive_stream.h | 2 + + modules/audio_coding/acm2/acm_receiver.h | 12 +- + modules/audio_coding/neteq/dtmf_buffer.cc | 6 +- + modules/audio_coding/neteq/merge.cc | 6 + + .../logging/apm_data_dumper.cc | 23 ++- + .../logging/apm_data_dumper.h | 67 ++++-- + modules/desktop_capture/desktop_capturer.h | 1 + + .../desktop_capture/fake_desktop_capturer.cc | 4 +- + .../linux/x11/mouse_cursor_monitor_x11.cc | 4 +- + .../linux/x11/screen_capturer_x11.cc | 2 +- + .../linux/x11/window_capturer_x11.cc | 12 +- + .../linux/x11/window_capturer_x11.h | 4 + + .../desktop_capture/linux/x11/x_error_trap.cc | 70 ++++--- + .../desktop_capture/linux/x11/x_error_trap.h | 29 ++- + .../mouse_cursor_monitor_win.cc | 7 +- + .../win/screen_capture_utils.cc | 3 +- + .../win/screen_capturer_win_gdi.cc | 1 + + .../win/screen_capturer_win_magnifier.cc | 16 +- + modules/rtp_rtcp/source/rtcp_sender.cc | 2 +- + .../rtp_rtcp/source/rtp_header_extensions.cc | 39 ++++ + .../rtp_rtcp/source/rtp_header_extensions.h | 15 ++ + modules/rtp_rtcp/source/rtp_packet.cc | 4 + + .../rtp_rtcp/source/rtp_packet_unittest.cc | 30 +++ + modules/rtp_rtcp/source/rtp_rtcp_config.h | 2 + + modules/rtp_rtcp/source/rtp_sender.cc | 4 + + modules/utility/source/jvm_android.cc | 28 ++- + modules/video_capture/device_info_impl.cc | 2 +- + modules/video_capture/device_info_impl.h | 1 + + .../video_capture/linux/device_info_v4l2.cc | 193 +++++++++++++++++- + .../video_capture/linux/device_info_v4l2.h | 18 +- + .../video_capture/linux/video_capture_v4l2.cc | 7 + + modules/video_capture/video_capture.h | 45 +++- + .../video_capture/video_capture_factory.cc | 8 - + modules/video_capture/video_capture_impl.cc | 36 +++- + modules/video_capture/video_capture_impl.h | 6 +- + .../codecs/vp9/libvpx_vp9_encoder.cc | 2 + + .../codecs/vp9/libvpx_vp9_encoder.h | 4 + + modules/video_coding/generic_decoder.cc | 5 +- + modules/video_coding/session_info.cc | 32 ++- + test/fuzzers/rtp_packet_fuzzer.cc | 5 + + test/vcm_capturer.cc | 2 +- + 45 files changed, 652 insertions(+), 134 deletions(-) + +diff --git a/api/rtp_headers.cc b/api/rtp_headers.cc +index e0ad9eb26e..8e1efc7262 100644 +--- a/api/rtp_headers.cc ++++ b/api/rtp_headers.cc +@@ -26,7 +26,8 @@ RTPHeaderExtension::RTPHeaderExtension() + videoRotation(kVideoRotation_0), + hasVideoContentType(false), + videoContentType(VideoContentType::UNSPECIFIED), +- has_video_timing(false) {} ++ has_video_timing(false), ++ csrcAudioLevels() {} + + RTPHeaderExtension::RTPHeaderExtension(const RTPHeaderExtension& other) = + default; +diff --git a/api/rtp_headers.h b/api/rtp_headers.h +index 743fd6d1b6..261c984d05 100644 +--- a/api/rtp_headers.h ++++ b/api/rtp_headers.h +@@ -89,6 +89,19 @@ inline bool operator!=(const AbsoluteCaptureTime& lhs, + return !(lhs == rhs); + } + ++enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13 ++ ++// Audio level of CSRCs See: ++// https://tools.ietf.org/html/rfc6465 ++struct CsrcAudioLevelList { ++ CsrcAudioLevelList() : numAudioLevels(0) { } ++ CsrcAudioLevelList(const CsrcAudioLevelList&) = default; ++ CsrcAudioLevelList& operator=(const CsrcAudioLevelList&) = default; ++ uint8_t numAudioLevels; ++ // arrOfAudioLevels has the same ordering as RTPHeader.arrOfCSRCs ++ uint8_t arrOfAudioLevels[kRtpCsrcSize]; ++}; ++ + struct RTPHeaderExtension { + RTPHeaderExtension(); + RTPHeaderExtension(const RTPHeaderExtension& other); +@@ -144,9 +157,9 @@ struct RTPHeaderExtension { + std::string mid; + + absl::optional color_space; +-}; + +-enum { kRtpCsrcSize = 15 }; // RFC 3550 page 13 ++ CsrcAudioLevelList csrcAudioLevels; ++}; + + struct RTC_EXPORT RTPHeader { + RTPHeader(); +diff --git a/api/rtp_parameters.cc b/api/rtp_parameters.cc +index c48b8da02c..c1d12e5d8d 100644 +--- a/api/rtp_parameters.cc ++++ b/api/rtp_parameters.cc +@@ -148,7 +148,8 @@ bool RtpExtension::IsSupportedForAudio(absl::string_view uri) { + uri == webrtc::RtpExtension::kTransportSequenceNumberV2Uri || + uri == webrtc::RtpExtension::kMidUri || + uri == webrtc::RtpExtension::kRidUri || +- uri == webrtc::RtpExtension::kRepairedRidUri; ++ uri == webrtc::RtpExtension::kRepairedRidUri || ++ uri == webrtc::RtpExtension::kCsrcAudioLevelsUri; + } + + bool RtpExtension::IsSupportedForVideo(absl::string_view uri) { +diff --git a/call/BUILD.gn b/call/BUILD.gn +index f4c3295ff5..0e52e8fb3f 100644 +--- a/call/BUILD.gn ++++ b/call/BUILD.gn +@@ -20,6 +20,7 @@ rtc_library("call_interfaces") { + sources = [ + "audio_receive_stream.cc", + "audio_receive_stream.h", ++ "audio_send_stream.cc", + "audio_send_stream.h", + "audio_state.cc", + "audio_state.h", +@@ -32,9 +33,6 @@ rtc_library("call_interfaces") { + "syncable.cc", + "syncable.h", + ] +- if (!build_with_mozilla) { +- sources += [ "audio_send_stream.cc" ] +- } + + deps = [ + ":audio_sender_interface", +diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h +index 0fa257e5ba..15b313a3b9 100644 +--- a/call/video_receive_stream.h ++++ b/call/video_receive_stream.h +@@ -199,6 +199,8 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface { + // disabled. + KeyFrameReqMethod keyframe_method = KeyFrameReqMethod::kPliRtcp; + ++ bool tmmbr = false; ++ + // See LntfConfig for description. + LntfConfig lntf; + +diff --git a/modules/audio_coding/acm2/acm_receiver.h b/modules/audio_coding/acm2/acm_receiver.h +index 18b662aed0..a61247627f 100644 +--- a/modules/audio_coding/acm2/acm_receiver.h ++++ b/modules/audio_coding/acm2/acm_receiver.h +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + + #include "absl/types/optional.h" + #include "api/array_view.h" +@@ -215,12 +216,15 @@ class AcmReceiver { + + mutable Mutex mutex_; + absl::optional last_decoder_ RTC_GUARDED_BY(mutex_); +- ACMResampler resampler_ RTC_GUARDED_BY(mutex_); +- std::unique_ptr last_audio_buffer_ RTC_GUARDED_BY(mutex_); +- CallStatistics call_stats_ RTC_GUARDED_BY(mutex_); ++ ACMResampler resampler_; ++ ++ // After construction, this is only ever touched on the thread that calls ++ // AcmReceiver::GetAudio, and only modified in this method. ++ std::unique_ptr last_audio_buffer_; ++ CallStatistics call_stats_; + const std::unique_ptr neteq_; // NetEq is thread-safe; no lock needed. + Clock* const clock_; +- bool resampled_last_output_frame_ RTC_GUARDED_BY(mutex_); ++ std::atomic resampled_last_output_frame_; + }; + + } // namespace acm2 +diff --git a/modules/audio_coding/neteq/dtmf_buffer.cc b/modules/audio_coding/neteq/dtmf_buffer.cc +index 9f78aca6e2..115bfcf97b 100644 +--- a/modules/audio_coding/neteq/dtmf_buffer.cc ++++ b/modules/audio_coding/neteq/dtmf_buffer.cc +@@ -193,7 +193,11 @@ bool DtmfBuffer::Empty() const { + } + + int DtmfBuffer::SetSampleRate(int fs_hz) { +- if (fs_hz != 8000 && fs_hz != 16000 && fs_hz != 32000 && fs_hz != 48000) { ++ if (fs_hz != 8000 && ++ fs_hz != 16000 && ++ fs_hz != 32000 && ++ fs_hz != 44100 && ++ fs_hz != 48000) { + return kInvalidSampleRate; + } + max_extrapolation_samples_ = 7 * fs_hz / 100; +diff --git a/modules/audio_coding/neteq/merge.cc b/modules/audio_coding/neteq/merge.cc +index 22cf6a7754..0aec6d2597 100644 +--- a/modules/audio_coding/neteq/merge.cc ++++ b/modules/audio_coding/neteq/merge.cc +@@ -213,6 +213,12 @@ int16_t Merge::SignalScaling(const int16_t* input, + // Adjust muting factor if new vector is more or less of the BGN energy. + const auto mod_input_length = rtc::SafeMin( + 64 * rtc::dchecked_cast(fs_mult_), input_length); ++ ++ // Missing input, do no muting ++ if (mod_input_length == 0) { ++ return 16384; ++ } ++ + const int16_t expanded_max = + WebRtcSpl_MaxAbsValueW16(expanded_signal, mod_input_length); + int32_t factor = +diff --git a/modules/audio_processing/logging/apm_data_dumper.cc b/modules/audio_processing/logging/apm_data_dumper.cc +index 65d2167d37..f787b65604 100644 +--- a/modules/audio_processing/logging/apm_data_dumper.cc ++++ b/modules/audio_processing/logging/apm_data_dumper.cc +@@ -35,14 +35,20 @@ std::string FormFileName(absl::string_view output_dir, + int instance_index, + int reinit_index, + absl::string_view suffix) { +- char buf[1024]; +- rtc::SimpleStringBuilder ss(buf); +- if (!output_dir.empty()) { +- ss << output_dir; +- if (output_dir.back() != kPathDelimiter) { +- ss << kPathDelimiter; +- } ++#ifdef WEBRTC_WIN ++ char sep = '\\'; ++#else ++ char sep = '/'; ++#endif ++ ++ std::stringstream ss; ++ std::string base = webrtc::Trace::aec_debug_filename(); ++ ss << base; ++ ++ if (base.length() && base.back() != sep) { ++ ss << sep; + } ++ + ss << name << "_" << instance_index << "-" << reinit_index << suffix; + return ss.str(); + } +@@ -52,7 +58,8 @@ std::string FormFileName(absl::string_view output_dir, + + #if WEBRTC_APM_DEBUG_DUMP == 1 + ApmDataDumper::ApmDataDumper(int instance_index) +- : instance_index_(instance_index) {} ++ : instance_index_(instance_index) ++ , debug_written_(0) {} + #else + ApmDataDumper::ApmDataDumper(int instance_index) {} + #endif +diff --git a/modules/audio_processing/logging/apm_data_dumper.h b/modules/audio_processing/logging/apm_data_dumper.h +index 4ab6baad83..aa8496819b 100644 +--- a/modules/audio_processing/logging/apm_data_dumper.h ++++ b/modules/audio_processing/logging/apm_data_dumper.h +@@ -41,7 +41,7 @@ namespace webrtc { + // Functor used to use as a custom deleter in the map of file pointers to raw + // files. + struct RawFileCloseFunctor { +- void operator()(FILE* f) const { fclose(f); } ++ void operator()(FILE* f) const { if (f) fclose(f); } + }; + #endif + +@@ -100,6 +100,7 @@ class ApmDataDumper { + void InitiateNewSetOfRecordings() { + #if WEBRTC_APM_DEBUG_DUMP == 1 + ++recording_set_index_; ++ debug_written_ = 0; + #endif + } + +@@ -114,7 +115,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(&v, sizeof(v), 1, file); ++ if (file) { ++ fwrite(&v, sizeof(v), 1, file); ++ } + } + #endif + } +@@ -129,7 +132,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(v, sizeof(v[0]), v_length, file); ++ if (file) { ++ fwrite(v, sizeof(v[0]), v_length, file); ++ } + } + #endif + } +@@ -156,7 +161,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(&v, sizeof(v), 1, file); ++ if (file) { ++ fwrite(&v, sizeof(v), 1, file); ++ } + } + #endif + } +@@ -171,7 +178,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(v, sizeof(v[0]), v_length, file); ++ if (file) { ++ fwrite(v, sizeof(v[0]), v_length, file); ++ } + } + #endif + } +@@ -210,9 +219,11 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- for (size_t k = 0; k < v_length; ++k) { +- int16_t value = static_cast(v[k]); +- fwrite(&value, sizeof(value), 1, file); ++ if (file) { ++ for (size_t k = 0; k < v_length; ++k) { ++ int16_t value = static_cast(v[k]); ++ fwrite(&value, sizeof(value), 1, file); ++ } + } + } + #endif +@@ -240,7 +251,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(&v, sizeof(v), 1, file); ++ if (file) { ++ fwrite(&v, sizeof(v), 1, file); ++ } + } + #endif + } +@@ -255,7 +268,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(v, sizeof(v[0]), v_length, file); ++ if (file) { ++ fwrite(v, sizeof(v[0]), v_length, file); ++ } + } + #endif + } +@@ -282,7 +297,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(&v, sizeof(v), 1, file); ++ if (file) { ++ fwrite(&v, sizeof(v), 1, file); ++ } + } + #endif + } +@@ -297,7 +314,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(v, sizeof(v[0]), v_length, file); ++ if (file) { ++ fwrite(v, sizeof(v[0]), v_length, file); ++ } + } + #endif + } +@@ -311,7 +330,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(&v, sizeof(v), 1, file); ++ if (file) { ++ fwrite(&v, sizeof(v), 1, file); ++ } + } + #endif + } +@@ -326,7 +347,9 @@ class ApmDataDumper { + + if (recording_activated_) { + FILE* file = GetRawFile(name); +- fwrite(v, sizeof(v[0]), v_length, file); ++ if (file) { ++ fwrite(v, sizeof(v[0]), v_length, file); ++ } + } + #endif + } +@@ -369,6 +392,12 @@ class ApmDataDumper { + WavWriter* file = GetWavFile(name, sample_rate_hz, num_channels, + WavFile::SampleFormat::kFloat); + file->WriteSamples(v, v_length); ++ // Cheat and use aec_near as a stand-in for "size of the largest file" ++ // in the dump. We're looking to limit the total time, and that's a ++ // reasonable stand-in. ++ if (strcmp(name, "aec_near") == 0) { ++ updateDebugWritten(v_length * sizeof(float)); ++ } + } + #endif + } +@@ -405,6 +434,16 @@ class ApmDataDumper { + int sample_rate_hz, + int num_channels, + WavFile::SampleFormat format); ++ ++ uint32_t debug_written_ = 0; ++ ++ void updateDebugWritten(uint32_t amount) { ++ debug_written_ += amount; ++ if (debug_written_ >= webrtc::Trace::aec_debug_size()) { ++ SetActivated(false); ++ } ++ } ++ + #endif + }; + +diff --git a/modules/desktop_capture/desktop_capturer.h b/modules/desktop_capture/desktop_capturer.h +index d336723f18..6909a57891 100644 +--- a/modules/desktop_capture/desktop_capturer.h ++++ b/modules/desktop_capture/desktop_capturer.h +@@ -79,6 +79,7 @@ class RTC_EXPORT DesktopCapturer { + struct Source { + // The unique id to represent a Source of current DesktopCapturer. + SourceId id; ++ pid_t pid; + + // Title of the window or screen in UTF-8 encoding, maybe empty. This field + // should not be used to identify a source. +diff --git a/modules/desktop_capture/fake_desktop_capturer.cc b/modules/desktop_capture/fake_desktop_capturer.cc +index f9d9dbd2c4..67149bfcb9 100644 +--- a/modules/desktop_capture/fake_desktop_capturer.cc ++++ b/modules/desktop_capture/fake_desktop_capturer.cc +@@ -72,8 +72,8 @@ void FakeDesktopCapturer::SetSharedMemoryFactory( + } + + bool FakeDesktopCapturer::GetSourceList(DesktopCapturer::SourceList* sources) { +- sources->push_back({kWindowId, "A-Fake-DesktopCapturer-Window"}); +- sources->push_back({kScreenId}); ++ sources->push_back({kWindowId, 1, "A-Fake-DesktopCapturer-Window"}); ++ sources->push_back({kScreenId, 1}); + return true; + } + +diff --git a/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc b/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc +index d9c7635c1d..d4b85af6bd 100644 +--- a/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc ++++ b/modules/desktop_capture/linux/x11/mouse_cursor_monitor_x11.cc +@@ -38,6 +38,7 @@ namespace { + // searches up the list of the windows to find the root child that corresponds + // to `window`. + Window GetTopLevelWindow(Display* display, Window window) { ++ webrtc::XErrorTrap error_trap(display); + while (true) { + // If the window is in WithdrawnState then look at all of its children. + ::Window root, parent; +@@ -104,7 +105,7 @@ MouseCursorMonitorX11::~MouseCursorMonitorX11() { + } + + void MouseCursorMonitorX11::Init(Callback* callback, Mode mode) { +- // Init can be called only once per instance of MouseCursorMonitor. ++ // Init can be called only if not started + RTC_DCHECK(!callback_); + RTC_DCHECK(callback); + +@@ -116,6 +117,7 @@ void MouseCursorMonitorX11::Init(Callback* callback, Mode mode) { + + if (have_xfixes_) { + // Register for changes to the cursor shape. ++ XErrorTrap error_trap(display()); + XFixesSelectCursorInput(display(), window_, XFixesDisplayCursorNotifyMask); + x_display_->AddEventHandler(xfixes_event_base_ + XFixesCursorNotify, this); + +diff --git a/modules/desktop_capture/linux/x11/screen_capturer_x11.cc b/modules/desktop_capture/linux/x11/screen_capturer_x11.cc +index d5dcd7af86..fa6334e8ba 100644 +--- a/modules/desktop_capture/linux/x11/screen_capturer_x11.cc ++++ b/modules/desktop_capture/linux/x11/screen_capturer_x11.cc +@@ -302,7 +302,7 @@ bool ScreenCapturerX11::GetSourceList(SourceList* sources) { + char* monitor_title = XGetAtomName(display(), m.name); + + // Note name is an X11 Atom used to id the monitor. +- sources->push_back({static_cast(m.name), monitor_title}); ++ sources->push_back({static_cast(m.name), 0, monitor_title}); + XFree(monitor_title); + } + +diff --git a/modules/desktop_capture/linux/x11/window_capturer_x11.cc b/modules/desktop_capture/linux/x11/window_capturer_x11.cc +index b55f7e8fa9..2e17d44c0a 100644 +--- a/modules/desktop_capture/linux/x11/window_capturer_x11.cc ++++ b/modules/desktop_capture/linux/x11/window_capturer_x11.cc +@@ -57,6 +57,7 @@ bool WindowCapturerX11::GetSourceList(SourceList* sources) { + return GetWindowList(&atom_cache_, [this, sources](::Window window) { + Source w; + w.id = window; ++ w.pid = (pid_t)GetWindowProcessID(window); + if (this->GetWindowTitle(window, &w.title)) { + sources->push_back(w); + } +@@ -140,6 +141,7 @@ void WindowCapturerX11::Start(Callback* callback) { + + void WindowCapturerX11::CaptureFrame() { + TRACE_EVENT0("webrtc", "WindowCapturerX11::CaptureFrame"); ++ x_display_->ProcessPendingXEvents(); + + if (!x_server_pixel_buffer_.IsWindowValid()) { + RTC_LOG(LS_ERROR) << "The window is no longer valid."; +@@ -147,8 +149,6 @@ void WindowCapturerX11::CaptureFrame() { + return; + } + +- x_display_->ProcessPendingXEvents(); +- + if (!has_composite_extension_) { + // Without the Xcomposite extension we capture when the whole window is + // visible on screen and not covered by any other window. This is not +@@ -237,6 +237,14 @@ bool WindowCapturerX11::GetWindowTitle(::Window window, std::string* title) { + return result; + } + ++int WindowCapturerX11::GetWindowProcessID(::Window window) { ++ // Get _NET_WM_PID property of the window. ++ Atom process_atom = XInternAtom(display(), "_NET_WM_PID", True); ++ XWindowProperty process_id(display(), window, process_atom); ++ ++ return process_id.is_valid() ? *process_id.data() : 0; ++} ++ + // static + std::unique_ptr WindowCapturerX11::CreateRawWindowCapturer( + const DesktopCaptureOptions& options) { +diff --git a/modules/desktop_capture/linux/x11/window_capturer_x11.h b/modules/desktop_capture/linux/x11/window_capturer_x11.h +index ac591c272e..cfd29eca66 100644 +--- a/modules/desktop_capture/linux/x11/window_capturer_x11.h ++++ b/modules/desktop_capture/linux/x11/window_capturer_x11.h +@@ -22,6 +22,7 @@ + #include "modules/desktop_capture/desktop_capturer.h" + #include "modules/desktop_capture/desktop_geometry.h" + #include "modules/desktop_capture/linux/x11/shared_x_display.h" ++#include "modules/desktop_capture/linux/x11/x_window_property.h" + #include "modules/desktop_capture/linux/x11/window_finder_x11.h" + #include "modules/desktop_capture/linux/x11/x_atom_cache.h" + #include "modules/desktop_capture/linux/x11/x_server_pixel_buffer.h" +@@ -57,6 +58,9 @@ class WindowCapturerX11 : public DesktopCapturer, + // Returns window title for the specified X `window`. + bool GetWindowTitle(::Window window, std::string* title); + ++ // Returns the id of the owning process. ++ int GetWindowProcessID(::Window window); ++ + Callback* callback_ = nullptr; + + rtc::scoped_refptr x_display_; +diff --git a/modules/desktop_capture/linux/x11/x_error_trap.cc b/modules/desktop_capture/linux/x11/x_error_trap.cc +index 94e3a03c73..3314dd286c 100644 +--- a/modules/desktop_capture/linux/x11/x_error_trap.cc ++++ b/modules/desktop_capture/linux/x11/x_error_trap.cc +@@ -10,50 +10,60 @@ + + #include "modules/desktop_capture/linux/x11/x_error_trap.h" + +-#include +- + #include + +-#include "rtc_base/checks.h" +- +-namespace webrtc { ++#include + +-namespace { ++#include "rtc_base/checks.h" + +-static int g_last_xserver_error_code = 0; +-static std::atomic g_display_for_error_handler = nullptr; + +-Mutex* AcquireMutex() { +- static Mutex* mutex = new Mutex(); +- return mutex; +-} ++namespace webrtc { + +-int XServerErrorHandler(Display* display, XErrorEvent* error_event) { +- RTC_DCHECK_EQ(display, g_display_for_error_handler.load()); +- g_last_xserver_error_code = error_event->error_code; +- return 0; ++Bool XErrorTrap::XServerErrorHandler(Display* display, xReply* rep, ++ char* /* buf */, int /* len */, ++ XPointer data) { ++ XErrorTrap* self = reinterpret_cast(data); ++ if (rep->generic.type != X_Error || ++ // Overflow-safe last_request_read <= last_ignored_request_ for skipping ++ // async replies from requests before XErrorTrap was created. ++ self->last_ignored_request_ - display->last_request_read < ++ std::numeric_limits::max() >> 1) ++ return False; ++ self->last_xserver_error_code_ = rep->error.errorCode; ++ return True; + } + +-} // namespace +- +-XErrorTrap::XErrorTrap(Display* display) : mutex_lock_(AcquireMutex()) { +- // We don't expect this class to be used in a nested fashion so therefore +- // g_display_for_error_handler should never be valid here. +- RTC_DCHECK(!g_display_for_error_handler.load()); +- RTC_DCHECK(display); +- g_display_for_error_handler.store(display); +- g_last_xserver_error_code = 0; +- original_error_handler_ = XSetErrorHandler(&XServerErrorHandler); ++XErrorTrap::XErrorTrap(Display* display) ++ : display_(display), ++ last_xserver_error_code_(0), ++ enabled_(true) { ++ // Use async_handlers instead of XSetErrorHandler(). async_handlers can ++ // remain in place and then be safely removed at the right time even if a ++ // handler change happens concurrently on another thread. async_handlers ++ // are processed first and so can prevent errors reaching the global ++ // XSetErrorHandler handler. They also will not see errors from or affect ++ // handling of errors on other Displays, which may be processed on other ++ // threads. ++ LockDisplay(display); ++ async_handler_.next = display->async_handlers; ++ async_handler_.handler = XServerErrorHandler; ++ async_handler_.data = reinterpret_cast(this); ++ display->async_handlers = &async_handler_; ++ last_ignored_request_ = display->request; ++ UnlockDisplay(display); + } + + int XErrorTrap::GetLastErrorAndDisable() { +- g_display_for_error_handler.store(nullptr); +- XSetErrorHandler(original_error_handler_); +- return g_last_xserver_error_code; ++ assert(enabled_); ++ enabled_ = false; ++ LockDisplay(display_); ++ DeqAsyncHandler(display_, &async_handler_); ++ UnlockDisplay(display_); ++ return last_xserver_error_code_; + } + + XErrorTrap::~XErrorTrap() { +- if (g_display_for_error_handler.load() != nullptr) ++ if (enabled_) + GetLastErrorAndDisable(); + } + +diff --git a/modules/desktop_capture/linux/x11/x_error_trap.h b/modules/desktop_capture/linux/x11/x_error_trap.h +index 1f21ab969c..df7e86bf03 100644 +--- a/modules/desktop_capture/linux/x11/x_error_trap.h ++++ b/modules/desktop_capture/linux/x11/x_error_trap.h +@@ -11,30 +11,39 @@ + #ifndef MODULES_DESKTOP_CAPTURE_LINUX_X11_X_ERROR_TRAP_H_ + #define MODULES_DESKTOP_CAPTURE_LINUX_X11_X_ERROR_TRAP_H_ + +-#include +- +-#include "rtc_base/synchronization/mutex.h" ++#include ++#undef max // Xlibint.h defines this and it breaks std::max ++#undef min // Xlibint.h defines this and it breaks std::min + + namespace webrtc { + +-// Helper class that registers an X Window error handler. Caller can use ++// Helper class that registers X Window error handler. Caller can use + // GetLastErrorAndDisable() to get the last error that was caught, if any. ++// An XErrorTrap may be constructed on any thread, but errors are collected ++// from all threads and so |display| should be used only on one thread. ++// Other Displays are unaffected. + class XErrorTrap { + public: + explicit XErrorTrap(Display* display); ++ ~XErrorTrap(); + + XErrorTrap(const XErrorTrap&) = delete; + XErrorTrap& operator=(const XErrorTrap&) = delete; + +- ~XErrorTrap(); +- +- // Returns the last error if one was caught, otherwise 0. Also unregisters the +- // error handler and replaces it with `original_error_handler_`. ++ // Returns last error and removes unregisters the error handler. ++ // Must not be called more than once. + int GetLastErrorAndDisable(); + + private: +- MutexLock mutex_lock_; +- XErrorHandler original_error_handler_ = nullptr; ++ static Bool XServerErrorHandler(Display* display, xReply* rep, ++ char* /* buf */, int /* len */, ++ XPointer data); ++ ++ _XAsyncHandler async_handler_; ++ Display* display_; ++ unsigned long last_ignored_request_; ++ int last_xserver_error_code_; ++ bool enabled_; + }; + + } // namespace webrtc +diff --git a/modules/desktop_capture/mouse_cursor_monitor_win.cc b/modules/desktop_capture/mouse_cursor_monitor_win.cc +index c892d59955..18ef43eeb4 100644 +--- a/modules/desktop_capture/mouse_cursor_monitor_win.cc ++++ b/modules/desktop_capture/mouse_cursor_monitor_win.cc +@@ -88,6 +88,7 @@ MouseCursorMonitorWin::~MouseCursorMonitorWin() { + void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) { + RTC_DCHECK(!callback_); + RTC_DCHECK(callback); ++ RTC_DCHECK(IsGUIThread(false)); + + callback_ = callback; + mode_ = mode; +@@ -96,6 +97,8 @@ void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) { + } + + void MouseCursorMonitorWin::Capture() { ++// TODO: Bug 1666266. Commented out to pass new tests added in bug 1634044. ++// RTC_DCHECK(IsGUIThread(false)); + RTC_DCHECK(callback_); + + CURSORINFO cursor_info; +@@ -107,7 +110,8 @@ void MouseCursorMonitorWin::Capture() { + } + + if (!IsSameCursorShape(cursor_info, last_cursor_)) { +- if (cursor_info.flags == CURSOR_SUPPRESSED) { ++ // Mozilla - CURSOR_SUPPRESSED is win8 and above; so we seem not to be able to see the symbol ++ if (cursor_info.flags != CURSOR_SHOWING) { + // The cursor is intentionally hidden now, send an empty bitmap. + last_cursor_ = cursor_info; + callback_->OnMouseCursor(new MouseCursor( +@@ -168,6 +172,7 @@ void MouseCursorMonitorWin::Capture() { + } + + DesktopRect MouseCursorMonitorWin::GetScreenRect() { ++ RTC_DCHECK(IsGUIThread(false)); + RTC_DCHECK_NE(screen_, kInvalidScreenId); + if (screen_ == kFullDesktopScreenId) { + return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN), +diff --git a/modules/desktop_capture/win/screen_capture_utils.cc b/modules/desktop_capture/win/screen_capture_utils.cc +index 3d4aecf14d..1dc2918d08 100644 +--- a/modules/desktop_capture/win/screen_capture_utils.cc ++++ b/modules/desktop_capture/win/screen_capture_utils.cc +@@ -51,7 +51,7 @@ bool GetScreenList(DesktopCapturer::SourceList* screens, + continue; + } + +- screens->push_back({device_index, std::string()}); ++ screens->push_back({device_index, 0, std::string()}); + if (device_names) { + device_names->push_back(rtc::ToUtf8(device.DeviceName)); + } +@@ -147,6 +147,7 @@ DesktopRect GetFullscreenRect() { + + DesktopRect GetScreenRect(const DesktopCapturer::SourceId screen, + const std::wstring& device_key) { ++ RTC_DCHECK(IsGUIThread(false)); + if (screen == kFullDesktopScreenId) { + return GetFullscreenRect(); + } +diff --git a/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/modules/desktop_capture/win/screen_capturer_win_gdi.cc +index 57b1f71b0d..c6d4a75931 100644 +--- a/modules/desktop_capture/win/screen_capturer_win_gdi.cc ++++ b/modules/desktop_capture/win/screen_capturer_win_gdi.cc +@@ -186,6 +186,7 @@ void ScreenCapturerWinGdi::PrepareCaptureResources() { + } + + bool ScreenCapturerWinGdi::CaptureImage() { ++ RTC_DCHECK(IsGUIThread(false)); + DesktopRect screen_rect = + GetScreenRect(current_screen_id_, current_device_key_); + if (screen_rect.is_empty()) { +diff --git a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc b/modules/desktop_capture/win/screen_capturer_win_magnifier.cc +index 214eb0e463..ce747e0141 100644 +--- a/modules/desktop_capture/win/screen_capturer_win_magnifier.cc ++++ b/modules/desktop_capture/win/screen_capturer_win_magnifier.cc +@@ -49,17 +49,25 @@ ScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier() = default; + ScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() { + // DestroyWindow must be called before MagUninitialize. magnifier_window_ is + // destroyed automatically when host_window_ is destroyed. +- if (host_window_) ++ if (host_window_) { + DestroyWindow(host_window_); ++ host_window_ = NULL; ++ } + +- if (magnifier_initialized_) ++ if (magnifier_initialized_) { + mag_uninitialize_func_(); ++ magnifier_initialized_ = false; ++ } + +- if (mag_lib_handle_) ++ if (mag_lib_handle_) { + FreeLibrary(mag_lib_handle_); ++ mag_lib_handle_ = NULL; ++ } + +- if (desktop_dc_) ++ if (desktop_dc_) { + ReleaseDC(NULL, desktop_dc_); ++ desktop_dc_ = NULL; ++ } + } + + void ScreenCapturerWinMagnifier::Start(Callback* callback) { +diff --git a/modules/rtp_rtcp/source/rtcp_sender.cc b/modules/rtp_rtcp/source/rtcp_sender.cc +index 7983371097..983851a55b 100644 +--- a/modules/rtp_rtcp/source/rtcp_sender.cc ++++ b/modules/rtp_rtcp/source/rtcp_sender.cc +@@ -201,7 +201,7 @@ void RTCPSender::SetRTCPStatus(RtcpMode new_method) { + next_time_to_send_rtcp_ = absl::nullopt; + } else if (method_ == RtcpMode::kOff) { + // When switching on, reschedule the next packet +- SetNextRtcpSendEvaluationDuration(report_interval_ / 2); ++ SetNextRtcpSendEvaluationDuration(RTCP_INTERVAL_RAPID_SYNC_MS / 2); + } + method_ = new_method; + } +diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.cc b/modules/rtp_rtcp/source/rtp_header_extensions.cc +index 81961c69aa..a57d9e7f62 100644 +--- a/modules/rtp_rtcp/source/rtp_header_extensions.cc ++++ b/modules/rtp_rtcp/source/rtp_header_extensions.cc +@@ -446,6 +446,45 @@ bool PlayoutDelayLimits::Write(rtc::ArrayView data, + return true; + } + ++// CSRCAudioLevel ++// Sample Audio Level Encoding Using the One-Byte Header Format ++// Note that the range of len is 1 to 15 which is encoded as 0 to 14 ++// 0 1 2 3 ++// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++// | ID | len=2 |0| level 1 |0| level 2 |0| level 3 | ++// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ++ ++ ++constexpr RTPExtensionType CsrcAudioLevel::kId; ++constexpr const char* CsrcAudioLevel::kUri; ++ ++bool CsrcAudioLevel::Parse(rtc::ArrayView data, ++ CsrcAudioLevelList* csrcAudioLevels) { ++ if (data.size() < 1 || data.size() > kRtpCsrcSize) ++ return false; ++ csrcAudioLevels->numAudioLevels = data.size(); ++ for(uint8_t i = 0; i < csrcAudioLevels->numAudioLevels; i++) { ++ // Ensure range is 0 to 127 inclusive ++ csrcAudioLevels->arrOfAudioLevels[i] = 0x7f & data[i]; ++ } ++ return true; ++} ++ ++size_t CsrcAudioLevel::ValueSize(const CsrcAudioLevelList& csrcAudioLevels) { ++ return csrcAudioLevels.numAudioLevels; ++} ++ ++bool CsrcAudioLevel::Write(rtc::ArrayView data, ++ const CsrcAudioLevelList& csrcAudioLevels) { ++ RTC_DCHECK_GE(csrcAudioLevels.numAudioLevels, 0); ++ for(uint8_t i = 0; i < csrcAudioLevels.numAudioLevels; i++) { ++ data[i] = csrcAudioLevels.arrOfAudioLevels[i] & 0x7f; ++ } ++ // This extension if used must have at least one audio level ++ return csrcAudioLevels.numAudioLevels; ++} ++ + // Video Content Type. + // + // E.g. default video or screenshare. +diff --git a/modules/rtp_rtcp/source/rtp_header_extensions.h b/modules/rtp_rtcp/source/rtp_header_extensions.h +index d80e0da4f8..89c73955a2 100644 +--- a/modules/rtp_rtcp/source/rtp_header_extensions.h ++++ b/modules/rtp_rtcp/source/rtp_header_extensions.h +@@ -292,6 +292,21 @@ class ColorSpaceExtension { + static size_t WriteLuminance(uint8_t* data, float f, int denominator); + }; + ++class CsrcAudioLevel { ++ public: ++ static constexpr RTPExtensionType kId = kRtpExtensionCsrcAudioLevel; ++ static constexpr absl::string_view Uri() { ++ return RtpExtension::kCsrcAudioLevelsUri; ++ } ++ static constexpr const char* kUri = ++ "urn:ietf:params:rtp-hdrext:csrc-audio-level"; ++ ++ static bool Parse(rtc::ArrayView data, ++ CsrcAudioLevelList* csrcAudioLevels); ++ static size_t ValueSize(const CsrcAudioLevelList& csrcAudioLevels); ++ static bool Write(rtc::ArrayView data, const CsrcAudioLevelList& csrcAudioLevels); ++}; ++ + // Base extension class for RTP header extensions which are strings. + // Subclasses must defined kId and kUri static constexpr members. + class BaseRtpStringExtension { +diff --git a/modules/rtp_rtcp/source/rtp_packet.cc b/modules/rtp_rtcp/source/rtp_packet.cc +index 6c7dff322b..9495841984 100644 +--- a/modules/rtp_rtcp/source/rtp_packet.cc ++++ b/modules/rtp_rtcp/source/rtp_packet.cc +@@ -205,6 +205,10 @@ void RtpPacket::ZeroMutableExtensions() { + // Non-mutable extension. Don't change it. + break; + } ++ case RTPExtensionType::kRtpExtensionCsrcAudioLevel: { ++ // TODO: This is a Mozilla addition, we need to add a handler for this. ++ RTC_CHECK(false); ++ } + } + } + } +diff --git a/modules/rtp_rtcp/source/rtp_packet_unittest.cc b/modules/rtp_rtcp/source/rtp_packet_unittest.cc +index 1d51d75662..41bc114efb 100644 +--- a/modules/rtp_rtcp/source/rtp_packet_unittest.cc ++++ b/modules/rtp_rtcp/source/rtp_packet_unittest.cc +@@ -121,6 +121,18 @@ constexpr uint8_t kPacketWithMid[] = { + 0xbe, 0xde, 0x00, 0x01, + 0xb2, 'm', 'i', 'd'}; + ++constexpr uint8_t kCsrcAudioLevelExtensionId = 0xc; ++constexpr uint8_t kCsrcAudioLevelsSize = 4; ++constexpr uint8_t kCsrcAudioLevels[] = {0x7f, 0x00, 0x10, 0x08}; ++constexpr uint8_t kPacketWithCsrcAudioLevels[] = { ++ 0x90, kPayloadType, kSeqNumFirstByte, kSeqNumSecondByte, ++ 0x65, 0x43, 0x12, 0x78, ++ 0x12, 0x34, 0x56, 0x78, ++ 0xbe, 0xde, 0x00, 0x02, ++ (kCsrcAudioLevelExtensionId << 4) | (kCsrcAudioLevelsSize - 1), ++ 0x7f, 0x00, 0x10, ++ 0x08, 0x00, 0x00, 0x00}; ++ + constexpr uint32_t kCsrcs[] = {0x34567890, 0x32435465}; + constexpr uint8_t kPayload[] = {'p', 'a', 'y', 'l', 'o', 'a', 'd'}; + constexpr uint8_t kPacketPaddingSize = 8; +@@ -385,6 +397,24 @@ TEST(RtpPacketTest, FailsToSetUnregisteredExtension) { + EXPECT_EQ(packet.GetExtension(), absl::nullopt); + } + ++TEST(RtpPacketTest, CreateWithDynamicSizedExtensionCsrcAudioLevel) { ++ RtpPacketToSend::ExtensionManager extensions; ++ extensions.Register(kCsrcAudioLevelExtensionId); ++ RtpPacketToSend packet(&extensions); ++ packet.SetPayloadType(kPayloadType); ++ packet.SetSequenceNumber(kSeqNum); ++ packet.SetTimestamp(kTimestamp); ++ packet.SetSsrc(kSsrc); ++ CsrcAudioLevelList levels; ++ levels.numAudioLevels = kCsrcAudioLevelsSize; ++ for (uint8_t i = 0; i < kCsrcAudioLevelsSize; i++) { ++ levels.arrOfAudioLevels[i] = kCsrcAudioLevels[i]; ++ } ++ packet.SetExtension(levels); ++ EXPECT_THAT(kPacketWithCsrcAudioLevels, ++ ElementsAreArray(packet.data(), packet.size())); ++} ++ + TEST(RtpPacketTest, SetReservedExtensionsAfterPayload) { + const size_t kPayloadSize = 4; + RtpPacketToSend::ExtensionManager extensions; +diff --git a/modules/rtp_rtcp/source/rtp_rtcp_config.h b/modules/rtp_rtcp/source/rtp_rtcp_config.h +index 3e6aa3baae..9ac7696ce9 100644 +--- a/modules/rtp_rtcp/source/rtp_rtcp_config.h ++++ b/modules/rtp_rtcp/source/rtp_rtcp_config.h +@@ -18,6 +18,8 @@ namespace webrtc { + constexpr int kDefaultMaxReorderingThreshold = 50; // In sequence numbers. + constexpr int kRtcpMaxNackFields = 253; + ++constexpr TimeDelta RTCP_INTERVAL_RAPID_SYNC_MS = ++ TimeDelta::Millis(100); // RFX 6051 + constexpr TimeDelta RTCP_SEND_BEFORE_KEY_FRAME = TimeDelta::Millis(100); + constexpr int RTCP_MAX_REPORT_BLOCKS = 31; // RFC 3550 page 37 + } // namespace webrtc +diff --git a/modules/rtp_rtcp/source/rtp_sender.cc b/modules/rtp_rtcp/source/rtp_sender.cc +index ac3bd55e05..0ed7243d0a 100644 +--- a/modules/rtp_rtcp/source/rtp_sender.cc ++++ b/modules/rtp_rtcp/source/rtp_sender.cc +@@ -132,6 +132,10 @@ bool IsNonVolatile(RTPExtensionType type) { + case kRtpExtensionNumberOfExtensions: + RTC_DCHECK_NOTREACHED(); + return false; ++ case kRtpExtensionCsrcAudioLevel: ++ // TODO: Mozilla implement for CsrcAudioLevel ++ RTC_CHECK(false); ++ return false; + } + RTC_CHECK_NOTREACHED(); + } +diff --git a/modules/utility/source/jvm_android.cc b/modules/utility/source/jvm_android.cc +index ee9930bcaa..39ef12f428 100644 +--- a/modules/utility/source/jvm_android.cc ++++ b/modules/utility/source/jvm_android.cc +@@ -18,6 +18,16 @@ + #include "rtc_base/logging.h" + #include "rtc_base/platform_thread.h" + ++namespace mozilla { ++namespace jni { ++jclass GetClassRef(JNIEnv* aEnv, const char* aClassName); ++} ++} ++ ++#define TAG "JVM" ++#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) ++#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) ++ + namespace webrtc { + + JVM* g_jvm; +@@ -40,14 +50,11 @@ struct { + void LoadClasses(JNIEnv* jni) { + RTC_LOG(LS_INFO) << "LoadClasses:"; + for (auto& c : loaded_classes) { +- jclass localRef = FindClass(jni, c.name); +- RTC_LOG(LS_INFO) << "name: " << c.name; +- CHECK_EXCEPTION(jni) << "Error during FindClass: " << c.name; +- RTC_CHECK(localRef) << c.name; +- jclass globalRef = reinterpret_cast(jni->NewGlobalRef(localRef)); +- CHECK_EXCEPTION(jni) << "Error during NewGlobalRef: " << c.name; +- RTC_CHECK(globalRef) << c.name; +- c.clazz = globalRef; ++ ALOGD("name: %s", c.name); ++ jclass clsRef = mozilla::jni::GetClassRef(jni, c.name); ++ RTC_CHECK(clsRef) << c.name; ++ c.clazz = static_cast(jni->NewGlobalRef(clsRef)); ++ jni->DeleteLocalRef(clsRef); + } + } + +@@ -216,8 +223,9 @@ std::string JNIEnvironment::JavaToStdString(const jstring& j_string) { + + // static + void JVM::Initialize(JavaVM* jvm) { +- RTC_LOG(LS_INFO) << "JVM::Initialize"; +- RTC_CHECK(!g_jvm); ++ if (g_jvm) { ++ return; ++ } + g_jvm = new JVM(jvm); + } + +diff --git a/modules/video_capture/device_info_impl.cc b/modules/video_capture/device_info_impl.cc +index ff32a78580..7cccdb51a7 100644 +--- a/modules/video_capture/device_info_impl.cc ++++ b/modules/video_capture/device_info_impl.cc +@@ -65,7 +65,7 @@ int32_t DeviceInfoImpl::GetCapability(const char* deviceUniqueIdUTF8, + + // Make sure the number is valid + if (deviceCapabilityNumber >= (unsigned int)_captureCapabilities.size()) { +- RTC_LOG(LS_ERROR) << "Invalid deviceCapabilityNumber " ++ RTC_LOG(LS_ERROR) << deviceUniqueIdUTF8 << " Invalid deviceCapabilityNumber " + << deviceCapabilityNumber << ">= number of capabilities (" + << _captureCapabilities.size() << ")."; + return -1; +diff --git a/modules/video_capture/device_info_impl.h b/modules/video_capture/device_info_impl.h +index 546265049c..8acbef6d69 100644 +--- a/modules/video_capture/device_info_impl.h ++++ b/modules/video_capture/device_info_impl.h +@@ -42,6 +42,7 @@ class DeviceInfoImpl : public VideoCaptureModule::DeviceInfo { + /* Initialize this object*/ + + virtual int32_t Init() = 0; ++ int32_t Refresh() override { return 0; } + /* + * Fills the member variable _captureCapabilities with capabilities for the + * given device name. +diff --git a/modules/video_capture/linux/device_info_v4l2.cc b/modules/video_capture/linux/device_info_v4l2.cc +index 5af58015a7..28395a5a05 100644 +--- a/modules/video_capture/linux/device_info_v4l2.cc ++++ b/modules/video_capture/linux/device_info_v4l2.cc +@@ -27,15 +27,187 @@ + #include "modules/video_capture/video_capture_impl.h" + #include "rtc_base/logging.h" + ++#ifdef WEBRTC_LINUX ++#define EVENT_SIZE ( sizeof (struct inotify_event) ) ++#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) ++#endif ++ + namespace webrtc { + namespace videocapturemodule { +-DeviceInfoV4l2::DeviceInfoV4l2() : DeviceInfoImpl() {} ++#ifdef WEBRTC_LINUX ++void DeviceInfoV4l2::HandleEvent(inotify_event* event, int fd) ++{ ++ if (event->mask & IN_CREATE) { ++ if (fd == _fd_v4l || fd == _fd_snd) { ++ DeviceChange(); ++ } else if ((event->mask & IN_ISDIR) && (fd == _fd_dev)) { ++ if (_wd_v4l < 0) { ++ // Sometimes inotify_add_watch failed if we call it immediately after receiving this event ++ // Adding 5ms delay to let file system settle down ++ usleep(5*1000); ++ _wd_v4l = inotify_add_watch(_fd_v4l, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); ++ if (_wd_v4l >= 0) { ++ DeviceChange(); ++ } ++ } ++ if (_wd_snd < 0) { ++ usleep(5*1000); ++ _wd_snd = inotify_add_watch(_fd_snd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); ++ if (_wd_snd >= 0) { ++ DeviceChange(); ++ } ++ } ++ } ++ } else if (event->mask & IN_DELETE) { ++ if (fd == _fd_v4l || fd == _fd_snd) { ++ DeviceChange(); ++ } ++ } else if (event->mask & IN_DELETE_SELF) { ++ if (fd == _fd_v4l) { ++ inotify_rm_watch(_fd_v4l, _wd_v4l); ++ _wd_v4l = -1; ++ } else if (fd == _fd_snd) { ++ inotify_rm_watch(_fd_snd, _wd_snd); ++ _wd_snd = -1; ++ } else { ++ assert(false); ++ } ++ } ++} ++ ++int DeviceInfoV4l2::EventCheck(int fd) ++{ ++ struct timeval timeout; ++ fd_set rfds; ++ ++ timeout.tv_sec = 0; ++ timeout.tv_usec = 100000; ++ ++ FD_ZERO(&rfds); ++ FD_SET(fd, &rfds); ++ ++ return select(fd+1, &rfds, NULL, NULL, &timeout); ++} ++ ++int DeviceInfoV4l2::HandleEvents(int fd) ++{ ++ char buffer[BUF_LEN]; ++ ++ ssize_t r = read(fd, buffer, BUF_LEN); ++ ++ if (r <= 0) { ++ return r; ++ } ++ ++ ssize_t buffer_i = 0; ++ inotify_event* pevent; ++ size_t eventSize; ++ int count = 0; ++ ++ while (buffer_i < r) ++ { ++ pevent = (inotify_event *) (&buffer[buffer_i]); ++ eventSize = sizeof(inotify_event) + pevent->len; ++ char event[sizeof(inotify_event) + FILENAME_MAX + 1] // null-terminated ++ __attribute__ ((aligned(__alignof__(struct inotify_event)))); ++ ++ memcpy(event, pevent, eventSize); ++ ++ HandleEvent((inotify_event*)(event), fd); ++ ++ buffer_i += eventSize; ++ count++; ++ } ++ ++ return count; ++} ++ ++int DeviceInfoV4l2::ProcessInotifyEvents() ++{ ++ while (!_isShutdown) { ++ if (EventCheck(_fd_dev) > 0) { ++ if (HandleEvents(_fd_dev) < 0) { ++ break; ++ } ++ } ++ if (EventCheck(_fd_v4l) > 0) { ++ if (HandleEvents(_fd_v4l) < 0) { ++ break; ++ } ++ } ++ if (EventCheck(_fd_snd) > 0) { ++ if (HandleEvents(_fd_snd) < 0) { ++ break; ++ } ++ } ++ } ++ return 0; ++} ++ ++void DeviceInfoV4l2::InotifyEventThread(void* obj) ++{ ++ static_cast (obj)->InotifyProcess(); ++} ++ ++void DeviceInfoV4l2::InotifyProcess() ++{ ++ _fd_v4l = inotify_init(); ++ _fd_snd = inotify_init(); ++ _fd_dev = inotify_init(); ++ if (_fd_v4l >= 0 && _fd_snd >= 0 && _fd_dev >= 0) { ++ _wd_v4l = inotify_add_watch(_fd_v4l, "/dev/v4l/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); ++ _wd_snd = inotify_add_watch(_fd_snd, "/dev/snd/by-path/", IN_CREATE | IN_DELETE | IN_DELETE_SELF); ++ _wd_dev = inotify_add_watch(_fd_dev, "/dev/", IN_CREATE); ++ ProcessInotifyEvents(); ++ ++ if (_wd_v4l >= 0) { ++ inotify_rm_watch(_fd_v4l, _wd_v4l); ++ } ++ ++ if (_wd_snd >= 0) { ++ inotify_rm_watch(_fd_snd, _wd_snd); ++ } ++ ++ if (_wd_dev >= 0) { ++ inotify_rm_watch(_fd_dev, _wd_dev); ++ } ++ ++ close(_fd_v4l); ++ close(_fd_snd); ++ close(_fd_dev); ++ } ++} ++#endif ++ ++DeviceInfoV4l2::DeviceInfoV4l2() : DeviceInfoImpl() ++#ifdef WEBRTC_LINUX ++ , _inotifyEventThread(new rtc::PlatformThread( ++ InotifyEventThread, this, "InotifyEventThread")) ++ , _isShutdown(false) ++#endif ++{ ++#ifdef WEBRTC_LINUX ++ if (_inotifyEventThread) ++ { ++ _inotifyEventThread->Start(); ++ } ++} ++#endif + + int32_t DeviceInfoV4l2::Init() { + return 0; + } + +-DeviceInfoV4l2::~DeviceInfoV4l2() {} ++DeviceInfoV4l2::~DeviceInfoV4l2() { ++#ifdef WEBRTC_LINUX ++ _isShutdown = true; ++ ++ if (_inotifyEventThread) { ++ _inotifyEventThread->Stop(); ++ _inotifyEventThread = nullptr; ++ } ++#endif ++} + + uint32_t DeviceInfoV4l2::NumberOfDevices() { + uint32_t count = 0; +@@ -68,15 +240,17 @@ int32_t DeviceInfoV4l2::GetDeviceName(uint32_t deviceNumber, + char* deviceUniqueIdUTF8, + uint32_t deviceUniqueIdUTF8Length, + char* /*productUniqueIdUTF8*/, +- uint32_t /*productUniqueIdUTF8Length*/) { ++ uint32_t /*productUniqueIdUTF8Length*/, ++ pid_t* /*pid*/) { + // Travel through /dev/video [0-63] + uint32_t count = 0; + char device[20]; + int fd = -1; + bool found = false; + struct v4l2_capability cap; +- for (int n = 0; n < 64; n++) { +- snprintf(device, sizeof(device), "/dev/video%d", n); ++ int device_index; ++ for (device_index = 0; device_index < 64; device_index++) { ++ sprintf(device, "/dev/video%d", device_index); + if ((fd = open(device, O_RDONLY)) != -1) { + // query device capabilities and make sure this is a video capture device + if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0 || +@@ -129,8 +303,15 @@ int32_t DeviceInfoV4l2::GetDeviceName(uint32_t deviceNumber, + RTC_LOG(LS_INFO) << "buffer passed is too small"; + return -1; + } ++ } else { ++ // if there's no bus info to use for uniqueId, invent one - and it has to be repeatable ++ if (snprintf(deviceUniqueIdUTF8, ++ deviceUniqueIdUTF8Length, "fake_%u", device_index) >= ++ (int) deviceUniqueIdUTF8Length) ++ { ++ return -1; ++ } + } +- + return 0; + } + +diff --git a/modules/video_capture/linux/device_info_v4l2.h b/modules/video_capture/linux/device_info_v4l2.h +index fb95a6020d..95432a509d 100644 +--- a/modules/video_capture/linux/device_info_v4l2.h ++++ b/modules/video_capture/linux/device_info_v4l2.h +@@ -15,6 +15,9 @@ + + #include "modules/video_capture/device_info_impl.h" + ++#include "rtc_base/platform_thread.h" ++#include ++ + namespace webrtc { + namespace videocapturemodule { + class DeviceInfoV4l2 : public DeviceInfoImpl { +@@ -28,7 +31,8 @@ class DeviceInfoV4l2 : public DeviceInfoImpl { + char* deviceUniqueIdUTF8, + uint32_t deviceUniqueIdUTF8Length, + char* productUniqueIdUTF8 = 0, +- uint32_t productUniqueIdUTF8Length = 0) override; ++ uint32_t productUniqueIdUTF8Length = 0, ++ pid_t* pid=0) override; + /* + * Fills the membervariable _captureCapabilities with capabilites for the + * given device name. +@@ -45,6 +49,18 @@ class DeviceInfoV4l2 : public DeviceInfoImpl { + + private: + bool IsDeviceNameMatches(const char* name, const char* deviceUniqueIdUTF8); ++ ++#ifdef WEBRTC_LINUX ++ void HandleEvent(inotify_event* event, int fd); ++ int EventCheck(int fd); ++ int HandleEvents(int fd); ++ int ProcessInotifyEvents(); ++ std::unique_ptr _inotifyEventThread; ++ static void InotifyEventThread(void*); ++ void InotifyProcess(); ++ int _fd_v4l, _fd_dev, _wd_v4l, _wd_dev; /* accessed on InotifyEventThread thread */ ++ std::atomic _isShutdown; ++#endif + }; + } // namespace videocapturemodule + } // namespace webrtc +diff --git a/modules/video_capture/linux/video_capture_v4l2.cc b/modules/video_capture/linux/video_capture_v4l2.cc +index 5101a67e0c..1dc13b01aa 100644 +--- a/modules/video_capture/linux/video_capture_v4l2.cc ++++ b/modules/video_capture/linux/video_capture_v4l2.cc +@@ -50,6 +50,13 @@ int32_t VideoCaptureModuleV4L2::Init(const char* deviceUniqueIdUTF8) { + memcpy(_deviceUniqueId, deviceUniqueIdUTF8, len + 1); + } + ++ int device_index; ++ if (sscanf(deviceUniqueIdUTF8,"fake_%d", &device_index) == 1) ++ { ++ _deviceId = device_index; ++ return 0; ++ } ++ + int fd; + char device[32]; + bool found = false; +diff --git a/modules/video_capture/video_capture.h b/modules/video_capture/video_capture.h +index eddc31414a..187eba76a0 100644 +--- a/modules/video_capture/video_capture.h ++++ b/modules/video_capture/video_capture.h +@@ -15,15 +15,48 @@ + #include "api/video/video_sink_interface.h" + #include "modules/video_capture/raw_video_sink_interface.h" + #include "modules/video_capture/video_capture_defines.h" ++#include ++ ++#if defined(ANDROID) ++#include ++#endif + + namespace webrtc { + ++class VideoInputFeedBack ++{ ++public: ++ virtual void OnDeviceChange() = 0; ++protected: ++ virtual ~VideoInputFeedBack(){} ++}; ++ ++#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) ++ int32_t SetCaptureAndroidVM(JavaVM* javaVM); ++#endif ++ + class VideoCaptureModule : public rtc::RefCountInterface { + public: + // Interface for receiving information about available camera devices. + class DeviceInfo { + public: + virtual uint32_t NumberOfDevices() = 0; ++ virtual int32_t Refresh() = 0; ++ virtual void DeviceChange() { ++ for (auto inputCallBack : _inputCallBacks) { ++ inputCallBack->OnDeviceChange(); ++ } ++ } ++ virtual void RegisterVideoInputFeedBack(VideoInputFeedBack* callBack) { ++ _inputCallBacks.insert(callBack); ++ } ++ ++ virtual void DeRegisterVideoInputFeedBack(VideoInputFeedBack* callBack) { ++ auto it = _inputCallBacks.find(callBack); ++ if (it != _inputCallBacks.end()) { ++ _inputCallBacks.erase(it); ++ } ++ } + + // Returns the available capture devices. + // deviceNumber - Index of capture device. +@@ -38,7 +71,8 @@ class VideoCaptureModule : public rtc::RefCountInterface { + char* deviceUniqueIdUTF8, + uint32_t deviceUniqueIdUTF8Length, + char* productUniqueIdUTF8 = 0, +- uint32_t productUniqueIdUTF8Length = 0) = 0; ++ uint32_t productUniqueIdUTF8Length = 0, ++ pid_t* pid = 0) = 0; + + // Returns the number of capabilities this device. + virtual int32_t NumberOfCapabilities(const char* deviceUniqueIdUTF8) = 0; +@@ -70,6 +104,8 @@ class VideoCaptureModule : public rtc::RefCountInterface { + uint32_t positionY) = 0; + + virtual ~DeviceInfo() {} ++ private: ++ std::set _inputCallBacks; + }; + + // Register capture data callback +@@ -79,11 +115,16 @@ class VideoCaptureModule : public rtc::RefCountInterface { + RawVideoSinkInterface* dataCallback) = 0; + + // Remove capture data callback +- virtual void DeRegisterCaptureDataCallback() = 0; ++ virtual void DeRegisterCaptureDataCallback( ++ rtc::VideoSinkInterface *dataCallback) = 0; + + // Start capture device + virtual int32_t StartCapture(const VideoCaptureCapability& capability) = 0; + ++ virtual int32_t StopCaptureIfAllClientsClose() = 0; ++ ++ virtual bool FocusOnSelectedSource() { return false; } ++ + virtual int32_t StopCapture() = 0; + + // Returns the name of the device used by this module. +diff --git a/modules/video_capture/video_capture_factory.cc b/modules/video_capture/video_capture_factory.cc +index c0e1479caf..e4a46902e0 100644 +--- a/modules/video_capture/video_capture_factory.cc ++++ b/modules/video_capture/video_capture_factory.cc +@@ -16,19 +16,11 @@ namespace webrtc { + + rtc::scoped_refptr VideoCaptureFactory::Create( + const char* deviceUniqueIdUTF8) { +-#if defined(WEBRTC_ANDROID) || defined(WEBRTC_MAC) +- return nullptr; +-#else + return videocapturemodule::VideoCaptureImpl::Create(deviceUniqueIdUTF8); +-#endif + } + + VideoCaptureModule::DeviceInfo* VideoCaptureFactory::CreateDeviceInfo() { +-#if defined(WEBRTC_ANDROID) || defined(WEBRTC_MAC) +- return nullptr; +-#else + return videocapturemodule::VideoCaptureImpl::CreateDeviceInfo(); +-#endif + } + + } // namespace webrtc +diff --git a/modules/video_capture/video_capture_impl.cc b/modules/video_capture/video_capture_impl.cc +index d539b38264..d5ec4daae1 100644 +--- a/modules/video_capture/video_capture_impl.cc ++++ b/modules/video_capture/video_capture_impl.cc +@@ -76,7 +76,6 @@ VideoCaptureImpl::VideoCaptureImpl() + _requestedCapability(), + _lastProcessTimeNanos(rtc::TimeNanos()), + _lastFrameRateCallbackTimeNanos(rtc::TimeNanos()), +- _dataCallBack(NULL), + _rawDataCallBack(NULL), + _lastProcessFrameTimeNanos(rtc::TimeNanos()), + _rotateFrame(kVideoRotation_0), +@@ -89,7 +88,6 @@ VideoCaptureImpl::VideoCaptureImpl() + } + + VideoCaptureImpl::~VideoCaptureImpl() { +- DeRegisterCaptureDataCallback(); + if (_deviceUniqueId) + delete[] _deviceUniqueId; + } +@@ -98,26 +96,39 @@ void VideoCaptureImpl::RegisterCaptureDataCallback( + rtc::VideoSinkInterface* dataCallBack) { + MutexLock lock(&api_lock_); + RTC_DCHECK(!_rawDataCallBack); +- _dataCallBack = dataCallBack; ++ _dataCallBacks.insert(dataCallBack); + } + + void VideoCaptureImpl::RegisterCaptureDataCallback( + RawVideoSinkInterface* dataCallBack) { + MutexLock lock(&api_lock_); +- RTC_DCHECK(!_dataCallBack); ++ RTC_DCHECK(_dataCallBacks.empty()); + _rawDataCallBack = dataCallBack; + } + +-void VideoCaptureImpl::DeRegisterCaptureDataCallback() { ++void VideoCaptureImpl::DeRegisterCaptureDataCallback( ++ rtc::VideoSinkInterface* dataCallBack) { + MutexLock lock(&api_lock_); +- _dataCallBack = NULL; ++ auto it = _dataCallBacks.find(dataCallBack); ++ if (it != _dataCallBacks.end()) { ++ _dataCallBacks.erase(it); ++ } + _rawDataCallBack = NULL; + } ++ ++int32_t VideoCaptureImpl::StopCaptureIfAllClientsClose() { ++ if (_dataCallBacks.empty()) { ++ return StopCapture(); ++ } else { ++ return 0; ++ } ++} ++ + int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) { + UpdateFrameCount(); // frame count used for local frame rate callback. + +- if (_dataCallBack) { +- _dataCallBack->OnFrame(captureFrame); ++ for (auto dataCallBack : _dataCallBacks) { ++ dataCallBack->OnFrame(captureFrame); + } + + return 0; +@@ -204,7 +215,7 @@ int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame, + buffer.get()->StrideV(), 0, 0, // No Cropping + width, height, target_width, target_height, rotation_mode, + ConvertVideoType(frameInfo.videoType)); +- if (conversionResult < 0) { ++ if (conversionResult != 0) { + RTC_LOG(LS_ERROR) << "Failed to convert capture frame from type " + << static_cast(frameInfo.videoType) << "to I420."; + return -1; +@@ -219,6 +230,13 @@ int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame, + .build(); + captureFrame.set_ntp_time_ms(captureTime); + ++ // This is one ugly hack to let CamerasParent know what rotation ++ // the frame was captured at. Note that this goes against the intended ++ // meaning of rotation of the frame (how to rotate it before rendering). ++ // We do this so CamerasChild can scale to the proper dimensions ++ // later on in the pipe. ++ captureFrame.set_rotation(_rotateFrame); ++ + DeliverCapturedFrame(captureFrame); + + return 0; +diff --git a/modules/video_capture/video_capture_impl.h b/modules/video_capture/video_capture_impl.h +index fee93396d3..f874580471 100644 +--- a/modules/video_capture/video_capture_impl.h ++++ b/modules/video_capture/video_capture_impl.h +@@ -55,8 +55,10 @@ class VideoCaptureImpl : public VideoCaptureModule { + rtc::VideoSinkInterface* dataCallback) override; + virtual void RegisterCaptureDataCallback( + RawVideoSinkInterface* dataCallback) override; +- void DeRegisterCaptureDataCallback() override; ++ void DeRegisterCaptureDataCallback( ++ rtc::VideoSinkInterface* dataCallback) override; + ++ int32_t StopCaptureIfAllClientsClose() override; + int32_t SetCaptureRotation(VideoRotation rotation) override; + bool SetApplyRotation(bool enable) override; + bool GetApplyRotation() override; +@@ -98,7 +100,7 @@ class VideoCaptureImpl : public VideoCaptureModule { + // last time the frame rate callback function was called. + int64_t _lastFrameRateCallbackTimeNanos; + +- rtc::VideoSinkInterface* _dataCallBack; ++ std::set*> _dataCallBacks; + RawVideoSinkInterface* _rawDataCallBack; + + int64_t _lastProcessFrameTimeNanos; +diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc +index c2884c0395..35b13058a2 100644 +--- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc ++++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.cc +@@ -254,6 +254,7 @@ LibvpxVp9Encoder::LibvpxVp9Encoder(const cricket::VideoCodec& codec, + first_frame_in_picture_(true), + ss_info_needed_(false), + force_all_active_layers_(false), ++ num_cores_(0), + is_flexible_mode_(false), + variable_framerate_experiment_(ParseVariableFramerateConfig(trials)), + variable_framerate_controller_( +@@ -577,6 +578,7 @@ int LibvpxVp9Encoder::InitEncode(const VideoCodec* inst, + + force_key_frame_ = true; + pics_since_key_ = 0; ++ num_cores_ = settings.number_of_cores; + + scalability_mode_ = inst->GetScalabilityMode(); + if (scalability_mode_.has_value()) { +diff --git a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h +index 6b662ae8f9..bb871f8498 100644 +--- a/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h ++++ b/modules/video_coding/codecs/vp9/libvpx_vp9_encoder.h +@@ -67,6 +67,9 @@ class LibvpxVp9Encoder : public VP9Encoder { + // Call encoder initialize function and set control settings. + int InitAndSetControlSettings(const VideoCodec* inst); + ++ // Update frame size for codec. ++ int UpdateCodecFrameSize(const VideoFrame& input_image); ++ + bool PopulateCodecSpecific(CodecSpecificInfo* codec_specific, + absl::optional* spatial_idx, + absl::optional* temporal_idx, +@@ -150,6 +153,7 @@ class LibvpxVp9Encoder : public VP9Encoder { + VideoBitrateAllocation current_bitrate_allocation_; + bool ss_info_needed_; + bool force_all_active_layers_; ++ uint8_t num_cores_; + + std::unique_ptr svc_controller_; + absl::optional scalability_mode_; +diff --git a/modules/video_coding/generic_decoder.cc b/modules/video_coding/generic_decoder.cc +index b660e02b72..54467d1477 100644 +--- a/modules/video_coding/generic_decoder.cc ++++ b/modules/video_coding/generic_decoder.cc +@@ -32,7 +32,10 @@ namespace webrtc { + + namespace { + +-constexpr size_t kDecoderFrameMemoryLength = 10; ++// Changed from 10 to 30 in Mozilla Bug 989944: Increase decode ++// timestamp map to handle delayed decode on 8x10. The map is ++// now a deque (as of libwebrtc upstream commit 1c51ec4d74). ++constexpr size_t kDecoderFrameMemoryLength = 30; + + } + +diff --git a/modules/video_coding/session_info.cc b/modules/video_coding/session_info.cc +index 854230ae0a..e31b8b1d25 100644 +--- a/modules/video_coding/session_info.cc ++++ b/modules/video_coding/session_info.cc +@@ -210,16 +210,26 @@ size_t VCMSessionInfo::InsertBuffer(uint8_t* frame_buffer, + if (h264 && h264->packetization_type == kH264StapA) { + size_t required_length = 0; + const uint8_t* nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; +- while (nalu_ptr < packet_buffer + packet.sizeBytes) { ++ // Must check that incoming data length doesn't extend past end of buffer. ++ // We allow for 100 bytes of expansion due to startcodes being longer than ++ // length fields. ++ while (nalu_ptr + kLengthFieldLength <= packet_buffer + packet.sizeBytes) { + size_t length = BufferToUWord16(nalu_ptr); +- required_length += ++ if (nalu_ptr + kLengthFieldLength + length <= packet_buffer + packet.sizeBytes) { ++ required_length += + length + (packet.insertStartCode ? kH264StartCodeLengthBytes : 0); +- nalu_ptr += kLengthFieldLength + length; ++ nalu_ptr += kLengthFieldLength + length; ++ } else { ++ // Something is very wrong! ++ RTC_LOG(LS_ERROR) << "Failed to insert packet due to corrupt H264 STAP-A"; ++ return 0; ++ } + } + ShiftSubsequentPackets(packet_it, required_length); + nalu_ptr = packet_buffer + kH264NALHeaderLengthInBytes; + uint8_t* frame_buffer_ptr = frame_buffer + offset; +- while (nalu_ptr < packet_buffer + packet.sizeBytes) { ++ // we already know we won't go past end-of-buffer ++ while (nalu_ptr + kLengthFieldLength <= packet_buffer + packet.sizeBytes) { + size_t length = BufferToUWord16(nalu_ptr); + nalu_ptr += kLengthFieldLength; + frame_buffer_ptr += Insert(nalu_ptr, length, packet.insertStartCode, +@@ -447,12 +457,23 @@ int VCMSessionInfo::InsertPacket(const VCMPacket& packet, + return -2; + + if (packet.codec() == kVideoCodecH264) { +- frame_type_ = packet.video_header.frame_type; ++ // H.264 can have leading or trailing non-VCL (Video Coding Layer) ++ // NALUs, such as SPS/PPS/SEI and others. Also, the RTP marker bit is ++ // not reliable for the last packet of a frame (RFC 6184 5.1 - "Decoders ++ // [] MUST NOT rely on this property"), so allow out-of-order packets to ++ // update the first and last seq# range. Also mark as a key frame if ++ // any packet is of that type. ++ if (frame_type_ != VideoFrameType::kVideoFrameKey) { ++ frame_type_ = packet.video_header.frame_type; ++ } + if (packet.is_first_packet_in_frame() && + (first_packet_seq_num_ == -1 || + IsNewerSequenceNumber(first_packet_seq_num_, packet.seqNum))) { + first_packet_seq_num_ = packet.seqNum; + } ++ // Note: the code does *not* currently handle the Marker bit being totally ++ // absent from a frame. It does not, however, depend on it being on the last ++ // packet of the 'frame'/'session'. + if (packet.markerBit && + (last_packet_seq_num_ == -1 || + IsNewerSequenceNumber(packet.seqNum, last_packet_seq_num_))) { +@@ -499,7 +520,6 @@ int VCMSessionInfo::InsertPacket(const VCMPacket& packet, + + size_t returnLength = InsertBuffer(frame_buffer, packet_list_it); + UpdateCompleteSession(); +- + return static_cast(returnLength); + } + +diff --git a/test/fuzzers/rtp_packet_fuzzer.cc b/test/fuzzers/rtp_packet_fuzzer.cc +index 60afb986de..0e10a8fa3a 100644 +--- a/test/fuzzers/rtp_packet_fuzzer.cc ++++ b/test/fuzzers/rtp_packet_fuzzer.cc +@@ -164,6 +164,11 @@ void FuzzOneInput(const uint8_t* data, size_t size) { + // This extension requires state to read and so complicated that + // deserves own fuzzer. + break; ++ case kRtpExtensionCsrcAudioLevel: { ++ CsrcAudioLevelList levels; ++ packet.GetExtension(&levels); ++ break; ++ } + } + } + +diff --git a/test/vcm_capturer.cc b/test/vcm_capturer.cc +index a037f9eff6..e02fc722b2 100644 +--- a/test/vcm_capturer.cc ++++ b/test/vcm_capturer.cc +@@ -81,7 +81,7 @@ void VcmCapturer::Destroy() { + return; + + vcm_->StopCapture(); +- vcm_->DeRegisterCaptureDataCallback(); ++ vcm_->DeRegisterCaptureDataCallback(this); + // Release reference to VCM. + vcm_ = nullptr; + } +-- +2.34.1 + -- cgit v1.2.3