From a029073d3fa0e9a594c693800eea3edf015ca56f Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 3 Jan 2023 11:48:27 +0300 Subject: [PATCH 01/15] New webhooks playStart, playStop, recordStart issue #4666 --- .../antmedia/AntMediaApplicationAdapter.java | 92 +++++++++++--- .../io/antmedia/filter/AbstractFilter.java | 12 ++ .../antmedia/filter/DashStatisticsFilter.java | 6 +- .../antmedia/filter/HlsStatisticsFilter.java | 4 +- .../java/io/antmedia/muxer/MuxAdaptor.java | 9 +- .../antmedia/statistic/DashViewerStats.java | 5 +- .../io/antmedia/statistic/HlsViewerStats.java | 6 +- .../io/antmedia/statistic/IStreamStats.java | 4 +- .../io/antmedia/statistic/ViewerStats.java | 46 +++++-- .../AntMediaApplicationAdaptorUnitTest.java | 77 ++++++++++-- .../java/io/antmedia/test/Application.java | 6 +- .../java/io/antmedia/test/MuxerUnitTest.java | 2 +- .../test/filter/DashStatisticsFilterTest.java | 66 +++++++--- .../test/filter/HlsStatisticsFilterTest.java | 26 ++-- .../test/statistic/DashViewerStatsTest.java | 116 ++++++++++++++---- .../test/statistic/HlsViewerStatsTest.java | 34 +++-- 16 files changed, 389 insertions(+), 122 deletions(-) diff --git a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java index aef8b80db..77585af71 100644 --- a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java +++ b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.regex.Pattern; import java.util.Queue; import java.util.Set; @@ -47,8 +46,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.errorprone.annotations.NoAllocation; - import io.antmedia.cluster.ClusterNode; import io.antmedia.cluster.IClusterNotifier; import io.antmedia.datastore.db.DataStore; @@ -65,7 +62,6 @@ import io.antmedia.plugin.api.IFrameListener; import io.antmedia.plugin.api.IPacketListener; import io.antmedia.plugin.api.IStreamListener; -import io.antmedia.plugin.api.StreamParametersInfo; import io.antmedia.rest.RestServiceBase; import io.antmedia.rest.model.Result; import io.antmedia.security.AcceptOnlyStreamsInDataStore; @@ -99,6 +95,9 @@ public class AntMediaApplicationAdapter extends MultiThreadedApplicationAdapter public static final String HOOK_ACTION_PUBLISH_TIMEOUT_ERROR = "publishTimeoutError"; public static final String HOOK_ACTION_ENCODER_NOT_OPENED_ERROR = "encoderNotOpenedError"; public static final String HOOK_ACTION_ENDPOINT_FAILED = "endpointFailed"; + public static final String HOOK_ACTION_START_PLAY = "playStart"; + public static final String HOOK_ACTION_STOP_PLAY = "playStop"; + public static final String HOOK_ACTION_START_RECORD = "recordStart"; public static final String STREAMS = "streams"; @@ -488,7 +487,7 @@ public void closeBroadcast(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call live stream ended hook for stream:{}",streamId ); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_END_LIVE_STREAM, name, category, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_END_LIVE_STREAM, name, category, null, null, null, null)); } if (broadcast.isZombi()) { @@ -539,13 +538,63 @@ public void resetDASHStats(String streamId) { } } + public void sendStartPlayWebHook(final String viewerPlayType, final String streamId, final String viewerId){ + System.out.println("start play web hook called!"); + final Broadcast broadcast = getDataStore().get(streamId); + final String listenerHookURL = broadcast.getListenerHookURL(); + if (listenerHookURL == null || listenerHookURL.isEmpty()) { + return; + } + final String name = broadcast.getName(); + final String category = broadcast.getCategory(); + System.out.println(name + " "+category+" "+viewerId); + logger.info("Setting timer to call viewer play started hook for stream:{}", streamId); + vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_PLAY, name, category, + null, null, viewerId, null)); + } + + public void sendStopPlayWebHook(final String viewerPlayType, final String streamId, final String viewerId){ + final Broadcast broadcast = getDataStore().get(streamId); + final String listenerHookURL = broadcast.getListenerHookURL(); + if (listenerHookURL == null || listenerHookURL.isEmpty()) { + return; + } + final String name = broadcast.getName(); + final String category = broadcast.getCategory(); + logger.info("Setting timer to call viewer play stopped hook for stream:{}", streamId); + vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_STOP_PLAY, name, category, + null, null, viewerId, null)); + } + + public void sendStartRecordWebHook(final String streamId){ + final Broadcast broadcast = getDataStore().get(streamId); + System.out.println(broadcast.getStreamId()); + final String listenerHookURL = broadcast.getListenerHookURL(); + if (listenerHookURL == null || listenerHookURL.isEmpty()) { + return; + } + final String name = broadcast.getName(); + final String category = broadcast.getCategory(); + logger.info("Setting timer to call stream start recording hook for stream:{}", streamId); + vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_RECORD, name, category, + null, null, null, null)); + } + + private String getRtmpViewerId(){ + return "rtmp_" + RandomStringUtils.randomNumeric(8); + } + @Override public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) { - vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(item.getName(), true)); + final String streamId = item.getName(); + sendStartPlayWebHook(ViewerStats.RTMP_TYPE, streamId, getRtmpViewerId()); + vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, true)); } @Override public void streamPlayItemStop(ISubscriberStream stream, IPlayItem item) { - vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(item.getName(), false)); + final String streamId = item.getName(); + sendStopPlayWebHook(ViewerStats.RTMP_TYPE, streamId, getRtmpViewerId()); + vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, false)); } @Override @@ -557,6 +606,7 @@ public void streamSubscriberClose(ISubscriberStream stream) { public void startPublish(String streamId, long absoluteStartTimeMs, String publishType) { vertx.executeBlocking( handler -> { try { + System.out.println("START PUBLISH CALLED!"); Broadcast broadcast = updateBroadcastStatus(streamId, absoluteStartTimeMs, publishType, getDataStore().get(streamId)); @@ -567,7 +617,13 @@ public void startPublish(String streamId, long absoluteStartTimeMs, String publi final String category = broadcast.getCategory(); logger.info("Setting timer to call live stream started hook for stream:{}",streamId ); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_LIVE_STREAM, name, category, - null, null, null)); + null, null, null, null)); + } + + if ((broadcast.getMp4Enabled() == MuxAdaptor.RECORDING_ENABLED_FOR_STREAM || broadcast.getWebMEnabled() == MuxAdaptor.RECORDING_ENABLED_FOR_STREAM) + || (appSettings.isMp4MuxingEnabled() || appSettings.isWebMMuxingEnabled()) + ) { + sendStartRecordWebHook(streamId); } int ingestingStreamLimit = appSettings.getIngestingStreamLimit(); @@ -735,7 +791,7 @@ public void muxingFinished(final String streamId, File file, long startTime, lon final String baseName = vodName.substring(0, index); String finalListenerHookURL = listenerHookURL; logger.info("Setting timer for calling vod ready hook for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(finalListenerHookURL, streamId, HOOK_ACTION_VOD_READY, null, null, baseName, vodIdFinal, null)); + vertx.runOnContext(e -> notifyHook(finalListenerHookURL, streamId, HOOK_ACTION_VOD_READY, null, null, baseName, vodIdFinal, null, null)); } String muxerFinishScript = appSettings.getMuxerFinishScript(); @@ -806,7 +862,7 @@ public static String getRelativePath(String filePath){ * @return */ public StringBuilder notifyHook(String url, String id, String action, String streamName, String category, - String vodName, String vodId, String metadata) { + String vodName, String vodId, String viewerId, String metadata) { StringBuilder response = null; logger.info("Running notify hook url:{} stream id: {} action:{} vod name:{} vod id:{}", url, id, action, vodName, vodId); if (url != null && url.length() > 0) { @@ -829,6 +885,10 @@ public StringBuilder notifyHook(String url, String id, String action, String str variables.put("vodId", vodId); } + if(viewerId != null){ + variables.put("viewerId", viewerId); + } + if (metadata != null) { variables.put("metadata", metadata); } @@ -864,6 +924,7 @@ public StringBuilder sendPOST(String url, Map variables) throws httpPost.setEntity(postParams); try (CloseableHttpResponse httpResponse = httpClient.execute(httpPost)) { + System.out.println("http response came"); logger.info("POST Response Status:: {}" , httpResponse.getStatusLine().getStatusCode()); HttpEntity entity = httpResponse.getEntity(); @@ -1008,10 +1069,14 @@ public void setQualityParameters(String id, String quality, double speed, int pe } public DataStore getDataStore() { + System.out.println("get data store called"); //vertx should be initialized before calling this method if(dataStore == null) { + System.out.println("data store is null"); dataStore = dataStoreFactory.getDataStore(); + System.out.println(dataStore); + } return dataStore; } @@ -1304,7 +1369,7 @@ public synchronized void incrementEncoderNotOpenedError(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call encoder not opened error for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENCODER_NOT_OPENED_ERROR, name, category, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENCODER_NOT_OPENED_ERROR, name, category, null, null, null,null)); } } } @@ -1329,7 +1394,7 @@ public synchronized void publishTimeoutError(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call hook that means live stream is not started to the publish timeout for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_PUBLISH_TIMEOUT_ERROR, name, category, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_PUBLISH_TIMEOUT_ERROR, name, category, null, null, null, null)); } } } @@ -1441,7 +1506,6 @@ private boolean isEncoderSettingsValid(List encoderSettingsList /** * * @param newSettings - * @param checkUpdateTime * @return true if timing is valid, false if it is invalid */ public boolean isIncomingTimeValid(AppSettings newSettings) @@ -1686,7 +1750,7 @@ public void endpointFailedUpdate(String streamId, String url) { logger.info("Setting timer to call rtmp endpoint failed hook for stream:{}", streamId); JSONObject jsonObject = new JSONObject(); jsonObject.put("rtmp-url", url); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENDPOINT_FAILED, name, category, null, null, jsonObject.toJSONString())); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENDPOINT_FAILED, name, category, null, null, null, jsonObject.toJSONString())); } } } diff --git a/src/main/java/io/antmedia/filter/AbstractFilter.java b/src/main/java/io/antmedia/filter/AbstractFilter.java index f15b73eec..35552a668 100644 --- a/src/main/java/io/antmedia/filter/AbstractFilter.java +++ b/src/main/java/io/antmedia/filter/AbstractFilter.java @@ -9,6 +9,7 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletException; +import io.antmedia.AntMediaApplicationAdapter; import org.apache.catalina.util.NetMask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -154,5 +155,16 @@ public Broadcast getBroadcast(String streamId) { } return broadcast; } + + protected AntMediaApplicationAdapter getAntMediaApplicationAdapter(){ + AntMediaApplicationAdapter antMediaApplicationAdapter = null; + ApplicationContext context = getAppContext(); + if (context != null) + { + antMediaApplicationAdapter= (AntMediaApplicationAdapter)context.getBean(AntMediaApplicationAdapter.BEAN_NAME); + } + return antMediaApplicationAdapter; + + } } diff --git a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java index 980e0c9a6..51e3b6dd3 100644 --- a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.HttpMethod; +import io.antmedia.statistic.ViewerStats; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +26,7 @@ public class DashStatisticsFilter extends AbstractFilter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - + System.out.println("i got called"); HttpServletRequest httpRequest =(HttpServletRequest)request; String method = httpRequest.getMethod(); @@ -52,8 +53,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(DashViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId); - + stats.registerNewViewer(streamId, sessionId, subscriberId, ViewerStats.DASH_TYPE, getAntMediaApplicationAdapter()); } } } diff --git a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java index 0e3ff9f68..d7ab64e09 100644 --- a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.HttpMethod; +import io.antmedia.statistic.ViewerStats; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,8 +53,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(HlsViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId); - + stats.registerNewViewer(streamId, sessionId, subscriberId, ViewerStats.HLS_TYPE, getAntMediaApplicationAdapter()); } } } diff --git a/src/main/java/io/antmedia/muxer/MuxAdaptor.java b/src/main/java/io/antmedia/muxer/MuxAdaptor.java index 2c19d852d..a28c3fc9f 100644 --- a/src/main/java/io/antmedia/muxer/MuxAdaptor.java +++ b/src/main/java/io/antmedia/muxer/MuxAdaptor.java @@ -1681,7 +1681,6 @@ private Muxer addMp4Muxer() { * @return */ public RecordMuxer startRecording(RecordType recordType) { - if (!isRecording.get()) { logger.warn("Starting recording return false for stream:{} because stream is being prepared", streamId); return null; @@ -1692,7 +1691,6 @@ public RecordMuxer startRecording(RecordType recordType) { return null; } - RecordMuxer muxer = null; if(recordType == RecordType.MP4) { Mp4Muxer mp4Muxer = createMp4Muxer(); @@ -1862,10 +1860,15 @@ public Result startRtmpStreaming(String rtmpUrl, int resolutionHeight) } public void sendEndpointErrorNotifyHook(String url){ + AntMediaApplicationAdapter adaptor = getAntMediaApplicationAdaptor(); + adaptor.endpointFailedUpdate(this.streamId, url); + } + + protected AntMediaApplicationAdapter getAntMediaApplicationAdaptor(){ IContext context = MuxAdaptor.this.scope.getContext(); ApplicationContext appCtx = context.getApplicationContext(); AntMediaApplicationAdapter adaptor = (AntMediaApplicationAdapter) appCtx.getBean(AntMediaApplicationAdapter.BEAN_NAME); - adaptor.endpointFailedUpdate(this.streamId, url); + return adaptor; } /** diff --git a/src/main/java/io/antmedia/statistic/DashViewerStats.java b/src/main/java/io/antmedia/statistic/DashViewerStats.java index 74b6197c2..1f160570c 100644 --- a/src/main/java/io/antmedia/statistic/DashViewerStats.java +++ b/src/main/java/io/antmedia/statistic/DashViewerStats.java @@ -1,6 +1,7 @@ package io.antmedia.statistic; +import io.antmedia.AntMediaApplicationAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -28,11 +29,11 @@ public void setApplicationContext(ApplicationContext applicationContext) { AppSettings settings = (AppSettings)applicationContext.getBean(AppSettings.BEAN_NAME); timeoutMS = getTimeoutMSFromSettings(settings, timeoutMS, DASH_TYPE); - + final AntMediaApplicationAdapter antMediaApplicationAdapter = (AntMediaApplicationAdapter)applicationContext.getBean(AntMediaApplicationAdapter.BEAN_NAME); vertx.setPeriodic(DEFAULT_TIME_PERIOD_FOR_VIEWER_COUNT, yt-> { synchronized (lock) { - updateViewerCountProcess(DASH_TYPE); + updateViewerCountProcess(DASH_TYPE, antMediaApplicationAdapter); } }); } diff --git a/src/main/java/io/antmedia/statistic/HlsViewerStats.java b/src/main/java/io/antmedia/statistic/HlsViewerStats.java index 126fe9e3a..ca7a0a611 100644 --- a/src/main/java/io/antmedia/statistic/HlsViewerStats.java +++ b/src/main/java/io/antmedia/statistic/HlsViewerStats.java @@ -1,5 +1,6 @@ package io.antmedia.statistic; +import io.antmedia.AntMediaApplicationAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -28,11 +29,12 @@ public void setApplicationContext(ApplicationContext applicationContext) { AppSettings settings = (AppSettings)applicationContext.getBean(AppSettings.BEAN_NAME); timeoutMS = getTimeoutMSFromSettings(settings, timeoutMS, HLS_TYPE); - + final AntMediaApplicationAdapter antMediaApplicationAdapter = (AntMediaApplicationAdapter)applicationContext.getBean(AntMediaApplicationAdapter.BEAN_NAME); + vertx.setPeriodic(DEFAULT_TIME_PERIOD_FOR_VIEWER_COUNT, yt-> { synchronized (lock) { - updateViewerCountProcess(HLS_TYPE); + updateViewerCountProcess(HLS_TYPE, antMediaApplicationAdapter); } }); } diff --git a/src/main/java/io/antmedia/statistic/IStreamStats.java b/src/main/java/io/antmedia/statistic/IStreamStats.java index 00d250c1e..81a2d9e25 100644 --- a/src/main/java/io/antmedia/statistic/IStreamStats.java +++ b/src/main/java/io/antmedia/statistic/IStreamStats.java @@ -1,5 +1,7 @@ package io.antmedia.statistic; +import io.antmedia.AntMediaApplicationAdapter; + public interface IStreamStats { /** @@ -7,7 +9,7 @@ public interface IStreamStats { * @param streamId * @param sessionId */ - void registerNewViewer(String streamId, String sessionId, String subscriberId); + void registerNewViewer(String streamId, String sessionId, String subscriberId, String playType, AntMediaApplicationAdapter antMediaApplicationAdapter); /** diff --git a/src/main/java/io/antmedia/statistic/ViewerStats.java b/src/main/java/io/antmedia/statistic/ViewerStats.java index 252bcce25..acea7cb86 100644 --- a/src/main/java/io/antmedia/statistic/ViewerStats.java +++ b/src/main/java/io/antmedia/statistic/ViewerStats.java @@ -6,6 +6,7 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import io.antmedia.AntMediaApplicationAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,16 +21,18 @@ public class ViewerStats { protected static Logger logger = LoggerFactory.getLogger(ViewerStats.class); - + protected Vertx vertx; public static final String HLS_TYPE = "hls"; public static final String DASH_TYPE = "dash"; - + public static final String RTMP_TYPE = "rtmp"; + public static final String WEBRTC_TYPE = "webrtc"; + + private DataStore dataStore; protected DataStoreFactory dataStoreFactory; - public static final int DEFAULT_TIME_PERIOD_FOR_VIEWER_COUNT = 10000; /** @@ -49,14 +52,15 @@ public class ViewerStats { */ protected int timeoutMS = 20000; - public void registerNewViewer(String streamId, String sessionId, String subscriberId) + public void registerNewViewer(String streamId, String sessionId, String subscriberId, String viewerPlayType, AntMediaApplicationAdapter antMediaApplicationAdapter) { + System.out.println("i got called3!"); + //do not block the thread, run in vertx event queue vertx.runOnContext(h -> { - synchronized (lock) { //synchronize with database update calculations, because some odd cases may happen - + System.out.println("i got called!"); Map viewerMap = streamsViewerMap.get(streamId); if (viewerMap == null) { viewerMap = new ConcurrentHashMap<>(); @@ -66,7 +70,18 @@ public void registerNewViewer(String streamId, String sessionId, String subscrib int streamIncrementCounter = getIncreaseCounterMap(streamId); streamIncrementCounter++; increaseCounterMap.put(streamId, streamIncrementCounter); - + System.out.println(sessionId); + System.out.println(subscriberId); + System.out.println("yunus yunus yunus"); + System.out.println(antMediaApplicationAdapter.getName()); + if(subscriberId != null && !subscriberId.equals("undefined")){ + System.out.println("send start play web hook with not null subs id"); + antMediaApplicationAdapter.sendStartPlayWebHook(viewerPlayType, streamId, subscriberId); + }else{ + System.out.println("send start play web hook with null subs id"); + + antMediaApplicationAdapter.sendStartPlayWebHook(viewerPlayType, streamId, sessionId); + } } viewerMap.put(sessionId, System.currentTimeMillis()); streamsViewerMap.put(streamId, viewerMap); @@ -85,7 +100,7 @@ public void registerNewViewer(String streamId, String sessionId, String subscrib }); } - + public void resetViewerMap(String streamID, String type) { Iterator> viewerIterator; @@ -110,7 +125,7 @@ public void resetViewerMap(String streamID, String type) { logger.info("Reset {} Stream ID: {} remove failed or null", type, streamID); } } - + public int getViewerCount(String streamId) { Map viewerMap = streamsViewerMap.get(streamId); int viewerCount = 0; @@ -206,7 +221,7 @@ public void setVertx(Vertx vertx) { this.vertx = vertx; } - public void updateViewerCountProcess(String type) { + public void updateViewerCountProcess(String type, AntMediaApplicationAdapter antMediaApplicationAdapter) { Iterator>> streamIterator = streamsViewerMap.entrySet().iterator(); @@ -243,9 +258,17 @@ public void updateViewerCountProcess(String type) { // regard it as not a viewer viewerIterator.remove(); numberOfDecrement++; - + String sessionId = viewer.getKey(); String subscriberId = sessionId2subscriberId.get(sessionId); + System.out.println("yunus yunus yunus stop"); + System.out.println(subscriberId); + + if(subscriberId !=null && !subscriberId.equals("undefined")){ + antMediaApplicationAdapter.sendStopPlayWebHook(type,streamId,subscriberId); + }else{ + antMediaApplicationAdapter.sendStopPlayWebHook(type,streamId,sessionId); + } // set subscriber status to not connected if(subscriberId != null) { // add a disconnected event to the subscriber @@ -307,5 +330,4 @@ public void updateViewerCountProcess(String type) { } } - } diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index 8341e015e..eaee0a3f9 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; @@ -32,6 +33,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; +import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomUtils; import org.apache.http.HttpEntity; import org.apache.http.StatusLine; @@ -641,10 +643,10 @@ public void testNotifyHook() { AntMediaApplicationAdapter spyAdaptor = Mockito.spy(adapter); - StringBuilder notifyHook = spyAdaptor.notifyHook(null, null, null, null, null, null, null, null); + StringBuilder notifyHook = spyAdaptor.notifyHook(null, null, null, null, null, null, null, null, null); assertNull(notifyHook); - notifyHook = spyAdaptor.notifyHook("", null, null, null, null, null, null, null); + notifyHook = spyAdaptor.notifyHook("", null, null, null, null, null, null, null, null); assertNull(notifyHook); @@ -656,8 +658,10 @@ public void testNotifyHook() { String vodName = "vod name" + String.valueOf((Math.random() * 10000)); String vodId = String.valueOf((Math.random() * 10000)); + String viewerId = String.valueOf((Math.random() * 10000)); + String url = "this is url"; - notifyHook = spyAdaptor.notifyHook(url, id, action, streamName, category, vodName, vodId, null); + notifyHook = spyAdaptor.notifyHook(url, id, action, streamName, category, vodName, vodId, viewerId, null); assertNull(notifyHook); try { @@ -673,6 +677,7 @@ public void testNotifyHook() { assertEquals(category, variablesMap.get("category")); assertEquals(vodName, variablesMap.get("vodName")); assertEquals(vodId, variablesMap.get("vodId")); + assertEquals(viewerId, variablesMap.get("viewerId")); } catch (IOException e) { e.printStackTrace(); @@ -681,7 +686,7 @@ public void testNotifyHook() { url = "this is second url"; - notifyHook = spyAdaptor.notifyHook(url, id, null, null, null, null, null, null); + notifyHook = spyAdaptor.notifyHook(url, id, null, null, null, null, null, null, null); assertNull(notifyHook); try { @@ -734,6 +739,7 @@ public void testNotifyHookErrors(){ ArgumentCaptor captureCategory = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodName = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodId = ArgumentCaptor.forClass(String.class); + ArgumentCaptor captureViewerId = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureMetadata = ArgumentCaptor.forClass(String.class); /* @@ -748,7 +754,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -774,7 +780,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(2)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -799,7 +805,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(3)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -854,6 +860,7 @@ public void testNotifyHookFromMuxingFinished() { ArgumentCaptor captureCategory = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodName = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodId = ArgumentCaptor.forClass(String.class); + ArgumentCaptor captureViewerId = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureMetadata = ArgumentCaptor.forClass(String.class); @@ -863,7 +870,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is never called verify(spyAdaptor, never()).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); /* @@ -889,7 +896,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is called 1 time verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -923,7 +930,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that no new notifyHook is called verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); called = true; } @@ -952,7 +959,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is called 2 times verify(spyAdaptor, times(2)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -1775,5 +1782,53 @@ public void testAppDeletion() adapter.stopApplication(true); verify(dataStore, timeout(ClusterNode.NODE_UPDATE_PERIOD+1000)).close(true); } + @Test + public void testRecordStartedHook() throws Exception { + final AntMediaApplicationAdapter spyAdaptor = Mockito.spy(adapter); + AppSettings appSettings = new AppSettings(); + spyAdaptor.setAppSettings(appSettings); + + Broadcast broadcast = new Broadcast(); + assertNull(spyAdaptor.getListenerHookURL(broadcast)); + broadcast.setMp4Enabled(MuxAdaptor.RECORDING_ENABLED_FOR_STREAM); + String hookURL = "listener_hook_url"; + appSettings.setListenerHookURL(hookURL); + + assertEquals(hookURL, spyAdaptor.getListenerHookURL(broadcast)); + + + appSettings = new AppSettings(); + spyAdaptor.setServerSettings(new ServerSettings()); + spyAdaptor.setAppSettings(appSettings); + DataStore dataStore = new InMemoryDataStore("testHook"); + DataStoreFactory dsf = Mockito.mock(DataStoreFactory.class); + Mockito.when(dsf.getDataStore()).thenReturn(dataStore); + spyAdaptor.setDataStoreFactory(dsf); + spyAdaptor.setDataStore(dataStore); + broadcast.setStreamId("stream1"); + broadcast.setName("name"); + broadcast.setCategory("category"); + broadcast.setListenerHookURL(hookURL); + dataStore.save(broadcast); + String streamId = broadcast.getStreamId(); + + + doReturn(new StringBuilder()).when(spyAdaptor).sendPOST(anyString(),anyMap()); + + spyAdaptor.startPublish(streamId, 0, IAntMediaStreamHandler.PUBLISH_TYPE_WEBRTC); + verify(spyAdaptor, times(1)).sendStartRecordWebHook(streamId); + Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + verify(spyAdaptor,times(1)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_RECORD, broadcast.getName(),broadcast.getCategory(),null,null,null,null); + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + } } diff --git a/src/test/java/io/antmedia/test/Application.java b/src/test/java/io/antmedia/test/Application.java index e2a28ac58..f3d1fb427 100644 --- a/src/test/java/io/antmedia/test/Application.java +++ b/src/test/java/io/antmedia/test/Application.java @@ -23,7 +23,8 @@ public class Application extends AntMediaApplicationAdapter implements IAntMedia public static boolean enableSourceHealthUpdate = false; public static List notifyVodId = new ArrayList<>();; - + + public static List notifyViewerId = new ArrayList<>();; @Override @@ -51,7 +52,7 @@ public static void resetFields() { @Override public StringBuilder notifyHook(String url, String id, String action, String streamName, String category, - String vodName, String vodId, String metadata) { + String vodName, String vodId, String viewerId, String metadata) { logger.info("notify hook action: {}", action); notifyHookAction.add(action); notitfyURL.add(url); @@ -60,6 +61,7 @@ public StringBuilder notifyHook(String url, String id, String action, String str notifyCategory.add(category); notifyVodName.add(vodName); notifyVodId.add(vodId); + notifyViewerId.add(viewerId); return null; } diff --git a/src/test/java/io/antmedia/test/MuxerUnitTest.java b/src/test/java/io/antmedia/test/MuxerUnitTest.java index 51b1aa8ac..f21f0eaca 100644 --- a/src/test/java/io/antmedia/test/MuxerUnitTest.java +++ b/src/test/java/io/antmedia/test/MuxerUnitTest.java @@ -1679,7 +1679,7 @@ public void testMp4MuxingAndNotifyCallback() { Application app = (Application) applicationContext.getBean("web.handler"); AntMediaApplicationAdapter appAdaptor = Mockito.spy(app); - doReturn(new StringBuilder("")).when(appAdaptor).notifyHook(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString()); + doReturn(new StringBuilder("")).when(appAdaptor).notifyHook(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString()); assertNotNull(appAdaptor); //just check below value that it is not null, this is not related to this case but it should be tested diff --git a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java index 0f83e17b2..2c2597e8b 100644 --- a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java @@ -1,14 +1,11 @@ package io.antmedia.test.filter; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; import java.io.IOException; +import java.util.concurrent.TimeUnit; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -18,8 +15,13 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import io.antmedia.AntMediaApplicationAdapter; +import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.awaitility.Awaitility; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -130,8 +132,10 @@ public void testDoFilter() { .thenReturn(context); when(filterconfig.getServletContext()).thenReturn(servletContext); - - + + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + try { dashStatisticsFilter.init(filterconfig); //when(dashStatisticsFilter.getStreamStats()).thenReturn(streamStats); @@ -160,12 +164,31 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); dashStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - - - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); - - - + + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + /*verify(antMediaApplicationAdapter, times(1)).sendStartPlayWebHook(ViewerStats.DASH_TYPE, streamId, null); + + Awaitility.await().atMost(10, TimeUnit.SECONDS).until(()-> { + boolean called = false; + try { + Broadcast broadcast = dataStore.get(streamId); + String url = broadcast.getListenerHookURL(); + String id = streamId; + String action = AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY; + String streamName = broadcast.getName(); + String category = broadcast.getCategory(); + //String viewerId = sessionId; + verify(antMediaApplicationAdapter,times(1)).notifyHook(url,id,action,streamName,category, null, null,null, null); + called = true; + } catch (Exception e) { + e.printStackTrace(); + + } + return called; + });*/ + + + } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); @@ -189,7 +212,10 @@ public void testDASHViewerLimit() { IStreamStats streamStats = mock(IStreamStats.class); when(context.getBean(DashViewerStats.BEAN_NAME)).thenReturn(streamStats); - + + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + when(context.isRunning()).thenReturn(true); DataStoreFactory dsf = mock(DataStoreFactory.class); when(context.getBean(DataStoreFactory.BEAN_NAME)).thenReturn(dsf); @@ -211,17 +237,17 @@ public void testDASHViewerLimit() { try { dashStatisticsFilter.init(filterconfig); //when(dashStatisticsFilter.getStreamStats()).thenReturn(streamStats); - + String sessionId = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); broadcast.setDashViewerCount(1); String sessionId2 = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); broadcast.setDashViewerCount(2); String sessionId3 = requestDash(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java index a2a233ff0..eb65f6a2b 100644 --- a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java @@ -18,6 +18,8 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import io.antmedia.AntMediaApplicationAdapter; +import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.junit.After; @@ -130,7 +132,8 @@ public void testDoFilter() { .thenReturn(context); when(filterconfig.getServletContext()).thenReturn(servletContext); - + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); try { hlsStatisticsFilter.init(filterconfig); @@ -159,12 +162,9 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); hlsStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - - - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); - - - + + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); @@ -205,20 +205,22 @@ public void testHLSViewerLimit() { broadcast.setHlsViewerLimit(2); when(dataStore.get(streamId)).thenReturn(broadcast); - + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + try { hlsStatisticsFilter.init(filterconfig); - + String sessionId = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); broadcast.setHlsViewerCount(1); String sessionId2 = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); broadcast.setHlsViewerCount(2); String sessionId3 = requestHls(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java index 86fd027f3..b6d383678 100644 --- a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java @@ -4,17 +4,25 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import io.antmedia.security.AcceptOnlyStreamsInDataStore; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.impl.client.CloseableHttpClient; import org.awaitility.Awaitility; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.Mockito; +import org.red5.server.api.IContext; +import org.red5.server.api.scope.IScope; import org.springframework.context.ApplicationContext; import ch.qos.logback.classic.Logger; @@ -34,8 +42,8 @@ public class DashViewerStatsTest { - static Vertx vertx; - + static Vertx vertx; + @BeforeClass public static void beforeClass() { vertx = io.vertx.core.Vertx.vertx(); @@ -64,10 +72,11 @@ public void testDASHViewerCount() { // TODO Auto-generated catch block e.printStackTrace(); } + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -81,7 +90,7 @@ public void testDASHViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -115,7 +124,9 @@ public void testSubscriberEvents() { String sessionId = String.valueOf((Math.random() * 999999)); // check if viewer is added - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -154,6 +165,10 @@ public void testGetTimeout() { @Test public void testSetApplicationContextSubscribers() { ApplicationContext context = mock(ApplicationContext.class); + AntMediaApplicationAdapter adapter = new AntMediaApplicationAdapter(); + AppSettings appSettings = new AppSettings(); + adapter.setAppSettings(appSettings); + adapter.setVertx(vertx); try { @@ -173,20 +188,39 @@ public void testSetApplicationContextSubscribers() { when(context.getBean(AppSettings.BEAN_NAME)).thenReturn(settings); when(context.getBean(ServerSettings.BEAN_NAME)).thenReturn(new ServerSettings()); - + + IScope scope = mock(IScope.class); + + when(scope.getName()).thenReturn("junit"); + adapter.setScope(scope); + adapter.setDataStoreFactory(dsf); + AntMediaApplicationAdapter spyAdapter = Mockito.spy(adapter); + + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(spyAdapter); + + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + Mockito.doReturn(httpClient).when(spyAdapter).getHttpClient(); + + CloseableHttpResponse httpResponse = Mockito.mock(CloseableHttpResponse.class); + Mockito.when(httpClient.execute(Mockito.any())).thenReturn(httpResponse); + Mockito.when(httpResponse.getStatusLine()).thenReturn(Mockito.mock(StatusLine.class)); + + Mockito.when(httpResponse.getEntity()).thenReturn(null); + DashViewerStats viewerStats = new DashViewerStats(); viewerStats.setTimePeriodMS(1000); viewerStats.setApplicationContext(context); - Broadcast broadcast = new Broadcast(); broadcast.setStatus(AntMediaApplicationAdapter.BROADCAST_STATUS_BROADCASTING); broadcast.setName("name"); + broadcast.setListenerHookURL("url"); dsf.setWriteStatsToDatastore(true); dsf.setApplicationContext(context); String streamId = dsf.getDataStore().save(broadcast); + assertEquals(1000, viewerStats.getTimePeriodMS()); assertEquals(10000, viewerStats.getTimeoutMS()); @@ -214,11 +248,28 @@ public void testSetApplicationContextSubscribers() { subscriberPlay3.setSubscriberId("subscriber3"); subscriberPlay3.setB32Secret("6qsp6qhndryqs56zjmvs37i6gqtjsdvc"); subscriberPlay3.setType(Subscriber.PLAY_TYPE); - dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); - - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId()); - + dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); + + //spyAdapter.setDataStoreFactory(dsf); + + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + + + Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + verify(spyAdapter, times(2)).sendStartPlayWebHook(ViewerStats.DASH_TYPE, streamId, subscriberPlay.getSubscriberId()); + verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay.getSubscriberId(),null); + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 2 ); @@ -227,11 +278,11 @@ public void testSetApplicationContextSubscribers() { Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getTotalViewerCount() == 2 ); - + //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId()); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId()); - + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -246,7 +297,6 @@ public void testSetApplicationContextSubscribers() { return subData.isConnected() && subData.getCurrentConcurrentConnections() == 2 && eventExist; }); - // Check viewer is online Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> dsf.getDataStore().get(streamId).getDashViewerCount() == 2); @@ -254,7 +304,24 @@ public void testSetApplicationContextSubscribers() { // Wait some time for detect disconnect Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> dsf.getDataStore().get(streamId).getDashViewerCount() == 0); - + + + Awaitility.await().atMost(20, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + verify(spyAdapter, times(2)).sendStopPlayWebHook(ViewerStats.DASH_TYPE, streamId, subscriberPlay2.getSubscriberId()); + + verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_STOP_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay2.getSubscriberId(),null); + + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + assertEquals(0, viewerStats.getViewerCount(streamId)); assertEquals(0, viewerStats.getIncreaseCounterMap(streamId)); assertEquals(0, viewerStats.getTotalViewerCount()); @@ -276,7 +343,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -356,8 +423,9 @@ public void testSetApplicationContext() { assertEquals(10000, viewerStats.getTimeoutMS()); String sessionId = "sessionId" + (int)(Math.random() * 10000); + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -369,7 +437,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(30, TimeUnit.SECONDS).until( @@ -391,7 +459,7 @@ public void testSetApplicationContext() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(30, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); diff --git a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java index fd3a3eadb..f99b6db73 100644 --- a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java @@ -65,10 +65,11 @@ public void testHLSViewerCount() { // TODO Auto-generated catch block e.printStackTrace(); } + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -82,7 +83,7 @@ public void testHLSViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -115,8 +116,12 @@ public void testSubscriberEvents() { dataStore.addSubscriber(subscriberPlay.getStreamId(), subscriberPlay); String sessionId = String.valueOf((Math.random() * 999999)); + + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + + // check if viewer is added - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -213,10 +218,11 @@ public void testSetApplicationContextSubscribers() { subscriberPlay3.setSubscriberId("subscriber3"); subscriberPlay3.setB32Secret("6qsp6qhndryqs56zjmvs37i6gqtjsdvc"); subscriberPlay3.setType(Subscriber.PLAY_TYPE); - dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); - - - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); + dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); + + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -226,9 +232,10 @@ public void testSetApplicationContextSubscribers() { Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getTotalViewerCount() == 1 ); - + + //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { @@ -275,7 +282,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -353,8 +360,9 @@ public void testSetApplicationContext() { assertEquals(10000, viewerStats.getTimeoutMS()); String sessionId = "sessionId" + (int)(Math.random() * 10000); + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -366,7 +374,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(20, TimeUnit.SECONDS).until( @@ -388,7 +396,7 @@ public void testSetApplicationContext() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); From 88444c5f1b466b25717c9d33d23f41edcfaffdaa Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 3 Jan 2023 11:48:27 +0300 Subject: [PATCH 02/15] New webhooks playStart, playStop, recordStart issue #4666 --- .../antmedia/AntMediaApplicationAdapter.java | 84 ++++++++++-- .../io/antmedia/filter/AbstractFilter.java | 12 ++ .../antmedia/filter/DashStatisticsFilter.java | 6 +- .../antmedia/filter/HlsStatisticsFilter.java | 4 +- .../java/io/antmedia/muxer/MuxAdaptor.java | 9 +- .../antmedia/statistic/DashViewerStats.java | 5 +- .../io/antmedia/statistic/HlsViewerStats.java | 6 +- .../io/antmedia/statistic/IStreamStats.java | 4 +- .../io/antmedia/statistic/ViewerStats.java | 34 +++-- .../AntMediaApplicationAdaptorUnitTest.java | 77 +++++++++-- .../java/io/antmedia/test/Application.java | 6 +- .../java/io/antmedia/test/MuxerUnitTest.java | 2 +- .../test/filter/DashStatisticsFilterTest.java | 66 ++++++--- .../test/filter/HlsStatisticsFilterTest.java | 26 ++-- .../test/statistic/DashViewerStatsTest.java | 128 ++++++++++++++---- .../test/statistic/HlsViewerStatsTest.java | 43 ++++-- 16 files changed, 383 insertions(+), 129 deletions(-) diff --git a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java index aef8b80db..f9e2372e2 100644 --- a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java +++ b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java @@ -15,7 +15,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.regex.Pattern; import java.util.Queue; import java.util.Set; @@ -47,8 +46,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.errorprone.annotations.NoAllocation; - import io.antmedia.cluster.ClusterNode; import io.antmedia.cluster.IClusterNotifier; import io.antmedia.datastore.db.DataStore; @@ -65,7 +62,6 @@ import io.antmedia.plugin.api.IFrameListener; import io.antmedia.plugin.api.IPacketListener; import io.antmedia.plugin.api.IStreamListener; -import io.antmedia.plugin.api.StreamParametersInfo; import io.antmedia.rest.RestServiceBase; import io.antmedia.rest.model.Result; import io.antmedia.security.AcceptOnlyStreamsInDataStore; @@ -99,6 +95,9 @@ public class AntMediaApplicationAdapter extends MultiThreadedApplicationAdapter public static final String HOOK_ACTION_PUBLISH_TIMEOUT_ERROR = "publishTimeoutError"; public static final String HOOK_ACTION_ENCODER_NOT_OPENED_ERROR = "encoderNotOpenedError"; public static final String HOOK_ACTION_ENDPOINT_FAILED = "endpointFailed"; + public static final String HOOK_ACTION_START_PLAY = "playStart"; + public static final String HOOK_ACTION_STOP_PLAY = "playStop"; + public static final String HOOK_ACTION_START_RECORD = "recordStart"; public static final String STREAMS = "streams"; @@ -488,7 +487,7 @@ public void closeBroadcast(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call live stream ended hook for stream:{}",streamId ); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_END_LIVE_STREAM, name, category, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_END_LIVE_STREAM, name, category, null, null, null, null)); } if (broadcast.isZombi()) { @@ -539,13 +538,60 @@ public void resetDASHStats(String streamId) { } } + public void sendStartPlayWebHook(final String viewerPlayType, final String streamId, final String viewerId){ + final Broadcast broadcast = getDataStore().get(streamId); + final String listenerHookURL = broadcast.getListenerHookURL(); + if (listenerHookURL == null || listenerHookURL.isEmpty()) { + return; + } + final String name = broadcast.getName(); + final String category = broadcast.getCategory(); + logger.info("Setting timer to call viewer play started hook for stream:{}", streamId); + vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_PLAY, name, category, + null, null, viewerId, null)); + } + + public void sendStopPlayWebHook(final String viewerPlayType, final String streamId, final String viewerId){ + final Broadcast broadcast = getDataStore().get(streamId); + final String listenerHookURL = broadcast.getListenerHookURL(); + if (listenerHookURL == null || listenerHookURL.isEmpty()) { + return; + } + final String name = broadcast.getName(); + final String category = broadcast.getCategory(); + logger.info("Setting timer to call viewer play stopped hook for stream:{}", streamId); + vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_STOP_PLAY, name, category, + null, null, viewerId, null)); + } + + public void sendStartRecordWebHook(final String streamId){ + final Broadcast broadcast = getDataStore().get(streamId); + final String listenerHookURL = broadcast.getListenerHookURL(); + if (listenerHookURL == null || listenerHookURL.isEmpty()) { + return; + } + final String name = broadcast.getName(); + final String category = broadcast.getCategory(); + logger.info("Setting timer to call stream start recording hook for stream:{}", streamId); + vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_RECORD, name, category, + null, null, null, null)); + } + + private String getRtmpViewerId(){ + return "rtmp_" + RandomStringUtils.randomNumeric(8); + } + @Override public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) { - vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(item.getName(), true)); + final String streamId = item.getName(); + sendStartPlayWebHook(ViewerStats.RTMP_TYPE, streamId, getRtmpViewerId()); + vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, true)); } @Override public void streamPlayItemStop(ISubscriberStream stream, IPlayItem item) { - vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(item.getName(), false)); + final String streamId = item.getName(); + sendStopPlayWebHook(ViewerStats.RTMP_TYPE, streamId, getRtmpViewerId()); + vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, false)); } @Override @@ -557,7 +603,6 @@ public void streamSubscriberClose(ISubscriberStream stream) { public void startPublish(String streamId, long absoluteStartTimeMs, String publishType) { vertx.executeBlocking( handler -> { try { - Broadcast broadcast = updateBroadcastStatus(streamId, absoluteStartTimeMs, publishType, getDataStore().get(streamId)); final String listenerHookURL = getListenerHookURL(broadcast); @@ -567,7 +612,13 @@ public void startPublish(String streamId, long absoluteStartTimeMs, String publi final String category = broadcast.getCategory(); logger.info("Setting timer to call live stream started hook for stream:{}",streamId ); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_LIVE_STREAM, name, category, - null, null, null)); + null, null, null, null)); + } + + if ((broadcast.getMp4Enabled() == MuxAdaptor.RECORDING_ENABLED_FOR_STREAM || broadcast.getWebMEnabled() == MuxAdaptor.RECORDING_ENABLED_FOR_STREAM) + || (appSettings.isMp4MuxingEnabled() || appSettings.isWebMMuxingEnabled()) + ) { + sendStartRecordWebHook(streamId); } int ingestingStreamLimit = appSettings.getIngestingStreamLimit(); @@ -735,7 +786,7 @@ public void muxingFinished(final String streamId, File file, long startTime, lon final String baseName = vodName.substring(0, index); String finalListenerHookURL = listenerHookURL; logger.info("Setting timer for calling vod ready hook for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(finalListenerHookURL, streamId, HOOK_ACTION_VOD_READY, null, null, baseName, vodIdFinal, null)); + vertx.runOnContext(e -> notifyHook(finalListenerHookURL, streamId, HOOK_ACTION_VOD_READY, null, null, baseName, vodIdFinal, null, null)); } String muxerFinishScript = appSettings.getMuxerFinishScript(); @@ -806,7 +857,7 @@ public static String getRelativePath(String filePath){ * @return */ public StringBuilder notifyHook(String url, String id, String action, String streamName, String category, - String vodName, String vodId, String metadata) { + String vodName, String vodId, String viewerId, String metadata) { StringBuilder response = null; logger.info("Running notify hook url:{} stream id: {} action:{} vod name:{} vod id:{}", url, id, action, vodName, vodId); if (url != null && url.length() > 0) { @@ -829,6 +880,10 @@ public StringBuilder notifyHook(String url, String id, String action, String str variables.put("vodId", vodId); } + if(viewerId != null){ + variables.put("viewerId", viewerId); + } + if (metadata != null) { variables.put("metadata", metadata); } @@ -1304,7 +1359,7 @@ public synchronized void incrementEncoderNotOpenedError(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call encoder not opened error for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENCODER_NOT_OPENED_ERROR, name, category, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENCODER_NOT_OPENED_ERROR, name, category, null, null, null,null)); } } } @@ -1329,7 +1384,7 @@ public synchronized void publishTimeoutError(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call hook that means live stream is not started to the publish timeout for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_PUBLISH_TIMEOUT_ERROR, name, category, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_PUBLISH_TIMEOUT_ERROR, name, category, null, null, null, null)); } } } @@ -1441,7 +1496,6 @@ private boolean isEncoderSettingsValid(List encoderSettingsList /** * * @param newSettings - * @param checkUpdateTime * @return true if timing is valid, false if it is invalid */ public boolean isIncomingTimeValid(AppSettings newSettings) @@ -1686,7 +1740,7 @@ public void endpointFailedUpdate(String streamId, String url) { logger.info("Setting timer to call rtmp endpoint failed hook for stream:{}", streamId); JSONObject jsonObject = new JSONObject(); jsonObject.put("rtmp-url", url); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENDPOINT_FAILED, name, category, null, null, jsonObject.toJSONString())); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENDPOINT_FAILED, name, category, null, null, null, jsonObject.toJSONString())); } } } diff --git a/src/main/java/io/antmedia/filter/AbstractFilter.java b/src/main/java/io/antmedia/filter/AbstractFilter.java index f15b73eec..35552a668 100644 --- a/src/main/java/io/antmedia/filter/AbstractFilter.java +++ b/src/main/java/io/antmedia/filter/AbstractFilter.java @@ -9,6 +9,7 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletException; +import io.antmedia.AntMediaApplicationAdapter; import org.apache.catalina.util.NetMask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -154,5 +155,16 @@ public Broadcast getBroadcast(String streamId) { } return broadcast; } + + protected AntMediaApplicationAdapter getAntMediaApplicationAdapter(){ + AntMediaApplicationAdapter antMediaApplicationAdapter = null; + ApplicationContext context = getAppContext(); + if (context != null) + { + antMediaApplicationAdapter= (AntMediaApplicationAdapter)context.getBean(AntMediaApplicationAdapter.BEAN_NAME); + } + return antMediaApplicationAdapter; + + } } diff --git a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java index 980e0c9a6..51e3b6dd3 100644 --- a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.HttpMethod; +import io.antmedia.statistic.ViewerStats; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +26,7 @@ public class DashStatisticsFilter extends AbstractFilter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - + System.out.println("i got called"); HttpServletRequest httpRequest =(HttpServletRequest)request; String method = httpRequest.getMethod(); @@ -52,8 +53,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(DashViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId); - + stats.registerNewViewer(streamId, sessionId, subscriberId, ViewerStats.DASH_TYPE, getAntMediaApplicationAdapter()); } } } diff --git a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java index 0e3ff9f68..d7ab64e09 100644 --- a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java @@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.HttpMethod; +import io.antmedia.statistic.ViewerStats; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,8 +53,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(HlsViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId); - + stats.registerNewViewer(streamId, sessionId, subscriberId, ViewerStats.HLS_TYPE, getAntMediaApplicationAdapter()); } } } diff --git a/src/main/java/io/antmedia/muxer/MuxAdaptor.java b/src/main/java/io/antmedia/muxer/MuxAdaptor.java index 2c19d852d..a28c3fc9f 100644 --- a/src/main/java/io/antmedia/muxer/MuxAdaptor.java +++ b/src/main/java/io/antmedia/muxer/MuxAdaptor.java @@ -1681,7 +1681,6 @@ private Muxer addMp4Muxer() { * @return */ public RecordMuxer startRecording(RecordType recordType) { - if (!isRecording.get()) { logger.warn("Starting recording return false for stream:{} because stream is being prepared", streamId); return null; @@ -1692,7 +1691,6 @@ public RecordMuxer startRecording(RecordType recordType) { return null; } - RecordMuxer muxer = null; if(recordType == RecordType.MP4) { Mp4Muxer mp4Muxer = createMp4Muxer(); @@ -1862,10 +1860,15 @@ public Result startRtmpStreaming(String rtmpUrl, int resolutionHeight) } public void sendEndpointErrorNotifyHook(String url){ + AntMediaApplicationAdapter adaptor = getAntMediaApplicationAdaptor(); + adaptor.endpointFailedUpdate(this.streamId, url); + } + + protected AntMediaApplicationAdapter getAntMediaApplicationAdaptor(){ IContext context = MuxAdaptor.this.scope.getContext(); ApplicationContext appCtx = context.getApplicationContext(); AntMediaApplicationAdapter adaptor = (AntMediaApplicationAdapter) appCtx.getBean(AntMediaApplicationAdapter.BEAN_NAME); - adaptor.endpointFailedUpdate(this.streamId, url); + return adaptor; } /** diff --git a/src/main/java/io/antmedia/statistic/DashViewerStats.java b/src/main/java/io/antmedia/statistic/DashViewerStats.java index 74b6197c2..1f160570c 100644 --- a/src/main/java/io/antmedia/statistic/DashViewerStats.java +++ b/src/main/java/io/antmedia/statistic/DashViewerStats.java @@ -1,6 +1,7 @@ package io.antmedia.statistic; +import io.antmedia.AntMediaApplicationAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -28,11 +29,11 @@ public void setApplicationContext(ApplicationContext applicationContext) { AppSettings settings = (AppSettings)applicationContext.getBean(AppSettings.BEAN_NAME); timeoutMS = getTimeoutMSFromSettings(settings, timeoutMS, DASH_TYPE); - + final AntMediaApplicationAdapter antMediaApplicationAdapter = (AntMediaApplicationAdapter)applicationContext.getBean(AntMediaApplicationAdapter.BEAN_NAME); vertx.setPeriodic(DEFAULT_TIME_PERIOD_FOR_VIEWER_COUNT, yt-> { synchronized (lock) { - updateViewerCountProcess(DASH_TYPE); + updateViewerCountProcess(DASH_TYPE, antMediaApplicationAdapter); } }); } diff --git a/src/main/java/io/antmedia/statistic/HlsViewerStats.java b/src/main/java/io/antmedia/statistic/HlsViewerStats.java index 126fe9e3a..ca7a0a611 100644 --- a/src/main/java/io/antmedia/statistic/HlsViewerStats.java +++ b/src/main/java/io/antmedia/statistic/HlsViewerStats.java @@ -1,5 +1,6 @@ package io.antmedia.statistic; +import io.antmedia.AntMediaApplicationAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.ApplicationContext; @@ -28,11 +29,12 @@ public void setApplicationContext(ApplicationContext applicationContext) { AppSettings settings = (AppSettings)applicationContext.getBean(AppSettings.BEAN_NAME); timeoutMS = getTimeoutMSFromSettings(settings, timeoutMS, HLS_TYPE); - + final AntMediaApplicationAdapter antMediaApplicationAdapter = (AntMediaApplicationAdapter)applicationContext.getBean(AntMediaApplicationAdapter.BEAN_NAME); + vertx.setPeriodic(DEFAULT_TIME_PERIOD_FOR_VIEWER_COUNT, yt-> { synchronized (lock) { - updateViewerCountProcess(HLS_TYPE); + updateViewerCountProcess(HLS_TYPE, antMediaApplicationAdapter); } }); } diff --git a/src/main/java/io/antmedia/statistic/IStreamStats.java b/src/main/java/io/antmedia/statistic/IStreamStats.java index 00d250c1e..81a2d9e25 100644 --- a/src/main/java/io/antmedia/statistic/IStreamStats.java +++ b/src/main/java/io/antmedia/statistic/IStreamStats.java @@ -1,5 +1,7 @@ package io.antmedia.statistic; +import io.antmedia.AntMediaApplicationAdapter; + public interface IStreamStats { /** @@ -7,7 +9,7 @@ public interface IStreamStats { * @param streamId * @param sessionId */ - void registerNewViewer(String streamId, String sessionId, String subscriberId); + void registerNewViewer(String streamId, String sessionId, String subscriberId, String playType, AntMediaApplicationAdapter antMediaApplicationAdapter); /** diff --git a/src/main/java/io/antmedia/statistic/ViewerStats.java b/src/main/java/io/antmedia/statistic/ViewerStats.java index 252bcce25..c3617dd7a 100644 --- a/src/main/java/io/antmedia/statistic/ViewerStats.java +++ b/src/main/java/io/antmedia/statistic/ViewerStats.java @@ -6,6 +6,7 @@ import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import io.antmedia.AntMediaApplicationAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,16 +21,18 @@ public class ViewerStats { protected static Logger logger = LoggerFactory.getLogger(ViewerStats.class); - + protected Vertx vertx; public static final String HLS_TYPE = "hls"; public static final String DASH_TYPE = "dash"; - + public static final String RTMP_TYPE = "rtmp"; + public static final String WEBRTC_TYPE = "webrtc"; + + private DataStore dataStore; protected DataStoreFactory dataStoreFactory; - public static final int DEFAULT_TIME_PERIOD_FOR_VIEWER_COUNT = 10000; /** @@ -49,14 +52,12 @@ public class ViewerStats { */ protected int timeoutMS = 20000; - public void registerNewViewer(String streamId, String sessionId, String subscriberId) + public void registerNewViewer(String streamId, String sessionId, String subscriberId, String viewerPlayType, AntMediaApplicationAdapter antMediaApplicationAdapter) { //do not block the thread, run in vertx event queue vertx.runOnContext(h -> { - synchronized (lock) { //synchronize with database update calculations, because some odd cases may happen - Map viewerMap = streamsViewerMap.get(streamId); if (viewerMap == null) { viewerMap = new ConcurrentHashMap<>(); @@ -66,7 +67,11 @@ public void registerNewViewer(String streamId, String sessionId, String subscrib int streamIncrementCounter = getIncreaseCounterMap(streamId); streamIncrementCounter++; increaseCounterMap.put(streamId, streamIncrementCounter); - + if(subscriberId != null && !subscriberId.equals("undefined")){ + antMediaApplicationAdapter.sendStartPlayWebHook(viewerPlayType, streamId, subscriberId); + }else{ + antMediaApplicationAdapter.sendStartPlayWebHook(viewerPlayType, streamId, sessionId); + } } viewerMap.put(sessionId, System.currentTimeMillis()); streamsViewerMap.put(streamId, viewerMap); @@ -85,7 +90,7 @@ public void registerNewViewer(String streamId, String sessionId, String subscrib }); } - + public void resetViewerMap(String streamID, String type) { Iterator> viewerIterator; @@ -110,7 +115,7 @@ public void resetViewerMap(String streamID, String type) { logger.info("Reset {} Stream ID: {} remove failed or null", type, streamID); } } - + public int getViewerCount(String streamId) { Map viewerMap = streamsViewerMap.get(streamId); int viewerCount = 0; @@ -206,7 +211,7 @@ public void setVertx(Vertx vertx) { this.vertx = vertx; } - public void updateViewerCountProcess(String type) { + public void updateViewerCountProcess(String type, AntMediaApplicationAdapter antMediaApplicationAdapter) { Iterator>> streamIterator = streamsViewerMap.entrySet().iterator(); @@ -243,9 +248,15 @@ public void updateViewerCountProcess(String type) { // regard it as not a viewer viewerIterator.remove(); numberOfDecrement++; - + String sessionId = viewer.getKey(); String subscriberId = sessionId2subscriberId.get(sessionId); + + if(subscriberId !=null && !subscriberId.equals("undefined")){ + antMediaApplicationAdapter.sendStopPlayWebHook(type,streamId,subscriberId); + }else{ + antMediaApplicationAdapter.sendStopPlayWebHook(type,streamId,sessionId); + } // set subscriber status to not connected if(subscriberId != null) { // add a disconnected event to the subscriber @@ -307,5 +318,4 @@ public void updateViewerCountProcess(String type) { } } - } diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index 8341e015e..eaee0a3f9 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -7,6 +7,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.timeout; @@ -32,6 +33,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; +import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomUtils; import org.apache.http.HttpEntity; import org.apache.http.StatusLine; @@ -641,10 +643,10 @@ public void testNotifyHook() { AntMediaApplicationAdapter spyAdaptor = Mockito.spy(adapter); - StringBuilder notifyHook = spyAdaptor.notifyHook(null, null, null, null, null, null, null, null); + StringBuilder notifyHook = spyAdaptor.notifyHook(null, null, null, null, null, null, null, null, null); assertNull(notifyHook); - notifyHook = spyAdaptor.notifyHook("", null, null, null, null, null, null, null); + notifyHook = spyAdaptor.notifyHook("", null, null, null, null, null, null, null, null); assertNull(notifyHook); @@ -656,8 +658,10 @@ public void testNotifyHook() { String vodName = "vod name" + String.valueOf((Math.random() * 10000)); String vodId = String.valueOf((Math.random() * 10000)); + String viewerId = String.valueOf((Math.random() * 10000)); + String url = "this is url"; - notifyHook = spyAdaptor.notifyHook(url, id, action, streamName, category, vodName, vodId, null); + notifyHook = spyAdaptor.notifyHook(url, id, action, streamName, category, vodName, vodId, viewerId, null); assertNull(notifyHook); try { @@ -673,6 +677,7 @@ public void testNotifyHook() { assertEquals(category, variablesMap.get("category")); assertEquals(vodName, variablesMap.get("vodName")); assertEquals(vodId, variablesMap.get("vodId")); + assertEquals(viewerId, variablesMap.get("viewerId")); } catch (IOException e) { e.printStackTrace(); @@ -681,7 +686,7 @@ public void testNotifyHook() { url = "this is second url"; - notifyHook = spyAdaptor.notifyHook(url, id, null, null, null, null, null, null); + notifyHook = spyAdaptor.notifyHook(url, id, null, null, null, null, null, null, null); assertNull(notifyHook); try { @@ -734,6 +739,7 @@ public void testNotifyHookErrors(){ ArgumentCaptor captureCategory = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodName = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodId = ArgumentCaptor.forClass(String.class); + ArgumentCaptor captureViewerId = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureMetadata = ArgumentCaptor.forClass(String.class); /* @@ -748,7 +754,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -774,7 +780,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(2)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -799,7 +805,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(3)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -854,6 +860,7 @@ public void testNotifyHookFromMuxingFinished() { ArgumentCaptor captureCategory = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodName = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureVodId = ArgumentCaptor.forClass(String.class); + ArgumentCaptor captureViewerId = ArgumentCaptor.forClass(String.class); ArgumentCaptor captureMetadata = ArgumentCaptor.forClass(String.class); @@ -863,7 +870,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is never called verify(spyAdaptor, never()).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); /* @@ -889,7 +896,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is called 1 time verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -923,7 +930,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that no new notifyHook is called verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); called = true; } @@ -952,7 +959,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is called 2 times verify(spyAdaptor, times(2)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -1775,5 +1782,53 @@ public void testAppDeletion() adapter.stopApplication(true); verify(dataStore, timeout(ClusterNode.NODE_UPDATE_PERIOD+1000)).close(true); } + @Test + public void testRecordStartedHook() throws Exception { + final AntMediaApplicationAdapter spyAdaptor = Mockito.spy(adapter); + AppSettings appSettings = new AppSettings(); + spyAdaptor.setAppSettings(appSettings); + + Broadcast broadcast = new Broadcast(); + assertNull(spyAdaptor.getListenerHookURL(broadcast)); + broadcast.setMp4Enabled(MuxAdaptor.RECORDING_ENABLED_FOR_STREAM); + String hookURL = "listener_hook_url"; + appSettings.setListenerHookURL(hookURL); + + assertEquals(hookURL, spyAdaptor.getListenerHookURL(broadcast)); + + + appSettings = new AppSettings(); + spyAdaptor.setServerSettings(new ServerSettings()); + spyAdaptor.setAppSettings(appSettings); + DataStore dataStore = new InMemoryDataStore("testHook"); + DataStoreFactory dsf = Mockito.mock(DataStoreFactory.class); + Mockito.when(dsf.getDataStore()).thenReturn(dataStore); + spyAdaptor.setDataStoreFactory(dsf); + spyAdaptor.setDataStore(dataStore); + broadcast.setStreamId("stream1"); + broadcast.setName("name"); + broadcast.setCategory("category"); + broadcast.setListenerHookURL(hookURL); + dataStore.save(broadcast); + String streamId = broadcast.getStreamId(); + + + doReturn(new StringBuilder()).when(spyAdaptor).sendPOST(anyString(),anyMap()); + + spyAdaptor.startPublish(streamId, 0, IAntMediaStreamHandler.PUBLISH_TYPE_WEBRTC); + verify(spyAdaptor, times(1)).sendStartRecordWebHook(streamId); + Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + verify(spyAdaptor,times(1)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_RECORD, broadcast.getName(),broadcast.getCategory(),null,null,null,null); + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + } } diff --git a/src/test/java/io/antmedia/test/Application.java b/src/test/java/io/antmedia/test/Application.java index e2a28ac58..f3d1fb427 100644 --- a/src/test/java/io/antmedia/test/Application.java +++ b/src/test/java/io/antmedia/test/Application.java @@ -23,7 +23,8 @@ public class Application extends AntMediaApplicationAdapter implements IAntMedia public static boolean enableSourceHealthUpdate = false; public static List notifyVodId = new ArrayList<>();; - + + public static List notifyViewerId = new ArrayList<>();; @Override @@ -51,7 +52,7 @@ public static void resetFields() { @Override public StringBuilder notifyHook(String url, String id, String action, String streamName, String category, - String vodName, String vodId, String metadata) { + String vodName, String vodId, String viewerId, String metadata) { logger.info("notify hook action: {}", action); notifyHookAction.add(action); notitfyURL.add(url); @@ -60,6 +61,7 @@ public StringBuilder notifyHook(String url, String id, String action, String str notifyCategory.add(category); notifyVodName.add(vodName); notifyVodId.add(vodId); + notifyViewerId.add(viewerId); return null; } diff --git a/src/test/java/io/antmedia/test/MuxerUnitTest.java b/src/test/java/io/antmedia/test/MuxerUnitTest.java index 51b1aa8ac..f21f0eaca 100644 --- a/src/test/java/io/antmedia/test/MuxerUnitTest.java +++ b/src/test/java/io/antmedia/test/MuxerUnitTest.java @@ -1679,7 +1679,7 @@ public void testMp4MuxingAndNotifyCallback() { Application app = (Application) applicationContext.getBean("web.handler"); AntMediaApplicationAdapter appAdaptor = Mockito.spy(app); - doReturn(new StringBuilder("")).when(appAdaptor).notifyHook(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString()); + doReturn(new StringBuilder("")).when(appAdaptor).notifyHook(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString()); assertNotNull(appAdaptor); //just check below value that it is not null, this is not related to this case but it should be tested diff --git a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java index 0f83e17b2..2c2597e8b 100644 --- a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java @@ -1,14 +1,11 @@ package io.antmedia.test.filter; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.*; import java.io.IOException; +import java.util.concurrent.TimeUnit; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -18,8 +15,13 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import io.antmedia.AntMediaApplicationAdapter; +import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.awaitility.Awaitility; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -130,8 +132,10 @@ public void testDoFilter() { .thenReturn(context); when(filterconfig.getServletContext()).thenReturn(servletContext); - - + + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + try { dashStatisticsFilter.init(filterconfig); //when(dashStatisticsFilter.getStreamStats()).thenReturn(streamStats); @@ -160,12 +164,31 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); dashStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - - - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); - - - + + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + /*verify(antMediaApplicationAdapter, times(1)).sendStartPlayWebHook(ViewerStats.DASH_TYPE, streamId, null); + + Awaitility.await().atMost(10, TimeUnit.SECONDS).until(()-> { + boolean called = false; + try { + Broadcast broadcast = dataStore.get(streamId); + String url = broadcast.getListenerHookURL(); + String id = streamId; + String action = AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY; + String streamName = broadcast.getName(); + String category = broadcast.getCategory(); + //String viewerId = sessionId; + verify(antMediaApplicationAdapter,times(1)).notifyHook(url,id,action,streamName,category, null, null,null, null); + called = true; + } catch (Exception e) { + e.printStackTrace(); + + } + return called; + });*/ + + + } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); @@ -189,7 +212,10 @@ public void testDASHViewerLimit() { IStreamStats streamStats = mock(IStreamStats.class); when(context.getBean(DashViewerStats.BEAN_NAME)).thenReturn(streamStats); - + + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + when(context.isRunning()).thenReturn(true); DataStoreFactory dsf = mock(DataStoreFactory.class); when(context.getBean(DataStoreFactory.BEAN_NAME)).thenReturn(dsf); @@ -211,17 +237,17 @@ public void testDASHViewerLimit() { try { dashStatisticsFilter.init(filterconfig); //when(dashStatisticsFilter.getStreamStats()).thenReturn(streamStats); - + String sessionId = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); broadcast.setDashViewerCount(1); String sessionId2 = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); broadcast.setDashViewerCount(2); String sessionId3 = requestDash(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java index a2a233ff0..eb65f6a2b 100644 --- a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java @@ -18,6 +18,8 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import io.antmedia.AntMediaApplicationAdapter; +import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.junit.After; @@ -130,7 +132,8 @@ public void testDoFilter() { .thenReturn(context); when(filterconfig.getServletContext()).thenReturn(servletContext); - + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); try { hlsStatisticsFilter.init(filterconfig); @@ -159,12 +162,9 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); hlsStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - - - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); - - - + + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); @@ -205,20 +205,22 @@ public void testHLSViewerLimit() { broadcast.setHlsViewerLimit(2); when(dataStore.get(streamId)).thenReturn(broadcast); - + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + try { hlsStatisticsFilter.init(filterconfig); - + String sessionId = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); broadcast.setHlsViewerCount(1); String sessionId2 = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); broadcast.setHlsViewerCount(2); String sessionId3 = requestHls(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java index 86fd027f3..edaf90bc3 100644 --- a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java @@ -4,17 +4,25 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.times; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; +import io.antmedia.security.AcceptOnlyStreamsInDataStore; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.impl.client.CloseableHttpClient; import org.awaitility.Awaitility; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.Mockito; +import org.red5.server.api.IContext; +import org.red5.server.api.scope.IScope; import org.springframework.context.ApplicationContext; import ch.qos.logback.classic.Logger; @@ -34,8 +42,8 @@ public class DashViewerStatsTest { - static Vertx vertx; - + static Vertx vertx; + @BeforeClass public static void beforeClass() { vertx = io.vertx.core.Vertx.vertx(); @@ -64,10 +72,11 @@ public void testDASHViewerCount() { // TODO Auto-generated catch block e.printStackTrace(); } + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -81,7 +90,7 @@ public void testDASHViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -115,7 +124,9 @@ public void testSubscriberEvents() { String sessionId = String.valueOf((Math.random() * 999999)); // check if viewer is added - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -154,6 +165,10 @@ public void testGetTimeout() { @Test public void testSetApplicationContextSubscribers() { ApplicationContext context = mock(ApplicationContext.class); + AntMediaApplicationAdapter adapter = new AntMediaApplicationAdapter(); + AppSettings appSettings = new AppSettings(); + adapter.setAppSettings(appSettings); + adapter.setVertx(vertx); try { @@ -173,20 +188,39 @@ public void testSetApplicationContextSubscribers() { when(context.getBean(AppSettings.BEAN_NAME)).thenReturn(settings); when(context.getBean(ServerSettings.BEAN_NAME)).thenReturn(new ServerSettings()); - + + IScope scope = mock(IScope.class); + + when(scope.getName()).thenReturn("junit"); + adapter.setScope(scope); + adapter.setDataStoreFactory(dsf); + AntMediaApplicationAdapter spyAdapter = Mockito.spy(adapter); + + when(context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(spyAdapter); + + CloseableHttpClient httpClient = Mockito.mock(CloseableHttpClient.class); + Mockito.doReturn(httpClient).when(spyAdapter).getHttpClient(); + + CloseableHttpResponse httpResponse = Mockito.mock(CloseableHttpResponse.class); + Mockito.when(httpClient.execute(Mockito.any())).thenReturn(httpResponse); + Mockito.when(httpResponse.getStatusLine()).thenReturn(Mockito.mock(StatusLine.class)); + + Mockito.when(httpResponse.getEntity()).thenReturn(null); + DashViewerStats viewerStats = new DashViewerStats(); viewerStats.setTimePeriodMS(1000); viewerStats.setApplicationContext(context); - Broadcast broadcast = new Broadcast(); broadcast.setStatus(AntMediaApplicationAdapter.BROADCAST_STATUS_BROADCASTING); broadcast.setName("name"); + broadcast.setListenerHookURL("url"); dsf.setWriteStatsToDatastore(true); dsf.setApplicationContext(context); String streamId = dsf.getDataStore().save(broadcast); + assertEquals(1000, viewerStats.getTimePeriodMS()); assertEquals(10000, viewerStats.getTimeoutMS()); @@ -214,11 +248,28 @@ public void testSetApplicationContextSubscribers() { subscriberPlay3.setSubscriberId("subscriber3"); subscriberPlay3.setB32Secret("6qsp6qhndryqs56zjmvs37i6gqtjsdvc"); subscriberPlay3.setType(Subscriber.PLAY_TYPE); - dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); - - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId()); - + dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); + + //spyAdapter.setDataStoreFactory(dsf); + + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + + + Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + verify(spyAdapter, times(2)).sendStartPlayWebHook(ViewerStats.DASH_TYPE, streamId, subscriberPlay.getSubscriberId()); + verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay.getSubscriberId(),null); + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 2 ); @@ -227,11 +278,11 @@ public void testSetApplicationContextSubscribers() { Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getTotalViewerCount() == 2 ); - + //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId()); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId()); - + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -246,7 +297,6 @@ public void testSetApplicationContextSubscribers() { return subData.isConnected() && subData.getCurrentConcurrentConnections() == 2 && eventExist; }); - // Check viewer is online Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> dsf.getDataStore().get(streamId).getDashViewerCount() == 2); @@ -254,7 +304,24 @@ public void testSetApplicationContextSubscribers() { // Wait some time for detect disconnect Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> dsf.getDataStore().get(streamId).getDashViewerCount() == 0); - + + + Awaitility.await().atMost(20, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + verify(spyAdapter, times(2)).sendStopPlayWebHook(ViewerStats.DASH_TYPE, streamId, subscriberPlay2.getSubscriberId()); + + verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_STOP_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay2.getSubscriberId(),null); + + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + assertEquals(0, viewerStats.getViewerCount(streamId)); assertEquals(0, viewerStats.getIncreaseCounterMap(streamId)); assertEquals(0, viewerStats.getTotalViewerCount()); @@ -276,7 +343,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -321,11 +388,13 @@ public void testSetApplicationContext() { ApplicationContext context = mock(ApplicationContext.class); try { - + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when((AntMediaApplicationAdapter) context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); DataStoreFactory dsf = new DataStoreFactory(); dsf.setDbType("memorydb"); dsf.setDbName("datastore"); when(context.getBean(DataStoreFactory.BEAN_NAME)).thenReturn(dsf); + antMediaApplicationAdapter.setDataStoreFactory(dsf); when(context.containsBean(AppSettings.BEAN_NAME)).thenReturn(true); @@ -356,9 +425,13 @@ public void testSetApplicationContext() { assertEquals(10000, viewerStats.getTimeoutMS()); String sessionId = "sessionId" + (int)(Math.random() * 10000); + antMediaApplicationAdapter.setAppSettings(settings); + + + //AntMediaApplicationAdapter spyAdapter = Mockito.spy(new AntMediaApplicationAdapter()); + + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); - viewerStats.registerNewViewer(streamId, sessionId, null); - Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -369,7 +442,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(30, TimeUnit.SECONDS).until( @@ -390,9 +463,8 @@ public void testSetApplicationContext() { Awaitility.await().atMost(30, TimeUnit.SECONDS).until( ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - - viewerStats.registerNewViewer(streamId, sessionId, null); - + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + Awaitility.await().atMost(30, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); diff --git a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java index fd3a3eadb..6849444af 100644 --- a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java @@ -65,10 +65,11 @@ public void testHLSViewerCount() { // TODO Auto-generated catch block e.printStackTrace(); } + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -82,7 +83,7 @@ public void testHLSViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -115,8 +116,12 @@ public void testSubscriberEvents() { dataStore.addSubscriber(subscriberPlay.getStreamId(), subscriberPlay); String sessionId = String.valueOf((Math.random() * 999999)); + + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + + // check if viewer is added - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -168,7 +173,10 @@ public void testSetApplicationContextSubscribers() { when(context.getBean(IAntMediaStreamHandler.VERTX_BEAN_NAME)).thenReturn(vertx); AppSettings settings = mock(AppSettings.class); - + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when((AntMediaApplicationAdapter) context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + antMediaApplicationAdapter.setDataStoreFactory(dsf); + antMediaApplicationAdapter.setAppSettings(settings); //set hls time to 1 when(settings.getHlsTime()).thenReturn("1"); @@ -213,10 +221,11 @@ public void testSetApplicationContextSubscribers() { subscriberPlay3.setSubscriberId("subscriber3"); subscriberPlay3.setB32Secret("6qsp6qhndryqs56zjmvs37i6gqtjsdvc"); subscriberPlay3.setType(Subscriber.PLAY_TYPE); - dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); - - - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId()); + dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); + + + + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -226,9 +235,10 @@ public void testSetApplicationContextSubscribers() { Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getTotalViewerCount() == 1 ); - + + //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { @@ -275,7 +285,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId()); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -329,7 +339,10 @@ public void testSetApplicationContext() { when(context.getBean(IAntMediaStreamHandler.VERTX_BEAN_NAME)).thenReturn(vertx); AppSettings settings = mock(AppSettings.class); - + AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); + when((AntMediaApplicationAdapter) context.getBean(AntMediaApplicationAdapter.BEAN_NAME)).thenReturn(antMediaApplicationAdapter); + antMediaApplicationAdapter.setDataStoreFactory(dsf); + antMediaApplicationAdapter.setAppSettings(settings); //set hls time to 1 when(settings.getHlsTime()).thenReturn("1"); @@ -354,7 +367,7 @@ public void testSetApplicationContext() { String sessionId = "sessionId" + (int)(Math.random() * 10000); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -366,7 +379,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(20, TimeUnit.SECONDS).until( @@ -388,7 +401,7 @@ public void testSetApplicationContext() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, null); + viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); From f4ec03a78f6f96717e71e85cdfa600bfba04ac7b Mon Sep 17 00:00:00 2001 From: lastpeony Date: Mon, 9 Jan 2023 09:06:57 +0300 Subject: [PATCH 03/15] New webhooks playStart, playStop, recordStart issue #4666 --- src/main/java/io/antmedia/filter/DashStatisticsFilter.java | 2 -- src/main/java/io/antmedia/statistic/ViewerStats.java | 2 -- .../io/antmedia/test/statistic/HlsViewerStatsTest.java | 7 ------- 3 files changed, 11 deletions(-) diff --git a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java index 51e3b6dd3..91d0f6adb 100644 --- a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java @@ -25,8 +25,6 @@ public class DashStatisticsFilter extends AbstractFilter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - - System.out.println("i got called"); HttpServletRequest httpRequest =(HttpServletRequest)request; String method = httpRequest.getMethod(); diff --git a/src/main/java/io/antmedia/statistic/ViewerStats.java b/src/main/java/io/antmedia/statistic/ViewerStats.java index a60cf536c..f3dabcd35 100644 --- a/src/main/java/io/antmedia/statistic/ViewerStats.java +++ b/src/main/java/io/antmedia/statistic/ViewerStats.java @@ -54,8 +54,6 @@ public class ViewerStats { public void registerNewViewer(String streamId, String sessionId, String subscriberId, String viewerPlayType, AntMediaApplicationAdapter antMediaApplicationAdapter) { - System.out.println("i got called3!"); - //do not block the thread, run in vertx event queue vertx.runOnContext(h -> { synchronized (lock) { diff --git a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java index 72edf5b8e..5c3da0068 100644 --- a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java @@ -223,12 +223,6 @@ public void testSetApplicationContextSubscribers() { subscriberPlay3.setType(Subscriber.PLAY_TYPE); dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); -<<<<<<< HEAD - -======= - AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); ->>>>>>> a029073d3fa0e9a594c693800eea3edf015ca56f - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -370,7 +364,6 @@ public void testSetApplicationContext() { assertEquals(10000, viewerStats.getTimeoutMS()); String sessionId = "sessionId" + (int)(Math.random() * 10000); - AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); From 671f9fae5fd46858a24d54a2770b41120b33cfd3 Mon Sep 17 00:00:00 2001 From: lastpeony Date: Mon, 9 Jan 2023 11:20:53 +0300 Subject: [PATCH 04/15] New webhooks playStart, playStop, recordStart issue #4666 --- .../AntMediaApplicationAdaptorUnitTest.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index eaee0a3f9..a339d355e 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -53,6 +53,8 @@ import org.mockito.Mockito; import org.red5.server.api.IContext; import org.red5.server.api.scope.IScope; +import org.red5.server.api.stream.IPlayItem; +import org.red5.server.api.stream.ISubscriberStream; import org.red5.server.stream.ClientBroadcastStream; import org.springframework.context.ApplicationContext; @@ -1831,4 +1833,69 @@ public void testRecordStartedHook() throws Exception { } + @Test + public void testRtmpStreamPlayStop() throws Exception { + final AntMediaApplicationAdapter spyAdaptor = Mockito.spy(adapter); + AppSettings appSettings = new AppSettings(); + spyAdaptor.setAppSettings(appSettings); + + Broadcast broadcast = new Broadcast(); + assertNull(spyAdaptor.getListenerHookURL(broadcast)); + broadcast.setMp4Enabled(MuxAdaptor.RECORDING_ENABLED_FOR_STREAM); + String hookURL = "listener_hook_url"; + appSettings.setListenerHookURL(hookURL); + + assertEquals(hookURL, spyAdaptor.getListenerHookURL(broadcast)); + + + appSettings = new AppSettings(); + spyAdaptor.setServerSettings(new ServerSettings()); + spyAdaptor.setAppSettings(appSettings); + DataStore dataStore = new InMemoryDataStore("test"); + DataStoreFactory dsf = Mockito.mock(DataStoreFactory.class); + Mockito.when(dsf.getDataStore()).thenReturn(dataStore); + spyAdaptor.setDataStoreFactory(dsf); + spyAdaptor.setDataStore(dataStore); + broadcast.setStreamId("stream1"); + broadcast.setName("name"); + broadcast.setCategory("category"); + broadcast.setListenerHookURL(hookURL); + dataStore.save(broadcast); + String streamId = broadcast.getStreamId(); + IPlayItem item = mock(IPlayItem.class); + ISubscriberStream stream = mock(ISubscriberStream.class); + doReturn(streamId).when(item).getName(); + doReturn(new StringBuilder()).when(spyAdaptor).sendPOST(anyString(),anyMap()); + assertEquals(spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount(), 0); + + spyAdaptor.streamPlayItemPlay(stream, item, true); + verify(spyAdaptor, times(1)).sendStartPlayWebHook(anyString(), anyString(), anyString()); + Awaitility.await().atMost(2, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + assertEquals(spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount(), 1); + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + spyAdaptor.streamPlayItemStop(stream, item); + verify(spyAdaptor, times(1)).sendStopPlayWebHook(anyString(), anyString(), anyString()); + Awaitility.await().atMost(2, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + ()-> { + boolean called = false; + try{ + assertEquals(spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount(), 0); + called = true; + }catch (Exception e){ + e.printStackTrace(); + } + return called; + }); + + } + } From a59ec876ab448665f5380f1df5194d62398cc4bc Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 10 Jan 2023 15:17:59 +0300 Subject: [PATCH 05/15] new web hooks --- src/main/java/io/antmedia/AntMediaApplicationAdapter.java | 4 ++-- src/main/java/io/antmedia/statistic/ViewerStats.java | 4 ++-- .../antmedia/test/AntMediaApplicationAdaptorUnitTest.java | 3 +-- .../io/antmedia/test/statistic/DashViewerStatsTest.java | 6 +----- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java index f9e2372e2..9ce2c3913 100644 --- a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java +++ b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java @@ -551,7 +551,7 @@ public void sendStartPlayWebHook(final String viewerPlayType, final String strea null, null, viewerId, null)); } - public void sendStopPlayWebHook(final String viewerPlayType, final String streamId, final String viewerId){ + public void sendStopPlayWebHook(final String streamId, final String viewerId){ final Broadcast broadcast = getDataStore().get(streamId); final String listenerHookURL = broadcast.getListenerHookURL(); if (listenerHookURL == null || listenerHookURL.isEmpty()) { @@ -590,7 +590,7 @@ public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean @Override public void streamPlayItemStop(ISubscriberStream stream, IPlayItem item) { final String streamId = item.getName(); - sendStopPlayWebHook(ViewerStats.RTMP_TYPE, streamId, getRtmpViewerId()); + sendStopPlayWebHook(streamId, getRtmpViewerId()); vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, false)); } diff --git a/src/main/java/io/antmedia/statistic/ViewerStats.java b/src/main/java/io/antmedia/statistic/ViewerStats.java index f3dabcd35..2a877e19f 100644 --- a/src/main/java/io/antmedia/statistic/ViewerStats.java +++ b/src/main/java/io/antmedia/statistic/ViewerStats.java @@ -254,9 +254,9 @@ public void updateViewerCountProcess(String type, AntMediaApplicationAdapter ant String subscriberId = sessionId2subscriberId.get(sessionId); if(subscriberId !=null && !subscriberId.equals("undefined")){ - antMediaApplicationAdapter.sendStopPlayWebHook(type,streamId,subscriberId); + antMediaApplicationAdapter.sendStopPlayWebHook(streamId,subscriberId); }else{ - antMediaApplicationAdapter.sendStopPlayWebHook(type,streamId,sessionId); + antMediaApplicationAdapter.sendStopPlayWebHook(streamId,sessionId); } // set subscriber status to not connected if(subscriberId != null) { diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index a339d355e..1b1db7a75 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -33,7 +33,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; -import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomUtils; import org.apache.http.HttpEntity; import org.apache.http.StatusLine; @@ -1883,7 +1882,7 @@ public void testRtmpStreamPlayStop() throws Exception { }); spyAdaptor.streamPlayItemStop(stream, item); - verify(spyAdaptor, times(1)).sendStopPlayWebHook(anyString(), anyString(), anyString()); + verify(spyAdaptor, times(1)).sendStopPlayWebHook(anyString(), anyString()); Awaitility.await().atMost(2, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean called = false; diff --git a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java index 8bbd949ae..89668a343 100644 --- a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java @@ -11,8 +11,6 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import io.antmedia.security.AcceptOnlyStreamsInDataStore; -import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.impl.client.CloseableHttpClient; @@ -21,11 +19,9 @@ import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mockito; -import org.red5.server.api.IContext; import org.red5.server.api.scope.IScope; import org.springframework.context.ApplicationContext; -import ch.qos.logback.classic.Logger; import io.antmedia.AntMediaApplicationAdapter; import io.antmedia.AppSettings; import io.antmedia.datastore.db.DataStore; @@ -310,7 +306,7 @@ public void testSetApplicationContextSubscribers() { ()-> { boolean called = false; try{ - verify(spyAdapter, times(2)).sendStopPlayWebHook(ViewerStats.DASH_TYPE, streamId, subscriberPlay2.getSubscriberId()); + verify(spyAdapter, times(2)).sendStopPlayWebHook(streamId, subscriberPlay2.getSubscriberId()); verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_STOP_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay2.getSubscriberId(),null); From f7297b122fde9adcc6924394a757eeee2f9634cc Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 17 Jan 2023 12:05:55 +0300 Subject: [PATCH 06/15] New webhooks playStart, playStop, recordStart issue #4666 --- src/main/java/io/antmedia/AntMediaApplicationAdapter.java | 4 ++-- src/main/java/io/antmedia/statistic/ViewerStats.java | 4 ++-- .../antmedia/test/AntMediaApplicationAdaptorUnitTest.java | 8 ++++---- .../io/antmedia/test/statistic/DashViewerStatsTest.java | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java index 9ce2c3913..faa1c8fa5 100644 --- a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java +++ b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java @@ -538,7 +538,7 @@ public void resetDASHStats(String streamId) { } } - public void sendStartPlayWebHook(final String viewerPlayType, final String streamId, final String viewerId){ + public void sendStartPlayWebHook(final String streamId, final String viewerId){ final Broadcast broadcast = getDataStore().get(streamId); final String listenerHookURL = broadcast.getListenerHookURL(); if (listenerHookURL == null || listenerHookURL.isEmpty()) { @@ -584,7 +584,7 @@ private String getRtmpViewerId(){ @Override public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) { final String streamId = item.getName(); - sendStartPlayWebHook(ViewerStats.RTMP_TYPE, streamId, getRtmpViewerId()); + sendStartPlayWebHook(streamId, getRtmpViewerId()); vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, true)); } @Override diff --git a/src/main/java/io/antmedia/statistic/ViewerStats.java b/src/main/java/io/antmedia/statistic/ViewerStats.java index 2a877e19f..8d26ec608 100644 --- a/src/main/java/io/antmedia/statistic/ViewerStats.java +++ b/src/main/java/io/antmedia/statistic/ViewerStats.java @@ -69,9 +69,9 @@ public void registerNewViewer(String streamId, String sessionId, String subscrib increaseCounterMap.put(streamId, streamIncrementCounter); if(subscriberId != null && !subscriberId.equals("undefined")){ - antMediaApplicationAdapter.sendStartPlayWebHook(viewerPlayType, streamId, subscriberId); + antMediaApplicationAdapter.sendStartPlayWebHook(streamId, subscriberId); }else{ - antMediaApplicationAdapter.sendStartPlayWebHook(viewerPlayType, streamId, sessionId); + antMediaApplicationAdapter.sendStartPlayWebHook(streamId, sessionId); } } viewerMap.put(sessionId, System.currentTimeMillis()); diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index 1b1db7a75..7c9c53f0c 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -1865,15 +1865,15 @@ public void testRtmpStreamPlayStop() throws Exception { ISubscriberStream stream = mock(ISubscriberStream.class); doReturn(streamId).when(item).getName(); doReturn(new StringBuilder()).when(spyAdaptor).sendPOST(anyString(),anyMap()); - assertEquals(spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount(), 0); + assertEquals(0, spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount()); spyAdaptor.streamPlayItemPlay(stream, item, true); - verify(spyAdaptor, times(1)).sendStartPlayWebHook(anyString(), anyString(), anyString()); + verify(spyAdaptor, times(1)).sendStartPlayWebHook(anyString(), anyString()); Awaitility.await().atMost(2, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean called = false; try{ - assertEquals(spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount(), 1); + assertEquals(1, spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount()); called = true; }catch (Exception e){ e.printStackTrace(); @@ -1887,7 +1887,7 @@ public void testRtmpStreamPlayStop() throws Exception { ()-> { boolean called = false; try{ - assertEquals(spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount(), 0); + assertEquals(0, spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount()); called = true; }catch (Exception e){ e.printStackTrace(); diff --git a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java index 89668a343..da744a353 100644 --- a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java @@ -256,7 +256,7 @@ public void testSetApplicationContextSubscribers() { ()-> { boolean called = false; try{ - verify(spyAdapter, times(2)).sendStartPlayWebHook(ViewerStats.DASH_TYPE, streamId, subscriberPlay.getSubscriberId()); + verify(spyAdapter, times(2)).sendStartPlayWebHook(streamId, subscriberPlay.getSubscriberId()); verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay.getSubscriberId(),null); called = true; }catch (Exception e){ From 0f612e8d9ffe906302fc0dbaaad02d4f91aa43cc Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 17 Jan 2023 14:02:01 +0300 Subject: [PATCH 07/15] New webhooks playStart, playStop, recordStart issue #4666 --- 1 | 14 ++++++++++++++ .../junit/streams/010377385515858588541652.m3u8 | 7 +++++++ .../streams/010377385515858588541652000000000.ts | 0 .../junit/streams/130648337158084781489317.m3u8 | 7 +++++++ .../streams/130648337158084781489317000000000.ts | 0 .../junit/streams/305147821057798436984629.m3u8 | 7 +++++++ .../streams/305147821057798436984629000000000.ts | 0 .../junit/streams/371459229667024016956787.m3u8 | 7 +++++++ .../streams/371459229667024016956787000000000.ts | 0 .../junit/streams/393657863698685730684471.m3u8 | 7 +++++++ .../streams/393657863698685730684471000000000.ts | 0 .../junit/streams/668883968102040044966364.m3u8 | 7 +++++++ .../streams/668883968102040044966364000000000.ts | 0 .../test/AntMediaApplicationAdaptorUnitTest.java | 2 +- 14 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 1 create mode 100644 null/webapps/junit/streams/010377385515858588541652.m3u8 create mode 100644 null/webapps/junit/streams/010377385515858588541652000000000.ts create mode 100644 null/webapps/junit/streams/130648337158084781489317.m3u8 create mode 100644 null/webapps/junit/streams/130648337158084781489317000000000.ts create mode 100644 null/webapps/junit/streams/305147821057798436984629.m3u8 create mode 100644 null/webapps/junit/streams/305147821057798436984629000000000.ts create mode 100644 null/webapps/junit/streams/371459229667024016956787.m3u8 create mode 100644 null/webapps/junit/streams/371459229667024016956787000000000.ts create mode 100644 null/webapps/junit/streams/393657863698685730684471.m3u8 create mode 100644 null/webapps/junit/streams/393657863698685730684471000000000.ts create mode 100644 null/webapps/junit/streams/668883968102040044966364.m3u8 create mode 100644 null/webapps/junit/streams/668883968102040044966364000000000.ts diff --git a/1 b/1 new file mode 100644 index 000000000..277e26a64 --- /dev/null +++ b/1 @@ -0,0 +1,14 @@ +New webhooks playStart, playStop, recordStart issue #4666 + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# +# On branch newWebHooks +# Your branch is up to date with 'origin/newWebHooks'. +# +# Changes to be committed: +# modified: src/main/java/io/antmedia/AntMediaApplicationAdapter.java +# modified: src/main/java/io/antmedia/statistic/ViewerStats.java +# modified: src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +# modified: src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java +# diff --git a/null/webapps/junit/streams/010377385515858588541652.m3u8 b/null/webapps/junit/streams/010377385515858588541652.m3u8 new file mode 100644 index 000000000..7c36dbcb2 --- /dev/null +++ b/null/webapps/junit/streams/010377385515858588541652.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:0 +#EXT-X-MEDIA-SEQUENCE:0 +#EXTINF:0.000000, +010377385515858588541652000000000.ts +#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/010377385515858588541652000000000.ts b/null/webapps/junit/streams/010377385515858588541652000000000.ts new file mode 100644 index 000000000..e69de29bb diff --git a/null/webapps/junit/streams/130648337158084781489317.m3u8 b/null/webapps/junit/streams/130648337158084781489317.m3u8 new file mode 100644 index 000000000..daf70df56 --- /dev/null +++ b/null/webapps/junit/streams/130648337158084781489317.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:0 +#EXT-X-MEDIA-SEQUENCE:0 +#EXTINF:0.000000, +130648337158084781489317000000000.ts +#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/130648337158084781489317000000000.ts b/null/webapps/junit/streams/130648337158084781489317000000000.ts new file mode 100644 index 000000000..e69de29bb diff --git a/null/webapps/junit/streams/305147821057798436984629.m3u8 b/null/webapps/junit/streams/305147821057798436984629.m3u8 new file mode 100644 index 000000000..6c0413eb9 --- /dev/null +++ b/null/webapps/junit/streams/305147821057798436984629.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:0 +#EXT-X-MEDIA-SEQUENCE:0 +#EXTINF:0.000000, +305147821057798436984629000000000.ts +#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/305147821057798436984629000000000.ts b/null/webapps/junit/streams/305147821057798436984629000000000.ts new file mode 100644 index 000000000..e69de29bb diff --git a/null/webapps/junit/streams/371459229667024016956787.m3u8 b/null/webapps/junit/streams/371459229667024016956787.m3u8 new file mode 100644 index 000000000..e9197ddb8 --- /dev/null +++ b/null/webapps/junit/streams/371459229667024016956787.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:0 +#EXT-X-MEDIA-SEQUENCE:0 +#EXTINF:0.000000, +371459229667024016956787000000000.ts +#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/371459229667024016956787000000000.ts b/null/webapps/junit/streams/371459229667024016956787000000000.ts new file mode 100644 index 000000000..e69de29bb diff --git a/null/webapps/junit/streams/393657863698685730684471.m3u8 b/null/webapps/junit/streams/393657863698685730684471.m3u8 new file mode 100644 index 000000000..c41118ae4 --- /dev/null +++ b/null/webapps/junit/streams/393657863698685730684471.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:0 +#EXT-X-MEDIA-SEQUENCE:0 +#EXTINF:0.000000, +393657863698685730684471000000000.ts +#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/393657863698685730684471000000000.ts b/null/webapps/junit/streams/393657863698685730684471000000000.ts new file mode 100644 index 000000000..e69de29bb diff --git a/null/webapps/junit/streams/668883968102040044966364.m3u8 b/null/webapps/junit/streams/668883968102040044966364.m3u8 new file mode 100644 index 000000000..ddb8ee3ee --- /dev/null +++ b/null/webapps/junit/streams/668883968102040044966364.m3u8 @@ -0,0 +1,7 @@ +#EXTM3U +#EXT-X-VERSION:3 +#EXT-X-TARGETDURATION:0 +#EXT-X-MEDIA-SEQUENCE:0 +#EXTINF:0.000000, +668883968102040044966364000000000.ts +#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/668883968102040044966364000000000.ts b/null/webapps/junit/streams/668883968102040044966364000000000.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index 7c9c53f0c..a31b3eaf2 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -1817,11 +1817,11 @@ public void testRecordStartedHook() throws Exception { doReturn(new StringBuilder()).when(spyAdaptor).sendPOST(anyString(),anyMap()); spyAdaptor.startPublish(streamId, 0, IAntMediaStreamHandler.PUBLISH_TYPE_WEBRTC); - verify(spyAdaptor, times(1)).sendStartRecordWebHook(streamId); Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean called = false; try{ + verify(spyAdaptor, times(1)).sendStartRecordWebHook(streamId); verify(spyAdaptor,times(1)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_RECORD, broadcast.getName(),broadcast.getCategory(),null,null,null,null); called = true; }catch (Exception e){ From 878221c97738efa324f6c352d0d9bba6c213b88f Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 17 Jan 2023 14:52:24 +0300 Subject: [PATCH 08/15] New webhooks playStart, playStop, recordStart issue #4666 --- .../antmedia/filter/DashStatisticsFilter.java | 3 +-- .../antmedia/filter/HlsStatisticsFilter.java | 3 +-- .../io/antmedia/statistic/IStreamStats.java | 3 ++- .../io/antmedia/statistic/ViewerStats.java | 2 +- .../test/filter/DashStatisticsFilterTest.java | 13 ++++------- .../test/filter/HlsStatisticsFilterTest.java | 9 ++++---- .../test/statistic/DashViewerStatsTest.java | 22 +++++++++---------- .../test/statistic/HlsViewerStatsTest.java | 18 +++++++-------- 8 files changed, 33 insertions(+), 40 deletions(-) diff --git a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java index 91d0f6adb..d1cb8d76e 100644 --- a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java @@ -10,7 +10,6 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.HttpMethod; -import io.antmedia.statistic.ViewerStats; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,7 +50,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(DashViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId, ViewerStats.DASH_TYPE, getAntMediaApplicationAdapter()); + stats.registerNewViewer(streamId, sessionId, subscriberId, getAntMediaApplicationAdapter()); } } } diff --git a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java index d7ab64e09..2ffee3186 100644 --- a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java @@ -10,7 +10,6 @@ import javax.servlet.http.HttpServletResponse; import javax.ws.rs.HttpMethod; -import io.antmedia.statistic.ViewerStats; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,7 +52,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(HlsViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId, ViewerStats.HLS_TYPE, getAntMediaApplicationAdapter()); + stats.registerNewViewer(streamId, sessionId, subscriberId, getAntMediaApplicationAdapter()); } } } diff --git a/src/main/java/io/antmedia/statistic/IStreamStats.java b/src/main/java/io/antmedia/statistic/IStreamStats.java index 81a2d9e25..f077eda34 100644 --- a/src/main/java/io/antmedia/statistic/IStreamStats.java +++ b/src/main/java/io/antmedia/statistic/IStreamStats.java @@ -6,10 +6,11 @@ public interface IStreamStats { /** * Register a new viewer to a stream + * * @param streamId * @param sessionId */ - void registerNewViewer(String streamId, String sessionId, String subscriberId, String playType, AntMediaApplicationAdapter antMediaApplicationAdapter); + void registerNewViewer(String streamId, String sessionId, String subscriberId, AntMediaApplicationAdapter antMediaApplicationAdapter); /** diff --git a/src/main/java/io/antmedia/statistic/ViewerStats.java b/src/main/java/io/antmedia/statistic/ViewerStats.java index 8d26ec608..7943011a1 100644 --- a/src/main/java/io/antmedia/statistic/ViewerStats.java +++ b/src/main/java/io/antmedia/statistic/ViewerStats.java @@ -52,7 +52,7 @@ public class ViewerStats { */ protected int timeoutMS = 20000; - public void registerNewViewer(String streamId, String sessionId, String subscriberId, String viewerPlayType, AntMediaApplicationAdapter antMediaApplicationAdapter) + public void registerNewViewer(String streamId, String sessionId, String subscriberId, AntMediaApplicationAdapter antMediaApplicationAdapter) { //do not block the thread, run in vertx event queue vertx.runOnContext(h -> { diff --git a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java index 2c2597e8b..69fd73d6a 100644 --- a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java @@ -5,7 +5,6 @@ import static org.mockito.Mockito.*; import java.io.IOException; -import java.util.concurrent.TimeUnit; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -16,12 +15,8 @@ import javax.servlet.http.HttpSession; import io.antmedia.AntMediaApplicationAdapter; -import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.awaitility.Awaitility; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -165,7 +160,7 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); dashStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); /*verify(antMediaApplicationAdapter, times(1)).sendStartPlayWebHook(ViewerStats.DASH_TYPE, streamId, null); Awaitility.await().atMost(10, TimeUnit.SECONDS).until(()-> { @@ -239,15 +234,15 @@ public void testDASHViewerLimit() { //when(dashStatisticsFilter.getStreamStats()).thenReturn(streamStats); String sessionId = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); broadcast.setDashViewerCount(1); String sessionId2 = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, antMediaApplicationAdapter); broadcast.setDashViewerCount(2); String sessionId3 = requestDash(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java index eb65f6a2b..ccbb29ffa 100644 --- a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java @@ -19,7 +19,6 @@ import javax.servlet.http.HttpSession; import io.antmedia.AntMediaApplicationAdapter; -import io.antmedia.statistic.ViewerStats; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.junit.After; @@ -163,7 +162,7 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); hlsStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); @@ -212,15 +211,15 @@ public void testHLSViewerLimit() { hlsStatisticsFilter.init(filterconfig); String sessionId = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); broadcast.setHlsViewerCount(1); String sessionId2 = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, antMediaApplicationAdapter); broadcast.setHlsViewerCount(2); String sessionId3 = requestHls(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java index da744a353..fa2ae99e0 100644 --- a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java @@ -72,7 +72,7 @@ public void testDASHViewerCount() { for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -86,7 +86,7 @@ public void testDASHViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -122,7 +122,7 @@ public void testSubscriberEvents() { // check if viewer is added AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -248,8 +248,8 @@ public void testSetApplicationContextSubscribers() { //spyAdapter.setDataStoreFactory(dsf); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId(), spyAdapter); Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -276,8 +276,8 @@ public void testSetApplicationContextSubscribers() { ()->viewerStats.getTotalViewerCount() == 2 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId(), spyAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { @@ -339,7 +339,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), ViewerStats.DASH_TYPE, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), spyAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -423,7 +423,7 @@ public void testSetApplicationContext() { String sessionId = "sessionId" + (int)(Math.random() * 10000); antMediaApplicationAdapter.setAppSettings(settings); - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -435,7 +435,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(30, TimeUnit.SECONDS).until( @@ -456,7 +456,7 @@ public void testSetApplicationContext() { Awaitility.await().atMost(30, TimeUnit.SECONDS).until( ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.DASH_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); Awaitility.await().atMost(30, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); diff --git a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java index 5c3da0068..42a78750e 100644 --- a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java @@ -69,7 +69,7 @@ public void testHLSViewerCount() { for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -83,7 +83,7 @@ public void testHLSViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -121,7 +121,7 @@ public void testSubscriberEvents() { // check if viewer is added - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -223,7 +223,7 @@ public void testSetApplicationContextSubscribers() { subscriberPlay3.setType(Subscriber.PLAY_TYPE); dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -236,7 +236,7 @@ public void testSetApplicationContextSubscribers() { //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { @@ -283,7 +283,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -365,7 +365,7 @@ public void testSetApplicationContext() { String sessionId = "sessionId" + (int)(Math.random() * 10000); - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -377,7 +377,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(20, TimeUnit.SECONDS).until( @@ -399,7 +399,7 @@ public void testSetApplicationContext() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, null, ViewerStats.HLS_TYPE, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); From 75347664ff9dd795e65f6a1078026672b7f5f88e Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 17 Jan 2023 22:13:01 +0300 Subject: [PATCH 09/15] New webhooks playStart, playStop, recordStart issue #4666 --- null/webapps/junit/streams/010377385515858588541652.m3u8 | 7 ------- .../junit/streams/010377385515858588541652000000000.ts | 0 null/webapps/junit/streams/130648337158084781489317.m3u8 | 7 ------- .../junit/streams/130648337158084781489317000000000.ts | 0 null/webapps/junit/streams/305147821057798436984629.m3u8 | 7 ------- .../junit/streams/305147821057798436984629000000000.ts | 0 null/webapps/junit/streams/371459229667024016956787.m3u8 | 7 ------- .../junit/streams/371459229667024016956787000000000.ts | 0 null/webapps/junit/streams/393657863698685730684471.m3u8 | 7 ------- .../junit/streams/393657863698685730684471000000000.ts | 0 null/webapps/junit/streams/668883968102040044966364.m3u8 | 7 ------- .../junit/streams/668883968102040044966364000000000.ts | 0 .../java/io/antmedia/AntMediaApplicationAdapter.java | 9 +++++++++ .../test/AntMediaApplicationAdaptorUnitTest.java | 4 ++-- 14 files changed, 11 insertions(+), 44 deletions(-) delete mode 100644 null/webapps/junit/streams/010377385515858588541652.m3u8 delete mode 100644 null/webapps/junit/streams/010377385515858588541652000000000.ts delete mode 100644 null/webapps/junit/streams/130648337158084781489317.m3u8 delete mode 100644 null/webapps/junit/streams/130648337158084781489317000000000.ts delete mode 100644 null/webapps/junit/streams/305147821057798436984629.m3u8 delete mode 100644 null/webapps/junit/streams/305147821057798436984629000000000.ts delete mode 100644 null/webapps/junit/streams/371459229667024016956787.m3u8 delete mode 100644 null/webapps/junit/streams/371459229667024016956787000000000.ts delete mode 100644 null/webapps/junit/streams/393657863698685730684471.m3u8 delete mode 100644 null/webapps/junit/streams/393657863698685730684471000000000.ts delete mode 100644 null/webapps/junit/streams/668883968102040044966364.m3u8 delete mode 100644 null/webapps/junit/streams/668883968102040044966364000000000.ts diff --git a/null/webapps/junit/streams/010377385515858588541652.m3u8 b/null/webapps/junit/streams/010377385515858588541652.m3u8 deleted file mode 100644 index 7c36dbcb2..000000000 --- a/null/webapps/junit/streams/010377385515858588541652.m3u8 +++ /dev/null @@ -1,7 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:3 -#EXT-X-TARGETDURATION:0 -#EXT-X-MEDIA-SEQUENCE:0 -#EXTINF:0.000000, -010377385515858588541652000000000.ts -#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/010377385515858588541652000000000.ts b/null/webapps/junit/streams/010377385515858588541652000000000.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/null/webapps/junit/streams/130648337158084781489317.m3u8 b/null/webapps/junit/streams/130648337158084781489317.m3u8 deleted file mode 100644 index daf70df56..000000000 --- a/null/webapps/junit/streams/130648337158084781489317.m3u8 +++ /dev/null @@ -1,7 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:3 -#EXT-X-TARGETDURATION:0 -#EXT-X-MEDIA-SEQUENCE:0 -#EXTINF:0.000000, -130648337158084781489317000000000.ts -#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/130648337158084781489317000000000.ts b/null/webapps/junit/streams/130648337158084781489317000000000.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/null/webapps/junit/streams/305147821057798436984629.m3u8 b/null/webapps/junit/streams/305147821057798436984629.m3u8 deleted file mode 100644 index 6c0413eb9..000000000 --- a/null/webapps/junit/streams/305147821057798436984629.m3u8 +++ /dev/null @@ -1,7 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:3 -#EXT-X-TARGETDURATION:0 -#EXT-X-MEDIA-SEQUENCE:0 -#EXTINF:0.000000, -305147821057798436984629000000000.ts -#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/305147821057798436984629000000000.ts b/null/webapps/junit/streams/305147821057798436984629000000000.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/null/webapps/junit/streams/371459229667024016956787.m3u8 b/null/webapps/junit/streams/371459229667024016956787.m3u8 deleted file mode 100644 index e9197ddb8..000000000 --- a/null/webapps/junit/streams/371459229667024016956787.m3u8 +++ /dev/null @@ -1,7 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:3 -#EXT-X-TARGETDURATION:0 -#EXT-X-MEDIA-SEQUENCE:0 -#EXTINF:0.000000, -371459229667024016956787000000000.ts -#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/371459229667024016956787000000000.ts b/null/webapps/junit/streams/371459229667024016956787000000000.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/null/webapps/junit/streams/393657863698685730684471.m3u8 b/null/webapps/junit/streams/393657863698685730684471.m3u8 deleted file mode 100644 index c41118ae4..000000000 --- a/null/webapps/junit/streams/393657863698685730684471.m3u8 +++ /dev/null @@ -1,7 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:3 -#EXT-X-TARGETDURATION:0 -#EXT-X-MEDIA-SEQUENCE:0 -#EXTINF:0.000000, -393657863698685730684471000000000.ts -#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/393657863698685730684471000000000.ts b/null/webapps/junit/streams/393657863698685730684471000000000.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/null/webapps/junit/streams/668883968102040044966364.m3u8 b/null/webapps/junit/streams/668883968102040044966364.m3u8 deleted file mode 100644 index ddb8ee3ee..000000000 --- a/null/webapps/junit/streams/668883968102040044966364.m3u8 +++ /dev/null @@ -1,7 +0,0 @@ -#EXTM3U -#EXT-X-VERSION:3 -#EXT-X-TARGETDURATION:0 -#EXT-X-MEDIA-SEQUENCE:0 -#EXTINF:0.000000, -668883968102040044966364000000000.ts -#EXT-X-ENDLIST diff --git a/null/webapps/junit/streams/668883968102040044966364000000000.ts b/null/webapps/junit/streams/668883968102040044966364000000000.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java index faa1c8fa5..5a740b501 100644 --- a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java +++ b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java @@ -540,6 +540,9 @@ public void resetDASHStats(String streamId) { public void sendStartPlayWebHook(final String streamId, final String viewerId){ final Broadcast broadcast = getDataStore().get(streamId); + if(broadcast == null){ + return; + } final String listenerHookURL = broadcast.getListenerHookURL(); if (listenerHookURL == null || listenerHookURL.isEmpty()) { return; @@ -553,6 +556,9 @@ public void sendStartPlayWebHook(final String streamId, final String viewerId){ public void sendStopPlayWebHook(final String streamId, final String viewerId){ final Broadcast broadcast = getDataStore().get(streamId); + if(broadcast == null){ + return; + } final String listenerHookURL = broadcast.getListenerHookURL(); if (listenerHookURL == null || listenerHookURL.isEmpty()) { return; @@ -566,6 +572,9 @@ public void sendStopPlayWebHook(final String streamId, final String viewerId){ public void sendStartRecordWebHook(final String streamId){ final Broadcast broadcast = getDataStore().get(streamId); + if(broadcast == null){ + return; + } final String listenerHookURL = broadcast.getListenerHookURL(); if (listenerHookURL == null || listenerHookURL.isEmpty()) { return; diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index a31b3eaf2..4ad815c26 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -1869,7 +1869,7 @@ public void testRtmpStreamPlayStop() throws Exception { spyAdaptor.streamPlayItemPlay(stream, item, true); verify(spyAdaptor, times(1)).sendStartPlayWebHook(anyString(), anyString()); - Awaitility.await().atMost(2, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean called = false; try{ @@ -1883,7 +1883,7 @@ public void testRtmpStreamPlayStop() throws Exception { spyAdaptor.streamPlayItemStop(stream, item); verify(spyAdaptor, times(1)).sendStopPlayWebHook(anyString(), anyString()); - Awaitility.await().atMost(2, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( + Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean called = false; try{ From daa8baa5ce40c361da333a30ea1e2bbff56690d3 Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 17 Jan 2023 22:51:19 +0300 Subject: [PATCH 10/15] New webhooks playStart, playStop, recordStart issue #4666 --- .../test/AntMediaApplicationAdaptorUnitTest.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index 4ad815c26..2a57ff3e2 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -1883,17 +1883,6 @@ public void testRtmpStreamPlayStop() throws Exception { spyAdaptor.streamPlayItemStop(stream, item); verify(spyAdaptor, times(1)).sendStopPlayWebHook(anyString(), anyString()); - Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( - ()-> { - boolean called = false; - try{ - assertEquals(0, spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount()); - called = true; - }catch (Exception e){ - e.printStackTrace(); - } - return called; - }); } From 6a387080d4350212eae4453b1b1eed23b1c6693f Mon Sep 17 00:00:00 2001 From: lastpeony Date: Tue, 17 Jan 2023 22:55:06 +0300 Subject: [PATCH 11/15] New webhooks playStart, playStop, recordStart issue #4666 --- 1 | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 1 diff --git a/1 b/1 deleted file mode 100644 index 277e26a64..000000000 --- a/1 +++ /dev/null @@ -1,14 +0,0 @@ -New webhooks playStart, playStop, recordStart issue #4666 - -# Please enter the commit message for your changes. Lines starting -# with '#' will be ignored, and an empty message aborts the commit. -# -# On branch newWebHooks -# Your branch is up to date with 'origin/newWebHooks'. -# -# Changes to be committed: -# modified: src/main/java/io/antmedia/AntMediaApplicationAdapter.java -# modified: src/main/java/io/antmedia/statistic/ViewerStats.java -# modified: src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java -# modified: src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java -# From a29f6926b02c9b9df3b23ea31e00037ea01fa747 Mon Sep 17 00:00:00 2001 From: lastpeony Date: Fri, 27 Jan 2023 13:10:43 +0300 Subject: [PATCH 12/15] jwt passed to hook --- .gitignore | 3 +- .../antmedia/AntMediaApplicationAdapter.java | 69 +++++++++---------- .../console/rest/AuthenticationFilter.java | 4 +- .../io/antmedia/filter/AbstractFilter.java | 40 +++++++++++ .../antmedia/filter/DashStatisticsFilter.java | 6 +- .../antmedia/filter/HlsStatisticsFilter.java | 6 +- .../java/io/antmedia/filter/JWTFilter.java | 32 +-------- .../io/antmedia/statistic/IStreamStats.java | 3 +- .../io/antmedia/statistic/ViewerStats.java | 19 +++-- .../AntMediaApplicationAdaptorUnitTest.java | 28 ++++---- .../java/io/antmedia/test/Application.java | 2 +- .../java/io/antmedia/test/MuxerUnitTest.java | 4 +- .../test/filter/DashStatisticsFilterTest.java | 30 ++------ .../test/filter/HlsStatisticsFilterTest.java | 8 +-- .../test/statistic/DashViewerStatsTest.java | 30 ++++---- .../test/statistic/HlsViewerStatsTest.java | 18 ++--- 16 files changed, 150 insertions(+), 152 deletions(-) diff --git a/.gitignore b/.gitignore index b162af25b..f138b18de 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ temp/ *.iml .idea -.fleet \ No newline at end of file +.fleet +/null/ \ No newline at end of file diff --git a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java index 5a740b501..51530e384 100644 --- a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java +++ b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java @@ -487,7 +487,7 @@ public void closeBroadcast(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call live stream ended hook for stream:{}",streamId ); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_END_LIVE_STREAM, name, category, null, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_END_LIVE_STREAM, name, category, null, null, null, null, null)); } if (broadcast.isZombi()) { @@ -538,7 +538,7 @@ public void resetDASHStats(String streamId) { } } - public void sendStartPlayWebHook(final String streamId, final String viewerId){ + public void sendStartPlayWebHook(final String streamId, final String viewerId, final String token){ final Broadcast broadcast = getDataStore().get(streamId); if(broadcast == null){ return; @@ -551,10 +551,10 @@ public void sendStartPlayWebHook(final String streamId, final String viewerId){ final String category = broadcast.getCategory(); logger.info("Setting timer to call viewer play started hook for stream:{}", streamId); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_PLAY, name, category, - null, null, viewerId, null)); + null, null, viewerId, token, null)); } - public void sendStopPlayWebHook(final String streamId, final String viewerId){ + public void sendStopPlayWebHook(final String streamId, final String viewerId, final String token){ final Broadcast broadcast = getDataStore().get(streamId); if(broadcast == null){ return; @@ -567,7 +567,7 @@ public void sendStopPlayWebHook(final String streamId, final String viewerId){ final String category = broadcast.getCategory(); logger.info("Setting timer to call viewer play stopped hook for stream:{}", streamId); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_STOP_PLAY, name, category, - null, null, viewerId, null)); + null, null, viewerId, token, null)); } public void sendStartRecordWebHook(final String streamId){ @@ -583,7 +583,7 @@ public void sendStartRecordWebHook(final String streamId){ final String category = broadcast.getCategory(); logger.info("Setting timer to call stream start recording hook for stream:{}", streamId); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_RECORD, name, category, - null, null, null, null)); + null, null, null, null, null)); } private String getRtmpViewerId(){ @@ -593,13 +593,13 @@ private String getRtmpViewerId(){ @Override public void streamPlayItemPlay(ISubscriberStream stream, IPlayItem item, boolean isLive) { final String streamId = item.getName(); - sendStartPlayWebHook(streamId, getRtmpViewerId()); + sendStartPlayWebHook(streamId, getRtmpViewerId(), null); vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, true)); } @Override public void streamPlayItemStop(ISubscriberStream stream, IPlayItem item) { final String streamId = item.getName(); - sendStopPlayWebHook(streamId, getRtmpViewerId()); + sendStopPlayWebHook(streamId, getRtmpViewerId(), null); vertx.setTimer(1, l -> getDataStore().updateRtmpViewerCount(streamId, false)); } @@ -621,7 +621,7 @@ public void startPublish(String streamId, long absoluteStartTimeMs, String publi final String category = broadcast.getCategory(); logger.info("Setting timer to call live stream started hook for stream:{}",streamId ); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_LIVE_STREAM, name, category, - null, null, null, null)); + null, null, null, null, null)); } if ((broadcast.getMp4Enabled() == MuxAdaptor.RECORDING_ENABLED_FOR_STREAM || broadcast.getWebMEnabled() == MuxAdaptor.RECORDING_ENABLED_FOR_STREAM) @@ -795,7 +795,7 @@ public void muxingFinished(final String streamId, File file, long startTime, lon final String baseName = vodName.substring(0, index); String finalListenerHookURL = listenerHookURL; logger.info("Setting timer for calling vod ready hook for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(finalListenerHookURL, streamId, HOOK_ACTION_VOD_READY, null, null, baseName, vodIdFinal, null, null)); + vertx.runOnContext(e -> notifyHook(finalListenerHookURL, streamId, HOOK_ACTION_VOD_READY, null, null, baseName, vodIdFinal, null, null, null)); } String muxerFinishScript = appSettings.getMuxerFinishScript(); @@ -840,33 +840,23 @@ public static String getRelativePath(String filePath){ /** * Notify hook with parameters below - * - * @param url - * is the url of the service to be called - * - * @param id - * is the stream id that is unique for each stream - * - * @param action - * is the name of the action to be notified, it has values such - * as {@link #HOOK_ACTION_END_LIVE_STREAM} - * {@link #HOOK_ACTION_START_LIVE_STREAM} - * - * @param streamName, - * name of the stream. It is not the name of the file. It is just - * a user friendly name - * - * @param category, - * category of the stream - * - * @param vodName name of the vod - * - * @param vodId id of the vod in the datastore - * + * + * @param streamName, name of the stream. It is not the name of the file. It is just + * a user friendly name + * @param category, category of the stream + * @param url is the url of the service to be called + * @param id is the stream id that is unique for each stream + * @param action is the name of the action to be notified, it has values such + * as {@link #HOOK_ACTION_END_LIVE_STREAM} + * {@link #HOOK_ACTION_START_LIVE_STREAM} + * @param vodName name of the vod + * @param vodId id of the vod in the datastore + * @param viewerId session id or subscriber id + * @param token play token * @return */ public StringBuilder notifyHook(String url, String id, String action, String streamName, String category, - String vodName, String vodId, String viewerId, String metadata) { + String vodName, String vodId, String viewerId, String token, String metadata) { StringBuilder response = null; logger.info("Running notify hook url:{} stream id: {} action:{} vod name:{} vod id:{}", url, id, action, vodName, vodId); if (url != null && url.length() > 0) { @@ -893,6 +883,10 @@ public StringBuilder notifyHook(String url, String id, String action, String str variables.put("viewerId", viewerId); } + if(token !=null){ + variables.put("token",token); + } + if (metadata != null) { variables.put("metadata", metadata); } @@ -908,7 +902,6 @@ public StringBuilder notifyHook(String url, String id, String action, String str } public StringBuilder sendPOST(String url, Map variables) throws IOException { - StringBuilder response = null; try (CloseableHttpClient httpClient = getHttpClient()) { @@ -1368,7 +1361,7 @@ public synchronized void incrementEncoderNotOpenedError(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call encoder not opened error for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENCODER_NOT_OPENED_ERROR, name, category, null, null, null,null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENCODER_NOT_OPENED_ERROR, name, category, null, null, null, null, null)); } } } @@ -1393,7 +1386,7 @@ public synchronized void publishTimeoutError(String streamId) { final String name = broadcast.getName(); final String category = broadcast.getCategory(); logger.info("Setting timer to call hook that means live stream is not started to the publish timeout for stream:{}", streamId); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_PUBLISH_TIMEOUT_ERROR, name, category, null, null, null, null)); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_PUBLISH_TIMEOUT_ERROR, name, category, null, null, null, null, null)); } } } @@ -1749,7 +1742,7 @@ public void endpointFailedUpdate(String streamId, String url) { logger.info("Setting timer to call rtmp endpoint failed hook for stream:{}", streamId); JSONObject jsonObject = new JSONObject(); jsonObject.put("rtmp-url", url); - vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENDPOINT_FAILED, name, category, null, null, null, jsonObject.toJSONString())); + vertx.runOnContext(e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_ENDPOINT_FAILED, name, category, null, null, null, null, jsonObject.toJSONString())); } } } diff --git a/src/main/java/io/antmedia/console/rest/AuthenticationFilter.java b/src/main/java/io/antmedia/console/rest/AuthenticationFilter.java index 4f1fb542b..5ea74b6f3 100644 --- a/src/main/java/io/antmedia/console/rest/AuthenticationFilter.java +++ b/src/main/java/io/antmedia/console/rest/AuthenticationFilter.java @@ -106,7 +106,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha if (serverSettings != null && serverSettings.isJwtServerControlEnabled() && httpRequest.getHeader(JWT_TOKEN) != null) { - if(checkJWT(httpRequest.getHeader(JWT_TOKEN))) { + if(checkJWTServerSettings(httpRequest.getHeader(JWT_TOKEN))) { chain.doFilter(request, response); } else { @@ -235,7 +235,7 @@ private boolean scopeAccessGranted(String userScope, String dispatchUrl){ } - private boolean checkJWT( String jwtString) { + private boolean checkJWTServerSettings(String jwtString) { boolean result = true; try { diff --git a/src/main/java/io/antmedia/filter/AbstractFilter.java b/src/main/java/io/antmedia/filter/AbstractFilter.java index 35552a668..4f403ccdb 100644 --- a/src/main/java/io/antmedia/filter/AbstractFilter.java +++ b/src/main/java/io/antmedia/filter/AbstractFilter.java @@ -2,6 +2,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; +import java.security.interfaces.RSAPublicKey; import java.util.List; import java.util.Queue; @@ -9,6 +10,15 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletException; +import com.auth0.jwk.Jwk; +import com.auth0.jwk.JwkException; +import com.auth0.jwk.JwkProvider; +import com.auth0.jwk.UrlJwkProvider; +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTVerificationException; +import com.auth0.jwt.interfaces.DecodedJWT; import io.antmedia.AntMediaApplicationAdapter; import org.apache.catalina.util.NetMask; import org.slf4j.Logger; @@ -166,5 +176,35 @@ protected AntMediaApplicationAdapter getAntMediaApplicationAdapter(){ return antMediaApplicationAdapter; } + protected boolean checkJWT(String jwtString) { + boolean result = true; + try { + AppSettings appSettings = getAppSettings(); + String jwksURL = appSettings.getJwksURL(); + + if (jwksURL != null && !jwksURL.isEmpty()) { + DecodedJWT jwt = JWT.decode(jwtString); + JwkProvider provider = new UrlJwkProvider(appSettings.getJwksURL()); + Jwk jwk = provider.get(jwt.getKeyId()); + Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); + algorithm.verify(jwt); + } + else { + Algorithm algorithm = Algorithm.HMAC256(appSettings.getJwtSecretKey()); + JWTVerifier verifier = JWT.require(algorithm) + .build(); + verifier.verify(jwtString); + } + + } + catch (JWTVerificationException ex) { + logger.error(ex.toString()); + result = false; + } catch (JwkException e) { + logger.error(e.toString()); + result = false; + } + return result; + } } diff --git a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java index d1cb8d76e..13c26b28b 100644 --- a/src/main/java/io/antmedia/filter/DashStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/DashStatisticsFilter.java @@ -17,6 +17,8 @@ import io.antmedia.statistic.DashViewerStats; import io.antmedia.statistic.IStreamStats; +import static io.antmedia.filter.JWTFilter.JWT_TOKEN; + public class DashStatisticsFilter extends AbstractFilter { protected static Logger logger = LoggerFactory.getLogger(DashStatisticsFilter.class); @@ -50,7 +52,9 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(DashViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId, getAntMediaApplicationAdapter()); + final String tokenId = request.getParameter("token"); + stats.registerNewViewer(streamId, sessionId, subscriberId, tokenId, getAntMediaApplicationAdapter()); + } } } diff --git a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java index 2ffee3186..d92aed26f 100644 --- a/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java +++ b/src/main/java/io/antmedia/filter/HlsStatisticsFilter.java @@ -17,6 +17,8 @@ import io.antmedia.statistic.HlsViewerStats; import io.antmedia.statistic.IStreamStats; +import static io.antmedia.filter.JWTFilter.JWT_TOKEN; + public class HlsStatisticsFilter extends AbstractFilter { protected static Logger logger = LoggerFactory.getLogger(HlsStatisticsFilter.class); @@ -52,7 +54,9 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha logger.debug("req ip {} session id {} stream id {} status {}", request.getRemoteHost(), sessionId, streamId, status); IStreamStats stats = getStreamStats(HlsViewerStats.BEAN_NAME); if (stats != null) { - stats.registerNewViewer(streamId, sessionId, subscriberId, getAntMediaApplicationAdapter()); + final String tokenId = request.getParameter("token"); + stats.registerNewViewer(streamId, sessionId, subscriberId, tokenId, getAntMediaApplicationAdapter()); + } } } diff --git a/src/main/java/io/antmedia/filter/JWTFilter.java b/src/main/java/io/antmedia/filter/JWTFilter.java index 99a0fdb6c..4893f39af 100644 --- a/src/main/java/io/antmedia/filter/JWTFilter.java +++ b/src/main/java/io/antmedia/filter/JWTFilter.java @@ -41,6 +41,8 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha HttpServletRequest httpRequest = (HttpServletRequest) request; if(appSettings != null && !appSettings.isJwtControlEnabled() || (httpRequest.getHeader(JWT_TOKEN) != null && checkJWT(httpRequest.getHeader(JWT_TOKEN)))) { + + chain.doFilter(request, response); return; } @@ -48,34 +50,4 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid App JWT Token"); } - private boolean checkJWT( String jwtString) { - boolean result = true; - try { - - String jwksURL = appSettings.getJwksURL(); - - if (jwksURL != null && !jwksURL.isEmpty()) { - DecodedJWT jwt = JWT.decode(jwtString); - JwkProvider provider = new UrlJwkProvider(appSettings.getJwksURL()); - Jwk jwk = provider.get(jwt.getKeyId()); - Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null); - algorithm.verify(jwt); - } - else { - Algorithm algorithm = Algorithm.HMAC256(appSettings.getJwtSecretKey()); - JWTVerifier verifier = JWT.require(algorithm) - .build(); - verifier.verify(jwtString); - } - - } - catch (JWTVerificationException ex) { - logger.error(ex.toString()); - result = false; - } catch (JwkException e) { - logger.error(e.toString()); - result = false; - } - return result; - } } diff --git a/src/main/java/io/antmedia/statistic/IStreamStats.java b/src/main/java/io/antmedia/statistic/IStreamStats.java index f077eda34..0b5c41e00 100644 --- a/src/main/java/io/antmedia/statistic/IStreamStats.java +++ b/src/main/java/io/antmedia/statistic/IStreamStats.java @@ -9,8 +9,9 @@ public interface IStreamStats { * * @param streamId * @param sessionId + * @param jwt */ - void registerNewViewer(String streamId, String sessionId, String subscriberId, AntMediaApplicationAdapter antMediaApplicationAdapter); + void registerNewViewer(String streamId, String sessionId, String subscriberId, String jwt, AntMediaApplicationAdapter antMediaApplicationAdapter); /** diff --git a/src/main/java/io/antmedia/statistic/ViewerStats.java b/src/main/java/io/antmedia/statistic/ViewerStats.java index 7943011a1..515a70a88 100644 --- a/src/main/java/io/antmedia/statistic/ViewerStats.java +++ b/src/main/java/io/antmedia/statistic/ViewerStats.java @@ -41,6 +41,7 @@ public class ViewerStats { private int timePeriodMS = DEFAULT_TIME_PERIOD_FOR_VIEWER_COUNT; Map> streamsViewerMap = new ConcurrentHashMap<>(); + Map sessionId2Jwt = new ConcurrentHashMap<>(); Map sessionId2subscriberId = new ConcurrentHashMap<>(); Map increaseCounterMap = new ConcurrentHashMap<>(); @@ -52,7 +53,7 @@ public class ViewerStats { */ protected int timeoutMS = 20000; - public void registerNewViewer(String streamId, String sessionId, String subscriberId, AntMediaApplicationAdapter antMediaApplicationAdapter) + public void registerNewViewer(String streamId, String sessionId, String subscriberId, String jwt, AntMediaApplicationAdapter antMediaApplicationAdapter) { //do not block the thread, run in vertx event queue vertx.runOnContext(h -> { @@ -69,9 +70,12 @@ public void registerNewViewer(String streamId, String sessionId, String subscrib increaseCounterMap.put(streamId, streamIncrementCounter); if(subscriberId != null && !subscriberId.equals("undefined")){ - antMediaApplicationAdapter.sendStartPlayWebHook(streamId, subscriberId); + antMediaApplicationAdapter.sendStartPlayWebHook(streamId, subscriberId, jwt); }else{ - antMediaApplicationAdapter.sendStartPlayWebHook(streamId, sessionId); + antMediaApplicationAdapter.sendStartPlayWebHook(streamId, sessionId, jwt); + } + if(jwt != null){ + sessionId2Jwt.put(sessionId, jwt); } } viewerMap.put(sessionId, System.currentTimeMillis()); @@ -106,6 +110,9 @@ public void resetViewerMap(String streamID, String type) { if(sessionId2subscriberId.containsKey(sessionId)) { sessionId2subscriberId.remove(sessionId); } + if(sessionId2Jwt.containsKey(sessionId)){ + sessionId2Jwt.remove(sessionId); + } } streamsViewerMap.get(streamID).clear(); @@ -252,11 +259,11 @@ public void updateViewerCountProcess(String type, AntMediaApplicationAdapter ant String sessionId = viewer.getKey(); String subscriberId = sessionId2subscriberId.get(sessionId); - + String jwt = sessionId2Jwt.get(sessionId); if(subscriberId !=null && !subscriberId.equals("undefined")){ - antMediaApplicationAdapter.sendStopPlayWebHook(streamId,subscriberId); + antMediaApplicationAdapter.sendStopPlayWebHook(streamId, subscriberId, jwt); }else{ - antMediaApplicationAdapter.sendStopPlayWebHook(streamId,sessionId); + antMediaApplicationAdapter.sendStopPlayWebHook(streamId, sessionId, jwt); } // set subscriber status to not connected if(subscriberId != null) { diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index 2a57ff3e2..55d3266ef 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -644,10 +644,10 @@ public void testNotifyHook() { AntMediaApplicationAdapter spyAdaptor = Mockito.spy(adapter); - StringBuilder notifyHook = spyAdaptor.notifyHook(null, null, null, null, null, null, null, null, null); + StringBuilder notifyHook = spyAdaptor.notifyHook(null, null, null, null, null, null, null, null, null, null); assertNull(notifyHook); - notifyHook = spyAdaptor.notifyHook("", null, null, null, null, null, null, null, null); + notifyHook = spyAdaptor.notifyHook("", null, null, null, null, null, null, null, null, null); assertNull(notifyHook); @@ -662,7 +662,7 @@ public void testNotifyHook() { String viewerId = String.valueOf((Math.random() * 10000)); String url = "this is url"; - notifyHook = spyAdaptor.notifyHook(url, id, action, streamName, category, vodName, vodId, viewerId, null); + notifyHook = spyAdaptor.notifyHook(url, id, action, streamName, category, vodName, vodId, viewerId, null, null); assertNull(notifyHook); try { @@ -687,7 +687,7 @@ public void testNotifyHook() { url = "this is second url"; - notifyHook = spyAdaptor.notifyHook(url, id, null, null, null, null, null, null, null); + notifyHook = spyAdaptor.notifyHook(url, id, null, null, null, null, null, null, null, null); assertNull(notifyHook); try { @@ -755,7 +755,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), null, captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -781,7 +781,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(2)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), null, captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -806,7 +806,7 @@ public void testNotifyHookErrors(){ //verify that notifyHook is called 1 time verify(spyAdaptor, times(3)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(),captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), null, captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -871,7 +871,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is never called verify(spyAdaptor, never()).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), null, captureMetadata.capture()); /* @@ -897,7 +897,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is called 1 time verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), null, captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -931,7 +931,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that no new notifyHook is called verify(spyAdaptor, times(1)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), null, captureMetadata.capture()); called = true; } @@ -960,7 +960,7 @@ public void testNotifyHookFromMuxingFinished() { //verify that notifyHook is called 2 times verify(spyAdaptor, times(2)).notifyHook(captureUrl.capture(), captureId.capture(), captureAction.capture(), - captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), captureMetadata.capture()); + captureStreamName.capture(), captureCategory.capture(), captureVodName.capture(), captureVodId.capture(), captureViewerId.capture(), null, captureMetadata.capture()); assertEquals(captureUrl.getValue(), broadcast.getListenerHookURL()); assertEquals(captureId.getValue(), broadcast.getStreamId()); @@ -1822,7 +1822,7 @@ public void testRecordStartedHook() throws Exception { boolean called = false; try{ verify(spyAdaptor, times(1)).sendStartRecordWebHook(streamId); - verify(spyAdaptor,times(1)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_RECORD, broadcast.getName(),broadcast.getCategory(),null,null,null,null); + verify(spyAdaptor,times(1)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_RECORD, broadcast.getName(),broadcast.getCategory(),null,null,null, null, null); called = true; }catch (Exception e){ e.printStackTrace(); @@ -1868,7 +1868,7 @@ public void testRtmpStreamPlayStop() throws Exception { assertEquals(0, spyAdaptor.getDataStore().get(streamId).getRtmpViewerCount()); spyAdaptor.streamPlayItemPlay(stream, item, true); - verify(spyAdaptor, times(1)).sendStartPlayWebHook(anyString(), anyString()); + verify(spyAdaptor, times(1)).sendStartPlayWebHook(anyString(), anyString(), any()); Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean called = false; @@ -1882,7 +1882,7 @@ public void testRtmpStreamPlayStop() throws Exception { }); spyAdaptor.streamPlayItemStop(stream, item); - verify(spyAdaptor, times(1)).sendStopPlayWebHook(anyString(), anyString()); + verify(spyAdaptor, times(1)).sendStopPlayWebHook(anyString(), anyString(), any()); } diff --git a/src/test/java/io/antmedia/test/Application.java b/src/test/java/io/antmedia/test/Application.java index f3d1fb427..7e255c6bb 100644 --- a/src/test/java/io/antmedia/test/Application.java +++ b/src/test/java/io/antmedia/test/Application.java @@ -52,7 +52,7 @@ public static void resetFields() { @Override public StringBuilder notifyHook(String url, String id, String action, String streamName, String category, - String vodName, String vodId, String viewerId, String metadata) { + String vodName, String vodId, String viewerId, String token, String metadata) { logger.info("notify hook action: {}", action); notifyHookAction.add(action); notitfyURL.add(url); diff --git a/src/test/java/io/antmedia/test/MuxerUnitTest.java b/src/test/java/io/antmedia/test/MuxerUnitTest.java index f21f0eaca..1b6e1472f 100644 --- a/src/test/java/io/antmedia/test/MuxerUnitTest.java +++ b/src/test/java/io/antmedia/test/MuxerUnitTest.java @@ -119,11 +119,9 @@ import io.antmedia.datastore.db.InMemoryDataStore; import io.antmedia.datastore.db.types.Broadcast; import io.antmedia.datastore.db.types.Endpoint; -import io.antmedia.datastore.db.types.StreamInfo; import io.antmedia.integration.AppFunctionalV2Test; import io.antmedia.integration.MuxingTest; import io.antmedia.muxer.HLSMuxer; -import io.antmedia.muxer.RecordMuxer; import io.antmedia.muxer.IAntMediaStreamHandler; import io.antmedia.muxer.Mp4Muxer; import io.antmedia.muxer.MuxAdaptor; @@ -1679,7 +1677,7 @@ public void testMp4MuxingAndNotifyCallback() { Application app = (Application) applicationContext.getBean("web.handler"); AntMediaApplicationAdapter appAdaptor = Mockito.spy(app); - doReturn(new StringBuilder("")).when(appAdaptor).notifyHook(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString()); + doReturn(new StringBuilder("")).when(appAdaptor).notifyHook(anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), null, anyString()); assertNotNull(appAdaptor); //just check below value that it is not null, this is not related to this case but it should be tested diff --git a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java index 69fd73d6a..a2abe13cd 100644 --- a/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/DashStatisticsFilterTest.java @@ -160,29 +160,7 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); dashStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); - /*verify(antMediaApplicationAdapter, times(1)).sendStartPlayWebHook(ViewerStats.DASH_TYPE, streamId, null); - - Awaitility.await().atMost(10, TimeUnit.SECONDS).until(()-> { - boolean called = false; - try { - Broadcast broadcast = dataStore.get(streamId); - String url = broadcast.getListenerHookURL(); - String id = streamId; - String action = AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY; - String streamName = broadcast.getName(); - String category = broadcast.getCategory(); - //String viewerId = sessionId; - verify(antMediaApplicationAdapter,times(1)).notifyHook(url,id,action,streamName,category, null, null,null, null); - called = true; - } catch (Exception e) { - e.printStackTrace(); - - } - return called; - });*/ - - + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); @@ -234,15 +212,15 @@ public void testDASHViewerLimit() { //when(dashStatisticsFilter.getStreamStats()).thenReturn(streamStats); String sessionId = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); broadcast.setDashViewerCount(1); String sessionId2 = requestDash(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, null, antMediaApplicationAdapter); broadcast.setDashViewerCount(2); String sessionId3 = requestDash(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, antMediaApplicationAdapter); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, null, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java index ccbb29ffa..d9e896c1b 100644 --- a/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java +++ b/src/test/java/io/antmedia/test/filter/HlsStatisticsFilterTest.java @@ -162,7 +162,7 @@ public void testDoFilter() { logger.info("session id {}, stream id {}", sessionId, streamId); hlsStatisticsFilter.doFilter(mockRequest, mockResponse, mockChain); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); @@ -211,15 +211,15 @@ public void testHLSViewerLimit() { hlsStatisticsFilter.init(filterconfig); String sessionId = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); broadcast.setHlsViewerCount(1); String sessionId2 = requestHls(streamId); - verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, antMediaApplicationAdapter); + verify(streamStats, times(1)).registerNewViewer(streamId, sessionId2, null, null, antMediaApplicationAdapter); broadcast.setHlsViewerCount(2); String sessionId3 = requestHls(streamId); - verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, antMediaApplicationAdapter); + verify(streamStats, never()).registerNewViewer(streamId, sessionId3, null, null, antMediaApplicationAdapter); } catch (ServletException|IOException e) { logger.error(ExceptionUtils.getStackTrace(e)); fail(ExceptionUtils.getStackTrace(e)); diff --git a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java index fa2ae99e0..58b50f153 100644 --- a/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/DashViewerStatsTest.java @@ -72,7 +72,7 @@ public void testDASHViewerCount() { for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -86,7 +86,7 @@ public void testDASHViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -122,7 +122,7 @@ public void testSubscriberEvents() { // check if viewer is added AntMediaApplicationAdapter antMediaApplicationAdapter = mock(AntMediaApplicationAdapter.class); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), null, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -248,16 +248,16 @@ public void testSetApplicationContextSubscribers() { //spyAdapter.setDataStoreFactory(dsf); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), spyAdapter); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId(), spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), null, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay.getSubscriberId(), null, spyAdapter); Awaitility.await().atMost(5, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean called = false; try{ - verify(spyAdapter, times(2)).sendStartPlayWebHook(streamId, subscriberPlay.getSubscriberId()); - verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay.getSubscriberId(),null); + verify(spyAdapter, times(2)).sendStartPlayWebHook(streamId, subscriberPlay.getSubscriberId(), null); + verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_START_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay.getSubscriberId(), null, null); called = true; }catch (Exception e){ e.printStackTrace(); @@ -276,8 +276,8 @@ public void testSetApplicationContextSubscribers() { ()->viewerStats.getTotalViewerCount() == 2 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), spyAdapter); - viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId(), spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), null, spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId2, subscriberPlay2.getSubscriberId(), null, spyAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { @@ -306,9 +306,9 @@ public void testSetApplicationContextSubscribers() { ()-> { boolean called = false; try{ - verify(spyAdapter, times(2)).sendStopPlayWebHook(streamId, subscriberPlay2.getSubscriberId()); + verify(spyAdapter, times(2)).sendStopPlayWebHook(streamId, subscriberPlay2.getSubscriberId(), null); - verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_STOP_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay2.getSubscriberId(),null); + verify(spyAdapter,times(2)).notifyHook(broadcast.getListenerHookURL(),streamId,AntMediaApplicationAdapter.HOOK_ACTION_STOP_PLAY, broadcast.getName(),broadcast.getCategory(),null,null,subscriberPlay2.getSubscriberId(), null, null); called = true; }catch (Exception e){ @@ -339,7 +339,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), spyAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), null, spyAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -423,7 +423,7 @@ public void testSetApplicationContext() { String sessionId = "sessionId" + (int)(Math.random() * 10000); antMediaApplicationAdapter.setAppSettings(settings); - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); Awaitility.await().atMost(30, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -435,7 +435,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(30, TimeUnit.SECONDS).until( @@ -456,7 +456,7 @@ public void testSetApplicationContext() { Awaitility.await().atMost(30, TimeUnit.SECONDS).until( ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); Awaitility.await().atMost(30, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); diff --git a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java index 42a78750e..0a4089949 100644 --- a/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java +++ b/src/test/java/io/antmedia/test/statistic/HlsViewerStatsTest.java @@ -69,7 +69,7 @@ public void testHLSViewerCount() { for (int i = 0; i < 100; i++) { String sessionId = String.valueOf((Math.random() * 999999)); - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -83,7 +83,7 @@ public void testHLSViewerCount() { //Add same session ID for (int i = 0; i < 10; i++) { String sessionId = "sameSessionID"; - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); } Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( @@ -121,7 +121,7 @@ public void testSubscriberEvents() { // check if viewer is added - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), null, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { boolean eventExist = false; @@ -223,7 +223,7 @@ public void testSetApplicationContextSubscribers() { subscriberPlay3.setType(Subscriber.PLAY_TYPE); dsf.getDataStore().addSubscriber(subscriberPlay3.getStreamId(), subscriberPlay3); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay.getSubscriberId(), null, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -236,7 +236,7 @@ public void testSetApplicationContextSubscribers() { //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay2.getSubscriberId(), null, antMediaApplicationAdapter); Awaitility.await().atMost(15, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()-> { @@ -283,7 +283,7 @@ public void testSetApplicationContextSubscribers() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, subscriberPlay3.getSubscriberId(), null, antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); @@ -365,7 +365,7 @@ public void testSetApplicationContext() { String sessionId = "sessionId" + (int)(Math.random() * 10000); - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); Awaitility.await().atMost(10, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until( ()->viewerStats.getViewerCount(streamId) == 1 ); @@ -377,7 +377,7 @@ public void testSetApplicationContext() { ()->viewerStats.getTotalViewerCount() == 1 ); //Viewer timeout increase - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); // Check viewer is online Awaitility.await().atMost(20, TimeUnit.SECONDS).until( @@ -399,7 +399,7 @@ public void testSetApplicationContext() { ()-> dsf.getDataStore().save(broadcast).equals(streamId)); - viewerStats.registerNewViewer(streamId, sessionId, null, antMediaApplicationAdapter); + viewerStats.registerNewViewer(streamId, sessionId, null, null, antMediaApplicationAdapter); Awaitility.await().atMost(20, TimeUnit.SECONDS).until( ()-> viewerStats.getViewerCount(streamId) == 1); From f68330c072fd57d2a472b2cc215dd863d6b03608 Mon Sep 17 00:00:00 2001 From: lastpeony Date: Thu, 2 Feb 2023 12:15:29 +0300 Subject: [PATCH 13/15] stop webrtc player with play token modification. --- .../io/antmedia/AntMediaApplicationAdapter.java | 17 +++++++++++++---- .../datastore/db/types/WebRTCViewerInfo.java | 16 ++++++++++++++-- .../io/antmedia/rest/BroadcastRestService.java | 12 +++++++++--- .../rest/BroadcastRestServiceV2UnitTest.java | 4 ++-- 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java index afe87b200..fadd8f4c7 100644 --- a/src/main/java/io/antmedia/AntMediaApplicationAdapter.java +++ b/src/main/java/io/antmedia/AntMediaApplicationAdapter.java @@ -550,9 +550,10 @@ public void sendStartPlayWebHook(final String streamId, final String viewerId, f } final String name = broadcast.getName(); final String category = broadcast.getCategory(); + final String metaData = broadcast.getMetaData(); logger.info("Setting timer to call viewer play started hook for stream:{}", streamId); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_PLAY, name, category, - null, null, viewerId, token, null)); + null, null, viewerId, token, metaData)); } public void sendStopPlayWebHook(final String streamId, final String viewerId, final String token){ @@ -566,9 +567,11 @@ public void sendStopPlayWebHook(final String streamId, final String viewerId, fi } final String name = broadcast.getName(); final String category = broadcast.getCategory(); + final String metaData = broadcast.getMetaData(); + logger.info("Setting timer to call viewer play stopped hook for stream:{}", streamId); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_STOP_PLAY, name, category, - null, null, viewerId, token, null)); + null, null, viewerId, token, metaData)); } public void sendStartRecordWebHook(final String streamId){ @@ -582,9 +585,10 @@ public void sendStartRecordWebHook(final String streamId){ } final String name = broadcast.getName(); final String category = broadcast.getCategory(); + final String metaData = broadcast.getMetaData(); logger.info("Setting timer to call stream start recording hook for stream:{}", streamId); vertx.setTimer(10, e -> notifyHook(listenerHookURL, streamId, HOOK_ACTION_START_RECORD, name, category, - null, null, null, null, null)); + null, null, null, null, metaData)); } private String getRtmpViewerId(){ @@ -1800,9 +1804,14 @@ public void removeStreamListener(IStreamListener listener) { streamListeners.remove(listener); } - public boolean stopPlaying(String viewerId) { + public boolean stopPlayingByViewerId(String viewerId) { return false; } + + public boolean stopPlayingByPlayToken(String playToken) { + return false; + } + public void stopPublish(String streamId) { vertx.executeBlocking(handler-> closeBroadcast(streamId) , null); } diff --git a/src/main/java/io/antmedia/datastore/db/types/WebRTCViewerInfo.java b/src/main/java/io/antmedia/datastore/db/types/WebRTCViewerInfo.java index 44260e053..118966224 100644 --- a/src/main/java/io/antmedia/datastore/db/types/WebRTCViewerInfo.java +++ b/src/main/java/io/antmedia/datastore/db/types/WebRTCViewerInfo.java @@ -40,7 +40,12 @@ public class WebRTCViewerInfo { @ApiModelProperty(value = "IP address of the edge to which viewer is connected") private String edgeAddress; - + /** + * Play token of the viewer + */ + @ApiModelProperty(value = "the token of the viewer") + private String tokenId; + public ObjectId getDbId() { return dbId; } @@ -72,5 +77,12 @@ public String getEdgeAddress() { public void setEdgeAddress(String edgeAddress) { this.edgeAddress = edgeAddress; } - + + public String getTokenId() { + return tokenId; + } + + public void setTokenId(String tokenId) { + this.tokenId = tokenId; + } } diff --git a/src/main/java/io/antmedia/rest/BroadcastRestService.java b/src/main/java/io/antmedia/rest/BroadcastRestService.java index 9ca381d0b..45ddb2417 100644 --- a/src/main/java/io/antmedia/rest/BroadcastRestService.java +++ b/src/main/java/io/antmedia/rest/BroadcastRestService.java @@ -1126,11 +1126,17 @@ public List getWebRTCViewerList(@ApiParam(value = "This is the @ApiOperation(value = "Stop player with a specified id", response = Result.class) @POST @Consumes(MediaType.APPLICATION_JSON) - @Path("/webrtc-viewers/{webrtc-viewer-id}/stop") + @Path("/webrtc-viewers/stop") @Produces(MediaType.APPLICATION_JSON) - public Result stopPlaying(@ApiParam(value = "the id of the webrtc viewer.", required = true) @PathParam("webrtc-viewer-id") String viewerId) + public Result stopPlaying(@ApiParam(value="the viewer id of webrtc viewer", required = false) @QueryParam("viewerId") String viewerId, + @ApiParam(value="the viewer id of webrtc viewer", required = false) @QueryParam("playToken") String playToken) { - boolean result = getApplication().stopPlaying(viewerId); + boolean result = false; + if(playToken != null){ + result = getApplication().stopPlayingByPlayToken(playToken); + }else if(viewerId != null){ + result = getApplication().stopPlayingByViewerId(viewerId); + } return new Result(result); } diff --git a/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java b/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java index 45685da5c..d181f23d5 100644 --- a/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java +++ b/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java @@ -2993,8 +2993,8 @@ public void testWebRTCViewerRestOperations(){ AntMediaApplicationAdapter testApp = Mockito.spy(new AntMediaApplicationAdapter()); restServiceSpy.setApplication(testApp); - restServiceSpy.stopPlaying(viewerId); - verify(testApp, times(1)).stopPlaying(viewerId); + restServiceSpy.stopPlaying(viewerId, null); + verify(testApp, times(1)).stopPlayingByViewerId(viewerId); } @Test From 4f6b3512767307a8cb4af73fd0856a4dafb624cd Mon Sep 17 00:00:00 2001 From: mekya Date: Tue, 13 Jun 2023 14:42:07 +0300 Subject: [PATCH 14/15] Fix test case --- .../io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java index 30f9af807..37f120600 100644 --- a/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java +++ b/src/test/java/io/antmedia/test/AntMediaApplicationAdaptorUnitTest.java @@ -1849,7 +1849,7 @@ public void testRecordStartedHook() throws Exception { spyAdaptor.setAppSettings(appSettings); Broadcast broadcast = new Broadcast(); - assertNull(spyAdaptor.getListenerHookURL(broadcast)); + assertEquals("", spyAdaptor.getListenerHookURL(broadcast)); broadcast.setMp4Enabled(MuxAdaptor.RECORDING_ENABLED_FOR_STREAM); String hookURL = "listener_hook_url"; appSettings.setListenerHookURL(hookURL); @@ -1897,7 +1897,7 @@ public void testRtmpStreamPlayStop() throws Exception { spyAdaptor.setAppSettings(appSettings); Broadcast broadcast = new Broadcast(); - assertNull(spyAdaptor.getListenerHookURL(broadcast)); + assertEquals("", spyAdaptor.getListenerHookURL(broadcast)); broadcast.setMp4Enabled(MuxAdaptor.RECORDING_ENABLED_FOR_STREAM); String hookURL = "listener_hook_url"; appSettings.setListenerHookURL(hookURL); From 6b5c02ade6d60b53cde0d480b354a182cec4ec99 Mon Sep 17 00:00:00 2001 From: lastpeony Date: Wed, 14 Jun 2023 18:48:43 +0300 Subject: [PATCH 15/15] refactoring rest call for backwards comp --- .../antmedia/rest/BroadcastRestService.java | 25 +++++++++++++------ .../rest/BroadcastRestServiceV2UnitTest.java | 4 +-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/antmedia/rest/BroadcastRestService.java b/src/main/java/io/antmedia/rest/BroadcastRestService.java index 8af4a4779..50dc597da 100644 --- a/src/main/java/io/antmedia/rest/BroadcastRestService.java +++ b/src/main/java/io/antmedia/rest/BroadcastRestService.java @@ -1210,23 +1210,34 @@ public List getWebRTCViewerList(@ApiParam(value = "This is the ) { return getDataStore().getWebRTCViewerList(offset, size ,sortBy, orderBy, search); } - - @ApiOperation(value = "Stop player with a specified id", response = Result.class) + + @ApiOperation(value = "Stop player with a specified viewer id", response = Result.class) + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Path("/webrtc-viewers/{webrtc-viewer-id}/stop") + @Produces(MediaType.APPLICATION_JSON) + public Result stopPlayingByViewerId(@ApiParam(value="the viewer id of webrtc viewer", required = false) @PathParam("webrtc-viewer-id") String viewerId) + { + boolean result = false; + if(viewerId != null){ + result = getApplication().stopPlayingByViewerId(viewerId); + } + return new Result(result); + } + + @ApiOperation(value = "Stop player with a specified play token", response = Result.class) @POST @Consumes(MediaType.APPLICATION_JSON) @Path("/webrtc-viewers/stop") @Produces(MediaType.APPLICATION_JSON) - public Result stopPlaying(@ApiParam(value="the viewer id of webrtc viewer", required = false) @QueryParam("viewerId") String viewerId, - @ApiParam(value="the viewer id of webrtc viewer", required = false) @QueryParam("playToken") String playToken) + public Result stopPlayingByPlayToken( + @ApiParam(value="the play token of webrtc viewer", required = false) @QueryParam("playToken") String playToken) { boolean result = false; if(playToken != null){ result = getApplication().stopPlayingByPlayToken(playToken); - }else if(viewerId != null){ - result = getApplication().stopPlayingByViewerId(viewerId); } return new Result(result); } - } diff --git a/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java b/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java index 37fe214a5..b82cd6e4b 100644 --- a/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java +++ b/src/test/java/io/antmedia/test/rest/BroadcastRestServiceV2UnitTest.java @@ -3065,9 +3065,9 @@ public void testWebRTCViewerRestOperations(){ AntMediaApplicationAdapter testApp = Mockito.spy(new AntMediaApplicationAdapter()); restServiceSpy.setApplication(testApp); - restServiceSpy.stopPlaying(viewerId, null); + restServiceSpy.stopPlayingByViewerId(viewerId); verify(testApp, times(1)).stopPlayingByViewerId(viewerId); - restServiceSpy.stopPlaying(null, "token"); + restServiceSpy.stopPlayingByPlayToken("token"); verify(testApp, times(1)).stopPlayingByPlayToken("token"); }