diff --git a/.gitignore b/.gitignore
index 0bab26c22a..be283a97a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
example/pubspec.lock
pubspec.lock
example/ios/Podfile.lock
+example/macos/Podfile.lock
GeneratedPluginRegistrant.java
example/android/.gradle
WorkspaceSettings.xcsettings
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2a1b4f9d9f..5622dfa68c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,785 +1,19 @@
# Changelog
---------------------------------------------
-[0.11.1] - 2024-06-17
+[0.0.6] - 2025.03.04
+- get remote participent's track from the stream id.
-* [macOS] Downgrade macOS system dependencies to 10.14.
+[0.0.5] - 2025.02.24
+- Dependencies updated to latest version.
-[0.11.0] - 2024-06-17
+[0.0.4] - 2024.10.18
+- Dependencies updated to latest version.
-* [Native] upgrade libwebrtc to m125.6422.
+[0.0.3] - 2024.07.17
+[0.0.2] - 2024.07.17
-[0.10.8] - 2024-06-05
+- Windows Support Fix
-* [iOS] fix(platform_view): fit cover works wrong (#1593)
-* [iOS/macOS] fix: Fix the issue that the video is not displayed when using 'video': true (#1592)
-* [Web] bump dart_webrtc to 1.4.6.
+[0.0.1] - 2024.07.17
-[0.10.7] - 2024-05-30
-
-* [iOS] feat: add PlatformView Renderer for iOS. (#1569)
-* [iOS] fix: audio session control for iOS. (#1590)
-
-[0.10.6] - 2024-05-13
-
-* [Web] Some important fixes for web.
-
-[0.10.5] - 2024-05-13
-
-* [Android] fix: make MediaDeviceInfo (Audio deviceId, label, groupId) consistent. (#1583)
-
-[0.10.4] - 2024-05-06
-
-* [iOS/macOS] chore: update swift webrtc sdks to 114.5735.10 (#1576)
-* [Android] fix: actually call selectAudioOutput in enableSpeakerButPreferBluetooth
-* [iOS] fix: remember speakerphone mode for ensureAudioSession (#1568)
-* [Windows/Linux] Fix handling of unimplemented method (#1563)
-
-[0.10.3] - 2024-04-09
-
-* [iOS/macOS] Fix compilation warning for iOS/macOS.
-
-[0.10.2] - 2024-04-08
-
-* [Native/Web] feat: add keyRingSize/discardFrameWhenCryptorNotReady to KeyProviderOptions.
-
-[0.10.1] - 2024-04-08
-
-* [Web] fix renderer issue for web.
-
-[0.10.0] - 2024-04-08
-
-* [Web] move to package:web.
-
-[0.9.48+hotfix.1] - 2024-02-05
-
-* [Android] bump version for libwebrtc.
-
-[0.9.48] - 2024-02-05
-
-* [Android] bump version for libwebrtc.
-* [iOS] Supports ensureAudioSsession method for iOS only. (#1514)
-* [Android] fix android wrong display size. (#1508).
-
-[0.9.47] - 2023-11-29
-
-* [Windows/Linux] fix: Check the invalid value of candidate and session description. (#1484)
-* [Windows/Linux/macOS] fix: screen sharing issue for desktop.
-* [Web] fix: platformViewRegistry getter is deprecated (#1485)
-* [Dart] Throw exception for set src object (#1491).
-
-[0.9.46] - 2023-10-25
-
-* [iOS/macOS] fix: Crop video output size to target settings. (#1472)
-* [Android] fix: Fix bluetooth sco not stopping after room disconnect (#1475)
-
-[0.9.45] - 2023-09-27
-
-* [iOS/macOS] fix: send message on non-platform thread.
-* [Windows] fix: fix setSrcObj with trackId for Windows.
-* [Windows] fix: fix "unlock of unowned mutex" error when call "captureFrame()" func on windows.
-
-[0.9.44] - 2023-09-25
-
-* [Windows] fix: fix Renderer bug for Windows.
-* [Native] fix: Use independent threads to process frame encryption/decryption
-* [Native] fix: Correct handle SIF frame
-* [Native] fix: Fix a fault tolerance judgment failure
-
-[0.9.43] - 2023-09-20
-
-* [Native] fix: send frame cryptor events from signaling thread.
-* [Native] fix: h264 freeze when using E2EE.
-
-[0.9.42+hotfix.1] - 2023-09-15
-
-* [Windows/Linux] fix: fix cannot start vp8/h264 encoder correctly.
-
-[0.9.42] - 2023-09-15
-
-* [Dart/Native] feat: add more framcryptor api (#1444)
-* [Dart/Native] feat: support scalability mode (#1442)
-* [Android] fix: Turn off audio routing in non communication modes (#1438)
-
-* [Android] feat: Add more control over android audio options.
-
-[0.9.41] - 2023-08-30
-
-* [Android] feat: Add more control over android audio options.
-
-[0.9.40] - 2023-08-16
-
-* [Windows/Linux] fix: nullptr checking for sender/receiver for getStats.
-
-[0.9.39] - 2023-08-14
-
-* [Dart/Native] feat: add async methods for getting pc states.
-
-[0.9.38] - 2023-08-11
-
-* [Android] fix: Expose helper to clearCommunicationDevice on AudioManager.AUDIOFOCUS_LOSS
-* [Android] feat: support force SW codec list for android, and disable HW codec for VP9 by default.
-* [Android] fix: issue for audio device switch (#1417)
-* [Android/iOS] feat: Added setZoom method to support camera zooming while streaming. (#1412).
-
-[0.9.37] - 2023-08-07
-
-* [Native] fix: Skip set_sdp_fmtp_line if sdpFmtpLine is empty.
-* [Android] fix: fix android earpiece not being replaced after wired headset is disconnected.
-* [Dart] fix: partially rebuild RTCVideoView when renderVideo value changes.
-* [Android] feat: expose android audio modes.
-* [Android] feat: support forceSWCodec for Android.
-* [Linux] fix: add $ORIGIN to rpath.
-
-[0.9.36] - 2023-07-13
-
-* [Native] upgrade libwebrtc to m114.5735.02.
-* [Windows/Linux] Add implementation to MediaStreamTrack.captureFrame() for linux/windows.
-* [Darwin/Android] Support to ignore network adapters used for ICE on Android, iOS and macOS.
-
-[0.9.35] - 2023-06-30
-
-* [iOS] feat: expose audio mode for ios.
-* [Darwin] fix: compiler warning for Darwin.
-* [Dart] Fix setMicrophoneMute() not awaitable.
-* [Native] Update libwebrtc to m114.
-* [Dart/Web] Separate frame cryptor to dart-webrtc.
-
-[0.9.34] - 2023-06-14
-
-* [Web] fix facingMode for flutter web mobile.
-
-[0.9.33] - 2023-06-08
-
-* [Android] fix frame drops for android.
-
-[0.9.32] - 2023-05-30
-
-* [Android] fix issue for get user audio.
-* [Android] fix getStats throw LinkedHasMap exception.
-
-[0.9.31] - 2023-05-23
-
-* [Darwin] Improve iOS/macOS H264 encoder (Upgrade to WebRTC-SDK M104.5112.17).
-
-[0.9.30+hotfix.2] - 2023-05-18
-
-* [Windows/Linux] fix bug for eventchannel proxy.
-* [Windows/Linux] fix: crash for pc.close/dispose on win/linux. (#1360)
-
-[0.9.30+hotfix.1] - 2023-05-17
-
-* [Windows/Linux] Fix compiler error.
-
-[0.9.30] - 2023-05-16
-
-* [Darwin] Handle exceptions for frame rate settings for darinw. (#1351)
-* [Android] Fix bluetooth device enumerate. (#1349)
-* [Darwin/Android/Windows/Linux] Added maxIPv6Networks configuration (#1350)
-* [iOS] Fix: broadcast extension not found fallback logic (#1347)
-* [Android] Move the call of capturer.stopCapture() outside the main thread to avoid blocking of flutter method call.
-* [Windows/Linux] Fix the crash issue of video room (#1343)
-
-[0.9.29+hotfix.1] - 2023-05-08
-
-* [Android] fix: application context null when app is terminated.
-* [Android/iOS] feat: add way to enable speaker but prefer bluetooth.
-
-[0.9.28] - 2023-05-08
-
-* [Windows/Linux] fix: use the correct transceiver id.
-* [Windows/Linux] fix: Support restart camera for Windows/Linux.
-
-[0.9.27] - 2023-04-27
-
-* [Darwin/Android/Windows/Linux] feat: framecryptor.
-* [Windows/Linux] Fix the type/code mistake.
-* [Windows/Linux] Fix uneffective RTPTransceiver::GetCurrentDirection.
-* [Windows/Linux] RTPtransceiver::getCurrentDirection returns correct value.
-
-[0.9.26] - 2023-04-16
-
-* [iOS/macOS] motify h264 profile-level-id to support high resolution.
-* [Dawrin/Android/Windows] feat: add RTCDegradationPreference to RTCRtpParameters.
-
-[0.9.25] - 2023-04-10
-
-* [Dawrin/Android/Windows] Add `addStreams` to `RTCRtpSender`
-* [Android] fix: label for Wired Headset. (#1305)
-* [Dawrin/Android/Windows] Feat/media stream track get settings (#1294)
-* [Android/iOS] Fix track lookup in the platform specific code for Android and iOS (#1289)
-* [iOS] fix: ICE Connectivity doesn't establish with DualSIM iPhones.
-* [Android] Switch to webrtc hosted on maven central (#1288)
-
-[0.9.24] - 2023-03-07
-
-* [iOS] avaudiosession mode changed to AVAudioSessionModeVideoChat (#1285)
-* [macOS] fix memory leak for screen capture.
-
-[0.9.23] - 2023-02-17
-
-* [Windows/Linux] Updated libwebrtc binary for windows/linux to fix two crashes.
-
-[0.9.22] - 2023-02-14
-
-* [iOS] fix: Without any setActive for rtc session, libwebrtc manages the session counter by itself. (#1266)
-* [dart] fix: remove rtpsender.dispose.
-* [web] fix video renderer issue for safari.
-* [macOS] Fixed macOS desktop capture crash with simulcast enabled.
-* [macOS] Fix the crash when setting the fps of the virtual camera.
-
-[0.9.21] - 2023-02-10
-
-* [Web] Fix: RTCRtpParameters.fromJsObject for Firefox.
-* [Web] Add bufferedamountlow.
-* [Android] Fixed frame capturer returning images with wrong colors (#1258).
-* [Windows] bug fix.
-
-[0.9.20] - 2023-02-03
-
-* [Dawrin/Android/Windows] Add getCapabilities/setCodecPreferences methods
-* [Darwin] buffered amount
-* [Linux] Fixed audio device name buffer size
-* [Android] Start audioswitch and only activate it when needed
-* [Darwin] Fix typo which broke GcmCryptoSuites
-
-[0.9.19] - 2023-01-10
-
-* [Dart] Fix getStats: change 'track' to 'trackId' (#1199)
-* [Android] keep the audio switch after stopping (#1202)
-* [Dart] Enhance RTC video view with placeholder builder property (#1206)
-* [Android] Use forked version of audio switch to avoid BLUETOOTH_CONNECT permission (#1218)
-
-[0.9.18] - 2022-12-12
-
-* [Web] Bump dart_webrtc to 1.0.12, Convert iceconnectionstate to connectionstate for Firefox.
-* [Android] Start AudioSwitchManager only when audio track added (fix #1163) (#1196)
-* [iOS] Implement detachFromEngineForRegistrar (#1192)
-* [iOS] Handle Platform Exception on addCandidate (#1190)
-* [Native] Code format with clang-format.
-
-[0.9.17] - 2022-11-28
-
-* [Android] Update android webrtc version to 104.5112.05
-* [iOS] Update WebRTC.xframework version to 104.5112.07
-
-[0.9.16] - 2022-11-14
-
-* [Linux] Fixed compiler error for flutter 3.3.8.
-* [Linux] Remove 32-bit precompiled binaries.
-* [Linux] Supports linux-x64 and linux-arm64.
-
-[0.9.15] - 2022-11-13
-
-* [Linux] Add Linux Support.
-
-[0.9.14] - 2022-11-12
-
-* [iOS] Fix setSpeakerOn has no effect after change AVAudioSession mode to playback.
-
-[0.9.13] - 2022-11-12
-
-* [Dart] Change MediaStream.clone to async.
-* [iOS] Fixed the bug that the mic indicator light was still on when mic recording was stopped.
-* [iOS/macOS/Android/Windows] Allow sdpMLineIndex to be null when addCandidate.
-* [macOS] Frame capture support for MacOS.
-* [Android] Add enableCpuOveruseDetection configuration (#1165).
-* [Android] Update comments (#1164).
-
-[0.9.12] - 2022-11-02
-
-* [iOS] Fixed the problem that iOS earphones and speakers do not switch.
-* [Windows] fix bug for rtpSender->RemoveTrack/pc->getStats.
-* [iOS] Return groupId.
-* [Web] MediaRecorder.startWeb() should expose the timeslice parameter.
-* [iOS] Implement RTCPeerConnectionDelegate didRemoveIceCandidates method.
-* [iOS] fix disposing Broadcast Sharing stream.
-
-[0.9.11] - 2022-10-16
-
-* [iOS] fix audio route/setSpeakerphoneOn issues.
-* [Windows] fix: Have same remote streams id then found wrong MediaStream.
-* [Dart] feat: RTCVideoRenderer supports specific trackId when setting MediaStream.
-
-[0.9.9+hotfix.1] - 2022-10-12
-
-* [Darwin] Fix getStats for darwin when trackId is NSNull.
-
-[0.9.9] - 2022-10-12
-
-* [Darwin/Android/Windows] Support getStats for RtpSender/RtpReceiver (Migrate from Legacy to Standard Stats for getStats).
-* [Android] Dispose streams and connections.
-* [Android] Support rtp transceiver direction type 4.
-* [Web] Update dart_webrtc dependendency.
-
-[0.9.8] - 2022-09-30
-
-* [Android] fix: Make sure local stream/track dispose correctly.
-* [Android] Remove bluetooth permission on peerConnectionInit.
-* [iOS] Fix system sound interruption on iOS (#1099).
-* [Android] Fix: call mode on app start (#1097).
-* [Dart] Avoid renderer initialization multiple times (#1067).
-
-[0.9.7] - 2022-09-13
-
-* [Windows] Support sendDtmf.
-* [Windows] Fixed getStats.
-
-[0.9.6] - 2022-09-06
-
-* [Dart] The dc created by didOpenDataChannel needs to set state to open.
-* [Dart] Added callback onFirstFrameRendered.
-
-[0.9.5] - 2022-08-30
-
-* [Android] fix: Fix crash when using multiple renderers.
-* [Android] fix bug with track dispose cannot close video
-* [Andorid/iOS/macOS/Windows] Fix bug of missing events in data-channel.
-
-[0.9.4] - 2022-08-22
-
-* [Andorid/iOS/macOS/Windows] New audio input/output selection API, ondevicechange event is used to monitor audio device changes.
-
-[0.9.3] - 2022-08-15
-
-* [Windows/macOS] Fix UI freeze when getting thumbnails.
-
-[0.9.2] - 2022-08-09
-
-* [Android] update libwebrtc to com.github.webrtc-sdk:android:104.5112.01.
-* [iOS/macOS] update WebRTC-SDK to 104.5112.02.
-* [Windows] update libwebrtc.dll to 104.5112.02.
-
-[0.9.1] - 2022-08-01
-
-* [iOS] fix : iOS app could not change camera resolutions cause by wrong datatype in the video Contraints.
-* [Darwin] bump version for .podspec.
-
-[0.9.0] - 2022-07-27
-
-* [macOS] Added screen-sharing support for macOS
-* [Windows] Added screen-sharing support for Windows
-* [iOS/macOS] fix: Fix compile warning for Darwin
-* [Darwin/Android/Windows] fix: Fix typo peerConnectoinEvent -> peerConnectionEvent for EventChannel name (#1019)
-
-[0.8.12] - 2022-07-15
-
-* [Darwin]: fix: camera release.
-
-[0.8.11] - 2022-07-11
-
-* [Windows] Fix variant exception of findLongInt. (#990)
-* [Windows] fix unable to get username/credential when parsing iceServers containing urls
-* [iOS] Fix RTCAudioSession properties set with libwebrtc m97, Fixes #987.
-
-[0.8.10] - 2022-06-28
-
-* [iOS] IPC Broadcast Upload Extension support for Screenshare
-
-[0.8.9] - 2022-06-08
-
-* [Android] Fixes DataChannel issue described in #974
-* [iOS] Fixes DataChannel issue described in #974
-* [Dawrin/Android/Windows] Split data channel's webrtc id from our internal id (#961)
-* [Windows] Update to m97.
-* [Windows] Add PeerConnectionState
-* [Windows] Fix can't open mic alone when built-in AEC is enabled.
-
-[0.8.8] - 2022-05-31
-
-* [Android] Added onBufferedAmountChange callback which will return currentBuffer and changedBuffer and implemented bufferedAmount.
-* [Android] Added onBufferedAmountLow callback which will return currentBuffer ans will be called if bufferedAmountLowThreshold is set a value.
-
-[0.8.7] - 2022-05-18
-
-* [iOS/macOS] fix: Use RTCYUVHelper instead of external libyuv library (#954).
-* [iOS/macOS] Flutter 3.0 crash fixes, setStreamHandler on main thread (#953)
-* [Android] Use mavenCentral() instead of jcenter() (#952)
-* [Windows] Use uint8_t* instead of string in DataChannel::Send method, fix binary send bug.
-* [Android] fix: "Reply already submitted" error and setVolume() not working on remote streams.
-
-[0.8.6] - 2022-05-08
-
-* [Web/Android/iOS/macOS] Support null tracks in replaceTrack/setTrack.
-* [macOS] Remove absolute path from resolved spec to make checksum stable.
-* [Android] Android 12 bluetooth permissions.
-* [Dart] fix wrong id type for data-channel.
-* [Android] Release i420 Buffer in FrameCapturer.
-
-[0.8.5] - 2022-04-01
-
-* [Dart] Expose RTCDataChannel.id (#898)
-* [Android] Enable H264 high profile for SimulcastVideoEncoderFactoryWrapper (#890)
-
-[0.8.4] - 2022-03-28
-
-* [Android] Fix simulcast factory not sending back EncoderInfo (#891)
-* [Android] fix: correct misspell in method screenRequestPermissions (#876)
-
-[0.8.3] - 2022-03-01
-
-* [Android/iOS] Update android/ios webrtc native sdk versions.
-* [Windows] Feature of selecting i/o audio devices by passing sourceId and/or deviceId constraints (#851).
-
-[0.8.2] - 2022-02-08
-
-* [Android/iOS/macOS/Web] Add restartIce.
-
-[0.8.1] - 2021-12-29
-
-* [Android/iOS] Bump webrtc-sdk version to 93.4577.01.
-
-[0.8.0] - 2021-12-05
-
-* [Dart] Refactor: Use webrtc interface. (#777)
-* [iOS] Fix crashes for FlutterRPScreenRecorder stop.
-* [Web] Don't stop tracks when disposing MediaStream (#760)
-* [Windows] Add the necessary parameters for onRemoveTrack (#763)
-* [Example] Properly start foreground service in example (#764)
-* [Android] Fix crash for Android, close #757 and #734.
-* [Dart] Fix typo in deprecated annotations.
-* [iOS] Fix IOS captureFrame and add support for remote stream captureFrame (#778)
-* [Windows] Fix parsing stun configuration (#789)
-* [Windows] Fix mute (#792)
-* [iOS/Android/Windows] New video constraints syntax (#790)
-
-[0.7.1] - 2021-11-04
-
-* [iOS/macOS] Update framework.
-* [Android] Update framework.
-* [Windows] Implement mediaStreamTrackSetEnable (#756).
-* [iOS/macOS] Enable audio capture when acquiring track.
-* [Android] Call stopCaptureWithCompletionHandler instead (#748)
-* [Windows] Fix bug for windows.
-
-[0.7.0+hotfix.2] - 2021-10-21
-
-* [iOS/macOS] Update .podspec for Darwin.
-
-[0.7.0+hotfix.1] - 2021-10-21
-
-* [Android] Fix bug for createDataChannel.
-
-[0.7.0] - 2021-10-20
-
-* [Android] Enable Android simulcast (#731)
-* [macOS] Use pre-compiled WebRTC for macOS. (#717)
-* [iOS/macOS] Fix the correct return value of createDataChannel under darwin.
-* [Windows] Fix using the wrong id to listen datachannel events.
-* [Dart] Fix(mediaStreamTrackSetEnable): remote track is unavaiable (#723).
-
-[0.6.10+hotfix.1] - 2021-10-01
-
-* [Web] Fix compiler errors for web.
-
-[0.6.10] - 2021-10-01
-
-* [iOS] Fix bug for RtpTransceiver.getCurrentDirection.
-* [Dart] Improve MethodChannel calling.
-
-[0.6.9] - 2021-10-01
-
-* [iOS] Update WebRTC build (#707).
-* [Windows] Add Unified-Plan support for windows. (#688)
-* [iOS] Improve audio handling on iOS (#705)
-
-[0.6.8] - 2021-09-27
-
-* [Android] Use ApplicationContext to verify permissions when activity is null.
-* [iOS] Add support for lightning microphone. (#693)
-* [Windows] Fix FlutterMediaStream::GetSources.
-* [Web] Fix Flutter 2.5.0 RTCVideoRendererWeb bug (#681)
-* [Web] Bug fix (#679)
-
-[0.6.7] - 2021-09-08
-
-* [Android] upgrade webrtc sdk to m92.92.4515.
-* [Web] `addTransceiver` bug fix (#675)
-* [Web] Use low-level jsutil to call createOffer/createrAnswer to solve the issue on safari/firefox.
-* [Dart] Fix currentDirection/direction implementation confusion.
-
-[0.6.6] - 2021.09.01
-
-* [Sponsorship] Thanks for LiveKit sponsorship.
-* [Web] Avoid removing all audio elements when stopping a single video renderer (#667)
-* [Web] Properly cleanup srcObject to avoid accidental dispose
-* [Dart] Removed warnings (#647)
-* [Web] Switch transferFromImageBitmap to be invoked using js.callMethod (#631)
-* [Web] Fix sending binary data over DataChannel in web implementation. (#634)
-* [Darwin] Nullable return for GetLocalDescription/GetRemoteDiscription
-* [Darwin] Fix incorrect argument name at RTCRtpSender (#600)
-
-[0.6.5] - 2021.06.18
-
-* [Android] Falling back to the first available camera fix #580
-* [Android] Fix application exit null-pointer exception (#582)
-* [Dart] Add label getter to DataChannel Interface (#585)
-* [Dart] Fix exception raised at RTCPeerConnection.removeTrack and RTCRtpSender.setParameters (#588)
-* [Dart] Fix: null check (#595)
-* [Dart] Fix: null check for RTCRtpTransceiverNative.fromMap
-
-[0.6.4] - 2021.05.02
-
-* [Android] Fix getting screen capture on Huawei only successful in the first time. (#523)
-* [Android] Add configuration "cryptoOptions" in parseRTCConfiguration().
-* [Dart] Change getLocalDescription,getRemoteDescription,RTCRtpSenderWeb.track returns to nullable.
-* [Dart] Fixed bug in RTCPeerConnectionWeb.removeTrack.
-* [Dart] Change MediaStreamTrack.captureFrame returns to ByteBuffer to compatible with web API.
-* [Dart] Do null safety check in onRemoveStream,onRemoveTrack and MediaStream.getTrackById.
-* [Android] Add reStartCamera method when the camera is preempted by other apps.
-* [Web] Refactored RTCVideoRendererWeb and RTCVideoViewWeb, using video and audio HTML tags to render audio and video streams separately.
-
-[0.6.3] - 2021.04.03
-
-* [Dart] Change RTCRtpSender.track to nullable.
-* [Web] Fix RTCVideoView/Renderer pauses when changing child in IndexedStack.
-
-[0.6.2] - 2021.04.02
-
-* [Dart] Use enumerateDevices instead of getSources.
-* [Android] Use flutter_background to fix screen capture example.
-
-[0.6.1] - 2021.04.02
-
-* [Darwin] Fixed getting crash when call setLocalDescription multiple time.
-* [Dart] Get more pub scores.
-
-[0.6.0] - 2021.04.01
-
-* [Sponsorship] Thanks for Stream sponsorship (#475)
-* [Android] Fixed a crash when switching cameras on Huawei devices.
-* [Windows] Correct signalingState & iceConnectionState event name on Windows. (#502)
-* [Dart] Clip behaviour. (#511)
-* [Dart] null-safety (@wer-mathurin Thanks for the hard work).
-* [Dart] Fix setMicrophoneMute (#466)
-* [Web] Fix pc.addTransceiver method, fix RTCRtpMediaType to string, fix (#437)
-* [Android] fix sdpSemantics issue (#478)
-
-[0.6.0-nullsafety.0] - 2021.03.22
-
-* [Dart] null-safety (@wer-mathurin Thanks for the hard work).
-
-[0.5.8] - 2021.01.26
-
-* [Web] Support selecting audio output.
-* [Web] Fix issue for getDisplayMedia with audio.
-* [Windows] Add Windows Support.
-* [macOS] Fix compile error for macos.
-* [Dart] Add FilterQuality to RTCVideoView.
-* [iOS/Android] Unified plan gettracks.
-* [iOS/Android] Bluetooth switching enabled when switching `enableSpeakerphone` value (if they are connected). #201 (#435)
-* [Android] Increase necessary Android min SDK version after add Unified-Plan API.
-
-[0.5.7] - 2020.11.21
-
-* [Web] Fix events callback for peerconnection.
-
-[0.5.6] - 2020.11.21
-
-* [Android/Darwin/Web] Add onResize event for RTCVideoRenderer.
-
-[0.5.5] - 2020.11.21
-
-* [Android/Darwin] Fix Simulcast issue.
-
-[0.5.4] - 2020.11.21
-
-* [Native/Web] Add videoWidth/videoHeight getter for RTCVideoRenderer.
-* [Web] Add optional parameter track to call getStats.
-
-[0.5.3] - 2020.11.21
-
-* Fix bug.
-
-[0.5.2] - 2020.11.19
-
-* Improve web code
-
-[0.5.1] - 2020.11.19
-
-* Improve unfied-plan API for web.
-* Add getTransceivers,getSenders, getReceivers methods.
-
-[0.5.0+1] - 2020.11.18
-
-* Remove dart-webrtc and reuse the code in dart:html
- because the code generated by package:js cannot be run in dart2js.
-
-[0.5.0] - 2020.11.15
-
-* [Web] Add Unified-Plan for Flutter Web.
-* [Web] Add video frame mirror support for web.
-* [Web] Support Simulcast for web.
-* [Web] Use dart-webrtc as flutter web plugin.
-* [Android/Darwin] Fix crash when unset streamIds in RtpTransceiverInit.
-* [Dart]Change the constraints of createOffer/createAnswer as optional.
-* [iOS]Fix adding track to stream igal committed (#413)
-
-[0.4.1] - 2020.11.11
-
-* Add transceiver to onTrack events.
-* Remove unnecessary log printing.
-* Fixed a crash caused by using GetTransceivers under non-unified-plan,
- close #389.
-* FIX - Invalid type inference (#392)
-* [Web]Add onEnded and onMuted for Web (#387)
-* [Darwin]Fix PeerConnectionState for darwin.
-* [Darwin] Fix compilation warning under darwin.
-* [Android] Fixed 'Sender is null' issue when removing track. (#401)
-* [iOS] fix removeTrack methodChannel response, onTrack's `stream` and `track` not being registered in native.
-* [Darwin/Android] `RtpSender` `setParameters` functionality.
-
-[0.4.0] - 2020.10.14
-
-* Support Unified-Plan for Android/iOS/macOS.
-* Add PeerConnectionState and add RTCTrackEvent..
-* [Android] Upgrade GoogleWebRTC@android to 1.0.32006.
-* [iOS] Upgrade GoogleWebRTC@ios to 1.1.31999.
-* Api standardization across implementation (#364), thanks @wer-mathurin.
-
-[0.3.3] - 2020.09.14
-
-* Add RTCDTMFSender for mobile, web and macOS.
-* Improve RenegotiationNeededCallback.
-* Refactor RTCVideoView for web and solve the resize problem.
-* Reduce code size.
-
-[0.3.2] - 2020.09.11
-
-* Reorganize the directory structure.
-* Replace class name navigator to MediaDevices.
-* Downgrade pedantic version to 1.9.0.
-
-[0.3.1] - 2020.09.11
-
-* [Dart] Apply pedantic linter and more rigorous analysis options.
-
-[0.3.0+1] - 2020.09.06
-
-* [Dart] FIX - missing null check onIceGatheringState (web)
-
-[0.3.0] - 2020.09.05
-
-* [Dart] Improve RTCVideoView.
-* [Android] Refactors Android plugin alongside the embedding V2 migration.
-* [Dart] Fix .ownerTag not defined for web.
-* [Dart] Added label as read only property.
-* [macOS] Updated WebRTC framework to work with AppStoreConnect.
-* [Dart] Make 'constraints' argument optional.
-* [Dart] Make createOffer constraints optional.
-* [iOS/Android/Web] Adding createLocalMediaStream method to PeerConnectionFactory.
-* [Web] Fixing multiple video renderers on the same HTML page for Flutter Web.
-* [iOS] Add peerConnectionId to data channel EventChannel.
-* [Android] Add library module ProGuard configuration file.
-* [iOS] Fix typo in render size change check condition
-* [README] Add missed Android usage hint.
-
-[0.2.8] - 2020.04.22
-
-* [macOS/iOS] Fix typo in render size change check condition.
-* [macOS] Fix hot restart videoCapturer crash.
-* [Android] Fix Android crash when getUserVideo.
-
-[0.2.7] - 2020.03.15
-
-* [macOS] Fix crash with H264 HW Encoder.
-* [Web] Add addTransceiver API.
-* [Android] Removed duplicate method that was causing compilation error.
-* [iOS] Use MrAlek Libyuv pod fixing incompatibility with FirebaseFirestore.
-* [iOS] Upgrade GoogleWebRTC dependency to 1.1.29400.
-
-[0.2.6] - 2020.02.03
-
-* Fixed the interruption of the Bluetooth headset that was playing music after the plugin started.
-
-[0.2.4] - 2020.02.03
-
-* Fixed bug.
-
-[0.2.3] - 2020.02.03
-
-* Fixed bug for enableSpeakerphone (Android/iOS).
-* Fix RtcVideoView not rebuild when setState called and renderer is changed.
-* Fix Android frame orientation.
-
-[0.2.2] - 2019.12.13
-
-* Removed the soft link of WebRTC.framework to fix compile errors of macos version when third-party flutter app depends on plugins
-
-[0.2.1] - 2019.12.12
-
-* Code format.
-* Remove unused files.
-
-[0.2.0] - 2019.12.12
-
-* Add support for macOS (channel dev).
-* Add support for Flutter Web (channel dev).
-* Add hasTorch support for Android (Camera2 API) and iOS.
-* Fix(PeerConnections) split dispose and close
-* Add microphone mute support for Android/iOS.
-* Add enable speakerphone support for Android/iOS.
-* Fix 'createIceServer' method Invalid value error (Android).
-* Store SignalingState/IceGatheringState/IceConnectionState in RTCPeerConnection.
-* Fixed rendering issues caused by remote MediaStream using the same msid/label when using multiple PeerConntions.
-
-[0.1.7] - 2019.05.16
-
-* Add RTCDataChannelMessage for data channel and remove base64 type.
-* Add streaming API for datachannel messages and state changes.
-* Remove cloudwebrtc prefix in the plugin method/event channel name.
-* Other bug fixes.
-
-[0.1.6] - 2019.03.31
-
-* Add getConfiguration/setConfiguration methods for Peerconnection.
-* Add object fit for RTCVideoView.
-
-[0.1.5] - 2019.03.27
-
-* Remove unnecessary parameter for getLocalDescription method.
-
-[0.1.4] - 2019.03.26
-
-* switchCamera method now returns future with isFrontCamera as result
-* Fix camera stuck in rare cases
-* Add getLocalDescription/getRemoteDescription methods
-
-[0.1.3] - 2019.03.25
-
-* Add horizontal flip (mirror) function for RTCVideoView.
-* Fixed ScreenCapture preview aspect ratio for Android.
-
-[0.1.2] - 2019.03.24
-
-* Fix compilation failure caused by invalid code.
-
-[0.1.1] - 2019.03.24
-
-* Migrated to AndroidX using Refactoring from Andoid Studio
-* Fix mediaStreamTrackSetEnable not working.
-* Fix iOS can't render video when resolution changes.
-* Some code style changes.
-
-[0.1.0] - 2019.01.21
-
-* Fix camera switch issues.
-* Support data channel, please use the latest demo to test.
-* Support screen sharing, but the work is not perfect, there is a problem with the local preview.
-
-[0.0.3] - 2018.12.20
-
-* Update WebRTC to 1.0.25821.
-* Implemented MediaStreamTrack.setVolume().
-* Add public getter for texture id.
-* Fixed getUserMedia does not work for capturing audio only.
-
-[0.0.2] - 2018.11.04
-
-* Add 'enabled' method for MediaStreamTrack.
-* Implement switch camera.
-* Add arm64-v8a and x86_64 architecture support for android.
-
-[0.0.1] - 2018.05.30
-
-* Initial release.
+- Initial release.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index bbab725aab..0000000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Contributing
-
-We love contributions from everyone, whether it's raising an issue, reporting a bug, adding a feature, or helping improve a document.
-Maintaining the flutter-webrtc plugin for all platforms is not an easy task, so everything you do is support for the project.
-
-# Pull Request
-We recommend that you create a related issue before PR so that others can find the answers they want in the issues.
diff --git a/README.md b/README.md
index f8387d1160..2436fa121a 100644
--- a/README.md
+++ b/README.md
@@ -1,48 +1,20 @@
-# Flutter-WebRTC
-
-[](https://opencollective.com/flutter-webrtc) [](https://pub.dartlang.org/packages/flutter_webrtc) [](https://gitter.im/flutter-webrtc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [](https://join.slack.com/t/flutterwebrtc/shared_invite/zt-q83o7y1s-FExGLWEvtkPKM8ku_F8cEQ)
+# VideoSDK-WebRTC
WebRTC plugin for Flutter Mobile/Desktop/Web
-
-
-Sponsored with 💖   by
-
-
-
-
-Enterprise Grade APIs for Feeds, Chat, & Video. Try the Flutter Video tutorial 💬
-
-
-
-
-
-
-
-
- LiveKit - Open source WebRTC infrastructure
-
-
## Functionality
| Feature | Android | iOS | [Web](https://flutter.dev/web) | macOS | Windows | Linux | [Embedded](https://github.com/sony/flutter-elinux) | [Fuchsia](https://fuchsia.dev/) |
| :-------------: | :-------------:| :-----: | :-----: | :-----: | :-----: | :-----: | :-----: | :-----: |
| Audio/Video | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | |
| Data Channel | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | |
-| Screen Capture | :heavy_check_mark: | [:heavy_check_mark:(*)](https://github.com/flutter-webrtc/flutter-webrtc/wiki/iOS-Screen-Sharing) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | |
+| Screen Capture | :heavy_check_mark: | [:heavy_check_mark:(*)](https://github.com/VideoSDK-webrtc/VideoSDK-webrtc/wiki/iOS-Screen-Sharing) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | |
| Unified-Plan | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | |
| Simulcast | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | [WIP] | |
| MediaRecorder | :warning: | :warning: | :heavy_check_mark: | | | | | |
-| End to End Encryption | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | |
+| SFrame/FrameCryptor | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | |
| Insertable Streams | | | | | | | | |
-Additional platform/OS support from the other community
-
-- flutter-tizen: https://github.com/flutter-tizen/plugins/tree/master/packages/flutter_webrtc
-- flutter-elinux(WIP): https://github.com/sony/flutter-elinux-plugins/issues/7
-
-Add `flutter_webrtc` as a [dependency in your pubspec.yaml file](https://flutter.io/using-packages/).
-
### iOS
Add the following entry to your _Info.plist_ file, located in `/ios/Runner/Info.plist`:
@@ -109,53 +81,3 @@ android {
```
If necessary, in the same `build.gradle` you will need to increase `minSdkVersion` of `defaultConfig` up to `23` (currently default Flutter generator set it to `16`).
-
-### Important reminder
-When you compile the release apk, you need to add the following operations,
-[Setup Proguard Rules](https://github.com/flutter-webrtc/flutter-webrtc/commit/d32dab13b5a0bed80dd9d0f98990f107b9b514f4)
-
-## Contributing
-
-The project is inseparable from the contributors of the community.
-
-- [CloudWebRTC](https://github.com/cloudwebrtc) - Original Author
-- [RainwayApp](https://github.com/rainwayapp) - Sponsor
-- [亢少军](https://github.com/kangshaojun) - Sponsor
-- [ION](https://github.com/pion/ion) - Sponsor
-- [reSipWebRTC](https://github.com/reSipWebRTC) - Sponsor
-- [沃德米科技](https://github.com/woodemi)-[36记手写板](https://www.36notes.com) - Sponsor
-- [阿斯特网络科技有限公司](https://www.astgo.net/) - Sponsor
-
-### Example
-
-For more examples, please refer to [flutter-webrtc-demo](https://github.com/cloudwebrtc/flutter-webrtc-demo/).
-
-## Contributors
-
-### Code Contributors
-
-This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
-
-
-### Financial Contributors
-
-Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/flutter-webrtc/contribute)]
-
-#### Individuals
-
-
-
-#### Organizations
-
-Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/flutter-webrtc/contribute)]
-
-
-
-
-
-
-
-
-
-
-
diff --git a/android/build.gradle b/android/build.gradle
index a94e70c0a7..80bae1cce0 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,8 +1,8 @@
-group 'com.cloudwebrtc.webrtc'
+group 'live.videosdk.webrtc'
version '1.0-SNAPSHOT'
buildscript {
- ext.kotlin_version = '1.6.10'
+ ext.kotlin_version = '1.7.10'
repositories {
google()
mavenCentral()
@@ -27,7 +27,7 @@ apply plugin: 'kotlin-android'
android {
if (project.android.hasProperty("namespace")) {
- namespace 'com.cloudwebrtc.webrtc'
+ namespace 'live.videosdk.webrtc'
}
compileSdkVersion 31
@@ -52,7 +52,7 @@ android {
}
dependencies {
- implementation 'io.github.webrtc-sdk:android:125.6422.02'
+ implementation 'io.github.webrtc-sdk:android:125.6422.03'
implementation 'com.github.davidliu:audioswitch:89582c47c9a04c62f90aa5e57251af4800a62c9a'
implementation 'androidx.annotation:annotation:1.1.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..ccebba7710
Binary files /dev/null and b/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..42defcc94b
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
+networkTimeout=10000
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/android/gradlew b/android/gradlew
new file mode 100755
index 0000000000..79a61d421c
--- /dev/null
+++ b/android/gradlew
@@ -0,0 +1,244 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
new file mode 100644
index 0000000000..6689b85bee
--- /dev/null
+++ b/android/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/android/local.properties b/android/local.properties
new file mode 100644
index 0000000000..832c3e0adf
--- /dev/null
+++ b/android/local.properties
@@ -0,0 +1,8 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Wed Jul 17 14:41:04 IST 2024
+sdk.dir=/Users/halimarajwani/Library/Android/sdk
diff --git a/android/proguard-rules.pro b/android/proguard-rules.pro
index 6ce9896196..21aa43f343 100644
--- a/android/proguard-rules.pro
+++ b/android/proguard-rules.pro
@@ -1,3 +1,3 @@
# Flutter WebRTC
--keep class com.cloudwebrtc.webrtc.** { *; }
+-keep class live.videosdk.webrtc.** { *; }
-keep class org.webrtc.** { *; }
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 903cbff16e..2e10918fa2 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,3 +1,3 @@
+ package="live.videosdk.webrtc">
diff --git a/android/src/main/java/com/cloudwebrtc/webrtc/CameraEventsHandler.java b/android/src/main/java/live/videosdk/webrtc/CameraEventsHandler.java
similarity index 57%
rename from android/src/main/java/com/cloudwebrtc/webrtc/CameraEventsHandler.java
rename to android/src/main/java/live/videosdk/webrtc/CameraEventsHandler.java
index e355b0c953..f8b888b1a4 100755
--- a/android/src/main/java/com/cloudwebrtc/webrtc/CameraEventsHandler.java
+++ b/android/src/main/java/live/videosdk/webrtc/CameraEventsHandler.java
@@ -1,46 +1,89 @@
-package com.cloudwebrtc.webrtc;
+package live.videosdk.webrtc;
import android.util.Log;
import org.webrtc.CameraVideoCapturer;
class CameraEventsHandler implements CameraVideoCapturer.CameraEventsHandler {
+
+
+ public enum CameraState {
+ NEW,
+ OPENING,
+ OPENED,
+ CLOSED,
+ DISCONNECTED,
+ ERROR,
+ FREEZED
+ }
+
private final static String TAG = FlutterWebRTCPlugin.TAG;
// Camera error handler - invoked when camera can not be opened
// or any camera exception happens on camera thread.
+ private CameraState state = CameraState.NEW;
+
+ public void waitForCameraOpen() {
+ Log.d(TAG, "CameraEventsHandler.waitForCameraOpen");
+ while (state != CameraState.OPENED && state != CameraState.ERROR) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void waitForCameraClosed() {
+ Log.d(TAG, "CameraEventsHandler.waitForCameraClosed");
+ while (state != CameraState.CLOSED && state != CameraState.ERROR) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
@Override
public void onCameraError(String errorDescription) {
Log.d(TAG, String.format("CameraEventsHandler.onCameraError: errorDescription=%s", errorDescription));
+ state = CameraState.ERROR;
}
// Called when camera is disconnected.
@Override
public void onCameraDisconnected() {
Log.d(TAG, "CameraEventsHandler.onCameraDisconnected");
+ state = CameraState.DISCONNECTED;
}
// Invoked when camera stops receiving frames
@Override
public void onCameraFreezed(String errorDescription) {
Log.d(TAG, String.format("CameraEventsHandler.onCameraFreezed: errorDescription=%s", errorDescription));
+ state = CameraState.FREEZED;
}
// Callback invoked when camera is opening.
@Override
public void onCameraOpening(String cameraName) {
Log.d(TAG, String.format("CameraEventsHandler.onCameraOpening: cameraName=%s", cameraName));
+ state = CameraState.OPENING;
}
// Callback invoked when first camera frame is available after camera is opened.
@Override
public void onFirstFrameAvailable() {
Log.d(TAG, "CameraEventsHandler.onFirstFrameAvailable");
+ state = CameraState.OPENED;
}
// Callback invoked when camera closed.
@Override
public void onCameraClosed() {
Log.d(TAG, "CameraEventsHandler.onFirstFrameAvailable");
+ state = CameraState.CLOSED;
+
}
}
diff --git a/android/src/main/java/com/cloudwebrtc/webrtc/DataChannelObserver.java b/android/src/main/java/live/videosdk/webrtc/DataChannelObserver.java
similarity index 96%
rename from android/src/main/java/com/cloudwebrtc/webrtc/DataChannelObserver.java
rename to android/src/main/java/live/videosdk/webrtc/DataChannelObserver.java
index 83f316a036..b09569959b 100755
--- a/android/src/main/java/com/cloudwebrtc/webrtc/DataChannelObserver.java
+++ b/android/src/main/java/live/videosdk/webrtc/DataChannelObserver.java
@@ -1,7 +1,7 @@
-package com.cloudwebrtc.webrtc;
+package live.videosdk.webrtc;
-import com.cloudwebrtc.webrtc.utils.AnyThreadSink;
-import com.cloudwebrtc.webrtc.utils.ConstraintsMap;
+import live.videosdk.webrtc.utils.AnyThreadSink;
+import live.videosdk.webrtc.utils.ConstraintsMap;
import org.webrtc.DataChannel;
diff --git a/android/src/main/java/com/cloudwebrtc/webrtc/FlutterRTCFrameCryptor.java b/android/src/main/java/live/videosdk/webrtc/FlutterRTCFrameCryptor.java
similarity index 98%
rename from android/src/main/java/com/cloudwebrtc/webrtc/FlutterRTCFrameCryptor.java
rename to android/src/main/java/live/videosdk/webrtc/FlutterRTCFrameCryptor.java
index 1592cc2cfe..b5294594a5 100644
--- a/android/src/main/java/com/cloudwebrtc/webrtc/FlutterRTCFrameCryptor.java
+++ b/android/src/main/java/live/videosdk/webrtc/FlutterRTCFrameCryptor.java
@@ -1,4 +1,4 @@
-package com.cloudwebrtc.webrtc;
+package live.videosdk.webrtc;
import android.util.Log;
@@ -22,9 +22,9 @@
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
-import com.cloudwebrtc.webrtc.utils.AnyThreadSink;
-import com.cloudwebrtc.webrtc.utils.ConstraintsMap;
-import com.cloudwebrtc.webrtc.utils.ConstraintsArray;
+import live.videosdk.webrtc.utils.AnyThreadSink;
+import live.videosdk.webrtc.utils.ConstraintsMap;
+import live.videosdk.webrtc.utils.ConstraintsArray;
public class FlutterRTCFrameCryptor {
@@ -152,8 +152,8 @@ private FrameCryptorAlgorithm frameCryptorAlgorithmFromInt(int algorithm) {
switch (algorithm) {
case 0:
return FrameCryptorAlgorithm.AES_GCM;
- case 1:
- return FrameCryptorAlgorithm.AES_CBC;
+ // case 1:
+ // return FrameCryptorAlgorithm.AES_CBC;
default:
return FrameCryptorAlgorithm.AES_GCM;
}
diff --git a/android/src/main/java/com/cloudwebrtc/webrtc/FlutterRTCVideoRenderer.java b/android/src/main/java/live/videosdk/webrtc/FlutterRTCVideoRenderer.java
similarity index 97%
rename from android/src/main/java/com/cloudwebrtc/webrtc/FlutterRTCVideoRenderer.java
rename to android/src/main/java/live/videosdk/webrtc/FlutterRTCVideoRenderer.java
index 61500ac844..b82328d67b 100755
--- a/android/src/main/java/com/cloudwebrtc/webrtc/FlutterRTCVideoRenderer.java
+++ b/android/src/main/java/live/videosdk/webrtc/FlutterRTCVideoRenderer.java
@@ -1,11 +1,11 @@
-package com.cloudwebrtc.webrtc;
+package live.videosdk.webrtc;
import android.util.Log;
import android.graphics.SurfaceTexture;
-import com.cloudwebrtc.webrtc.utils.AnyThreadSink;
-import com.cloudwebrtc.webrtc.utils.ConstraintsMap;
-import com.cloudwebrtc.webrtc.utils.EglUtils;
+import live.videosdk.webrtc.utils.AnyThreadSink;
+import live.videosdk.webrtc.utils.ConstraintsMap;
+import live.videosdk.webrtc.utils.EglUtils;
import java.util.List;
diff --git a/android/src/main/java/com/cloudwebrtc/webrtc/FlutterWebRTCPlugin.java b/android/src/main/java/live/videosdk/webrtc/FlutterWebRTCPlugin.java
similarity index 85%
rename from android/src/main/java/com/cloudwebrtc/webrtc/FlutterWebRTCPlugin.java
rename to android/src/main/java/live/videosdk/webrtc/FlutterWebRTCPlugin.java
index b2458a06de..b2133789d3 100644
--- a/android/src/main/java/com/cloudwebrtc/webrtc/FlutterWebRTCPlugin.java
+++ b/android/src/main/java/live/videosdk/webrtc/FlutterWebRTCPlugin.java
@@ -1,4 +1,4 @@
-package com.cloudwebrtc.webrtc;
+package live.videosdk.webrtc;
import android.app.Activity;
import android.app.Application;
@@ -11,9 +11,14 @@
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
-import com.cloudwebrtc.webrtc.audio.AudioSwitchManager;
-import com.cloudwebrtc.webrtc.utils.AnyThreadSink;
-import com.cloudwebrtc.webrtc.utils.ConstraintsMap;
+import live.videosdk.webrtc.audio.AudioSwitchManager;
+import live.videosdk.webrtc.utils.AnyThreadSink;
+import live.videosdk.webrtc.utils.ConstraintsMap;
+
+import live.videosdk.webrtc.audio.AudioProcessingController;
+
+import org.webrtc.ExternalAudioProcessingFactory;
+import org.webrtc.MediaStreamTrack;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
@@ -22,7 +27,7 @@
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugin.common.PluginRegistry.Registrar;
+
import io.flutter.view.TextureRegistry;
/**
@@ -41,28 +46,29 @@ public class FlutterWebRTCPlugin implements FlutterPlugin, ActivityAware, EventC
public EventChannel.EventSink eventSink;
public FlutterWebRTCPlugin() {
+ sharedSingleton = this;
}
- /**
- * Plugin registration.
- */
- public static void registerWith(Registrar registrar) {
- final FlutterWebRTCPlugin plugin = new FlutterWebRTCPlugin();
+ public static FlutterWebRTCPlugin sharedSingleton;
- plugin.startListening(registrar.context(), registrar.messenger(), registrar.textures());
+ public AudioProcessingController getAudioProcessingController() {
+ return methodCallHandler.audioProcessingController;
+ }
- if (registrar.activeContext() instanceof Activity) {
- plugin.methodCallHandler.setActivity((Activity) registrar.activeContext());
- }
- application = ((Application) registrar.context().getApplicationContext());
- application.registerActivityLifecycleCallbacks(plugin.observer);
+ public MediaStreamTrack getTrackForId(String trackId, String peerConnectionId) {
+ return methodCallHandler.getTrackForId(trackId, peerConnectionId);
+ }
+
+ public LocalTrack getLocalTrack(String trackId) {
+ return methodCallHandler.getLocalTrack(trackId);
+ }
- registrar.addViewDestroyListener(view -> {
- plugin.stopListening();
- return false;
- });
+ public MediaStreamTrack getRemoteTrack(String trackId) {
+ return methodCallHandler.getRemoteTrack(trackId);
}
+
+
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
startListening(binding.getApplicationContext(), binding.getBinaryMessenger(),
diff --git a/android/src/main/java/com/cloudwebrtc/webrtc/GetUserMediaImpl.java b/android/src/main/java/live/videosdk/webrtc/GetUserMediaImpl.java
similarity index 65%
rename from android/src/main/java/com/cloudwebrtc/webrtc/GetUserMediaImpl.java
rename to android/src/main/java/live/videosdk/webrtc/GetUserMediaImpl.java
index d48e73d305..059605eae5 100755
--- a/android/src/main/java/com/cloudwebrtc/webrtc/GetUserMediaImpl.java
+++ b/android/src/main/java/live/videosdk/webrtc/GetUserMediaImpl.java
@@ -1,4 +1,4 @@
-package com.cloudwebrtc.webrtc;
+package live.videosdk.webrtc;
import android.Manifest;
import android.app.Activity;
@@ -9,15 +9,9 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.Camera;
-import android.hardware.Camera.Parameters;
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.CameraCaptureSession;
-import android.hardware.camera2.CameraCharacteristics;
-import android.hardware.camera2.CameraDevice;
+
import android.hardware.camera2.CameraManager;
-import android.hardware.camera2.CaptureRequest;
+
import android.media.AudioDeviceInfo;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
@@ -29,38 +23,39 @@
import android.os.Looper;
import android.os.ResultReceiver;
import android.provider.MediaStore;
-import android.util.DisplayMetrics;
+
import android.util.Log;
-import android.util.Range;
+import android.util.Pair;
import android.util.SparseArray;
import android.view.Display;
-import android.view.Surface;
+
import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-import com.cloudwebrtc.webrtc.audio.AudioSwitchManager;
-import com.cloudwebrtc.webrtc.audio.AudioUtils;
-import com.cloudwebrtc.webrtc.record.AudioChannel;
-import com.cloudwebrtc.webrtc.record.AudioSamplesInterceptor;
-import com.cloudwebrtc.webrtc.record.MediaRecorderImpl;
-import com.cloudwebrtc.webrtc.record.OutputAudioSamplesInterceptor;
-import com.cloudwebrtc.webrtc.utils.Callback;
-import com.cloudwebrtc.webrtc.utils.ConstraintsArray;
-import com.cloudwebrtc.webrtc.utils.ConstraintsMap;
-import com.cloudwebrtc.webrtc.utils.EglUtils;
-import com.cloudwebrtc.webrtc.utils.MediaConstraintsUtils;
-import com.cloudwebrtc.webrtc.utils.ObjectType;
-import com.cloudwebrtc.webrtc.utils.PermissionUtils;
-
+import live.videosdk.webrtc.audio.AudioSwitchManager;
+import live.videosdk.webrtc.record.AudioChannel;
+import live.videosdk.webrtc.record.AudioSamplesInterceptor;
+import live.videosdk.webrtc.record.MediaRecorderImpl;
+import live.videosdk.webrtc.record.OutputAudioSamplesInterceptor;
+import live.videosdk.webrtc.utils.Callback;
+import live.videosdk.webrtc.utils.ConstraintsArray;
+import live.videosdk.webrtc.utils.ConstraintsMap;
+import live.videosdk.webrtc.audio.LocalAudioTrack;
+import live.videosdk.webrtc.utils.EglUtils;
+import live.videosdk.webrtc.utils.MediaConstraintsUtils;
+import live.videosdk.webrtc.utils.ObjectType;
+import live.videosdk.webrtc.utils.PermissionUtils;
+import live.videosdk.webrtc.video.LocalVideoTrack;
+import live.videosdk.webrtc.video.VideoCapturerInfo;
import org.webrtc.AudioSource;
import org.webrtc.AudioTrack;
import org.webrtc.Camera1Capturer;
import org.webrtc.Camera1Enumerator;
import org.webrtc.Camera2Capturer;
import org.webrtc.Camera2Enumerator;
-import org.webrtc.CameraEnumerationAndroid.CaptureFormat;
+import org.webrtc.Camera2Helper;
import org.webrtc.CameraEnumerator;
import org.webrtc.CameraVideoCapturer;
import org.webrtc.MediaConstraints;
@@ -72,9 +67,11 @@
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;
import org.webrtc.audio.JavaAudioDeviceModule;
-
+import org.webrtc.Camera1Helper;
+import org.webrtc.VideoFrame;
+import org.webrtc.CapturerObserver;
+import org.webrtc.Size;
import java.io.File;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -82,11 +79,12 @@
import io.flutter.plugin.common.MethodChannel.Result;
+
/**
* The implementation of {@code getUserMedia} extracted into a separate file in order to reduce
* complexity and to (somewhat) separate concerns.
*/
-class GetUserMediaImpl {
+public class GetUserMediaImpl {
private static final int DEFAULT_WIDTH = 1280;
private static final int DEFAULT_HEIGHT = 720;
private static final int DEFAULT_FPS = 30;
@@ -103,7 +101,7 @@ class GetUserMediaImpl {
static final String TAG = FlutterWebRTCPlugin.TAG;
- private final Map mVideoCapturers = new HashMap<>();
+ private final Map mVideoCapturers = new HashMap<>();
private final Map mSurfaceTextureHelpers = new HashMap<>();
private final StateProvider stateProvider;
private final Context applicationContext;
@@ -266,23 +264,22 @@ private void addDefaultAudioConstraints(MediaConstraints audioConstraints) {
* @param isFacing 'user' mapped with 'front' is true (default) 'environment' mapped with 'back'
* is false
* @param sourceId (String) use this sourceId and ignore facing mode if specified.
- * @return VideoCapturer can invoke with startCapture/stopCapture null
+ * @return Pair of deviceName to VideoCapturer. Can invoke with startCapture/stopCapture null
* if not matched camera with specified facing mode.
*/
- private Map createVideoCapturer(
- CameraEnumerator enumerator, boolean isFacing, String sourceId) {
- VideoCapturer videoCapturer = null;
- Map result = new HashMap();
+ private Pair createVideoCapturer(
+ CameraEnumerator enumerator, boolean isFacing, String sourceId, CameraEventsHandler cameraEventsHandler) {
+ VideoCapturer videoCapturer;
// if sourceId given, use specified sourceId first
final String[] deviceNames = enumerator.getDeviceNames();
if (sourceId != null && !sourceId.equals("")) {
for (String name : deviceNames) {
if (name.equals(sourceId)) {
- videoCapturer = enumerator.createCapturer(name, new CameraEventsHandler());
+ videoCapturer = enumerator.createCapturer(name, cameraEventsHandler);
if (videoCapturer != null) {
Log.d(TAG, "create user specified camera " + name + " succeeded");
- result.put(name, videoCapturer);
- return result;
+
+ return new Pair<>(name, videoCapturer);
} else {
Log.d(TAG, "create user specified camera " + name + " failed");
break; // fallback to facing mode
@@ -295,12 +292,11 @@ private Map createVideoCapturer(
String facingStr = isFacing ? "front" : "back";
for (String name : deviceNames) {
if (enumerator.isFrontFacing(name) == isFacing) {
- videoCapturer = enumerator.createCapturer(name, new CameraEventsHandler());
+ videoCapturer = enumerator.createCapturer(name, cameraEventsHandler);
if (videoCapturer != null) {
Log.d(TAG, "Create " + facingStr + " camera " + name + " succeeded");
- result.put(name, videoCapturer);
- return result;
+ return new Pair<>(name, videoCapturer);
} else {
Log.e(TAG, "Create " + facingStr + " camera " + name + " failed");
}
@@ -308,13 +304,13 @@ private Map createVideoCapturer(
}
// falling back to the first available camera
- if (videoCapturer == null && deviceNames.length > 0) {
- videoCapturer = enumerator.createCapturer(deviceNames[0], new CameraEventsHandler());
+ if (deviceNames.length > 0) {
+ videoCapturer = enumerator.createCapturer(deviceNames[0], cameraEventsHandler);
Log.d(TAG, "Falling back to the first available camera");
- result.put(deviceNames[0], videoCapturer);
+ return new Pair<>(deviceNames[0], videoCapturer);
}
- return result;
+ return null;
}
/**
@@ -376,7 +372,11 @@ private ConstraintsMap getUserAudio(ConstraintsMap constraints, MediaStream stre
if (deviceId != null) {
try {
- setPreferredInputDevice(deviceId);
+
+
+ if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ setPreferredInputDevice(Integer.parseInt(deviceId));
+ }
} catch (Exception e) {
Log.e(TAG, "setPreferredInputDevice failed", e);
}
@@ -385,7 +385,7 @@ private ConstraintsMap getUserAudio(ConstraintsMap constraints, MediaStream stre
AudioTrack track = pcFactory.createAudioTrack(trackId, audioSource);
stream.addTrack(track);
- stateProvider.putLocalTrack(track.id(), track);
+ stateProvider.putLocalTrack(track.id(), new LocalAudioTrack(track));
ConstraintsMap trackParams = new ConstraintsMap();
trackParams.putBoolean("enabled", track.enabled());
@@ -396,7 +396,9 @@ private ConstraintsMap getUserAudio(ConstraintsMap constraints, MediaStream stre
trackParams.putBoolean("remote", false);
if (deviceId == null) {
- deviceId = "" + getPreferredInputDevice(preferredInput);
+ if (VERSION.SDK_INT >= VERSION_CODES.M) {
+ deviceId = "" + getPreferredInputDevice(preferredInput);
+ }
}
ConstraintsMap settings = new ConstraintsMap();
@@ -515,7 +517,7 @@ protected void onReceiveResult(int requestCode, Bundle resultData) {
private void getDisplayMedia(final Result result, final MediaStream mediaStream, final Intent mediaProjectionData) {
/* Create ScreenCapture */
- MediaStreamTrack[] tracks = new MediaStreamTrack[1];
+ VideoTrack displayTrack = null;
VideoCapturer videoCapturer = null;
videoCapturer =
new OrientationAwareScreenCapturer(
@@ -550,7 +552,7 @@ public void onStop() {
Point size = new Point();
display.getRealSize(size);
- VideoCapturerInfo info = new VideoCapturerInfo();
+ VideoCapturerInfoEx info = new VideoCapturerInfoEx();
info.width = size.x;
info.height = size.y;
info.fps = DEFAULT_FPS;
@@ -563,41 +565,32 @@ public void onStop() {
String trackId = stateProvider.getNextTrackUUID();
mVideoCapturers.put(trackId, info);
- tracks[0] = pcFactory.createVideoTrack(trackId, videoSource);
+ displayTrack = pcFactory.createVideoTrack(trackId, videoSource);
ConstraintsArray audioTracks = new ConstraintsArray();
ConstraintsArray videoTracks = new ConstraintsArray();
ConstraintsMap successResult = new ConstraintsMap();
- for (MediaStreamTrack track : tracks) {
- if (track == null) {
- continue;
- }
+ if (displayTrack != null) {
+ String id = displayTrack.id();
- String id = track.id();
+ LocalVideoTrack displayLocalVideoTrack = new LocalVideoTrack(displayTrack);
+ videoSource.setVideoProcessor(displayLocalVideoTrack);
- if (track instanceof AudioTrack) {
- mediaStream.addTrack((AudioTrack) track);
- } else {
- mediaStream.addTrack((VideoTrack) track);
- }
- stateProvider.putLocalTrack(id, track);
+ stateProvider.putLocalTrack(id, displayLocalVideoTrack);
ConstraintsMap track_ = new ConstraintsMap();
- String kind = track.kind();
+ String kind = displayTrack.kind();
- track_.putBoolean("enabled", track.enabled());
+ track_.putBoolean("enabled", displayTrack.enabled());
track_.putString("id", id);
track_.putString("kind", kind);
track_.putString("label", kind);
- track_.putString("readyState", track.state().toString());
+ track_.putString("readyState", displayTrack.state().toString());
track_.putBoolean("remote", false);
- if (track instanceof AudioTrack) {
- audioTracks.pushMap(track_);
- } else {
- videoTracks.pushMap(track_);
- }
+ videoTracks.pushMap(track_);
+ mediaStream.addTrack(displayTrack);
}
String streamId = mediaStream.getId();
@@ -742,61 +735,130 @@ private ConstraintsMap getUserVideo(ConstraintsMap constraints, MediaStream medi
isFacing = facingMode == null || !facingMode.equals("environment");
String deviceId = getSourceIdConstraint(videoConstraintsMap);
- Map result = createVideoCapturer(cameraEnumerator, isFacing, deviceId);
+ CameraEventsHandler cameraEventsHandler = new CameraEventsHandler();
+ Pair result = createVideoCapturer(cameraEnumerator, isFacing, deviceId, cameraEventsHandler);
if (result == null) {
return null;
}
- if (deviceId == null) {
- deviceId = result.keySet().iterator().next();
- }
+ deviceId = result.first;
+ VideoCapturer videoCapturer = result.second;
- VideoCapturer videoCapturer = result.get(deviceId);
+ if (facingMode == null && cameraEnumerator.isFrontFacing(deviceId)) {
+ facingMode = "user";
+ } else if (facingMode == null && cameraEnumerator.isBackFacing(deviceId)) {
+ facingMode = "environment";
+ }
+ // else, leave facingMode as it was
PeerConnectionFactory pcFactory = stateProvider.getPeerConnectionFactory();
VideoSource videoSource = pcFactory.createVideoSource(false);
String threadName = Thread.currentThread().getName() + "_texture_camera_thread";
SurfaceTextureHelper surfaceTextureHelper =
SurfaceTextureHelper.create(threadName, EglUtils.getRootEglBaseContext());
- videoCapturer.initialize(
- surfaceTextureHelper, applicationContext, videoSource.getCapturerObserver());
+ if (surfaceTextureHelper == null) {
+ Log.e(TAG, "surfaceTextureHelper is null");
+ return null;
+ }
+ CapturerObserver customCapturerObserver = new CapturerObserver() {
+ WebRTCService webRTCService = WebRTCService.getInstance();
+ @Override
+ public void onCapturerStarted(boolean success) {
+ Log.d(TAG, "Capturer started: " + success);
+ videoSource.getCapturerObserver().onCapturerStarted(success);
+ }
+
+ @Override
+ public void onCapturerStopped() {
+ Log.d(TAG, "Capturer stopped");
+ videoSource.getCapturerObserver().onCapturerStopped();
+ }
+
+ @Override
+ public void onFrameCaptured(VideoFrame frame) {
+ try{
+ if(webRTCService.getVideoProcessor() != null && frame != null){
+ VideoFrame processedFrame = webRTCService.getVideoProcessor().onFrameReceived(frame);
+ if(processedFrame != null){
+ videoSource.getCapturerObserver().onFrameCaptured(processedFrame);
+ }else{
+ videoSource.getCapturerObserver().onFrameCaptured(frame);
+ }
+ } else{
+ videoSource.getCapturerObserver().onFrameCaptured(frame);
+ }
+
+ } catch(Exception e){
+ videoSource.getCapturerObserver().onFrameCaptured(frame);
+ }
+ }
+ };
+
+ videoCapturer.initialize(surfaceTextureHelper, applicationContext, customCapturerObserver);
+ // videoCapturer.initialize(
+ // surfaceTextureHelper, applicationContext, videoSource.getCapturerObserver());
- VideoCapturerInfo info = new VideoCapturerInfo();
+ VideoCapturerInfoEx info = new VideoCapturerInfoEx();
Integer videoWidth = getConstrainInt(videoConstraintsMap, "width");
- info.width = videoWidth != null
+ int targetWidth = videoWidth != null
? videoWidth
: videoConstraintsMandatory != null && videoConstraintsMandatory.hasKey("minWidth")
? videoConstraintsMandatory.getInt("minWidth")
: DEFAULT_WIDTH;
Integer videoHeight = getConstrainInt(videoConstraintsMap, "height");
- info.height = videoHeight != null
+ int targetHeight = videoHeight != null
? videoHeight
: videoConstraintsMandatory != null && videoConstraintsMandatory.hasKey("minHeight")
? videoConstraintsMandatory.getInt("minHeight")
: DEFAULT_HEIGHT;
Integer videoFrameRate = getConstrainInt(videoConstraintsMap, "frameRate");
- info.fps = videoFrameRate != null
+ int targetFps = videoFrameRate != null
? videoFrameRate
: videoConstraintsMandatory != null && videoConstraintsMandatory.hasKey("minFrameRate")
? videoConstraintsMandatory.getInt("minFrameRate")
: DEFAULT_FPS;
+ info.width = targetWidth;
+ info.height = targetHeight;
+ info.fps = targetFps;
info.capturer = videoCapturer;
- videoCapturer.startCapture(info.width, info.height, info.fps);
+ info.cameraName = deviceId;
+
+ // Find actual capture format.
+ Size actualSize = null;
+ if (videoCapturer instanceof Camera1Capturer) {
+ int cameraId = Camera1Helper.getCameraId(deviceId);
+ actualSize = Camera1Helper.findClosestCaptureFormat(cameraId, targetWidth, targetHeight);
+ } else if (videoCapturer instanceof Camera2Capturer) {
+ CameraManager cameraManager = (CameraManager) applicationContext.getSystemService(Context.CAMERA_SERVICE);
+ actualSize = Camera2Helper.findClosestCaptureFormat(cameraManager, deviceId, targetWidth, targetHeight);
+ }
+
+ if (actualSize != null) {
+ info.width = actualSize.width;
+ info.height = actualSize.height;
+ }
+
+ info.cameraEventsHandler = cameraEventsHandler;
+ videoCapturer.startCapture(targetWidth, targetHeight, targetFps);
+
+ cameraEventsHandler.waitForCameraOpen();
String trackId = stateProvider.getNextTrackUUID();
mVideoCapturers.put(trackId, info);
mSurfaceTextureHelpers.put(trackId, surfaceTextureHelper);
- Log.d(TAG, "changeCaptureFormat: " + info.width + "x" + info.height + "@" + info.fps);
- videoSource.adaptOutputFormat(info.width, info.height, info.fps);
+ Log.d(TAG, "Target: " + targetWidth + "x" + targetHeight + "@" + targetFps + ", Actual: " + info.width + "x" + info.height + "@" + info.fps);
VideoTrack track = pcFactory.createVideoTrack(trackId, videoSource);
mediaStream.addTrack(track);
- stateProvider.putLocalTrack(track.id(), track);
+ LocalVideoTrack localVideoTrack = new LocalVideoTrack(track);
+ videoSource.setVideoProcessor(localVideoTrack);
+
+ stateProvider.putLocalTrack(track.id(),localVideoTrack);
ConstraintsMap trackParams = new ConstraintsMap();
@@ -819,33 +881,30 @@ private ConstraintsMap getUserVideo(ConstraintsMap constraints, MediaStream medi
return trackParams;
}
- void removeVideoCapturerSync(String id) {
- synchronized (mVideoCapturers) {
- VideoCapturerInfo info = mVideoCapturers.get(id);
- if (info != null) {
- try {
- info.capturer.stopCapture();
- } catch (InterruptedException e) {
- Log.e(TAG, "removeVideoCapturer() Failed to stop video capturer");
- } finally {
- info.capturer.dispose();
- mVideoCapturers.remove(id);
- SurfaceTextureHelper helper = mSurfaceTextureHelpers.get(id);
- if (helper != null) {
- helper.stopListening();
- helper.dispose();
- mSurfaceTextureHelpers.remove(id);
- }
+ void removeVideoCapturer(String id) {
+ VideoCapturerInfoEx info = mVideoCapturers.get(id);
+ if (info != null) {
+ try {
+ info.capturer.stopCapture();
+ if (info.cameraEventsHandler != null) {
+ info.cameraEventsHandler.waitForCameraClosed();
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "removeVideoCapturer() Failed to stop video capturer");
+ } finally {
+ info.capturer.dispose();
+ mVideoCapturers.remove(id);
+ SurfaceTextureHelper helper = mSurfaceTextureHelpers.get(id);
+ if (helper != null) {
+ helper.stopListening();
+ helper.dispose();
+ mSurfaceTextureHelpers.remove(id);
}
}
}
}
- void removeVideoCapturer(String id) {
- new Thread(() -> {
- removeVideoCapturerSync(id);
- }).start();
- }
+
@RequiresApi(api = VERSION_CODES.M)
private void requestPermissions(
@@ -915,7 +974,7 @@ void switchCamera(String id, Result result) {
@Override
public void onCameraSwitchDone(boolean b) {
isFacing = !isFacing;
- isTorchOn = false;
+
result.success(b);
}
@@ -973,302 +1032,13 @@ void stopRecording(Integer id) {
}
}
- void hasTorch(String trackId, Result result) {
- VideoCapturerInfo info = mVideoCapturers.get(trackId);
- if (info == null) {
- resultError("hasTorch", "Video capturer not found for id: " + trackId, result);
- return;
- }
-
- if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP && info.capturer instanceof Camera2Capturer) {
- CameraManager manager;
- CameraDevice cameraDevice;
+
- try {
- Object session =
- getPrivateProperty(
- Camera2Capturer.class.getSuperclass(), info.capturer, "currentSession");
- manager =
- (CameraManager)
- getPrivateProperty(Camera2Capturer.class, info.capturer, "cameraManager");
- cameraDevice =
- (CameraDevice) getPrivateProperty(session.getClass(), session, "cameraDevice");
- } catch (NoSuchFieldWithNameException e) {
- // Most likely the upstream Camera2Capturer class have changed
- resultError("hasTorch", "[TORCH] Failed to get `" + e.fieldName + "` from `" + e.className + "`", result);
- return;
- }
- boolean flashIsAvailable;
- try {
- CameraCharacteristics characteristics =
- manager.getCameraCharacteristics(cameraDevice.getId());
- flashIsAvailable = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
- } catch (CameraAccessException e) {
- // Should never happen since we are already accessing the camera
- throw new RuntimeException(e);
- }
- result.success(flashIsAvailable);
- return;
- }
-
- if (info.capturer instanceof Camera1Capturer) {
- Camera camera;
-
- try {
- Object session =
- getPrivateProperty(
- Camera1Capturer.class.getSuperclass(), info.capturer, "currentSession");
- camera = (Camera) getPrivateProperty(session.getClass(), session, "camera");
- } catch (NoSuchFieldWithNameException e) {
- // Most likely the upstream Camera1Capturer class have changed
- resultError("hasTorch", "[TORCH] Failed to get `" + e.fieldName + "` from `" + e.className + "`", result);
- return;
- }
-
- Parameters params = camera.getParameters();
- List supportedModes = params.getSupportedFlashModes();
-
- result.success(
- supportedModes != null && supportedModes.contains(Parameters.FLASH_MODE_TORCH));
- return;
- }
-
- resultError("hasTorch", "[TORCH] Video capturer not compatible", result);
- }
-
- @RequiresApi(api = VERSION_CODES.LOLLIPOP)
- void setZoom(String trackId, double zoomLevel, Result result) {
- VideoCapturerInfo info = mVideoCapturers.get(trackId);
- if (info == null) {
- resultError("setZoom", "Video capturer not found for id: " + trackId, result);
- return;
- }
-
- if (info.capturer instanceof Camera2Capturer) {
- CameraCaptureSession captureSession;
- CameraDevice cameraDevice;
- CaptureFormat captureFormat;
- int fpsUnitFactor;
- Surface surface;
- Handler cameraThreadHandler;
- CameraManager manager;
-
- try {
- Object session =
- getPrivateProperty(
- Camera2Capturer.class.getSuperclass(), info.capturer, "currentSession");
- manager =
- (CameraManager)
- getPrivateProperty(Camera2Capturer.class, info.capturer, "cameraManager");
- captureSession =
- (CameraCaptureSession)
- getPrivateProperty(session.getClass(), session, "captureSession");
- cameraDevice =
- (CameraDevice) getPrivateProperty(session.getClass(), session, "cameraDevice");
- captureFormat =
- (CaptureFormat) getPrivateProperty(session.getClass(), session, "captureFormat");
- fpsUnitFactor = (int) getPrivateProperty(session.getClass(), session, "fpsUnitFactor");
- surface = (Surface) getPrivateProperty(session.getClass(), session, "surface");
- cameraThreadHandler =
- (Handler) getPrivateProperty(session.getClass(), session, "cameraThreadHandler");
- } catch (NoSuchFieldWithNameException e) {
- // Most likely the upstream Camera2Capturer class have changed
- resultError("setZoom", "[ZOOM] Failed to get `" + e.fieldName + "` from `" + e.className + "`", result);
- return;
- }
-
- try {
- final CaptureRequest.Builder captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
-
- final CameraCharacteristics cameraCharacteristics = manager.getCameraCharacteristics(cameraDevice.getId());
- final Rect rect = cameraCharacteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- final double maxZoomLevel = cameraCharacteristics.get(CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM);
-
- final double desiredZoomLevel = Math.max(1.0, Math.min(zoomLevel, maxZoomLevel));
-
- float ratio = 1.0f / (float)desiredZoomLevel;
-
- if (rect != null) {
- int croppedWidth = rect.width() - Math.round((float) rect.width() * ratio);
- int croppedHeight = rect.height() - Math.round((float) rect.height() * ratio);
- final Rect desiredRegion = new Rect(croppedWidth / 2, croppedHeight / 2, rect.width() - croppedWidth / 2, rect.height() - croppedHeight / 2);
- captureRequestBuilder.set(CaptureRequest.SCALER_CROP_REGION, desiredRegion);
- }
-
- captureRequestBuilder.set(
- CaptureRequest.FLASH_MODE,
- isTorchOn ? CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
- new Range<>(
- captureFormat.framerate.min / fpsUnitFactor,
- captureFormat.framerate.max / fpsUnitFactor));
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
- captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
- captureRequestBuilder.addTarget(surface);
- captureSession.setRepeatingRequest(
- captureRequestBuilder.build(), null, cameraThreadHandler);
- } catch (CameraAccessException e) {
- // Should never happen since we are already accessing the camera
- throw new RuntimeException(e);
- }
-
-
- result.success(null);
- return;
- }
-
- if (info.capturer instanceof Camera1Capturer) {
- Camera camera;
- try {
- Object session =
- getPrivateProperty(
- Camera1Capturer.class.getSuperclass(), info.capturer, "currentSession");
- camera = (Camera) getPrivateProperty(session.getClass(), session, "camera");
- } catch (NoSuchFieldWithNameException e) {
- // Most likely the upstream Camera1Capturer class have changed
- resultError("setZoom", "[ZOOM] Failed to get `" + e.fieldName + "` from `" + e.className + "`", result);
- return;
- }
-
- Camera.Parameters params = camera.getParameters();
- params.setFlashMode(
- isTorchOn ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF);
- if(params.isZoomSupported()) {
- int maxZoom = params.getMaxZoom();
- double desiredZoom = Math.max(0, Math.min(zoomLevel, maxZoom));
- params.setZoom((int)desiredZoom);
- result.success(null);
- return;
- }
- }
- resultError("setZoom", "[ZOOM] Video capturer not compatible", result);
- }
-
- @RequiresApi(api = VERSION_CODES.LOLLIPOP)
- void setTorch(String trackId, boolean torch, Result result) {
- VideoCapturerInfo info = mVideoCapturers.get(trackId);
- if (info == null) {
- resultError("setTorch", "Video capturer not found for id: " + trackId, result);
- return;
- }
-
- if (info.capturer instanceof Camera2Capturer) {
- CameraCaptureSession captureSession;
- CameraDevice cameraDevice;
- CaptureFormat captureFormat;
- int fpsUnitFactor;
- Surface surface;
- Handler cameraThreadHandler;
-
- try {
- Object session =
- getPrivateProperty(
- Camera2Capturer.class.getSuperclass(), info.capturer, "currentSession");
- CameraManager manager =
- (CameraManager)
- getPrivateProperty(Camera2Capturer.class, info.capturer, "cameraManager");
- captureSession =
- (CameraCaptureSession)
- getPrivateProperty(session.getClass(), session, "captureSession");
- cameraDevice =
- (CameraDevice) getPrivateProperty(session.getClass(), session, "cameraDevice");
- captureFormat =
- (CaptureFormat) getPrivateProperty(session.getClass(), session, "captureFormat");
- fpsUnitFactor = (int) getPrivateProperty(session.getClass(), session, "fpsUnitFactor");
- surface = (Surface) getPrivateProperty(session.getClass(), session, "surface");
- cameraThreadHandler =
- (Handler) getPrivateProperty(session.getClass(), session, "cameraThreadHandler");
- } catch (NoSuchFieldWithNameException e) {
- // Most likely the upstream Camera2Capturer class have changed
- resultError("setTorch", "[TORCH] Failed to get `" + e.fieldName + "` from `" + e.className + "`", result);
- return;
- }
-
- try {
- final CaptureRequest.Builder captureRequestBuilder =
- cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
- captureRequestBuilder.set(
- CaptureRequest.FLASH_MODE,
- torch ? CaptureRequest.FLASH_MODE_TORCH : CaptureRequest.FLASH_MODE_OFF);
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
- new Range<>(
- captureFormat.framerate.min / fpsUnitFactor,
- captureFormat.framerate.max / fpsUnitFactor));
- captureRequestBuilder.set(
- CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
- captureRequestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, false);
- captureRequestBuilder.addTarget(surface);
- captureSession.setRepeatingRequest(
- captureRequestBuilder.build(), null, cameraThreadHandler);
- } catch (CameraAccessException e) {
- // Should never happen since we are already accessing the camera
- throw new RuntimeException(e);
- }
-
- result.success(null);
- isTorchOn = torch;
- return;
- }
-
- if (info.capturer instanceof Camera1Capturer) {
- Camera camera;
- try {
- Object session =
- getPrivateProperty(
- Camera1Capturer.class.getSuperclass(), info.capturer, "currentSession");
- camera = (Camera) getPrivateProperty(session.getClass(), session, "camera");
- } catch (NoSuchFieldWithNameException e) {
- // Most likely the upstream Camera1Capturer class have changed
- resultError("setTorch", "[TORCH] Failed to get `" + e.fieldName + "` from `" + e.className + "`", result);
- return;
- }
-
- Camera.Parameters params = camera.getParameters();
- params.setFlashMode(
- torch ? Camera.Parameters.FLASH_MODE_TORCH : Camera.Parameters.FLASH_MODE_OFF);
- camera.setParameters(params);
-
- result.success(null);
- isTorchOn = torch;
- return;
- }
- resultError("setTorch", "[TORCH] Video capturer not compatible", result);
- }
-
- private Object getPrivateProperty(Class klass, Object object, String fieldName)
- throws NoSuchFieldWithNameException {
- try {
- Field field = klass.getDeclaredField(fieldName);
- field.setAccessible(true);
- return field.get(object);
- } catch (NoSuchFieldException e) {
- throw new NoSuchFieldWithNameException(klass.getName(), fieldName, e);
- } catch (IllegalAccessException e) {
- // Should never happen since we are calling `setAccessible(true)`
- throw new RuntimeException(e);
- }
- }
-
- private class NoSuchFieldWithNameException extends NoSuchFieldException {
-
- String className;
- String fieldName;
-
- NoSuchFieldWithNameException(String className, String fieldName, NoSuchFieldException e) {
- super(e.getMessage());
- this.className = className;
- this.fieldName = fieldName;
- }
- }
public void reStartCamera(IsCameraEnabled getCameraId) {
- for (Map.Entry item : mVideoCapturers.entrySet()) {
+ for (Map.Entry item : mVideoCapturers.entrySet()) {
if (!item.getValue().isScreenCapture && getCameraId.isEnabled(item.getKey())) {
item.getValue().capturer.startCapture(
item.getValue().width,
@@ -1283,27 +1053,21 @@ public interface IsCameraEnabled {
boolean isEnabled(String id);
}
- public class VideoCapturerInfo {
- VideoCapturer capturer;
- int width;
- int height;
- int fps;
- boolean isScreenCapture = false;
+ public static class VideoCapturerInfoEx extends VideoCapturerInfo {
+ public CameraEventsHandler cameraEventsHandler;
+ }
+
+ public VideoCapturerInfoEx getCapturerInfo(String trackId) {
+ return mVideoCapturers.get(trackId);
}
@RequiresApi(api = VERSION_CODES.M)
- void setPreferredInputDevice(String deviceId) {
+ void setPreferredInputDevice(int i) {
android.media.AudioManager audioManager = ((android.media.AudioManager) applicationContext.getSystemService(Context.AUDIO_SERVICE));
final AudioDeviceInfo[] devices = audioManager.getDevices(android.media.AudioManager.GET_DEVICES_INPUTS);
- if (devices.length > 0) {
- for (int i = 0; i < devices.length; i++) {
- AudioDeviceInfo device = devices[i];
- if(deviceId.equals(AudioUtils.getAudioDeviceId(device))) {
- preferredInput = device;
- audioDeviceModule.setPreferredInputDevice(preferredInput);
- return;
- }
- }
+ if (devices.length > i) {
+ preferredInput = devices[i];
+ audioDeviceModule.setPreferredInputDevice(preferredInput);
}
}
diff --git a/android/src/main/java/live/videosdk/webrtc/LocalTrack.java b/android/src/main/java/live/videosdk/webrtc/LocalTrack.java
new file mode 100644
index 0000000000..4cc5b0cb78
--- /dev/null
+++ b/android/src/main/java/live/videosdk/webrtc/LocalTrack.java
@@ -0,0 +1,31 @@
+package live.videosdk.webrtc;
+
+import org.webrtc.MediaStreamTrack;
+
+public class LocalTrack {
+ public LocalTrack(MediaStreamTrack track) {
+ this.track = track;
+ }
+
+ public MediaStreamTrack track;
+
+ public void dispose() {
+ track.dispose();
+ }
+
+ public boolean enabled() {
+ return track.enabled();
+ }
+
+ public void setEnabled(boolean enabled) {
+ track.setEnabled(enabled);
+ }
+
+ public String id() {
+ return track.id();
+ }
+
+ public String kind() {
+ return track.kind();
+ }
+}
\ No newline at end of file
diff --git a/android/src/main/java/com/cloudwebrtc/webrtc/MethodCallHandlerImpl.java b/android/src/main/java/live/videosdk/webrtc/MethodCallHandlerImpl.java
similarity index 89%
rename from android/src/main/java/com/cloudwebrtc/webrtc/MethodCallHandlerImpl.java
rename to android/src/main/java/live/videosdk/webrtc/MethodCallHandlerImpl.java
index ee46a609b8..0c002206ce 100644
--- a/android/src/main/java/com/cloudwebrtc/webrtc/MethodCallHandlerImpl.java
+++ b/android/src/main/java/live/videosdk/webrtc/MethodCallHandlerImpl.java
@@ -1,6 +1,6 @@
-package com.cloudwebrtc.webrtc;
+package live.videosdk.webrtc;
-import static com.cloudwebrtc.webrtc.utils.MediaConstraintsUtils.parseMediaConstraints;
+import static live.videosdk.webrtc.utils.MediaConstraintsUtils.parseMediaConstraints;
import android.app.Activity;
import android.content.Context;
@@ -8,6 +8,7 @@
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
+import android.media.MediaRecorder;
import android.media.AudioAttributes;
import android.media.AudioDeviceInfo;
import android.os.Build;
@@ -17,21 +18,29 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
-
-import com.cloudwebrtc.webrtc.audio.AudioDeviceKind;
-import com.cloudwebrtc.webrtc.audio.AudioSwitchManager;
-import com.cloudwebrtc.webrtc.audio.AudioUtils;
-import com.cloudwebrtc.webrtc.record.AudioChannel;
-import com.cloudwebrtc.webrtc.record.FrameCapturer;
-import com.cloudwebrtc.webrtc.utils.AnyThreadResult;
-import com.cloudwebrtc.webrtc.utils.Callback;
-import com.cloudwebrtc.webrtc.utils.ConstraintsArray;
-import com.cloudwebrtc.webrtc.utils.ConstraintsMap;
-import com.cloudwebrtc.webrtc.utils.EglUtils;
-import com.cloudwebrtc.webrtc.utils.ObjectType;
-import com.cloudwebrtc.webrtc.utils.PermissionUtils;
-import com.cloudwebrtc.webrtc.utils.Utils;
+import live.videosdk.webrtc.audio.AudioProcessingController;
+import live.videosdk.webrtc.audio.AudioDeviceKind;
+import live.videosdk.webrtc.audio.AudioSwitchManager;
+import live.videosdk.webrtc.audio.LocalAudioTrack;
+import live.videosdk.webrtc.audio.PlaybackSamplesReadyCallbackAdapter;
+import live.videosdk.webrtc.audio.RecordSamplesReadyCallbackAdapter;
+import live.videosdk.webrtc.audio.AudioUtils;
+import live.videosdk.webrtc.record.AudioChannel;
+import live.videosdk.webrtc.record.FrameCapturer;
+import live.videosdk.webrtc.utils.AnyThreadResult;
+import live.videosdk.webrtc.utils.Callback;
+import live.videosdk.webrtc.utils.ConstraintsArray;
+import live.videosdk.webrtc.utils.ConstraintsMap;
+import live.videosdk.webrtc.utils.EglUtils;
+import live.videosdk.webrtc.utils.ObjectType;
+import live.videosdk.webrtc.utils.PermissionUtils;
+import live.videosdk.webrtc.utils.Utils;
+import live .videosdk.webrtc.video.VideoCapturerInfo;
+import live .videosdk.webrtc.video.camera.CameraUtils;
+import live .videosdk.webrtc.video.camera.Point;
+import live .videosdk.webrtc.video.LocalVideoTrack;
import com.twilio.audioswitch.AudioDevice;
+import live.videosdk.webrtc.LocalTrack;
import org.webrtc.AudioTrack;
import org.webrtc.CryptoOptions;
@@ -96,14 +105,18 @@ public class MethodCallHandlerImpl implements MethodCallHandler, StateProvider {
private final TextureRegistry textures;
private PeerConnectionFactory mFactory;
private final Map localStreams = new HashMap<>();
- private final Map localTracks = new HashMap<>();
+ private final Map localTracks = new HashMap<>();
private final LongSparseArray renders = new LongSparseArray<>();
+ public RecordSamplesReadyCallbackAdapter recordSamplesReadyCallbackAdapter;
+
+ public PlaybackSamplesReadyCallbackAdapter playbackSamplesReadyCallbackAdapter;
/**
* The implementation of {@code getUserMedia} extracted into a separate file in order to reduce
* complexity and to (somewhat) separate concerns.
*/
private GetUserMediaImpl getUserMediaImpl;
+ private CameraUtils cameraUtils;
private AudioDeviceModule audioDeviceModule;
@@ -115,6 +128,8 @@ public class MethodCallHandlerImpl implements MethodCallHandler, StateProvider {
private CustomVideoDecoderFactory videoDecoderFactory;
+ public AudioProcessingController audioProcessingController;
+
MethodCallHandlerImpl(Context context, BinaryMessenger messenger, TextureRegistry textureRegistry) {
this.context = context;
this.textures = textureRegistry;
@@ -133,7 +148,7 @@ void dispose() {
mediaStream.dispose();
}
localStreams.clear();
- for (final MediaStreamTrack track : localTracks.values()) {
+ for (final LocalTrack track : localTracks.values()) {
track.dispose();
}
localTracks.clear();
@@ -142,7 +157,7 @@ void dispose() {
}
mPeerConnectionObservers.clear();
}
- private void initialize(int networkIgnoreMask, boolean forceSWCodec, List forceSWCodecList,
+ private void initialize(boolean bypassVoiceProcessing, int networkIgnoreMask, boolean forceSWCodec, List forceSWCodecList,
@Nullable ConstraintsMap androidAudioConfiguration) {
if (mFactory != null) {
return;
@@ -155,6 +170,8 @@ private void initialize(int networkIgnoreMask, boolean forceSWCodec, List= Build.VERSION_CODES.Q;
+ boolean useLowLatency = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
+ audioDeviceModuleBuilder.setUseHardwareAcousticEchoCanceler(useHardwareAudioProcessing)
+ .setUseLowLatency(useLowLatency)
+ .setUseHardwareNoiseSuppressor(useHardwareAudioProcessing);
+ }
+ audioDeviceModuleBuilder.setSamplesReadyCallback(recordSamplesReadyCallbackAdapter);
+ audioDeviceModuleBuilder.setPlaybackSamplesReadyCallback(playbackSamplesReadyCallbackAdapter);
+
+ recordSamplesReadyCallbackAdapter.addCallback(getUserMediaImpl.inputSamplesInterceptor);
- JavaAudioDeviceModule.Builder audioDeviceModuleBuilder = JavaAudioDeviceModule.builder(context)
- .setUseHardwareAcousticEchoCanceler(true)
- .setUseHardwareNoiseSuppressor(true)
- .setSamplesReadyCallback(getUserMediaImpl.inputSamplesInterceptor);
+ recordSamplesReadyCallbackAdapter.addCallback(new JavaAudioDeviceModule.SamplesReadyCallback() {
+ @Override
+ public void onWebRtcAudioRecordSamplesReady(JavaAudioDeviceModule.AudioSamples audioSamples) {
+ for(LocalTrack track : localTracks.values()) {
+ if (track instanceof LocalAudioTrack) {
+ ((LocalAudioTrack) track).onWebRtcAudioRecordSamplesReady(audioSamples);
+ }
+ }
+ }
+ });
if (audioAttributes != null) {
audioDeviceModuleBuilder.setAudioAttributes(audioAttributes);
}
audioDeviceModule = audioDeviceModuleBuilder.createAudioDeviceModule();
-
+ if(!bypassVoiceProcessing) {
+ if(JavaAudioDeviceModule.isBuiltInNoiseSuppressorSupported()) {
+ audioDeviceModule.setNoiseSuppressorEnabled(true);
+ }
+ }
getUserMediaImpl.audioDeviceModule = (JavaAudioDeviceModule) audioDeviceModule;
final Options options = new Options();
@@ -210,6 +259,9 @@ private void initialize(int networkIgnoreMask, boolean forceSWCodec, List audioTracks = new ArrayList<>();
List