From 967eb4d732f36ad0c6456254dd639e33da5a1b87 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 9 Jul 2025 15:47:03 +0200 Subject: [PATCH 01/16] add ios support --- .../WebRTCModule+RTCPeerConnection.m | 3 + .../WebRTCModule+VideoTrackAdapter.h | 4 + .../WebRTCModule+VideoTrackAdapter.m | 114 ++++++++++++++++++ ios/RCTWebRTC/WebRTCModule.h | 1 + 4 files changed, 122 insertions(+) diff --git a/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m b/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m index 20db4a56e..17f6707a8 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m @@ -94,6 +94,7 @@ @implementation WebRTCModule (RTCPeerConnection) peerConnection.remoteStreams = [NSMutableDictionary new]; peerConnection.remoteTracks = [NSMutableDictionary new]; peerConnection.videoTrackAdapters = [NSMutableDictionary new]; + peerConnection.videoDimensionDetectors = [NSMutableDictionary new]; peerConnection.webRTCModule = self; self.peerConnections[objectID] = peerConnection; @@ -329,6 +330,7 @@ @implementation WebRTCModule (RTCPeerConnection) RTCMediaStreamTrack *track = peerConnection.remoteTracks[key]; if (track.kind == kRTCMediaStreamTrackKindVideo) { [peerConnection removeVideoTrackAdapter:(RTCVideoTrack *)track]; + [peerConnection removeVideoDimensionDetector:(RTCVideoTrack *)track]; } } @@ -877,6 +879,7 @@ - (void)peerConnection:(RTC_OBJC_TYPE(RTCPeerConnection) *)peerConnection if (track.kind == kRTCMediaStreamTrackKindVideo) { RTCVideoTrack *videoTrack = (RTCVideoTrack *)track; [peerConnection addVideoTrackAdapter:videoTrack]; + [peerConnection addVideoDimensionDetector:videoTrack]; } peerConnection.remoteTracks[track.trackId] = track; diff --git a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h index 9ea8fa964..8e77ca97f 100644 --- a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h +++ b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h @@ -5,8 +5,12 @@ @interface RTCPeerConnection (VideoTrackAdapter) @property(nonatomic, strong) NSMutableDictionary *videoTrackAdapters; +@property(nonatomic, strong) NSMutableDictionary *videoDimensionDetectors; - (void)addVideoTrackAdapter:(RTCVideoTrack *)track; - (void)removeVideoTrackAdapter:(RTCVideoTrack *)track; +- (void)addVideoDimensionDetector:(RTCVideoTrack *)track; +- (void)removeVideoDimensionDetector:(RTCVideoTrack *)track; + @end diff --git a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m index af4e610ae..c2b034d10 100644 --- a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m +++ b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m @@ -121,6 +121,81 @@ - (void)setSize:(CGSize)size { @end +/* Entity responsible for detecting video dimension changes. It's implemented + * as a video renderer, which monitors the setSize: method to detect when + * video dimensions change and emits events accordingly. + */ +@interface VideoDimensionDetector : NSObject + +@property(copy, nonatomic) NSNumber *peerConnectionId; +@property(copy, nonatomic) NSString *trackId; +@property(weak, nonatomic) WebRTCModule *module; + +@end + +@implementation VideoDimensionDetector { + BOOL _disposed; + CGSize _currentSize; + BOOL _hasInitialSize; +} + +- (instancetype)initWith:(NSNumber *)peerConnectionId trackId:(NSString *)trackId webRTCModule:(WebRTCModule *)module { + self = [super init]; + if (self) { + self.peerConnectionId = peerConnectionId; + self.trackId = trackId; + self.module = module; + + _disposed = NO; + _currentSize = CGSizeZero; + _hasInitialSize = NO; + } + + return self; +} + +- (void)dispose { + _disposed = YES; +} + +- (void)emitDimensionChangeEvent:(CGSize)newSize { + [self.module sendEventWithName:kEventVideoTrackDimensionChanged + body:@{ + @"pcId" : self.peerConnectionId, + @"trackId" : self.trackId, + @"width" : @(newSize.width), + @"height" : @(newSize.height) + }]; + RCTLog(@"[VideoDimensionDetector] Dimension change event for pc %@ track %@: %fx%f", + self.peerConnectionId, + self.trackId, + newSize.width, + newSize.height); +} + +- (void)renderFrame:(nullable RTCVideoFrame *)frame { + // We don't need to do anything with frames for dimension detection + // The setSize: method will be called automatically when dimensions change +} + +- (void)setSize:(CGSize)size { + if (_disposed) { + return; + } + + // Check if this is a meaningful size change + if (!_hasInitialSize) { + _currentSize = size; + _hasInitialSize = YES; + [self emitDimensionChangeEvent:size]; + } else if (!CGSizeEqualToSize(_currentSize, size)) { + _currentSize = size; + [self emitDimensionChangeEvent:size]; + } +} + +@end + @implementation RTCPeerConnection (VideoTrackAdapter) - (NSMutableDictionary *)videoTrackAdapters { @@ -132,6 +207,15 @@ - (void)setVideoTrackAdapters:(NSMutableDictionary *)videoTrackA self, @selector(videoTrackAdapters), videoTrackAdapters, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } +- (NSMutableDictionary *)videoDimensionDetectors { + return objc_getAssociatedObject(self, _cmd); +} + +- (void)setVideoDimensionDetectors:(NSMutableDictionary *)videoDimensionDetectors { + objc_setAssociatedObject( + self, @selector(videoDimensionDetectors), videoDimensionDetectors, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + - (void)addVideoTrackAdapter:(RTCVideoTrack *)track { NSString *trackId = track.trackId; if ([self.videoTrackAdapters objectForKey:trackId] != nil) { @@ -163,4 +247,34 @@ - (void)removeVideoTrackAdapter:(RTCVideoTrack *)track { RCTLogTrace(@"[VideoTrackAdapter] Adapter removed for track %@", trackId); } +- (void)addVideoDimensionDetector:(RTCVideoTrack *)track { + NSString *trackId = track.trackId; + if ([self.videoDimensionDetectors objectForKey:trackId] != nil) { + RCTLogWarn(@"[VideoDimensionDetector] Detector already exists for track %@", trackId); + return; + } + + VideoDimensionDetector *dimensionDetector = [[VideoDimensionDetector alloc] initWith:self.reactTag + trackId:trackId + webRTCModule:self.webRTCModule]; + [self.videoDimensionDetectors setObject:dimensionDetector forKey:trackId]; + [track addRenderer:dimensionDetector]; + + RCTLogTrace(@"[VideoDimensionDetector] Detector created for track %@", trackId); +} + +- (void)removeVideoDimensionDetector:(RTCVideoTrack *)track { + NSString *trackId = track.trackId; + VideoDimensionDetector *dimensionDetector = [self.videoDimensionDetectors objectForKey:trackId]; + if (dimensionDetector == nil) { + RCTLogWarn(@"[VideoDimensionDetector] Detector doesn't exist for track %@", trackId); + return; + } + + [track removeRenderer:dimensionDetector]; + [dimensionDetector dispose]; + [self.videoDimensionDetectors removeObjectForKey:trackId]; + RCTLogTrace(@"[VideoDimensionDetector] Detector removed for track %@", trackId); +} + @end diff --git a/ios/RCTWebRTC/WebRTCModule.h b/ios/RCTWebRTC/WebRTCModule.h index e1f555428..3ff079e0e 100644 --- a/ios/RCTWebRTC/WebRTCModule.h +++ b/ios/RCTWebRTC/WebRTCModule.h @@ -18,6 +18,7 @@ static NSString *const kEventDataChannelDidChangeBufferedAmount = @"dataChannelD static NSString *const kEventDataChannelStateChanged = @"dataChannelStateChanged"; static NSString *const kEventDataChannelReceiveMessage = @"dataChannelReceiveMessage"; static NSString *const kEventMediaStreamTrackMuteChanged = @"mediaStreamTrackMuteChanged"; +static NSString *const kEventVideoTrackDimensionChanged = @"videoTrackDimensionChanged"; static NSString *const kEventMediaStreamTrackEnded = @"mediaStreamTrackEnded"; static NSString *const kEventPeerConnectionOnRemoveTrack = @"peerConnectionOnRemoveTrack"; static NSString *const kEventPeerConnectionOnTrack = @"peerConnectionOnTrack"; From 03850a7a7bb047223a871d30ac44c329ed48233c Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 9 Jul 2025 15:55:12 +0200 Subject: [PATCH 02/16] add android implementation --- .../WebRTCModule/PeerConnectionObserver.java | 2 + .../oney/WebRTCModule/VideoTrackAdapter.java | 81 +++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java b/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java index dfc2901a8..ac76e5a18 100644 --- a/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java +++ b/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java @@ -75,6 +75,7 @@ void dispose() { for (MediaStreamTrack track : this.remoteTracks.values()) { if (track instanceof VideoTrack) { videoTrackAdapters.removeAdapter((VideoTrack) track); + videoTrackAdapters.removeDimensionDetector((VideoTrack) track); } } @@ -432,6 +433,7 @@ public void onAddTrack(final RtpReceiver receiver, final MediaStream[] mediaStre if (!existingTrack) { if (track.kind().equals(MediaStreamTrack.VIDEO_TRACK_KIND)) { videoTrackAdapters.addAdapter((VideoTrack) track); + videoTrackAdapters.addDimensionDetector((VideoTrack) track); } remoteTracks.put(track.id(), track); } diff --git a/android/src/main/java/com/oney/WebRTCModule/VideoTrackAdapter.java b/android/src/main/java/com/oney/WebRTCModule/VideoTrackAdapter.java index 43ddbcbd7..486bfe6b7 100644 --- a/android/src/main/java/com/oney/WebRTCModule/VideoTrackAdapter.java +++ b/android/src/main/java/com/oney/WebRTCModule/VideoTrackAdapter.java @@ -23,6 +23,7 @@ public class VideoTrackAdapter { static final long MUTE_DELAY = 1500; private Map muteImplMap = new HashMap<>(); + private Map dimensionDetectorMap = new HashMap<>(); private Timer timer = new Timer("VideoTrackMutedTimer"); @@ -62,6 +63,32 @@ public void removeAdapter(VideoTrack videoTrack) { Log.d(TAG, "Deleted adapter for " + trackId); } + public void addDimensionDetector(VideoTrack videoTrack) { + String trackId = videoTrack.id(); + if (dimensionDetectorMap.containsKey(trackId)) { + Log.w(TAG, "Attempted to add dimension detector twice for track ID: " + trackId); + return; + } + + VideoDimensionDetectorImpl dimensionDetector = new VideoDimensionDetectorImpl(trackId); + Log.d(TAG, "Created dimension detector for " + trackId); + dimensionDetectorMap.put(trackId, dimensionDetector); + videoTrack.addSink(dimensionDetector); + } + + public void removeDimensionDetector(VideoTrack videoTrack) { + String trackId = videoTrack.id(); + VideoDimensionDetectorImpl dimensionDetector = dimensionDetectorMap.remove(trackId); + if (dimensionDetector == null) { + Log.w(TAG, "removeDimensionDetector - no detector for " + trackId); + return; + } + + videoTrack.removeSink(dimensionDetector); + dimensionDetector.dispose(); + Log.d(TAG, "Deleted dimension detector for " + trackId); + } + /** * Implements 'mute'/'unmute' events for remote video tracks through * the {@link VideoSink} interface. @@ -134,4 +161,58 @@ void dispose() { } } } + + /** + * Implements dimension change events for remote video tracks through + * the {@link VideoSink} interface. + */ + private class VideoDimensionDetectorImpl implements VideoSink { + private volatile boolean disposed; + private int currentWidth = 0; + private int currentHeight = 0; + private boolean hasInitialSize = false; + private final String trackId; + + VideoDimensionDetectorImpl(String trackId) { + this.trackId = trackId; + } + + @Override + public void onFrame(VideoFrame frame) { + if (disposed) { + return; + } + + int width = frame.getBuffer().getWidth(); + int height = frame.getBuffer().getHeight(); + + // Check if this is a meaningful size change + if (!hasInitialSize) { + currentWidth = width; + currentHeight = height; + hasInitialSize = true; + emitDimensionChangeEvent(width, height); + } else if (currentWidth != width || currentHeight != height) { + currentWidth = width; + currentHeight = height; + emitDimensionChangeEvent(width, height); + } + } + + private void emitDimensionChangeEvent(int width, int height) { + WritableMap params = Arguments.createMap(); + params.putInt("pcId", peerConnectionId); + params.putString("trackId", trackId); + params.putInt("width", width); + params.putInt("height", height); + + Log.d(TAG, "Dimension change event pcId: " + peerConnectionId + " trackId: " + trackId + " dimensions: " + width + "x" + height); + + VideoTrackAdapter.this.webRTCModule.sendEvent("videoTrackDimensionChanged", params); + } + + void dispose() { + disposed = true; + } + } } From c2351724ba8db35496d19a80cdf351c75572e67c Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 9 Jul 2025 16:16:07 +0200 Subject: [PATCH 03/16] add typescript support --- .../WebRTCModule/PeerConnectionObserver.java | 9 ++++++ .../com/oney/WebRTCModule/WebRTCModule.java | 19 +++++++++++ .../WebRTCModule+RTCPeerConnection.m | 32 +++++++++++++++++++ src/EventEmitter.ts | 1 + src/MediaStreamTrack.ts | 18 +++++++++++ src/RTCPeerConnection.ts | 18 +++++++++++ 6 files changed, 97 insertions(+) diff --git a/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java b/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java index ac76e5a18..b0190d3b1 100644 --- a/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java +++ b/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java @@ -79,6 +79,15 @@ void dispose() { } } + // Remove video track adapters for local tracks (from senders) + for (RtpSender sender : this.peerConnection.getSenders()) { + MediaStreamTrack track = sender.track(); + if (track instanceof VideoTrack) { + videoTrackAdapters.removeAdapter((VideoTrack) track); + videoTrackAdapters.removeDimensionDetector((VideoTrack) track); + } + } + // Remove DataChannel observers for (DataChannelWrapper dcw : dataChannels.values()) { DataChannel dataChannel = dcw.getDataChannel(); diff --git a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java index a8c71a69d..945ebb3cd 100644 --- a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java +++ b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java @@ -504,6 +504,12 @@ public WritableMap peerConnectionAddTransceiver(int id, ReadableMap options) { MediaStreamTrack track = getLocalTrack(trackId); transceiver = pco.addTransceiver( track, SerializeUtils.parseTransceiverOptions(options.getMap("init"))); + + // Add dimension detection for local video tracks + if (track instanceof VideoTrack) { + pco.videoTrackAdapters.addAdapter((VideoTrack) track); + pco.videoTrackAdapters.addDimensionDetector((VideoTrack) track); + } } else { // This should technically never happen as the JS side checks for that. @@ -556,6 +562,12 @@ public WritableMap peerConnectionAddTrack(int id, String trackId, ReadableMap op } } RtpSender sender = pco.getPeerConnection().addTrack(track, streamIds); + + // Add dimension detection for local video tracks + if (track instanceof VideoTrack) { + pco.videoTrackAdapters.addAdapter((VideoTrack) track); + pco.videoTrackAdapters.addDimensionDetector((VideoTrack) track); + } // Need to get the corresponding transceiver as well RtpTransceiver transceiver = pco.getTransceiver(sender.id()); @@ -591,6 +603,13 @@ public boolean peerConnectionRemoveTrack(int id, String senderId) { return false; } + // Remove video track adapters for local tracks + MediaStreamTrack track = sender.track(); + if (track instanceof VideoTrack) { + pco.videoTrackAdapters.removeAdapter((VideoTrack) track); + pco.videoTrackAdapters.removeDimensionDetector((VideoTrack) track); + } + return pco.getPeerConnection().removeTrack(sender); }) .get(); diff --git a/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m b/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m index 17f6707a8..5afd248d5 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m @@ -334,6 +334,15 @@ @implementation WebRTCModule (RTCPeerConnection) } } + // Remove video track adapters for local tracks (from senders) + for (RTCRtpSender *sender in peerConnection.senders) { + RTCMediaStreamTrack *track = sender.track; + if (track && track.kind == kRTCMediaStreamTrackKindVideo) { + [peerConnection removeVideoTrackAdapter:(RTCVideoTrack *)track]; + [peerConnection removeVideoDimensionDetector:(RTCVideoTrack *)track]; + } + } + // Clean up peerConnection's streams and tracks [peerConnection.remoteStreams removeAllObjects]; [peerConnection.remoteTracks removeAllObjects]; @@ -456,6 +465,14 @@ @implementation WebRTCModule (RTCPeerConnection) NSArray *streamIds = [options objectForKey:@"streamIds"]; RTCRtpSender *sender = [peerConnection addTrack:track streamIds:streamIds]; + + // Add dimension detection for local video tracks + if (track.kind == kRTCMediaStreamTrackKindVideo) { + RTCVideoTrack *videoTrack = (RTCVideoTrack *)track; + [peerConnection addVideoTrackAdapter:videoTrack]; + [peerConnection addVideoDimensionDetector:videoTrack]; + } + RTCRtpTransceiver *transceiver = nil; for (RTCRtpTransceiver *t in peerConnection.transceivers) { @@ -519,6 +536,13 @@ @implementation WebRTCModule (RTCPeerConnection) RTCRtpTransceiverInit *transceiverInit = [SerializeUtils parseTransceiverOptions:initOptions]; transceiver = [peerConnection addTransceiverWithTrack:track init:transceiverInit]; + + // Add dimension detection for local video tracks + if (track && track.kind == kRTCMediaStreamTrackKindVideo && self.localTracks[trackId]) { + RTCVideoTrack *videoTrack = (RTCVideoTrack *)track; + [peerConnection addVideoTrackAdapter:videoTrack]; + [peerConnection addVideoDimensionDetector:videoTrack]; + } } else { RCTLogWarn(@"peerConnectionAddTransceiver() no type nor trackId provided in options"); return; @@ -564,6 +588,14 @@ @implementation WebRTCModule (RTCPeerConnection) return; } + // Remove video track adapters for local tracks + RTCMediaStreamTrack *track = sender.track; + if (track && track.kind == kRTCMediaStreamTrackKindVideo) { + RTCVideoTrack *videoTrack = (RTCVideoTrack *)track; + [peerConnection removeVideoTrackAdapter:videoTrack]; + [peerConnection removeVideoDimensionDetector:videoTrack]; + } + ret = [peerConnection removeTrack:sender]; }); diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts index 48adb14fb..b21e49d47 100644 --- a/src/EventEmitter.ts +++ b/src/EventEmitter.ts @@ -22,6 +22,7 @@ const NATIVE_EVENTS = [ 'dataChannelReceiveMessage', 'dataChannelDidChangeBufferedAmount', 'mediaStreamTrackMuteChanged', + 'videoTrackDimensionChanged', 'mediaStreamTrackEnded', ]; diff --git a/src/MediaStreamTrack.ts b/src/MediaStreamTrack.ts index 1781a9179..2a2deb6d6 100644 --- a/src/MediaStreamTrack.ts +++ b/src/MediaStreamTrack.ts @@ -164,6 +164,24 @@ export default class MediaStreamTrack extends EventTarget { + if (ev.pcId !== this._pcId) { + return; + } + + // Check both receivers (remote tracks) and senders (local tracks) + const [ + track + ] = this.getReceivers() + .map(r => r.track) + .concat(this.getSenders().map(s => s.track)) + .filter(t => t?.id === ev.trackId); + + if (track) { + track._setVideoTrackDimensions(ev.width, ev.height); + } + }); } /** From 0b95fd116e4301428407a813ffc46737a9efa59e Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Wed, 9 Jul 2025 16:18:03 +0200 Subject: [PATCH 04/16] 125.3.2-alpha.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a0a7ce317..15dfa6ff6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.3.1", + "version": "125.3.2-alpha.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.3.1", + "version": "125.3.2-alpha.1", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index 4e889a747..7a8ca50a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.3.1", + "version": "125.3.2-alpha.1", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From b7d3140db83799a541182d0c6da3b493ac521f08 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 14:08:28 +0200 Subject: [PATCH 05/16] fixes for local tracks --- .../oney/WebRTCModule/GetUserMediaImpl.java | 39 +++++++++++++++++-- .../WebRTCModule/PeerConnectionObserver.java | 4 +- .../com/oney/WebRTCModule/WebRTCModule.java | 8 ++-- src/RTCPeerConnection.ts | 4 +- 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java b/android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java index abc41042f..ede36d2ac 100644 --- a/android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java +++ b/android/src/main/java/com/oney/WebRTCModule/GetUserMediaImpl.java @@ -425,8 +425,12 @@ VideoTrack createVideoTrack(AbstractVideoCaptureController videoCaptureControlle VideoTrack track = pcFactory.createVideoTrack(id, videoSource); + // Add dimension detection for local video tracks immediately when created + VideoTrackAdapter localTrackAdapter = new VideoTrackAdapter(webRTCModule, -1); // Use -1 for local tracks + localTrackAdapter.addDimensionDetector(track); + track.setEnabled(true); - tracks.put(id, new TrackPrivate(track, videoSource, videoCaptureController, surfaceTextureHelper)); + tracks.put(id, new TrackPrivate(track, videoSource, videoCaptureController, surfaceTextureHelper, localTrackAdapter)); videoCaptureController.startCapture(); @@ -444,8 +448,14 @@ MediaStreamTrack cloneTrack(String trackId) { String id = UUID.randomUUID().toString(); MediaStreamTrack nativeTrack = track.track; final MediaStreamTrack clonedNativeTrack; + VideoTrackAdapter clonedVideoTrackAdapter = null; + if (nativeTrack instanceof VideoTrack) { clonedNativeTrack = pcFactory.createVideoTrack(id, (VideoSource) track.mediaSource); + + // Create dimension detection for cloned video tracks + clonedVideoTrackAdapter = new VideoTrackAdapter(webRTCModule, -1); + clonedVideoTrackAdapter.addDimensionDetector((VideoTrack) clonedNativeTrack); } else { clonedNativeTrack = pcFactory.createAudioTrack(id, (AudioSource) track.mediaSource); } @@ -455,7 +465,8 @@ MediaStreamTrack cloneTrack(String trackId) { clonedNativeTrack, track.mediaSource, track.videoCaptureController, - track.surfaceTextureHelper + track.surfaceTextureHelper, + clonedVideoTrackAdapter ); clone.setParent(track); tracks.put(id, clone); @@ -519,6 +530,11 @@ private static class TrackPrivate { private final SurfaceTextureHelper surfaceTextureHelper; + /** + * The {@code VideoTrackAdapter} for dimension detection if {@link #track} is a {@link VideoTrack}. + */ + public final VideoTrackAdapter videoTrackAdapter; + /** * Whether this object has been disposed or not. */ @@ -538,16 +554,28 @@ private static class TrackPrivate { * @param videoCaptureController the {@code AbstractVideoCaptureController} from which the * specified {@code mediaSource} was created if the specified * {@code track} is a {@link VideoTrack} + * @param surfaceTextureHelper the {@code SurfaceTextureHelper} for video rendering + * @param videoTrackAdapter the {@code VideoTrackAdapter} for dimension detection if video track */ public TrackPrivate(MediaStreamTrack track, MediaSource mediaSource, - AbstractVideoCaptureController videoCaptureController, SurfaceTextureHelper surfaceTextureHelper) { + AbstractVideoCaptureController videoCaptureController, SurfaceTextureHelper surfaceTextureHelper, + VideoTrackAdapter videoTrackAdapter) { this.track = track; this.mediaSource = mediaSource; this.videoCaptureController = videoCaptureController; this.surfaceTextureHelper = surfaceTextureHelper; + this.videoTrackAdapter = videoTrackAdapter; this.disposed = false; } + /** + * Backwards compatibility constructor for audio tracks + */ + public TrackPrivate(MediaStreamTrack track, MediaSource mediaSource, + AbstractVideoCaptureController videoCaptureController, SurfaceTextureHelper surfaceTextureHelper) { + this(track, mediaSource, videoCaptureController, surfaceTextureHelper, null); + } + public void dispose() { final boolean isClone = this.isClone(); if (!disposed) { @@ -557,6 +585,11 @@ public void dispose() { } } + // Clean up VideoTrackAdapter for video tracks + if (!isClone && videoTrackAdapter != null && track instanceof VideoTrack) { + videoTrackAdapter.removeDimensionDetector((VideoTrack) track); + } + /* * As per webrtc library documentation - The caller still has ownership of {@code * surfaceTextureHelper} and is responsible for making sure surfaceTextureHelper.dispose() is diff --git a/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java b/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java index b0190d3b1..32b028f82 100644 --- a/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java +++ b/android/src/main/java/com/oney/WebRTCModule/PeerConnectionObserver.java @@ -41,7 +41,7 @@ class PeerConnectionObserver implements PeerConnection.Observer { final Map remoteStreamIds; // Stream ID -> React tag final Map remoteStreams; // React tag -> MediaStream final Map remoteTracks; - private final VideoTrackAdapter videoTrackAdapters; + final VideoTrackAdapter videoTrackAdapters; private final WebRTCModule webRTCModule; PeerConnectionObserver(WebRTCModule webRTCModule, int id) { @@ -84,7 +84,7 @@ void dispose() { MediaStreamTrack track = sender.track(); if (track instanceof VideoTrack) { videoTrackAdapters.removeAdapter((VideoTrack) track); - videoTrackAdapters.removeDimensionDetector((VideoTrack) track); + // Note: dimension detection for local tracks is cleaned up when track is disposed } } diff --git a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java index 945ebb3cd..ad76ed376 100644 --- a/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java +++ b/android/src/main/java/com/oney/WebRTCModule/WebRTCModule.java @@ -505,10 +505,9 @@ public WritableMap peerConnectionAddTransceiver(int id, ReadableMap options) { transceiver = pco.addTransceiver( track, SerializeUtils.parseTransceiverOptions(options.getMap("init"))); - // Add dimension detection for local video tracks + // Add mute detection for local video tracks (dimension detection is handled at track creation) if (track instanceof VideoTrack) { pco.videoTrackAdapters.addAdapter((VideoTrack) track); - pco.videoTrackAdapters.addDimensionDetector((VideoTrack) track); } } else { @@ -563,10 +562,9 @@ public WritableMap peerConnectionAddTrack(int id, String trackId, ReadableMap op } RtpSender sender = pco.getPeerConnection().addTrack(track, streamIds); - // Add dimension detection for local video tracks + // Add mute detection for local video tracks (dimension detection is handled at track creation) if (track instanceof VideoTrack) { pco.videoTrackAdapters.addAdapter((VideoTrack) track); - pco.videoTrackAdapters.addDimensionDetector((VideoTrack) track); } // Need to get the corresponding transceiver as well @@ -607,7 +605,7 @@ public boolean peerConnectionRemoveTrack(int id, String senderId) { MediaStreamTrack track = sender.track(); if (track instanceof VideoTrack) { pco.videoTrackAdapters.removeAdapter((VideoTrack) track); - pco.videoTrackAdapters.removeDimensionDetector((VideoTrack) track); + // Note: dimension detection for local tracks is cleaned up when track is disposed } return pco.getPeerConnection().removeTrack(sender); diff --git a/src/RTCPeerConnection.ts b/src/RTCPeerConnection.ts index 02face803..861dc3bc0 100644 --- a/src/RTCPeerConnection.ts +++ b/src/RTCPeerConnection.ts @@ -727,7 +727,9 @@ export default class RTCPeerConnection extends EventTarget { - if (ev.pcId !== this._pcId) { + // For local tracks (pcId: -1), process on all peer connections that have the track + // For remote tracks, only process on the matching peer connection + if (ev.pcId !== -1 && ev.pcId !== this._pcId) { return; } From b2c84fa48ffbd58376cd065d86867b02b12bebb4 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 14:08:51 +0200 Subject: [PATCH 06/16] 125.3.2-alpha.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 15dfa6ff6..f4c076723 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.3.2-alpha.1", + "version": "125.3.2-alpha.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@stream-io/react-native-webrtc", - "version": "125.3.2-alpha.1", + "version": "125.3.2-alpha.2", "license": "MIT", "dependencies": { "base64-js": "1.5.1", diff --git a/package.json b/package.json index 7a8ca50a0..d903696a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@stream-io/react-native-webrtc", - "version": "125.3.2-alpha.1", + "version": "125.3.2-alpha.2", "repository": { "type": "git", "url": "git+https://github.com/GetStream/react-native-webrtc.git" From 1f3db3f1b0a3fd719a315173acd045e52da553a2 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 14:22:07 +0200 Subject: [PATCH 07/16] move listener to media stream track level --- src/MediaStreamTrack.ts | 13 +++++++++++++ src/RTCPeerConnection.ts | 20 -------------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/MediaStreamTrack.ts b/src/MediaStreamTrack.ts index 2a2deb6d6..5dc49be96 100644 --- a/src/MediaStreamTrack.ts +++ b/src/MediaStreamTrack.ts @@ -258,6 +258,19 @@ export default class MediaStreamTrack extends EventTarget { + if (ev.trackId !== this.id) { + return; + } + + console.log(`[DEBUG] MediaStreamTrack received dimension event: ${ev.width}x${ev.height}`); + this._setVideoTrackDimensions(ev.width, ev.height); + console.log('[DEBUG] MediaStreamTrack settings after update:', this.getSettings()); + }); + } } release(): void { diff --git a/src/RTCPeerConnection.ts b/src/RTCPeerConnection.ts index 861dc3bc0..cc88293d7 100644 --- a/src/RTCPeerConnection.ts +++ b/src/RTCPeerConnection.ts @@ -725,26 +725,6 @@ export default class RTCPeerConnection extends EventTarget { - // For local tracks (pcId: -1), process on all peer connections that have the track - // For remote tracks, only process on the matching peer connection - if (ev.pcId !== -1 && ev.pcId !== this._pcId) { - return; - } - - // Check both receivers (remote tracks) and senders (local tracks) - const [ - track - ] = this.getReceivers() - .map(r => r.track) - .concat(this.getSenders().map(s => s.track)) - .filter(t => t?.id === ev.trackId); - - if (track) { - track._setVideoTrackDimensions(ev.width, ev.height); - } - }); } /** From 852ad3ace6865c3e28401ad2fb8c941700572aef Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 14:29:29 +0200 Subject: [PATCH 08/16] listener for remote tracks --- src/RTCPeerConnection.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/RTCPeerConnection.ts b/src/RTCPeerConnection.ts index cc88293d7..e2dc79111 100644 --- a/src/RTCPeerConnection.ts +++ b/src/RTCPeerConnection.ts @@ -725,6 +725,22 @@ export default class RTCPeerConnection extends EventTarget { + // Only handle remote tracks (pcId !== -1) and only for this peer connection + if (ev.pcId === -1 || ev.pcId !== this._pcId) { + return; + } + + const [ + track + ] = this.getReceivers().map(r => r.track).filter(t => t?.id === ev.trackId); + + if (track) { + track._setVideoTrackDimensions(ev.width, ev.height); + } + }); } /** From 5086ea752c2c730b2e5c1aadf3e87afa834e8b35 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 14:56:38 +0200 Subject: [PATCH 09/16] remove debug logs --- src/MediaStreamTrack.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/MediaStreamTrack.ts b/src/MediaStreamTrack.ts index 5dc49be96..b866df6d5 100644 --- a/src/MediaStreamTrack.ts +++ b/src/MediaStreamTrack.ts @@ -266,9 +266,7 @@ export default class MediaStreamTrack extends EventTarget Date: Fri, 11 Jul 2025 16:55:20 +0200 Subject: [PATCH 10/16] ios fixes for local tracks --- ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m | 59 ++++++++++++++++++- .../WebRTCModule+RTCPeerConnection.m | 11 ++-- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m index eafae4394..d3a835d63 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m @@ -60,6 +60,9 @@ - (RTCVideoTrack *)createVideoTrackWithCaptureController: videoTrack.captureController = captureController; [captureController startCapture]; + // Add dimension detection for local video tracks immediately + [self addLocalVideoTrackDimensionDetection:videoTrack]; + return videoTrack; #endif } @@ -136,6 +139,9 @@ - (RTCVideoTrack *)createVideoTrack:(NSDictionary *)constraints { [videoCaptureController startCapture]; #endif + // Add dimension detection for local video tracks immediately + [self addLocalVideoTrackDimensionDetection:videoTrack]; + return videoTrack; #endif } @@ -159,6 +165,9 @@ - (RTCVideoTrack *)createScreenCaptureVideoTrack { videoTrack.captureController = screenCaptureController; [screenCaptureController startCapture]; + // Add dimension detection for local video tracks immediately + [self addLocalVideoTrackDimensionDetection:videoTrack]; + return videoTrack; } @@ -276,7 +285,7 @@ - (RTCVideoTrack *)createScreenCaptureVideoTrack { #endif } -#pragma mark - Other stream related APIs +#pragma mark - enumerateDevices RCT_EXPORT_METHOD(enumerateDevices : (RCTResponseSenderBlock)callback) { #if TARGET_OS_TV @@ -332,6 +341,45 @@ - (RTCVideoTrack *)createScreenCaptureVideoTrack { #endif } +#pragma mark - Local Video Track Dimension Detection + +- (void)addLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack { + if (!videoTrack) { + return; + } + + // Create a dimension detector for this local track + VideoDimensionDetector *detector = [[VideoDimensionDetector alloc] initWith:@(-1) // -1 for local tracks + trackId:videoTrack.trackId + webRTCModule:self]; + + // Store the detector using associated objects on the track itself + objc_setAssociatedObject(videoTrack, @selector(addLocalVideoTrackDimensionDetection:), detector, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // Add the detector as a renderer to the track + [videoTrack addRenderer:detector]; + + RCTLogTrace(@"[VideoTrackAdapter] Local dimension detector created for track %@", videoTrack.trackId); +} + +- (void)removeLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack { + if (!videoTrack) { + return; + } + + // Get the associated detector + VideoDimensionDetector *detector = objc_getAssociatedObject(videoTrack, @selector(addLocalVideoTrackDimensionDetection:)); + + if (detector) { + [videoTrack removeRenderer:detector]; + [detector dispose]; + objc_setAssociatedObject(videoTrack, @selector(addLocalVideoTrackDimensionDetection:), nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + RCTLogTrace(@"[VideoTrackAdapter] Local dimension detector removed for track %@", videoTrack.trackId); + } +} + +#pragma mark - Other stream related APIs + RCT_EXPORT_METHOD(mediaStreamCreate : (nonnull NSString *)streamID) { RTCMediaStream *mediaStream = [self.peerConnectionFactory mediaStreamWithStreamId:streamID]; self.localStreams[streamID] = mediaStream; @@ -393,6 +441,11 @@ - (RTCVideoTrack *)createScreenCaptureVideoTrack { RTCMediaStreamTrack *track = self.localTracks[trackID]; if (track) { + // Clean up dimension detection for local video tracks + if ([track.kind isEqualToString:@"video"]) { + [self removeLocalVideoTrackDimensionDetection:(RTCVideoTrack *)track]; + } + track.isEnabled = NO; [track.captureController stopCapture]; [self.localTracks removeObjectForKey:trackID]; @@ -425,6 +478,10 @@ - (RTCVideoTrack *)createScreenCaptureVideoTrack { RTCVideoSource *videoSource = originalVideoTrack.source; RTCVideoTrack *videoTrack = [self.peerConnectionFactory videoTrackWithSource:videoSource trackId:trackUUID]; videoTrack.isEnabled = originalTrack.isEnabled; + + // Add dimension detection for cloned local video tracks + [self addLocalVideoTrackDimensionDetection:videoTrack]; + [self.localTracks setObject:videoTrack forKey:trackUUID]; for (NSString* streamId in self.localStreams) { RTCMediaStream* stream = [self.localStreams objectForKey:streamId]; diff --git a/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m b/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m index 5afd248d5..379ab295f 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCPeerConnection.m @@ -339,7 +339,7 @@ @implementation WebRTCModule (RTCPeerConnection) RTCMediaStreamTrack *track = sender.track; if (track && track.kind == kRTCMediaStreamTrackKindVideo) { [peerConnection removeVideoTrackAdapter:(RTCVideoTrack *)track]; - [peerConnection removeVideoDimensionDetector:(RTCVideoTrack *)track]; + // Note: dimension detection for local tracks cleaned up at track release } } @@ -466,11 +466,10 @@ @implementation WebRTCModule (RTCPeerConnection) NSArray *streamIds = [options objectForKey:@"streamIds"]; RTCRtpSender *sender = [peerConnection addTrack:track streamIds:streamIds]; - // Add dimension detection for local video tracks + // Add mute detection for local video tracks (dimension detection handled at track creation) if (track.kind == kRTCMediaStreamTrackKindVideo) { RTCVideoTrack *videoTrack = (RTCVideoTrack *)track; [peerConnection addVideoTrackAdapter:videoTrack]; - [peerConnection addVideoDimensionDetector:videoTrack]; } RTCRtpTransceiver *transceiver = nil; @@ -537,11 +536,10 @@ @implementation WebRTCModule (RTCPeerConnection) transceiver = [peerConnection addTransceiverWithTrack:track init:transceiverInit]; - // Add dimension detection for local video tracks + // Add mute detection for local video tracks (dimension detection handled at track creation) if (track && track.kind == kRTCMediaStreamTrackKindVideo && self.localTracks[trackId]) { RTCVideoTrack *videoTrack = (RTCVideoTrack *)track; [peerConnection addVideoTrackAdapter:videoTrack]; - [peerConnection addVideoDimensionDetector:videoTrack]; } } else { RCTLogWarn(@"peerConnectionAddTransceiver() no type nor trackId provided in options"); @@ -588,12 +586,11 @@ @implementation WebRTCModule (RTCPeerConnection) return; } - // Remove video track adapters for local tracks + // Remove mute detection for local tracks (dimension detection cleaned up at track release) RTCMediaStreamTrack *track = sender.track; if (track && track.kind == kRTCMediaStreamTrackKindVideo) { RTCVideoTrack *videoTrack = (RTCVideoTrack *)track; [peerConnection removeVideoTrackAdapter:videoTrack]; - [peerConnection removeVideoDimensionDetector:videoTrack]; } ret = [peerConnection removeTrack:sender]; From dae4a071da84a8f1ed1d71337e58bf3aee6d7a3e Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 17:09:43 +0200 Subject: [PATCH 11/16] fix compilation errors --- ios/RCTWebRTC/WebRTCModule+RTCMediaStream.h | 3 +++ ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m | 1 + ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h | 8 ++++++++ 3 files changed, 12 insertions(+) diff --git a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.h b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.h index da281ac80..5b6353fd0 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.h +++ b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.h @@ -10,4 +10,7 @@ (CaptureController * (^)(RTCVideoSource *))captureControllerCreator; - (NSArray *)createMediaStream:(NSArray *)tracks; +- (void)addLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack; +- (void)removeLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack; + @end \ No newline at end of file diff --git a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m index d3a835d63..3d730a83f 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m @@ -10,6 +10,7 @@ #import "WebRTCModuleOptions.h" #import "WebRTCModule+RTCMediaStream.h" #import "WebRTCModule+RTCPeerConnection.h" +#import "WebRTCModule+VideoTrackAdapter.h" #import "ProcessorProvider.h" #import "ScreenCaptureController.h" diff --git a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h index 8e77ca97f..056062852 100644 --- a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h +++ b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h @@ -1,7 +1,15 @@ #import +#import #import "WebRTCModule.h" +@interface VideoDimensionDetector : NSObject + +- (instancetype)initWith:(NSNumber *)peerConnectionId trackId:(NSString *)trackId webRTCModule:(WebRTCModule *)module; +- (void)dispose; + +@end + @interface RTCPeerConnection (VideoTrackAdapter) @property(nonatomic, strong) NSMutableDictionary *videoTrackAdapters; From 5ed2f103335e14c6e9ad80c70731c9ad6bb4e4ec Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 17:15:17 +0200 Subject: [PATCH 12/16] fix duplicate declarations --- ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h | 4 ++++ ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h index 056062852..c80098aad 100644 --- a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h +++ b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.h @@ -5,6 +5,10 @@ @interface VideoDimensionDetector : NSObject +@property(copy, nonatomic) NSNumber *peerConnectionId; +@property(copy, nonatomic) NSString *trackId; +@property(weak, nonatomic) WebRTCModule *module; + - (instancetype)initWith:(NSNumber *)peerConnectionId trackId:(NSString *)trackId webRTCModule:(WebRTCModule *)module; - (void)dispose; diff --git a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m index c2b034d10..49ae665aa 100644 --- a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m +++ b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m @@ -125,13 +125,6 @@ - (void)setSize:(CGSize)size { * as a video renderer, which monitors the setSize: method to detect when * video dimensions change and emits events accordingly. */ -@interface VideoDimensionDetector : NSObject - -@property(copy, nonatomic) NSNumber *peerConnectionId; -@property(copy, nonatomic) NSString *trackId; -@property(weak, nonatomic) WebRTCModule *module; - -@end @implementation VideoDimensionDetector { BOOL _disposed; From dde6aaff1ca4d4972243301f58c7e836841ffb60 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 17:21:06 +0200 Subject: [PATCH 13/16] ios: add to supported event --- ios/RCTWebRTC/WebRTCModule.m | 1 + 1 file changed, 1 insertion(+) diff --git a/ios/RCTWebRTC/WebRTCModule.m b/ios/RCTWebRTC/WebRTCModule.m index 6917aee12..6951cad90 100644 --- a/ios/RCTWebRTC/WebRTCModule.m +++ b/ios/RCTWebRTC/WebRTCModule.m @@ -131,6 +131,7 @@ - (dispatch_queue_t)methodQueue { kEventDataChannelStateChanged, kEventDataChannelReceiveMessage, kEventMediaStreamTrackMuteChanged, + kEventVideoTrackDimensionChanged, kEventMediaStreamTrackEnded, kEventPeerConnectionOnRemoveTrack, kEventPeerConnectionOnTrack From eab311d73f44e7f11f8184556bb779f454eafd8c Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 17:28:47 +0200 Subject: [PATCH 14/16] add logs for local tracks --- ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m | 2 +- ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m index 3d730a83f..0c33e52a0 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m @@ -360,7 +360,7 @@ - (void)addLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack { // Add the detector as a renderer to the track [videoTrack addRenderer:detector]; - RCTLogTrace(@"[VideoTrackAdapter] Local dimension detector created for track %@", videoTrack.trackId); + RCTLog(@"[VideoTrackAdapter] Local dimension detector created for track %@", videoTrack.trackId); } - (void)removeLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack { diff --git a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m index 49ae665aa..2f6dbe7aa 100644 --- a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m +++ b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m @@ -169,6 +169,12 @@ - (void)emitDimensionChangeEvent:(CGSize)newSize { - (void)renderFrame:(nullable RTCVideoFrame *)frame { // We don't need to do anything with frames for dimension detection // The setSize: method will be called automatically when dimensions change + static int frameCount = 0; + frameCount++; + if (frameCount % 30 == 0) { // Log every 30 frames to avoid spam + RCTLog(@"[VideoDimensionDetector] renderFrame called for track %@ (pcId: %@), frame count: %d", + self.trackId, self.peerConnectionId, frameCount); + } } - (void)setSize:(CGSize)size { @@ -176,6 +182,9 @@ - (void)setSize:(CGSize)size { return; } + RCTLog(@"[VideoDimensionDetector] setSize called for track %@ (pcId: %@): %fx%f", + self.trackId, self.peerConnectionId, size.width, size.height); + // Check if this is a meaningful size change if (!_hasInitialSize) { _currentSize = size; From 1a173e58d60ae174e2ef2de195e51b9cc4918ce0 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 17:40:56 +0200 Subject: [PATCH 15/16] add more logs --- ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m | 2 +- .../WebRTCModule+VideoTrackAdapter.m | 9 ------ src/MediaStreamTrack.ts | 32 ++++++++++++++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m index 0c33e52a0..3d730a83f 100644 --- a/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m +++ b/ios/RCTWebRTC/WebRTCModule+RTCMediaStream.m @@ -360,7 +360,7 @@ - (void)addLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack { // Add the detector as a renderer to the track [videoTrack addRenderer:detector]; - RCTLog(@"[VideoTrackAdapter] Local dimension detector created for track %@", videoTrack.trackId); + RCTLogTrace(@"[VideoTrackAdapter] Local dimension detector created for track %@", videoTrack.trackId); } - (void)removeLocalVideoTrackDimensionDetection:(RTCVideoTrack *)videoTrack { diff --git a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m index 2f6dbe7aa..49ae665aa 100644 --- a/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m +++ b/ios/RCTWebRTC/WebRTCModule+VideoTrackAdapter.m @@ -169,12 +169,6 @@ - (void)emitDimensionChangeEvent:(CGSize)newSize { - (void)renderFrame:(nullable RTCVideoFrame *)frame { // We don't need to do anything with frames for dimension detection // The setSize: method will be called automatically when dimensions change - static int frameCount = 0; - frameCount++; - if (frameCount % 30 == 0) { // Log every 30 frames to avoid spam - RCTLog(@"[VideoDimensionDetector] renderFrame called for track %@ (pcId: %@), frame count: %d", - self.trackId, self.peerConnectionId, frameCount); - } } - (void)setSize:(CGSize)size { @@ -182,9 +176,6 @@ - (void)setSize:(CGSize)size { return; } - RCTLog(@"[VideoDimensionDetector] setSize called for track %@ (pcId: %@): %fx%f", - self.trackId, self.peerConnectionId, size.width, size.height); - // Check if this is a meaningful size change if (!_hasInitialSize) { _currentSize = size; diff --git a/src/MediaStreamTrack.ts b/src/MediaStreamTrack.ts index b866df6d5..321f81571 100644 --- a/src/MediaStreamTrack.ts +++ b/src/MediaStreamTrack.ts @@ -66,7 +66,16 @@ export default class MediaStreamTrack extends EventTarget { - if (ev.trackId !== this.id) { + console.log('[MediaStreamTrack] Received dimension event:', { + trackId: this.id, + eventTrackId: ev.trackId, + pcId: ev.pcId, + width: ev.width, + height: ev.height, + match: ev.trackId === this.id, + isLocal: ev.pcId === -1 + }); + + // Only handle local tracks (pcId === -1) and only for this track + if (ev.pcId !== -1 || ev.trackId !== this.id) { + console.log( + `[MediaStreamTrack] Ignoring event - pcId: ${ev.pcId}, ` + + `trackId match: ${ev.trackId === this.id}` + ); + return; } + console.log( + `[MediaStreamTrack] Processing dimension change for track ${this.id}: ` + + `${ev.width}x${ev.height}` + ); this._setVideoTrackDimensions(ev.width, ev.height); }); } From ed10d9784b85e3890fb62db38a0b4dcff768fd95 Mon Sep 17 00:00:00 2001 From: Santhosh Vaiyapuri Date: Fri, 11 Jul 2025 18:12:35 +0200 Subject: [PATCH 16/16] remove logs --- src/MediaStreamTrack.ts | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/src/MediaStreamTrack.ts b/src/MediaStreamTrack.ts index 321f81571..4eed72819 100644 --- a/src/MediaStreamTrack.ts +++ b/src/MediaStreamTrack.ts @@ -66,16 +66,7 @@ export default class MediaStreamTrack extends EventTarget { - console.log('[MediaStreamTrack] Received dimension event:', { - trackId: this.id, - eventTrackId: ev.trackId, - pcId: ev.pcId, - width: ev.width, - height: ev.height, - match: ev.trackId === this.id, - isLocal: ev.pcId === -1 - }); - // Only handle local tracks (pcId === -1) and only for this track if (ev.pcId !== -1 || ev.trackId !== this.id) { - console.log( - `[MediaStreamTrack] Ignoring event - pcId: ${ev.pcId}, ` + - `trackId match: ${ev.trackId === this.id}` - ); - return; } - console.log( - `[MediaStreamTrack] Processing dimension change for track ${this.id}: ` + - `${ev.width}x${ev.height}` - ); this._setVideoTrackDimensions(ev.width, ev.height); }); }