diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/DefaultWebRTCListener.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/DefaultWebRTCListener.java index 091a962b..ad28829d 100644 --- a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/DefaultWebRTCListener.java +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/DefaultWebRTCListener.java @@ -10,6 +10,7 @@ import de.tavendo.autobahn.WebSocket; import io.antmedia.webrtcandroidframework.core.StreamInfo; import io.antmedia.webrtcandroidframework.websocket.Broadcast; +import io.antmedia.webrtcandroidframework.websocket.Subscriber; /** * Default implementation of {@link IWebRTCListener} @@ -258,6 +259,18 @@ public void onLeft(String streamId) { callbackCalled(messageText); } + @Override + public void onSubscriberCount(String streamId, int count) { + String messageText = "On Subscriber Count "+streamId; + callbackCalled(messageText); + } + + @Override + public void onSubscriberList(String streamId, Subscriber[] subscribers) { + String messageText = "On Subscriber List "+streamId; + callbackCalled(messageText); + } + @Override public void onPlayAttempt(String streamId) { String messageText = "Play attempt for stream "+streamId; diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCClient.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCClient.java index 78362306..f9f51e3b 100644 --- a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCClient.java +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCClient.java @@ -368,4 +368,20 @@ void publish(String streamId, String token, boolean videoCallEnabled, boolean au */ boolean isSendVideoEnabled(); + /** + * Called to get the subscriber count for a broadcast + * + * @param streamId: id for the broadcast + */ + void getSubscriberCount(String streamId); + + /** + * Called to get the subscriber list for a broadcast + * + * @param streamId: id for the broadcast + * @param offset: offset of the list + * @param size: size of the list + */ + void getSubscriberList(String streamId, long offset, long size); + } diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCListener.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCListener.java index f38a3558..56a89a2e 100644 --- a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCListener.java +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/api/IWebRTCListener.java @@ -7,6 +7,7 @@ import de.tavendo.autobahn.WebSocket; import io.antmedia.webrtcandroidframework.core.StreamInfo; import io.antmedia.webrtcandroidframework.websocket.Broadcast; +import io.antmedia.webrtcandroidframework.websocket.Subscriber; /** * Created by karinca on 23.10.2017. @@ -251,4 +252,14 @@ public interface IWebRTCListener { * It's called when user left P2P room. */ void onLeft(String streamId); + + /** + * It's called when Subscriber Count received. + */ + void onSubscriberCount(String streamId, int count); + + /** + * It's called when Subscriber List received. + */ + void onSubscriberList(String streamId, Subscriber[] subscribers); } diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/core/WebRTCClient.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/core/WebRTCClient.java index 872f0241..9b0fee28 100644 --- a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/core/WebRTCClient.java +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/core/WebRTCClient.java @@ -86,11 +86,29 @@ import io.antmedia.webrtcandroidframework.apprtc.AppRTCAudioManager; import io.antmedia.webrtcandroidframework.websocket.AntMediaSignallingEvents; import io.antmedia.webrtcandroidframework.websocket.Broadcast; +import io.antmedia.webrtcandroidframework.websocket.Subscriber; import io.antmedia.webrtcandroidframework.websocket.WebSocketHandler; public class WebRTCClient implements IWebRTCClient, AntMediaSignallingEvents { private static final String TAG = "WebRTCClient"; + @Override + public void onSubscriberCount(String streamId, int count) { + this.handler.post(() -> { + if (config.webRTCListener != null) { + config.webRTCListener.onSubscriberCount(streamId, count); + } + }); + } + + @Override + public void onSubscriberList(String streamId, Subscriber[] subscribers) { + this.handler.post(() -> { + if (config.webRTCListener != null) { + config.webRTCListener.onSubscriberList(streamId, subscribers); + } + }); + } public enum Mode { PUBLISH, PLAY, P2P, MULTI_TRACK_PLAY @@ -2853,6 +2871,20 @@ public boolean isSendVideoEnabled() { return sendVideoEnabled; } + @Override + public void getSubscriberCount(String streamId) { + if (wsHandler != null && wsHandler.isConnected()) { + wsHandler.getSubscriberCount(streamId); + } + } + + @Override + public void getSubscriberList(String streamId, long offset, long size) { + if (wsHandler != null && wsHandler.isConnected()) { + wsHandler.getSubscriberList(streamId, offset, size); + } + } + @Override public boolean isSendAudioEnabled() { return sendAudioEnabled; diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/AntMediaSignallingEvents.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/AntMediaSignallingEvents.java index cbdfb403..b63d531e 100644 --- a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/AntMediaSignallingEvents.java +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/AntMediaSignallingEvents.java @@ -152,4 +152,18 @@ public interface AntMediaSignallingEvents { * @param streamId Peer to peer room name/id. */ void onLeft(String streamId); + + /** + * It's called when subscriber count received from server + * @param streamId Stream Id + * @param count Count + */ + void onSubscriberCount(String streamId, int count); + + /** + * It's called when subscriber list received from server + * @param streamId Stream Id + * @param subscribers subscriber array + */ + void onSubscriberList(String streamId, Subscriber[] subscribers); } \ No newline at end of file diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/Subscriber.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/Subscriber.java new file mode 100644 index 00000000..03b105db --- /dev/null +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/Subscriber.java @@ -0,0 +1,49 @@ +package io.antmedia.webrtcandroidframework.websocket; + + +public class Subscriber { + + private String subscriberId; + private String streamId; + private boolean connected; + private int currentConcurrentConnections = 0; + private int concurrentConnectionsLimit = 1; + + public void setSubscriberId(String subscriberId) { + this.subscriberId = subscriberId; + } + + public String getSubscriberId() { + return subscriberId; + } + + public void setStreamId(String streamId) { + this.streamId = streamId; + } + + public String getStreamId() { + return streamId; + } + public boolean isConnected() { + return connected; + } + public void setConnected(boolean connected) { + this.connected = connected; + } + + public int getCurrentConcurrentConnections() { + return currentConcurrentConnections; + } + + public void setCurrentConcurrentConnections(int currentConcurrentConnections) { + this.currentConcurrentConnections = currentConcurrentConnections; + } + + public int getConcurrentConnectionsLimit() { + return concurrentConnectionsLimit; + } + + public void setConcurrentConnectionsLimit(int concurrentConnectionsLimit) { + this.concurrentConnectionsLimit = concurrentConnectionsLimit; + } +} diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketConstants.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketConstants.java index b8a30604..1d6894ad 100644 --- a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketConstants.java +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketConstants.java @@ -70,18 +70,48 @@ private WebSocketConstants() { public static final String PUBLISH_COMMAND = "publish"; - public static final String RESOLUTION_CHANGE_INFO_COMMAND = "resolutionChangeInfo"; - public static final String PUBLISH_STARTED = "publish_started"; public static final String PUBLISH_FINISHED = "publish_finished"; public static final String ERROR_CODE = "error_code"; + public static final String LINK_SESSION = "linkSession"; + + public static final String REGISTER_ORIGIN_SERVER = "registerOriginServer"; + + public static final String REGISTER_EDGE_SERVER = "registerEdgeServer"; + + public static final String REGISTER_BROADCAST = "registerBroadcast"; + public static final String NO_STREAM_EXIST = "no_stream_exist"; public static final String JOIN_ROOM_COMMAND = "joinRoom"; + + /** + * This is the command that is sent from the server when a stream is started so that player can send a play command + * or take any action + */ + public static final String STREAMING_STARTED = "streaming_started"; + + /** + * Command to get ICE server configuration to frontend from server + */ + public static final String GET_ICE_SERVER_CONFIG = "getIceServerConfig"; + + public static final String ICE_SERVER_CONFIG_NOTIFICATION = "iceServerConfig"; + + public static final String STUN_SERVER_URI = "stunServerUri"; + + public static final String TURN_SERVER_USERNAME = "turnServerUsername"; + + public static final String TURN_SERVER_CREDENTIAL = "turnServerCredential"; + + /** + * Please use {@link #MAIN_TRACK} instead + */ + @Deprecated(forRemoval = true, since = "2.11.3") public static final String ROOM = "room"; public static final String JOIN_COMMAND = "join"; @@ -102,6 +132,13 @@ private WebSocketConstants() { public static final String LEAVED_THE_ROOM = "leavedFromRoom"; + /** + * This is error definition and it's sent when one requests to get room information + * and there is no active stream or no room + */ + public static final String ROOM_NOT_ACTIVE = "no_active_streams_in_room"; + + /** * this token is used to access resources or start broadcast when token security is enabled */ @@ -151,6 +188,13 @@ private WebSocketConstants() { */ public static final String NOT_ALLOWED_UNREGISTERED_STREAM = "not_allowed_unregistered_streams"; + + /** + * This is sent back to the user if mainTrack + */ + public static final String MAX_SUBTRACK_COUNT_REACHED = "main_track_has_max_subtrack_count__not_allowed_to_add_more_subtracks"; + + /** * This is sent back to the user when there is no room specified in * joining the video conference @@ -176,8 +220,16 @@ private WebSocketConstants() { public static final String STREAM_TIME_INVALID = "stream_not_active_or_expired"; + /** + * This is sent back to the user if token is not valid + */ public static final String UNAUTHORIZED = "unauthorized_access"; + /** + * This is sent back to the user when subscriber is blocked to play or publish + */ + public static final String BLOCKED = "user_blocked"; + /** * This is sent back to the user when a new play message received while * it is playing or it is just to play @@ -207,6 +259,11 @@ private WebSocketConstants() { */ public static final String FORCE_STREAM_QUALITY = "forceStreamQuality"; + /** + * Command that client stream change resolution notication. + */ + public static final String RESOLUTION_CHANGE_INFO_COMMAND = "resolutionChangeInfo"; + /** * Command that let server returns information about a specific room. * This info includes stream ID's list in room. @@ -324,7 +381,7 @@ private WebSocketConstants() { * Error definition, it's send when remote description is not set, it's generally due to * encoder incompatibilities */ - public static final Object NOT_SET_REMOTE_DESCRIPTION = "notSetRemoteDescription"; + public static final String NOT_SET_REMOTE_DESCRIPTION = "notSetRemoteDescription"; /** * P2P Mode used in session user parameters @@ -404,6 +461,12 @@ private WebSocketConstants() { */ public static final String LICENCE_SUSPENDED = "license_suspended_please_renew_license"; + /** + * It's sent to determine mainTrackId if exists + */ + public static final String MAIN_TRACK = "mainTrack"; + + /** * It's sent as parameter conference mode */ @@ -419,6 +482,11 @@ private WebSocketConstants() { */ public static final String AMCU = "amcu"; + /** + * It's sent for conference in MCU mode + */ + public static final String MULTI_TRACK = "multitrack"; + /** * It's sent for conference in legacy mode */ @@ -430,15 +498,75 @@ private WebSocketConstants() { public static final String SESSION_RESTORED_DESCRIPTION = "session_restored"; /** - * It's sent to determine mainTrackId if exists + * It's the field that maps sdp mid to stream id */ - public static final String MAIN_TRACK = "mainTrack"; + public static final String ID_MAPPING = "idMapping"; + + /** + * It can be used to add some meta data to a broadcast + */ + public static final String META_DATA = "metaData"; + + /** + * Command to update the meta data for a broadcast + */ + public static final String UPDATE_STREAM_META_DATA_COMMAND = "updateStreamMetaData"; + + /** + * Command to inform AMS if a stream is pinned in conference mode + */ + public static final String ASSIGN_VIDEO_TRACK_COMMAND = "assignVideoTrackCommand"; + + /** + * Command to change visible streams in conference mode, used for pagination + */ + public static final String UPDATE_VIDEO_TRACK_ASSIGNMENTS_COMMAND = "updateVideoTrackAssignmentsCommand"; + + /** + * Command to set max video track count in conference + */ + public static final String SET_MAX_VIDEO_TRACK_COUNT_COMMAND = "setMaxVideoTrackCountCommand"; + + /** + * Command to get debug info in conference + */ + public static final String GET_DEBUG_INFO_COMMAND = "getDebugInfo"; + + /** + * Generated debug info in conference + */ + public static final String DEBUG_INFO = "debugInfo"; + + /** + * Track id that is pinned for a stream + */ + public static final String VIDEO_TRACK_ID = "videoTrackId"; + + /** + * Start index of a list for pagination + */ + public static final String OFFSET = "offset"; + + /** + * Length of a page for pagination + */ + public static final String SIZE = "size"; + + /** + * maximum number of tracks + */ + public static final String MAX_TRACK_COUNT = "maxTrackCount"; /** * Command to get broadcast object */ public static final String GET_BROADCAST_OBJECT_COMMAND = "getBroadcastObject"; + /** + * Command to get video track assignments + */ + public static final String GET_VIDEO_TRACK_ASSIGNMENTS_COMMAND = "getVideoTrackAssignmentsCommand"; + /** * broadcast object notification */ @@ -449,6 +577,156 @@ private WebSocketConstants() { */ public static final String BROADCAST = "broadcast"; + public static final String AUTH_TOKEN_NOT_VALID_ERROR_DEFINITION = "authenticationTokenNotValid"; + + public static final String MISSING_PARAMETER_DEFINITION = "missingParameter"; + + /** + * Information field in websocket communication + */ + public static final String INFORMATION = "information"; + + /** + * Success field in websocket communication. If it's value true, the operation is successful. + * If it's value is false, the operation is failed + */ + public static final String SUCCESS = "success"; + + /** + * Topic field to send push notification + */ + public static final String PUSH_NOTIFICATION_TOPIC = "pushNotificationTopic"; + + /** + * Subscriber id list to send push notification + */ + public static final String SUBSCRIBER_ID_LIST_TO_NOTIFY = "subscriberIdsToNotify"; + + /** + * Participant role in the room + */ + public static final String ROLE = "role"; + + /** + * Command to get subtrack infos for a main track + */ + public static final String GET_SUBTRACKS_COMMAND = "getSubtracks"; + + /** + * Command to get subtrack count for a main track + */ + public static final String GET_SUBTRACKS_COUNT_COMMAND = "getSubtracksCount"; + + /** + * subtrack (broadcast) object list notification + */ + public static final String SUBTRACK_LIST_NOTIFICATION = "subtrackList"; + + + /** + * Command to get subscriber list size + */ + public static final String GET_SUBSCRIBER_LIST_SIZE = "getSubscriberCount"; + + /** + * subscriber count notification + */ + public static final String SUBSCRIBER_COUNT = "subscriberCount"; + + /** + * Command to get subscribers for a stream + */ + public static final String GET_SUBSCRIBER_LIST = "getSubscribers"; + + /** + * subscribers list notification + */ + public static final String SUBSCRIBER_LIST_NOTIFICATION = "subscriberList"; + + /** + * status field in websocket communication + */ + public static final String STATUS = "status"; + + /** + * sort field used for sorting subtracks + */ + public static final String SORT_BY = "sortBy"; + + /** + * order (asc, desc) field used for ordering subtracks + */ + public static final String ORDER_BY = "orderBy"; + + /** + * search field used for searching subtracks + */ + public static final String SEARCH = "search"; + + + /* + * count field in websocket communication + */ + public static final String COUNT = "count"; + + /** + * subtrack (broadcast) object count notification + */ + public static final String SUBTRACK_COUNT_NOTIFICATION = "subtrackCount"; + + /** + * subtrack (broadcast) object list + */ + public static final String SUBTRACK_LIST = "subtrackList"; + + /** + * subscribers list + */ + public static final String SUBCRIBER_LIST = "subscriberList"; + + /** + * This is the error definition that is sent when the stream does not get video or audio packet for the timeout duration. + * Currently it's implemented for WebRTC ingest + */ + public static final String NO_PACKET_RECEIVED_FOR_TIMEOUT_DURATION = "noPacketReceivedForTimeoutDuration"; + + /** + * This is the error definition that is sent when mainTrack cannot be created or updated in publishing process. + */ + public static final String MAINTRACK_DB_OPERATION_FAILED = "mainTrackDBOperationFailed"; + + + /** + * This is passed in play websocket method to define the publisher stream id (if available) which uses same websocket channel with player + * For example in conference case a participant use same websocket to publish its stream and to play the others + */ + public static final String USER_PUBLISH_ID = "userPublishId"; + + /** + * Notification to notify a new subtrack addition to a main track + */ + public static final String SUBTRACK_ADDED = "subtrackAdded"; + + /** + * Notification to notify a new subtrack removal to a main track + */ + public static final String SUBTRACK_REMOVED = "subtrackRemoved"; + + /** + * This is the error definition that is sent when the stream does not exist or not streaming + */ + public static final String STREAM_NOT_EXIST_OR_NOT_STREAMING_DEFINITION = "stream_not_exist_or_not_streaming"; + + /** + * This is the error definition that is sent when the stream exits but not available as WebRTC because webrtc is not enabled + */ + public static final String WEBRTC_NOT_ENABLED_TO_PLAYBACK_DEFINITION = "webrtc_not_enabled"; + + /** + * This is the definition that is sent when the is about to start for auto/start stop streams + */ + public static final String STREAMING_STARTS_SOON_DEFINITION = "streaming_starts_soon"; + public static final int WEBSOCKET_CONNECTION_TIMEOUT = 10000; //10 sec } diff --git a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketHandler.java b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketHandler.java index 19c5fcad..5227867b 100644 --- a/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketHandler.java +++ b/webrtc-android-framework/src/main/java/io/antmedia/webrtcandroidframework/websocket/WebSocketHandler.java @@ -277,11 +277,26 @@ else if (definition.equals(WebSocketConstants.BROADCAST_OBJECT_NOTIFICATION)) { String broadcastJson = json.getString(WebSocketConstants.BROADCAST); Broadcast broadcast = gson.fromJson(broadcastJson, Broadcast.class); signallingListener.onBroadcastObject(broadcast); - }else if(definition.equals(WebSocketConstants.RESOLUTION_CHANGE_INFO_COMMAND)){ + } + else if(definition.equals(WebSocketConstants.RESOLUTION_CHANGE_INFO_COMMAND)){ int resolution = json.getInt(WebSocketConstants.STREAM_HEIGHT); signallingListener.onResolutionChange(streamId, resolution); } + else if(definition.equals(WebSocketConstants.SUBSCRIBER_COUNT)){ + int count = json.getInt(WebSocketConstants.COUNT); + signallingListener.onSubscriberCount(streamId, count); + } + else if(definition.equals(WebSocketConstants.SUBSCRIBER_LIST_NOTIFICATION)){ + JSONArray subscriberList = json.getJSONArray(WebSocketConstants.SUBCRIBER_LIST); + Subscriber[] subscribers = new Subscriber[subscriberList.length()]; + for (int i = 0; i < subscriberList.length(); i++) { + String subscriberJson = subscriberList.getString(i); + Subscriber subscriber = gson.fromJson(subscriberJson, Subscriber.class); + subscribers[i] = subscriber; + } + signallingListener.onSubscriberList(streamId, subscribers); + } } else if (commandText.equals(WebSocketConstants.TRACK_LIST)) { JSONArray trackList = json.getJSONArray(WebSocketConstants.TRACK_LIST); @@ -685,4 +700,29 @@ public void setWsReconnectionHandler(Handler wsReconnectionHandler) { this.wsReconnectionHandler = wsReconnectionHandler; } + public void getSubscriberCount(String streamId) { + checkIfCalledOnValidThread(); + JSONObject json = new JSONObject(); + try { + json.put(WebSocketConstants.COMMAND, WebSocketConstants.GET_SUBSCRIBER_LIST_SIZE); + json.put(WebSocketConstants.STREAM_ID, streamId); + sendTextMessage(json.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public void getSubscriberList(String streamId, long offset, long size) { + checkIfCalledOnValidThread(); + JSONObject json = new JSONObject(); + try { + json.put(WebSocketConstants.COMMAND, WebSocketConstants.GET_SUBSCRIBER_LIST); + json.put(WebSocketConstants.STREAM_ID, streamId); + json.put(WebSocketConstants.OFFSET, offset); + json.put(WebSocketConstants.SIZE, size); + sendTextMessage(json.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } } diff --git a/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/SubscriberTest.java b/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/SubscriberTest.java new file mode 100644 index 00000000..7d0a0b63 --- /dev/null +++ b/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/SubscriberTest.java @@ -0,0 +1,40 @@ +package io.antmedia.webrtcandroidframework; + +import org.junit.Test; +import static org.junit.Assert.*; + +import io.antmedia.webrtcandroidframework.websocket.Subscriber; + +public class SubscriberTest { + + @Test + public void testSubscriberFields() { + Subscriber subscriber = new Subscriber(); + + subscriber.setSubscriberId("sub123"); + assertEquals("sub123", subscriber.getSubscriberId()); + + subscriber.setStreamId("streamABC"); + assertEquals("streamABC", subscriber.getStreamId()); + + subscriber.setConnected(true); + assertTrue(subscriber.isConnected()); + + subscriber.setCurrentConcurrentConnections(3); + assertEquals(3, subscriber.getCurrentConcurrentConnections()); + + subscriber.setConcurrentConnectionsLimit(10); + assertEquals(10, subscriber.getConcurrentConnectionsLimit()); + } + + @Test + public void testDefaultValues() { + Subscriber subscriber = new Subscriber(); + + assertNull(subscriber.getSubscriberId()); + assertNull(subscriber.getStreamId()); + assertFalse(subscriber.isConnected()); + assertEquals(0, subscriber.getCurrentConcurrentConnections()); + assertEquals(1, subscriber.getConcurrentConnectionsLimit()); + } +} diff --git a/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebRTCClientTest.java b/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebRTCClientTest.java index 36dfefa7..4906b4f0 100644 --- a/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebRTCClientTest.java +++ b/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebRTCClientTest.java @@ -81,6 +81,7 @@ import io.antmedia.webrtcandroidframework.core.StreamInfo; import io.antmedia.webrtcandroidframework.core.WebRTCClient; import io.antmedia.webrtcandroidframework.websocket.Broadcast; +import io.antmedia.webrtcandroidframework.websocket.Subscriber; import io.antmedia.webrtcandroidframework.websocket.WebSocketConstants; import io.antmedia.webrtcandroidframework.websocket.WebSocketHandler; @@ -1400,4 +1401,25 @@ public void testLeaveP2P() { Mockito.verify(webRTCClient, times(1)).release(true); } + @Test + public void testSubscriberQueries() { + String streamId = "stream1"; + webRTCClient.getSubscriberCount(streamId); + verify(wsHandler, times(1)).getSubscriberCount(streamId); + + webRTCClient.getSubscriberList(streamId, 5, 15); + verify(wsHandler, times(1)).getSubscriberList(streamId, 5, 15); + + + webRTCClient.onSubscriberCount(streamId, 13); + verify(listener, times(1)).onSubscriberCount(streamId, 13); + + Subscriber subscriber1 = mock(Subscriber.class); + Subscriber subscriber2 = mock(Subscriber.class); + + Subscriber[] subscribers = {subscriber1, subscriber2}; + webRTCClient.onSubscriberList(streamId, subscribers); + + verify(listener, times(1)).onSubscriberList(streamId, subscribers); + } } diff --git a/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebSocketHandlerTest.java b/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebSocketHandlerTest.java index 079b2c23..d8cc03b6 100644 --- a/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebSocketHandlerTest.java +++ b/webrtc-android-framework/src/test/java/io/antmedia/webrtcandroidframework/WebSocketHandlerTest.java @@ -23,10 +23,13 @@ import de.tavendo.autobahn.WebSocketException; import io.antmedia.webrtcandroidframework.websocket.AntMediaSignallingEvents; import io.antmedia.webrtcandroidframework.websocket.Broadcast; +import io.antmedia.webrtcandroidframework.websocket.Subscriber; import io.antmedia.webrtcandroidframework.websocket.WebSocketConstants; import io.antmedia.webrtcandroidframework.websocket.WebSocketHandler; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.*; import com.google.gson.Gson; @@ -494,4 +497,111 @@ public void testWsReconnection(){ } + @Test + public void testGetSubscriberCount() throws JSONException { + String streamId = "stream123"; + ArgumentCaptor jsonCaptor = ArgumentCaptor.forClass(String.class); + + webSocketHandler.getSubscriberCount(streamId); + + verify(webSocketHandler, times(1)).sendTextMessage(jsonCaptor.capture()); + + JSONObject expectedJson = new JSONObject(); + expectedJson.put(WebSocketConstants.COMMAND, WebSocketConstants.GET_SUBSCRIBER_LIST_SIZE); + expectedJson.put(WebSocketConstants.STREAM_ID, streamId); + + assertEquals(expectedJson.toString(), jsonCaptor.getValue()); + } + + @Test + public void testGetSubscriberList() throws JSONException { + String streamId = "stream123"; + long offset = 0; + long size = 10; + ArgumentCaptor jsonCaptor = ArgumentCaptor.forClass(String.class); + + webSocketHandler.getSubscriberList(streamId, offset, size); + + verify(webSocketHandler, times(1)).sendTextMessage(jsonCaptor.capture()); + + JSONObject expectedJson = new JSONObject(); + expectedJson.put(WebSocketConstants.COMMAND, WebSocketConstants.GET_SUBSCRIBER_LIST); + expectedJson.put(WebSocketConstants.STREAM_ID, streamId); + expectedJson.put(WebSocketConstants.OFFSET, offset); + expectedJson.put(WebSocketConstants.SIZE, size); + + assertEquals(expectedJson.toString(), jsonCaptor.getValue()); + } + + @Test + public void testOnTextMessageSubscriberCountNotification() throws JSONException { + doReturn(true).when(webSocketHandler).isConnected(); + + String streamId = "stream123"; + int count = 7; + + JSONObject json = new JSONObject(); + json.put(WebSocketConstants.COMMAND, WebSocketConstants.NOTIFICATION_COMMAND); + json.put(WebSocketConstants.DEFINITION, WebSocketConstants.SUBSCRIBER_COUNT); + json.put(WebSocketConstants.STREAM_ID, streamId); + json.put(WebSocketConstants.COUNT, count); + + webSocketHandler.onTextMessage(json.toString()); + + verify(signallingListener).onSubscriberCount(streamId, count); + } + + + @Test + public void testOnTextMessageSubscriberListNotification() throws JSONException { + doReturn(true).when(webSocketHandler).isConnected(); + + String streamId = "stream123"; + + JSONObject subscriber1 = new JSONObject(); + subscriber1.put("subscriberId", "sub1"); + subscriber1.put("streamId", streamId); + subscriber1.put("connected", true); + subscriber1.put("currentConcurrentConnections", 2); + subscriber1.put("concurrentConnectionsLimit", 5); + + JSONObject subscriber2 = new JSONObject(); + subscriber2.put("subscriberId", "sub2"); + subscriber2.put("streamId", streamId); + subscriber2.put("connected", false); + subscriber2.put("currentConcurrentConnections", 1); + subscriber2.put("concurrentConnectionsLimit", 3); + + JSONArray subscriberArray = new JSONArray(); + subscriberArray.put(subscriber1.toString()); + subscriberArray.put(subscriber2.toString()); + + JSONObject json = new JSONObject(); + json.put(WebSocketConstants.COMMAND, WebSocketConstants.NOTIFICATION_COMMAND); + json.put(WebSocketConstants.DEFINITION, WebSocketConstants.SUBSCRIBER_LIST_NOTIFICATION); + json.put(WebSocketConstants.STREAM_ID, streamId); + json.put(WebSocketConstants.SUBCRIBER_LIST, subscriberArray); + + webSocketHandler.onTextMessage(json.toString()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(Subscriber[].class); + verify(signallingListener).onSubscriberList(eq(streamId), captor.capture()); + + Subscriber[] result = captor.getValue(); + assertEquals(2, result.length); + + assertEquals("sub1", result[0].getSubscriberId()); + assertEquals(streamId, result[0].getStreamId()); + assertTrue(result[0].isConnected()); + assertEquals(2, result[0].getCurrentConcurrentConnections()); + assertEquals(5, result[0].getConcurrentConnectionsLimit()); + + assertEquals("sub2", result[1].getSubscriberId()); + assertEquals(streamId, result[1].getStreamId()); + assertFalse(result[1].isConnected()); + assertEquals(1, result[1].getCurrentConcurrentConnections()); + assertEquals(3, result[1].getConcurrentConnectionsLimit()); + } + + }