From 03ab5404ee9af2ba6ed5a535cff9f1ef464a9648 Mon Sep 17 00:00:00 2001 From: Marq Roldan Date: Tue, 9 Mar 2021 21:02:47 +0800 Subject: [PATCH 1/4] Added torch support on ios --- docs/README.md | 1 + ios/RCTTWVideoModule.m | 27 ++++++++++++++++++++++++++- src/TwilioVideo.ios.js | 5 +++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 0d63c0a7..306bc02e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -70,6 +70,7 @@ onCameraDidStopRunning | func | no | | Called when the camera has stopped runin onStatsReceived | func | no | | Called when stats are received (after calling getStats) onNetworkQualityLevelsChanged | func | no | | Called when the network quality levels of a participant have changed (only if enableNetworkQualityReporting is set to True when connecting) onDominantSpeakerDidChange | func | no | | Called when dominant speaker changes @param {{ participant, room }} dominant participant +onCameraFlashToggled | func | no | | Called when dominant speaker changes @param {{ isFlashOn, error }} dominant participant ----- **src/TwilioVideoLocalView.android.js** diff --git a/ios/RCTTWVideoModule.m b/ios/RCTTWVideoModule.m index fce4ce4d..0ac0747f 100644 --- a/ios/RCTTWVideoModule.m +++ b/ios/RCTTWVideoModule.m @@ -35,6 +35,7 @@ static NSString* cameraDidStopRunning = @"cameraDidStopRunning"; static NSString* statsReceived = @"statsReceived"; static NSString* networkQualityLevelsChanged = @"networkQualityLevelsChanged"; +static NSString* onCameraFlashToggled = @"onCameraFlashToggled"; static const CMVideoDimensions kRCTTWVideoAppCameraSourceDimensions = (CMVideoDimensions){900, 720}; @@ -111,7 +112,8 @@ - (dispatch_queue_t)methodQueue { cameraInterruptionEnded, statsReceived, networkQualityLevelsChanged, - dominantSpeakerDidChange + dominantSpeakerDidChange, + onCameraFlashToggled ]; } @@ -275,6 +277,29 @@ - (bool)_setLocalVideoEnabled:(bool)enabled { } } +RCT_EXPORT_METHOD(toggleFlash) { + NSMutableDictionary *body = [[NSMutableDictionary alloc] init]; + if (self.camera) { + AVCaptureDevice *device = self.camera.device; + if ([device hasTorch]){ + [device lockForConfiguration:nil]; + if (!device.torchActive) { + [device setTorchMode:AVCaptureTorchModeOn]; + } else { + [device setTorchMode:AVCaptureTorchModeOff]; + } + BOOL isFlashOn = device.torchActive; + [device unlockForConfiguration]; + [body addEntriesFromDictionary:@{ @"isFlashOn" : [NSNumber numberWithBool:!isFlashOn] }]; + } else { + [body addEntriesFromDictionary:@{ @"error" : @"Flash is not supported in current camera mode" }]; + } + } else { + [body addEntriesFromDictionary:@{ @"error" : @"There's no camera available" }]; + } + [self sendEventCheckingListenerWithName:onCameraFlashToggled body:body]; +} + RCT_EXPORT_METHOD(toggleSoundSetup:(BOOL)speaker) { NSError *error = nil; kTVIDefaultAVAudioSessionConfigurationBlock(); diff --git a/src/TwilioVideo.ios.js b/src/TwilioVideo.ios.js index 7d3cc0e8..9541d9e6 100644 --- a/src/TwilioVideo.ios.js +++ b/src/TwilioVideo.ios.js @@ -415,6 +415,11 @@ export default class TwilioVideo extends Component { if (this.props.onDominantSpeakerDidChange) { this.props.onDominantSpeakerDidChange(data) } + }), + this._eventEmitter.addListener('onCameraFlashToggled', data => { + if (this.props.onCameraFlashToggled) { + this.props.onCameraFlashToggled(data) + } }) ] } From c4c5d0b08344442ad43e7ba0101f831a8f6e8c4e Mon Sep 17 00:00:00 2001 From: Marq Roldan Date: Tue, 9 Mar 2021 22:12:59 +0800 Subject: [PATCH 2/4] Added Torch support in android --- .../library/CustomTwilioVideoView.java | 33 ++++++++++++++++++- .../library/CustomTwilioVideoViewManager.java | 10 ++++++ src/TwilioVideo.android.js | 17 ++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/android/src/main/java/com/twiliorn/library/CustomTwilioVideoView.java b/android/src/main/java/com/twiliorn/library/CustomTwilioVideoView.java index b75982fe..888bdd3c 100644 --- a/android/src/main/java/com/twiliorn/library/CustomTwilioVideoView.java +++ b/android/src/main/java/com/twiliorn/library/CustomTwilioVideoView.java @@ -16,6 +16,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.hardware.Camera; import android.media.AudioAttributes; import android.media.AudioFocusRequest; import android.media.AudioManager; @@ -37,6 +38,7 @@ import com.twilio.video.AudioTrackPublication; import com.twilio.video.BaseTrackStats; import com.twilio.video.CameraCapturer; +import com.twilio.video.CameraParameterUpdater; import com.twilio.video.ConnectOptions; import com.twilio.video.LocalAudioTrack; import com.twilio.video.LocalAudioTrackPublication; @@ -81,6 +83,7 @@ import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_AUDIO_CHANGED; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CAMERA_SWITCHED; +import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CAMERA_FLASH_TOGGLED; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CONNECTED; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CONNECT_FAILURE; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_DISCONNECTED; @@ -132,7 +135,8 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene Events.ON_PARTICIPANT_DISABLED_AUDIO_TRACK, Events.ON_STATS_RECEIVED, Events.ON_NETWORK_QUALITY_LEVELS_CHANGED, - Events.ON_DOMINANT_SPEAKER_CHANGED + Events.ON_DOMINANT_SPEAKER_CHANGED, + Events.ON_CAMERA_FLASH_TOGGLED }) public @interface Events { String ON_CAMERA_SWITCHED = "onCameraSwitched"; @@ -157,6 +161,7 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene String ON_STATS_RECEIVED = "onStatsReceived"; String ON_NETWORK_QUALITY_LEVELS_CHANGED = "onNetworkQualityLevelsChanged"; String ON_DOMINANT_SPEAKER_CHANGED = "onDominantSpeakerDidChange"; + String ON_CAMERA_FLASH_TOGGLED = "onCameraFlashToggled"; } private final ThemedReactContext themedReactContext; @@ -565,6 +570,32 @@ public void switchCamera() { } } + private final CameraParameterUpdater flashToggler = parameters -> { + if (parameters.getFlashMode() != null) { + String flashMode = Camera.Parameters.FLASH_MODE_OFF.equals(parameters.getFlashMode()) ? + Camera.Parameters.FLASH_MODE_TORCH : + Camera.Parameters.FLASH_MODE_OFF; + parameters.setFlashMode(flashMode); + WritableMap event = new WritableNativeMap(); + event.putBoolean("isFlashOn", flashMode == Camera.Parameters.FLASH_MODE_TORCH); + pushEvent(CustomTwilioVideoView.this, ON_CAMERA_FLASH_TOGGLED, event); + } else { + WritableMap event = new WritableNativeMap(); + event.putString("error", "Flash is not supported in current camera mode"); + pushEvent(CustomTwilioVideoView.this, ON_CAMERA_FLASH_TOGGLED, event); + } + }; + + public void toggleFlash() { + if (cameraCapturer != null) { + cameraCapturer.updateCameraParameters(flashToggler); + } else { + WritableMap event = new WritableNativeMap(); + event.putString("error", "There's no camera available"); + pushEvent(CustomTwilioVideoView.this, ON_CAMERA_FLASH_TOGGLED, event); + } + } + public void toggleVideo(boolean enabled) { isVideoEnabled = enabled; if (localVideoTrack != null) { diff --git a/android/src/main/java/com/twiliorn/library/CustomTwilioVideoViewManager.java b/android/src/main/java/com/twiliorn/library/CustomTwilioVideoViewManager.java index 971c6da1..2396c34d 100644 --- a/android/src/main/java/com/twiliorn/library/CustomTwilioVideoViewManager.java +++ b/android/src/main/java/com/twiliorn/library/CustomTwilioVideoViewManager.java @@ -20,6 +20,7 @@ import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_AUDIO_CHANGED; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CAMERA_SWITCHED; +import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CAMERA_FLASH_TOGGLED; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CONNECTED; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_CONNECT_FAILURE; import static com.twiliorn.library.CustomTwilioVideoView.Events.ON_DISCONNECTED; @@ -59,6 +60,7 @@ public class CustomTwilioVideoViewManager extends SimpleViewManager getCommandsMap() { .put("connectToRoom", CONNECT_TO_ROOM) .put("disconnect", DISCONNECT) .put("switchCamera", SWITCH_CAMERA) + .put("toggleFlash", TOGGLE_FLASH) .put("toggleVideo", TOGGLE_VIDEO) .put("toggleSound", TOGGLE_SOUND) .put("getStats", GET_STATS) diff --git a/src/TwilioVideo.android.js b/src/TwilioVideo.android.js index 8750bb51..5c7909e2 100644 --- a/src/TwilioVideo.android.js +++ b/src/TwilioVideo.android.js @@ -143,7 +143,12 @@ const propTypes = { * Called when dominant speaker changes * @param {{ participant, room }} dominant participant and room */ - onDominantSpeakerDidChange: PropTypes.func + onDominantSpeakerDidChange: PropTypes.func, + /** + * Called when torch is done attempting to toggle + * @param {{ error, isFlashOn }} + */ + onCameraFlashToggled: PropTypes.func, } const nativeEvents = { @@ -160,7 +165,8 @@ const nativeEvents = { toggleBluetoothHeadset: 11, sendString: 12, publishVideo: 13, - publishAudio: 14 + publishAudio: 14, + toggleFlash: 15 } class CustomTwilioVideoView extends Component { @@ -218,6 +224,10 @@ class CustomTwilioVideoView extends Component { this.runCommand(nativeEvents.switchCamera, []) } + toggleFlash() { + this.runCommand(nativeEvents.toggleFlash, []); + } + setLocalVideoEnabled (enabled) { this.runCommand(nativeEvents.toggleVideo, [enabled]) return Promise.resolve(enabled) @@ -287,7 +297,8 @@ class CustomTwilioVideoView extends Component { 'onParticipantDisabledAudioTrack', 'onStatsReceived', 'onNetworkQualityLevelsChanged', - 'onDominantSpeakerDidChange' + 'onDominantSpeakerDidChange', + 'onCameraFlashToggled' ].reduce((wrappedEvents, eventName) => { if (this.props[eventName]) { return { From e36768e8c424f45ddc1fcdd420954fad2ca48b21 Mon Sep 17 00:00:00 2001 From: Marq Roldan Date: Tue, 9 Mar 2021 22:21:57 +0800 Subject: [PATCH 3/4] Added missing documentation for `onCameraFlashToggled` --- docs/README.md | 1 + index.d.ts | 3 +++ src/TwilioVideo.ios.js | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/docs/README.md b/docs/README.md index 306bc02e..131f5b7b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -34,6 +34,7 @@ onParticipantDisabledAudioTrack | func | no | | Called when an audio track has onStatsReceived | func | no | | Callback that is called when stats are received (after calling getStats) onNetworkQualityLevelsChanged | func | no | | Callback that is called when network quality levels are changed (only if enableNetworkQualityReporting in connect is set to true) onDominantSpeakerDidChange | func | no | | Called when dominant speaker changes @param {{ participant, room }} dominant participant and room +onCameraFlashToggled | func | no | | Called when dominant speaker changes @param {{ isFlashOn, error }} dominant participant ----- **src/TwilioVideo.ios.js** diff --git a/index.d.ts b/index.d.ts index da889a1b..1034bcd5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -68,9 +68,12 @@ declare module "react-native-twilio-video-webrtc" { export type NetworkLevelChangeEventCb = (p: NetworkLevelChangeEventArgs) => void; + export type CameraToggled = (p: { isFlashOn: boolean, error?: string}) => void; + export type TwilioVideoProps = ViewProps & { onCameraDidStart?: () => void; onCameraDidStopRunning?: (err: any) => void; + onCameraFlashToggled?: CameraToggled; onCameraWasInterrupted?: () => void; onParticipantAddedAudioTrack?: TrackEventCb; onParticipantAddedVideoTrack?: TrackEventCb; diff --git a/src/TwilioVideo.ios.js b/src/TwilioVideo.ios.js index 9541d9e6..d4f5aaf6 100644 --- a/src/TwilioVideo.ios.js +++ b/src/TwilioVideo.ios.js @@ -150,6 +150,11 @@ export default class TwilioVideo extends Component { * @param {{ participant, room }} dominant participant */ onDominantSpeakerDidChange: PropTypes.func, + /** + * Called when torch is done attempting to toggle + * @param {{ error, isFlashOn }} + */ + onCameraFlashToggled: PropTypes.func, ...View.propTypes } From c9f3b3d892858f7f1b44d2c8de0396f9d9cc0034 Mon Sep 17 00:00:00 2001 From: Marq Roldan Date: Wed, 10 Mar 2021 09:22:50 +0800 Subject: [PATCH 4/4] Added missing method for flash toggling on iOS --- index.d.ts | 1 + src/TwilioVideo.ios.js | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/index.d.ts b/index.d.ts index 1034bcd5..6567f8bb 100644 --- a/index.d.ts +++ b/index.d.ts @@ -128,6 +128,7 @@ declare module "react-native-twilio-video-webrtc" { connect: (options: iOSConnectParams | androidConnectParams) => void; disconnect: () => void; flipCamera: () => void; + toggleFlash: () => void; toggleSoundSetup: (speaker: boolean) => void; getStats: () => void; publishLocalAudio: () => void; diff --git a/src/TwilioVideo.ios.js b/src/TwilioVideo.ios.js index d4f5aaf6..2070693f 100644 --- a/src/TwilioVideo.ios.js +++ b/src/TwilioVideo.ios.js @@ -213,6 +213,13 @@ export default class TwilioVideo extends Component { TWVideoModule.flipCamera() } + /** + * Toggle Torch functionality + */ + toggleFlash () { + TWVideoModule.toggleFlash() + } + /** * Toggle audio setup from speaker (default) and headset */