8
8
*/
9
9
package com .twiliorn .library ;
10
10
11
+ import java .nio .ByteBuffer ;
12
+ import java .util .HashMap ;
13
+ import java .util .Map ;
14
+
11
15
import android .content .BroadcastReceiver ;
12
16
import android .content .Context ;
13
17
import android .content .Intent ;
17
21
import android .media .AudioManager ;
18
22
import android .os .Build ;
19
23
import android .os .Handler ;
24
+ import android .os .HandlerThread ;
20
25
import android .support .annotation .NonNull ;
21
26
import android .support .annotation .StringDef ;
22
27
import android .util .Log ;
43
48
import com .twilio .video .RemoteAudioTrack ;
44
49
import com .twilio .video .RemoteAudioTrackPublication ;
45
50
import com .twilio .video .RemoteAudioTrackStats ;
51
+ import com .twilio .video .LocalDataTrack ;
46
52
import com .twilio .video .RemoteDataTrack ;
47
53
import com .twilio .video .RemoteDataTrackPublication ;
48
54
import com .twilio .video .RemoteParticipant ;
73
79
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_CONNECTED ;
74
80
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_CONNECT_FAILURE ;
75
81
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_DISCONNECTED ;
82
+ import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_DATATRACK_MESSAGE_RECEIVED ;
83
+ import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_ADDED_DATA_TRACK ;
76
84
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_ADDED_AUDIO_TRACK ;
77
85
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_ADDED_VIDEO_TRACK ;
78
86
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_CONNECTED ;
81
89
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_DISCONNECTED ;
82
90
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_ENABLED_AUDIO_TRACK ;
83
91
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_ENABLED_VIDEO_TRACK ;
92
+ import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_REMOVED_DATA_TRACK ;
84
93
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_REMOVED_AUDIO_TRACK ;
85
94
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_PARTICIPANT_REMOVED_VIDEO_TRACK ;
86
95
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_STATS_RECEIVED ;
87
96
import static com .twiliorn .library .CustomTwilioVideoView .Events .ON_VIDEO_CHANGED ;
88
97
89
98
public class CustomTwilioVideoView extends View implements LifecycleEventListener , AudioManager .OnAudioFocusChangeListener {
90
99
private static final String TAG = "CustomTwilioVideoView" ;
100
+ private static final String DATA_TRACK_MESSAGE_THREAD_NAME = "DataTrackMessages" ;
91
101
private boolean enableRemoteAudio = false ;
92
102
93
103
@ Retention (RetentionPolicy .SOURCE )
@@ -100,6 +110,9 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene
100
110
Events .ON_PARTICIPANT_CONNECTED ,
101
111
Events .ON_PARTICIPANT_DISCONNECTED ,
102
112
Events .ON_PARTICIPANT_ADDED_VIDEO_TRACK ,
113
+ Events .ON_DATATRACK_MESSAGE_RECEIVED ,
114
+ Events .ON_PARTICIPANT_ADDED_DATA_TRACK ,
115
+ Events .ON_PARTICIPANT_REMOVED_DATA_TRACK ,
103
116
Events .ON_PARTICIPANT_REMOVED_VIDEO_TRACK ,
104
117
Events .ON_PARTICIPANT_ADDED_AUDIO_TRACK ,
105
118
Events .ON_PARTICIPANT_REMOVED_AUDIO_TRACK ,
@@ -117,6 +130,9 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene
117
130
String ON_DISCONNECTED = "onRoomDidDisconnect" ;
118
131
String ON_PARTICIPANT_CONNECTED = "onRoomParticipantDidConnect" ;
119
132
String ON_PARTICIPANT_DISCONNECTED = "onRoomParticipantDidDisconnect" ;
133
+ String ON_DATATRACK_MESSAGE_RECEIVED = "onDataTrackMessageReceived" ;
134
+ String ON_PARTICIPANT_ADDED_DATA_TRACK = "onParticipantAddedDataTrack" ;
135
+ String ON_PARTICIPANT_REMOVED_DATA_TRACK = "onParticipantRemovedDataTrack" ;
120
136
String ON_PARTICIPANT_ADDED_VIDEO_TRACK = "onParticipantAddedVideoTrack" ;
121
137
String ON_PARTICIPANT_REMOVED_VIDEO_TRACK = "onParticipantRemovedVideoTrack" ;
122
138
String ON_PARTICIPANT_ADDED_AUDIO_TRACK = "onParticipantAddedAudioTrack" ;
@@ -158,6 +174,17 @@ public class CustomTwilioVideoView extends View implements LifecycleEventListene
158
174
private IntentFilter intentFilter ;
159
175
private BecomingNoisyReceiver myNoisyAudioStreamReceiver ;
160
176
177
+ // Dedicated thread and handler for messages received from a RemoteDataTrack
178
+ private final HandlerThread dataTrackMessageThread =
179
+ new HandlerThread (DATA_TRACK_MESSAGE_THREAD_NAME );
180
+ private Handler dataTrackMessageThreadHandler ;
181
+
182
+ private LocalDataTrack localDataTrack ;
183
+
184
+ // Map used to map remote data tracks to remote participants
185
+ private final Map <RemoteDataTrack , RemoteParticipant > dataTrackRemoteParticipantMap =
186
+ new HashMap <>();
187
+
161
188
public CustomTwilioVideoView (ThemedReactContext context ) {
162
189
super (context );
163
190
this .themedReactContext = context ;
@@ -178,6 +205,15 @@ public CustomTwilioVideoView(ThemedReactContext context) {
178
205
audioManager = (AudioManager ) themedReactContext .getSystemService (Context .AUDIO_SERVICE );
179
206
myNoisyAudioStreamReceiver = new BecomingNoisyReceiver ();
180
207
intentFilter = new IntentFilter (Intent .ACTION_HEADSET_PLUG );
208
+
209
+ // Create the local data track
210
+ // localDataTrack = LocalDataTrack.create(this);
211
+ localDataTrack = LocalDataTrack .create (getContext ());
212
+
213
+ // Start the thread where data messages are received
214
+ dataTrackMessageThread .start ();
215
+ dataTrackMessageThreadHandler = new Handler (dataTrackMessageThread .getLooper ());
216
+
181
217
}
182
218
183
219
// ===== SETUP =================================================================================
@@ -247,6 +283,7 @@ private void createLocalMedia(boolean enableAudio, boolean enableVideo) {
247
283
248
284
// ===== LIFECYCLE EVENTS ======================================================================
249
285
286
+
250
287
@ Override
251
288
public void onHostResume () {
252
289
/*
@@ -322,6 +359,11 @@ public void onHostDestroy() {
322
359
localAudioTrack .release ();
323
360
localAudioTrack = null ;
324
361
}
362
+
363
+ // Quit the data track message thread
364
+ dataTrackMessageThread .quit ();
365
+
366
+
325
367
}
326
368
327
369
public void releaseResource () {
@@ -367,6 +409,12 @@ public void connectToRoom(boolean enableAudio) {
367
409
connectOptionsBuilder .videoTracks (Collections .singletonList (localVideoTrack ));
368
410
}
369
411
412
+ //LocalDataTrack localDataTrack = LocalDataTrack.create(getContext());
413
+
414
+ if (localDataTrack != null ) {
415
+ connectOptionsBuilder .dataTracks (Collections .singletonList (localDataTrack ));
416
+ }
417
+
370
418
room = Video .connect (getContext (), connectOptionsBuilder .build (), roomListener ());
371
419
}
372
420
@@ -455,6 +503,13 @@ public void disconnect() {
455
503
}
456
504
}
457
505
506
+ // ===== SEND STRING ON DATA TRACK ======================================================================
507
+ public void sendString (String message ) {
508
+ if (localDataTrack != null ) {
509
+ localDataTrack .send (message );
510
+ }
511
+ }
512
+
458
513
// ===== BUTTON LISTENERS ======================================================================
459
514
private static void setThumbnailMirror () {
460
515
if (cameraCapturer != null ) {
@@ -643,6 +698,7 @@ private Room.Listener roomListener() {
643
698
@ Override
644
699
public void onConnected (Room room ) {
645
700
localParticipant = room .getLocalParticipant ();
701
+
646
702
WritableMap event = new WritableNativeMap ();
647
703
event .putString ("roomName" , room .getName ());
648
704
event .putString ("roomSid" , room .getSid ());
@@ -656,6 +712,10 @@ public void onConnected(Room room) {
656
712
657
713
pushEvent (CustomTwilioVideoView .this , ON_CONNECTED , event );
658
714
715
+
716
+ //There is not .publish it's publishTrack
717
+ localParticipant .publishTrack (localDataTrack );
718
+
659
719
for (RemoteParticipant participant : participants ) {
660
720
addParticipant (room , participant );
661
721
}
@@ -706,6 +766,7 @@ public void onDisconnected(Room room, TwilioException e) {
706
766
@ Override
707
767
public void onParticipantConnected (Room room , RemoteParticipant participant ) {
708
768
addParticipant (room , participant );
769
+
709
770
}
710
771
711
772
@ Override
@@ -726,19 +787,31 @@ public void onRecordingStopped(Room room) {
726
787
/*
727
788
* Called when participant joins the room
728
789
*/
729
- private void addParticipant (Room room , RemoteParticipant participant ) {
790
+ private void addParticipant (Room room , RemoteParticipant remoteParticipant ) {
730
791
731
792
WritableMap event = new WritableNativeMap ();
732
793
event .putString ("roomName" , room .getName ());
733
794
event .putString ("roomSid" , room .getSid ());
734
- event .putMap ("participant" , buildParticipant (participant ));
795
+ event .putMap ("participant" , buildParticipant (remoteParticipant ));
735
796
736
797
pushEvent (this , ON_PARTICIPANT_CONNECTED , event );
737
798
738
799
/*
739
800
* Start listening for participant media events
740
801
*/
741
- participant .setListener (mediaListener ());
802
+ remoteParticipant .setListener (mediaListener ());
803
+
804
+ for (final RemoteDataTrackPublication remoteDataTrackPublication :
805
+ remoteParticipant .getRemoteDataTracks ()) {
806
+ /*
807
+ * Data track messages are received on the thread that calls setListener. Post the
808
+ * invocation of setting the listener onto our dedicated data track message thread.
809
+ */
810
+ if (remoteDataTrackPublication .isTrackSubscribed ()) {
811
+ dataTrackMessageThreadHandler .post (() -> addRemoteDataTrack (remoteParticipant ,
812
+ remoteDataTrackPublication .getRemoteDataTrack ()));
813
+ }
814
+ }
742
815
}
743
816
744
817
/*
@@ -754,6 +827,10 @@ private void removeParticipant(Room room, RemoteParticipant participant) {
754
827
//participant.setListener(null);
755
828
}
756
829
830
+ private void addRemoteDataTrack (RemoteParticipant remoteParticipant , RemoteDataTrack remoteDataTrack ) {
831
+ dataTrackRemoteParticipantMap .put (remoteDataTrack , remoteParticipant );
832
+ remoteDataTrack .setListener (remoteDataTrackListener ());
833
+ }
757
834
758
835
// ====== MEDIA LISTENER =======================================================================
759
836
@@ -786,14 +863,19 @@ public void onAudioTrackUnpublished(RemoteParticipant participant, RemoteAudioTr
786
863
787
864
}
788
865
789
- @ Override
790
- public void onDataTrackSubscribed (RemoteParticipant participant , RemoteDataTrackPublication publication , RemoteDataTrack dataTrack ) {
791
866
792
- }
793
867
794
868
@ Override
795
- public void onDataTrackUnsubscribed (RemoteParticipant participant , RemoteDataTrackPublication publication , RemoteDataTrack dataTrack ) {
869
+ public void onDataTrackSubscribed (RemoteParticipant remoteParticipant , RemoteDataTrackPublication remoteDataTrackPublication , RemoteDataTrack remoteDataTrack ) {
870
+ WritableMap event = buildParticipantDataEvent (remoteParticipant );
871
+ pushEvent (CustomTwilioVideoView .this , ON_PARTICIPANT_ADDED_DATA_TRACK , event );
872
+ dataTrackMessageThreadHandler .post (() -> addRemoteDataTrack (remoteParticipant , remoteDataTrack ));
873
+ }
796
874
875
+ @ Override
876
+ public void onDataTrackUnsubscribed (RemoteParticipant remoteParticipant , RemoteDataTrackPublication publication , RemoteDataTrack remoteDataTrack ) {
877
+ WritableMap event = buildParticipantDataEvent (remoteParticipant );
878
+ pushEvent (CustomTwilioVideoView .this , ON_PARTICIPANT_REMOVED_DATA_TRACK , event );
797
879
}
798
880
799
881
@ Override
@@ -869,6 +951,17 @@ private WritableMap buildParticipant(Participant participant) {
869
951
return participantMap ;
870
952
}
871
953
954
+
955
+ private WritableMap buildParticipantDataEvent (Participant participant ) {
956
+ WritableMap participantMap = buildParticipant (participant );
957
+ WritableMap participantMap2 = buildParticipant (participant );
958
+
959
+ WritableMap event = new WritableNativeMap ();
960
+ event .putMap ("participant" , participantMap );
961
+ event .putMap ("track" , participantMap2 );
962
+ return event ;
963
+ }
964
+
872
965
private WritableMap buildParticipantVideoEvent (Participant participant , TrackPublication publication ) {
873
966
WritableMap participantMap = buildParticipant (participant );
874
967
@@ -883,6 +976,12 @@ private WritableMap buildParticipantVideoEvent(Participant participant, TrackPub
883
976
return event ;
884
977
}
885
978
979
+ private WritableMap buildDataTrackEvent (String message ) {
980
+ WritableMap event = new WritableNativeMap ();
981
+ event .putString ("message" , message );
982
+ return event ;
983
+ }
984
+
886
985
private void addParticipantVideo (Participant participant , RemoteVideoTrackPublication publication ) {
887
986
WritableMap event = this .buildParticipantVideoEvent (participant , publication );
888
987
pushEvent (CustomTwilioVideoView .this , ON_PARTICIPANT_ADDED_VIDEO_TRACK , event );
@@ -924,4 +1023,21 @@ public static void registerThumbnailVideoView(VideoView v) {
924
1023
}
925
1024
setThumbnailMirror ();
926
1025
}
1026
+
1027
+ private RemoteDataTrack .Listener remoteDataTrackListener () {
1028
+ return new RemoteDataTrack .Listener () {
1029
+
1030
+ @ Override
1031
+ public void onMessage (RemoteDataTrack remoteDataTrack , ByteBuffer byteBuffer ) {
1032
+
1033
+ }
1034
+
1035
+
1036
+ @ Override
1037
+ public void onMessage (RemoteDataTrack remoteDataTrack , String message ) {
1038
+ WritableMap event = buildDataTrackEvent (message );
1039
+ pushEvent (CustomTwilioVideoView .this , ON_DATATRACK_MESSAGE_RECEIVED , event );
1040
+ }
1041
+ };
1042
+ }
927
1043
}
0 commit comments