3636import static io .agora .api .example .common .model .Examples .ADVANCED ;
3737import static io .agora .rtc .video .VideoCanvas .RENDER_MODE_FIT ;
3838import static io .agora .rtc .video .VideoCanvas .RENDER_MODE_HIDDEN ;
39- import static io .agora .rtc .video .VideoEncoderConfiguration .FRAME_RATE .FRAME_RATE_FPS_15 ;
40- import static io .agora .rtc .video .VideoEncoderConfiguration .ORIENTATION_MODE .ORIENTATION_MODE_ADAPTIVE ;
4139import static io .agora .rtc .video .VideoEncoderConfiguration .STANDARD_BITRATE ;
42- import static io .agora .rtc .video .VideoEncoderConfiguration .VD_640x360 ;
4340
4441@ Example (
4542 index = 12 ,
@@ -59,7 +56,8 @@ public class JoinMultipleChannel extends BaseFragment implements View.OnClickLis
5956 private boolean joined = false ;
6057 private String channel1 ;
6158 private String channel2 ;
62- private RtcChannel rtcChannel ;
59+ private RtcChannel rtcChannel1 ;
60+ private RtcChannel rtcChannel2 ;
6361
6462 @ Nullable
6563 @ Override
@@ -100,6 +98,7 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState)
10098 * @param handler IRtcEngineEventHandler is an abstract class providing default implementation.
10199 * The SDK uses this class to report to the app on SDK runtime events.*/
102100 engine = RtcEngine .create (context .getApplicationContext (), getString (R .string .agora_app_id ), iRtcEngineEventHandler );
101+ setupVideo ();
103102 }
104103 catch (Exception e )
105104 {
@@ -128,14 +127,16 @@ public void onClick(View v)
128127 {
129128 if (!joined )
130129 {
130+ engine .stopPreview ();
131131 CommonUtil .hideInputBoard (getActivity (), et_channel );
132132 // call when join button hit
133133 channel1 = et_channel .getText ().toString ();
134134 channel2 = channel1 + "-2" ;
135135 // Check permission
136136 if (AndPermission .hasPermissions (this , Permission .Group .STORAGE , Permission .Group .MICROPHONE , Permission .Group .CAMERA ))
137137 {
138- joinChannel (channel1 );
138+ joinFirstChannel ();
139+ joinSecondChannel ();
139140 return ;
140141 }
141142 // Request permission
@@ -146,8 +147,10 @@ public void onClick(View v)
146147 ).onGranted (permissions ->
147148 {
148149 // Permissions Granted
149- joinChannel (channel1 );
150+ joinFirstChannel ();
151+ joinSecondChannel ();
150152 }).start ();
153+ join .setEnabled (false );
151154 }
152155 else
153156 {
@@ -169,14 +172,14 @@ public void onClick(View v)
169172 * the onLeaveChannel callback.
170173 * 2:If you call the leaveChannel method during CDN live streaming, the SDK
171174 * triggers the removeInjectStreamUrl method.*/
172- engine .leaveChannel ();
173- rtcChannel .leaveChannel ();
175+ rtcChannel2 .leaveChannel ();
176+ rtcChannel1 .leaveChannel ();
174177 join .setText (getString (R .string .join ));
175178 }
176179 }
177180 }
178181
179- private void joinChannel ( String channelId )
182+ private void setupVideo ( )
180183 {
181184 // Check if the context is valid
182185 Context context = getContext ();
@@ -195,6 +198,7 @@ private void joinChannel(String channelId)
195198 fl_local .addView (surfaceView , new FrameLayout .LayoutParams (ViewGroup .LayoutParams .MATCH_PARENT , ViewGroup .LayoutParams .MATCH_PARENT ));
196199 // Setup local video to render your local camera preview
197200 engine .setupLocalVideo (new VideoCanvas (surfaceView , RENDER_MODE_HIDDEN , 0 ));
201+ engine .startPreview ();
198202 // Set audio route to microPhone
199203 engine .setDefaultAudioRoutetoSpeakerphone (false );
200204
@@ -217,41 +221,91 @@ private void joinChannel(String channelId)
217221 VideoEncoderConfiguration .ORIENTATION_MODE .valueOf (((MainApplication )getActivity ().getApplication ()).getGlobalSettings ().getVideoEncodingOrientation ())
218222 ));
219223
220- /**Please configure accessToken in the string_config file.
221- * A temporary token generated in Console. A temporary token is valid for 24 hours. For details, see
222- * https://docs.agora.io/en/Agora%20Platform/token?platform=All%20Platforms#get-a-temporary-token
223- * A token generated at the server. This applies to scenarios with high-security requirements. For details, see
224- * https://docs.agora.io/en/cloud-recording/token_server_java?platform=Java*/
225- String accessToken = getString (R .string .agora_access_token );
226- if (TextUtils .equals (accessToken , "" ) || TextUtils .equals (accessToken , "<#YOUR ACCESS TOKEN#>" ))
227- {
228- accessToken = null ;
229- }
230- /** Allows a user to join a channel.
231- if you do not specify the uid, we will generate the uid for you*/
224+ }
232225
233- ChannelMediaOptions option = new ChannelMediaOptions ();
234- option .autoSubscribeAudio = true ;
235- option .autoSubscribeVideo = true ;
236- int res = engine .joinChannel (accessToken , channelId , "Extra Optional Data" , 0 , option );
237- if (res != 0 || !joinSecondChannel ())
238- {
239- // Usually happens with invalid parameters
240- // Error code description can be found at:
241- // en: https://docs.agora.io/en/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
242- // cn: https://docs.agora.io/cn/Voice/API%20Reference/java/classio_1_1agora_1_1rtc_1_1_i_rtc_engine_event_handler_1_1_error_code.html
243- showAlert (RtcEngine .getErrorDescription (Math .abs (res )));
244- return ;
245- }
246- // Prevent repeated entry
247- join .setEnabled (false );
226+ private boolean joinFirstChannel () {
227+ // 1. Create rtcChannel
228+ rtcChannel1 = engine .createRtcChannel (channel1 );
229+ rtcChannel1 .setClientRole (Constants .CLIENT_ROLE_BROADCASTER );
230+ // 2. Set rtcChannelEventHandler
231+ rtcChannel1 .setRtcChannelEventHandler (new IRtcChannelEventHandler () {
232+ // Override events
233+ /**
234+ * Occurs when the local user joins a specified channel.
235+ * The channel name assignment is based on channelName specified in the joinChannel method.
236+ * If the uid is not specified when joinChannel is called, the server automatically assigns a uid.
237+ *
238+ * @param rtcChannel Channel object
239+ * @param uid User ID
240+ * @param elapsed Time elapsed (ms) from the user calling joinChannel until this callback is triggered
241+ */
242+ @ Override
243+ public void onJoinChannelSuccess (RtcChannel rtcChannel , int uid , int elapsed ) {
244+ super .onJoinChannelSuccess (rtcChannel , uid , elapsed );
245+ Log .i (TAG , String .format ("onJoinChannelSuccess channel %s uid %d" , channel1 , uid ));
246+ showLongToast (String .format ("onJoinChannelSuccess channel %s uid %d" , channel1 , uid ));
247+ myUid = uid ;
248+ joined = true ;
249+ handler .post (new Runnable () {
250+ @ Override
251+ public void run () {
252+ join .setEnabled (true );
253+ join .setText (getString (R .string .leave ));
254+ }
255+ });
256+ }
257+ /**
258+ * Occurs when a remote user (Communication)/host (Live Broadcast) joins the channel.
259+ *
260+ * @param uid ID of the user whose audio state changes.
261+ * @param elapsed Time delay (ms) from the local user calling joinChannel/setClientRole
262+ * until this callback is triggered.
263+ */
264+ @ Override
265+ public void onUserJoined (RtcChannel rtcChannel , int uid , int elapsed ) {
266+ super .onUserJoined (rtcChannel , uid , elapsed );
267+ Log .i (TAG , "onUserJoined->" + uid );
268+ showLongToast (String .format ("user %d joined!" , uid ));
269+ /**Check if the context is correct*/
270+ Context context = getContext ();
271+ if (context == null ) {
272+ return ;
273+ }
274+ handler .post (() ->
275+ {
276+ /**Display remote video stream*/
277+ SurfaceView surfaceView = null ;
278+ if (fl_remote .getChildCount () > 0 ) {
279+ fl_remote .removeAllViews ();
280+ }
281+ // Create render view by RtcEngine
282+ surfaceView = RtcEngine .CreateRendererView (context );
283+ surfaceView .setZOrderMediaOverlay (true );
284+ // Add to the remote container
285+ fl_remote .addView (surfaceView , new FrameLayout .LayoutParams (ViewGroup .LayoutParams .MATCH_PARENT , ViewGroup .LayoutParams .MATCH_PARENT ));
286+
287+ // Setup remote video to render
288+ engine .setupRemoteVideo (new VideoCanvas (surfaceView , RENDER_MODE_FIT , channel1 , uid ));
289+ });
290+ }
291+ });
292+ // 3. Configurate mediaOptions
293+ ChannelMediaOptions mediaOptions = new ChannelMediaOptions ();
294+ mediaOptions .autoSubscribeAudio = true ;
295+ mediaOptions .autoSubscribeVideo = true ;
296+ mediaOptions .publishLocalAudio = true ;
297+ mediaOptions .publishLocalVideo = true ;
298+ // 4. Join channel
299+ int ret = rtcChannel1 .joinChannel (null , "" , 0 , mediaOptions );
300+ return (ret == 0 );
248301 }
249302
250303 private boolean joinSecondChannel () {
251304 // 1. Create rtcChannel
252- rtcChannel = engine .createRtcChannel (channel2 );
305+ rtcChannel2 = engine .createRtcChannel (channel2 );
306+ rtcChannel2 .setClientRole (Constants .CLIENT_ROLE_AUDIENCE );
253307 // 2. Set rtcChannelEventHandler
254- rtcChannel .setRtcChannelEventHandler (new IRtcChannelEventHandler () {
308+ rtcChannel2 .setRtcChannelEventHandler (new IRtcChannelEventHandler () {
255309 // Override events
256310 /**
257311 * Occurs when the local user joins a specified channel.
@@ -316,11 +370,14 @@ public void onUserJoined(RtcChannel rtcChannel, int uid, int elapsed) {
316370 ChannelMediaOptions mediaOptions = new ChannelMediaOptions ();
317371 mediaOptions .autoSubscribeAudio = true ;
318372 mediaOptions .autoSubscribeVideo = true ;
373+ mediaOptions .publishLocalVideo = false ;
374+ mediaOptions .publishLocalAudio = false ;
319375 // 4. Join channel
320- int ret = rtcChannel .joinChannel (null , "" , 0 , mediaOptions );
376+ int ret = rtcChannel2 .joinChannel (null , "" , 0 , mediaOptions );
321377 return (ret == 0 );
322378 }
323379
380+
324381 /**
325382 * IRtcEngineEventHandler is an abstract class providing default implementation.
326383 * The SDK uses this class to report to the app on SDK runtime events.
0 commit comments