6969import com .twilio .video .TrackPublication ;
7070import com .twilio .video .TwilioException ;
7171import com .twilio .video .Video ;
72- import com .twilio .video .VideoConstraints ;
7372import com .twilio .video .VideoDimensions ;
73+ import com .twilio .video .VideoFormat ;
7474
7575import org .webrtc .voiceengine .WebRtcAudioManager ;
7676
77+ import tvi .webrtc .Camera1Enumerator ;
78+
7779import java .lang .annotation .Retention ;
7880import java .lang .annotation .RetentionPolicy ;
7981import java .util .Collections ;
@@ -109,6 +111,8 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene
109111 private boolean enableNetworkQualityReporting = false ;
110112 private boolean isVideoEnabled = false ;
111113 private boolean dominantSpeakerEnabled = false ;
114+ private static String frontFacingDevice ;
115+ private static String backFacingDevice ;
112116 private boolean maintainVideoTrackInBackground = false ;
113117
114118 @ Retention (RetentionPolicy .SOURCE )
@@ -234,29 +238,27 @@ public CustomTwilioVideoView(ThemedReactContext context) {
234238
235239 // ===== SETUP =================================================================================
236240
237- private VideoConstraints buildVideoConstraints () {
238- return new VideoConstraints .Builder ()
239- .minVideoDimensions (VideoDimensions .CIF_VIDEO_DIMENSIONS )
240- .maxVideoDimensions (VideoDimensions .CIF_VIDEO_DIMENSIONS )
241- .minFps (5 )
242- .maxFps (15 )
243- .build ();
241+ private VideoFormat buildVideoFormat () {
242+ return new VideoFormat (VideoDimensions .CIF_VIDEO_DIMENSIONS , 15 );
244243 }
245244
246- private CameraCapturer createCameraCaputer (Context context , CameraCapturer . CameraSource cameraSource ) {
245+ private CameraCapturer createCameraCaputer (Context context , String cameraId ) {
247246 CameraCapturer newCameraCapturer = null ;
248247 try {
249248 newCameraCapturer = new CameraCapturer (
250249 context ,
251- cameraSource ,
250+ cameraId ,
252251 new CameraCapturer .Listener () {
253252 @ Override
254253 public void onFirstFrameAvailable () {
255254 }
256255
257256 @ Override
258- public void onCameraSwitched () {
257+ public void onCameraSwitched (String newCameraId ) {
259258 setThumbnailMirror ();
259+ WritableMap event = new WritableNativeMap ();
260+ event .putBoolean ("isBackCamera" , isCurrentCameraSourceBackFacing ());
261+ pushEvent (CustomTwilioVideoView .this , ON_CAMERA_SWITCHED , event );
260262 }
261263
262264 @ Override
@@ -271,27 +273,40 @@ public void onError(int i) {
271273 }
272274 }
273275
276+ private void buildDeviceInfo () {
277+ Camera1Enumerator enumerator = new Camera1Enumerator ();
278+ String [] deviceNames = enumerator .getDeviceNames ();
279+ backFacingDevice = null ;
280+ frontFacingDevice = null ;
281+ for (String deviceName : deviceNames ) {
282+ if (enumerator .isBackFacing (deviceName ) && enumerator .getSupportedFormats (deviceName ).size () > 0 ) {
283+ backFacingDevice = deviceName ;
284+ } else if (enumerator .isFrontFacing (deviceName ) && enumerator .getSupportedFormats (deviceName ).size () > 0 ) {
285+ frontFacingDevice = deviceName ;
286+ }
287+ }
288+ }
289+
274290 private boolean createLocalVideo (boolean enableVideo ) {
275- isVideoEnabled = enableVideo ;
291+ isVideoEnabled = enableVideo ;
276292 // Share your camera
277- cameraCapturer = this .createCameraCaputer (getContext (), CameraCapturer .CameraSource .FRONT_CAMERA );
278- if (cameraCapturer == null ){
279- cameraCapturer = this .createCameraCaputer (getContext (), CameraCapturer .CameraSource .BACK_CAMERA );
280- }
281- if (cameraCapturer == null ){
293+ buildDeviceInfo ();
294+ if (this .frontFacingDevice != null ) {
295+ cameraCapturer = this .createCameraCaputer (getContext (), frontFacingDevice );
296+ } else if (this .backFacingDevice != null ) {
297+ cameraCapturer = this .createCameraCaputer (getContext (), backFacingDevice );
298+ } else {
282299 WritableMap event = new WritableNativeMap ();
283300 event .putString ("error" , "No camera is supported on this device" );
284301 pushEvent (CustomTwilioVideoView .this , ON_CONNECT_FAILURE , event );
285302 return false ;
286303 }
287304
288- if (cameraCapturer .getSupportedFormats ().size () > 0 ) {
289- localVideoTrack = LocalVideoTrack .create (getContext (), enableVideo , cameraCapturer , buildVideoConstraints ());
290- if (thumbnailVideoView != null && localVideoTrack != null ) {
291- localVideoTrack .addRenderer (thumbnailVideoView );
292- }
293- setThumbnailMirror ();
305+ localVideoTrack = LocalVideoTrack .create (getContext (), enableVideo , cameraCapturer , buildVideoFormat ());
306+ if (thumbnailVideoView != null && localVideoTrack != null ) {
307+ localVideoTrack .addSink (thumbnailVideoView );
294308 }
309+ setThumbnailMirror ();
295310 return true ;
296311 }
297312
@@ -308,12 +323,12 @@ public void onHostResume() {
308323 * If the local video track was released when the app was put in the background, recreate.
309324 */
310325 if (cameraCapturer != null && localVideoTrack == null ) {
311- localVideoTrack = LocalVideoTrack .create (getContext (), isVideoEnabled , cameraCapturer , buildVideoConstraints ());
326+ localVideoTrack = LocalVideoTrack .create (getContext (), isVideoEnabled , cameraCapturer , buildVideoFormat ());
312327 }
313328
314329 if (localVideoTrack != null ) {
315330 if (thumbnailVideoView != null ) {
316- localVideoTrack .addRenderer (thumbnailVideoView );
331+ localVideoTrack .addSink (thumbnailVideoView );
317332 }
318333
319334 /*
@@ -545,11 +560,14 @@ public void sendString(String message) {
545560 }
546561 }
547562
563+ private static boolean isCurrentCameraSourceBackFacing () {
564+ return cameraCapturer != null && cameraCapturer .getCameraId () == backFacingDevice ;
565+ }
566+
548567 // ===== BUTTON LISTENERS ======================================================================
549568 private static void setThumbnailMirror () {
550569 if (cameraCapturer != null ) {
551- CameraCapturer .CameraSource cameraSource = cameraCapturer .getCameraSource ();
552- final boolean isBackCamera = (cameraSource == CameraCapturer .CameraSource .BACK_CAMERA );
570+ final boolean isBackCamera = isCurrentCameraSourceBackFacing ();
553571 if (thumbnailVideoView != null && thumbnailVideoView .getVisibility () == View .VISIBLE ) {
554572 thumbnailVideoView .setMirror (!isBackCamera );
555573 }
@@ -558,12 +576,12 @@ private static void setThumbnailMirror() {
558576
559577 public void switchCamera () {
560578 if (cameraCapturer != null ) {
561- cameraCapturer . switchCamera ();
562- CameraCapturer . CameraSource cameraSource = cameraCapturer . getCameraSource ();
563- final boolean isBackCamera = cameraSource == CameraCapturer . CameraSource . BACK_CAMERA ;
564- WritableMap event = new WritableNativeMap ();
565- event . putBoolean ( "isBackCamera" , isBackCamera );
566- pushEvent ( CustomTwilioVideoView . this , ON_CAMERA_SWITCHED , event );
579+ final boolean isBackCamera = isCurrentCameraSourceBackFacing ();
580+ if ( frontFacingDevice != null && ( isBackCamera || backFacingDevice == null )) {
581+ cameraCapturer . switchCamera ( frontFacingDevice ) ;
582+ } else {
583+ cameraCapturer . switchCamera ( backFacingDevice );
584+ }
567585 }
568586 }
569587
@@ -1145,9 +1163,9 @@ public static void registerPrimaryVideoView(PatchedVideoView v, String trackSid)
11451163 continue ;
11461164 }
11471165 if (publication .getTrackSid ().equals (trackSid )) {
1148- track .addRenderer (v );
1166+ track .addSink (v );
11491167 } else {
1150- track .removeRenderer (v );
1168+ track .removeSink (v );
11511169 }
11521170 }
11531171 }
@@ -1157,7 +1175,7 @@ public static void registerPrimaryVideoView(PatchedVideoView v, String trackSid)
11571175 public static void registerThumbnailVideoView (PatchedVideoView v ) {
11581176 thumbnailVideoView = v ;
11591177 if (localVideoTrack != null ) {
1160- localVideoTrack .addRenderer (v );
1178+ localVideoTrack .addSink (v );
11611179 }
11621180 setThumbnailMirror ();
11631181 }
0 commit comments