From 7074771b4a5c64caffd21e036e6187c6d6f2f40c Mon Sep 17 00:00:00 2001 From: mekya Date: Mon, 30 Dec 2024 21:12:40 +0300 Subject: [PATCH 1/5] Add encoder parameters to AppSettings --- src/main/java/io/antmedia/AppSettings.java | 86 +++++++++++++++++-- .../antmedia/plugin/api/IStreamListener.java | 8 +- .../io/antmedia/test/AppSettingsUnitTest.java | 6 +- 3 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/main/java/io/antmedia/AppSettings.java b/src/main/java/io/antmedia/AppSettings.java index 26403eed8..132363bbf 100644 --- a/src/main/java/io/antmedia/AppSettings.java +++ b/src/main/java/io/antmedia/AppSettings.java @@ -1346,41 +1346,69 @@ public class AppSettings implements Serializable{ /** * Name of the encoder to be used in adaptive bitrate, * If there is a GPU, server tries to open h264_nvenc, - * If there is no GPU, server tries to open libx264 by default - * Can be h264_nvenc or libx264. If you set h264_nvenc but it cannot be opened then libx264 will be used, - * Name of the encoder to be used in adaptive bitrate, - * If there is a GPU, server tries to open h264_nvenc, - * If there is no GPU, server tries to open libx264 by default + * If there is no GPU, server tries to open openh264 by default + * Can be h264_nvenc or openh264. If you set h264_nvenc and then if it cannot be opened, libx264 will be used, */ @Value( "${encoderName:${" + SETTINGS_ENCODING_ENCODER_NAME +":}}") private String encoderName = ""; + + /** + * Encoder specific parameters in key-value mapping way with JSON objects. + * + * Keys should match the encoder names officially in ffmpeg for instance libopenh264, h264_nvenc, vpx, hevc_nvenc + * + * Then you can have a json object like this which includes the parameters for the encoder + * { + * "libopenh264": { + * "profile":"main", + * + * }, + * "vpx": { + * "deadline":"realtime", + * }, + * "h264_nvenc": { + * "preset":"ll" + * } + * } + */ + @Value("${encoderParameters:{}}") + private Map> encoderParameters = new HashMap<>(); /** * Encoder's preset value in adaptive bitrate * Libx264 presets are there * https://trac.ffmpeg.org/wiki/Encode/H.264 * Ant Media Server uses "veryfast" by default + * + * @Deprecated use {@link #encoderParameters} * */ @Value("${encoderPreset:${" + SETTINGS_ENCODING_PRESET +":}}") + @Deprecated private String encoderPreset = ""; /** * Encoder profile in adaptive bitrate, * It's baseline by default. + * @Deprecated use {@link #encoderParameters} */ @Value( "${encoderProfile:${" + SETTINGS_ENCODING_PROFILE +":}}") + @Deprecated private String encoderProfile = ""; /** * Encoder level in adaptive bitrate + * @Deprecated use {@link #encoderParameters} */ + @Deprecated @Value( "${encoderLevel:${" + SETTINGS_ENCODING_LEVEL +":}}") private String encoderLevel = ""; /** * Encoding rate control in adaptive bitrate + * @Deprecated use {@link #encoderParameters} */ + @Deprecated @Value( "${encoderRc:${" + SETTINGS_ENCODING_RC +":}}") private String encoderRc = ""; @@ -1389,7 +1417,10 @@ public class AppSettings implements Serializable{ * This is the x264-params in ffmpeg * Specific settings for selected encoder, * For libx264 please check https://trac.ffmpeg.org/wiki/Encode/H.264 + * + * @Deprecated use {@link #encoderParameters} */ + @Deprecated @Value( "${encoderSpecific:${" + SETTINGS_ENCODING_SPECIFIC +":}}") private String encoderSpecific = ""; @@ -1410,8 +1441,10 @@ public class AppSettings implements Serializable{ /** * Set quality/speed ratio modifier, Higher values speed up the encode at the cost of quality. + * @Deprecated use {@link #encoderParameters} */ @Value( "${vp8EncoderSpeed:${" + SETTINGS_ENCODING_VP8_SPEED +":4}}") + @Deprecated private int vp8EncoderSpeed = 4; /** @@ -1419,8 +1452,11 @@ public class AppSettings implements Serializable{ * best * good * realtime + * + * @Deprecated use {@link #encoderParameters} */ @Value( "${vp8EncoderDeadline:${" + SETTINGS_ENCODING_VP8_DEADLINE +":realtime}}") + @Deprecated private String vp8EncoderDeadline = "realtime"; /** @@ -1720,15 +1756,34 @@ public class AppSettings implements Serializable{ @Value("${dataChannelWebHookURL:${" + SETTINGS_DATA_CHANNEL_WEBHOOK_URL+":}}") private String dataChannelWebHookURL = ""; - + /** + * @Deprecated. Please use {@link #encoderParameters} + */ + @Deprecated private String h265EncoderPreset; - + + /** + * @Deprecated. Please use {@link #encoderParameters} + */ + @Deprecated private String h265EncoderProfile; + /** + * @Deprecated. Please use {@link #encoderParameters} + */ + @Deprecated private String h265EncoderRc; + /** + * @Deprecated. Please use {@link #encoderParameters} + */ + @Deprecated private String h265EncoderSpecific; + /** + * @Deprecated. Please use {@link #encoderParameters} + */ + @Deprecated private String h265EncoderLevel; /** @@ -1781,9 +1836,10 @@ public class AppSettings implements Serializable{ /** * Constant Rate Factor used by x264, x265, VP8, * Use values between 4-51 - * + * @Deprecated. Please use {@link #encoderParameters} */ @Value("${constantRateFactor:${"+SETTINGS_CONSTANT_RATE_FACTOR+":23}}") + @Deprecated private String constantRateFactor = "23"; /** @@ -4179,4 +4235,18 @@ public int getS3TransferBufferSizeInBytes() { public void setS3TransferBufferSizeInBytes(int s3TransferBufferSizeInBytes) { this.s3TransferBufferSizeInBytes = s3TransferBufferSizeInBytes; } + + /** + * @return the encoderParameters + */ + public Map> getEncoderParameters() { + return encoderParameters; + } + + /** + * @param encoderParameters the encoderParameters to set + */ + public void setEncoderParameters(Map> encoderParameters) { + this.encoderParameters = encoderParameters; + } } diff --git a/src/main/java/io/antmedia/plugin/api/IStreamListener.java b/src/main/java/io/antmedia/plugin/api/IStreamListener.java index 4fb3bd463..2fe30c30e 100644 --- a/src/main/java/io/antmedia/plugin/api/IStreamListener.java +++ b/src/main/java/io/antmedia/plugin/api/IStreamListener.java @@ -13,7 +13,9 @@ public interface IStreamListener { * @Deprecated use {@link #streamStarted(Broadcast)} because Broadcast object may be deleted when this method is called */ @Deprecated (since="3.0", forRemoval = true) - public void streamStarted(String streamId); + public default void streamStarted(String streamId) { + //do nothing + } /** * AMS inform the plugins when a stream is started with this method. @@ -31,7 +33,9 @@ public default void streamStarted(Broadcast broadcast) { * @Deprecated use {@link #streamFinished(Broadcast)} because Broadcast object may be deleted when this method is called */ @Deprecated (since="3.0", forRemoval = true) - public void streamFinished(String streamId); + public default void streamFinished(String streamId) { + //do nothing + } /** * AMS inform the plugins when a stream is finished with this method. diff --git a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java index 1f7dd9a0c..4fcac4d91 100644 --- a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java +++ b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java @@ -662,13 +662,17 @@ public void testUnsetAppSettings(AppSettings appSettings) { assertEquals(10000000, appSettings.getS3TransferBufferSizeInBytes()); appSettings.setS3TransferBufferSizeInBytes(50000); assertEquals(50000, appSettings.getS3TransferBufferSizeInBytes()); + + map = appSettings.getEncoderParameters(); + assertNotNull(map); + assertEquals(0, map.size()); //if we add a new field, we just need to check its default value in this test //When a new field is added or removed please update the number of fields and make this test pass //by also checking its default value. assertEquals("New field is added to settings. PAY ATTENTION: Please CHECK ITS DEFAULT VALUE and fix the number of fields.", - 198, numberOfFields); + 199, numberOfFields); } From 85c32676111d40c4250c83456d4418345fc97007 Mon Sep 17 00:00:00 2001 From: mekya Date: Tue, 31 Dec 2024 09:37:02 +0300 Subject: [PATCH 2/5] Fix setter/getter name and improve test stability --- src/main/java/io/antmedia/AppSettings.java | 22 ++++++++++++------- .../io/antmedia/integration/MuxingTest.java | 4 ++-- .../io/antmedia/test/AppSettingsUnitTest.java | 2 +- .../java/io/antmedia/test/MuxerUnitTest.java | 2 +- .../antmedia/test/StreamFetcherUnitTest.java | 4 +++- 5 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/antmedia/AppSettings.java b/src/main/java/io/antmedia/AppSettings.java index 132363bbf..f95ceabd4 100644 --- a/src/main/java/io/antmedia/AppSettings.java +++ b/src/main/java/io/antmedia/AppSettings.java @@ -4053,14 +4053,6 @@ public void setHlsSegmentType(String hlsSegmentType) { this.hlsSegmentType = hlsSegmentType; } - public String getHlsSegmentFileSuffixFormat() { - return hlsSegmentFileSuffixFormat; - } - - public void setHlsSegmentFileNameFormat(String hlsSegmentFileSuffixFormat) { - this.hlsSegmentFileSuffixFormat = hlsSegmentFileSuffixFormat; - } - public String getRecordingSubfolder() { return recordingSubfolder; } @@ -4249,4 +4241,18 @@ public Map> getEncoderParameters() { public void setEncoderParameters(Map> encoderParameters) { this.encoderParameters = encoderParameters; } + + /** + * @return the hlsSegmentFileSuffixFormat + */ + public String getHlsSegmentFileSuffixFormat() { + return hlsSegmentFileSuffixFormat; + } + + /** + * @param hlsSegmentFileSuffixFormat the hlsSegmentFileSuffixFormat to set + */ + public void setHlsSegmentFileSuffixFormat(String hlsSegmentFileSuffixFormat) { + this.hlsSegmentFileSuffixFormat = hlsSegmentFileSuffixFormat; + } } diff --git a/src/test/java/io/antmedia/integration/MuxingTest.java b/src/test/java/io/antmedia/integration/MuxingTest.java index 2cf751fad..853381eec 100644 --- a/src/test/java/io/antmedia/integration/MuxingTest.java +++ b/src/test/java/io/antmedia/integration/MuxingTest.java @@ -833,7 +833,7 @@ public void testHLSSegmentFileName() { boolean hlsEnabled = appSettings.isHlsMuxingEnabled(); appSettings.setHlsMuxingEnabled(true); String hlsSegmentFileNameFormat = appSettings.getHlsSegmentFileSuffixFormat(); - appSettings.setHlsSegmentFileNameFormat("-%Y%m%d-%s"); + appSettings.setHlsSegmentFileSuffixFormat("-%Y%m%d-%s"); result = ConsoleAppRestServiceTest.callSetAppSettings("LiveApp", appSettings); assertTrue(result.isSuccess()); @@ -887,7 +887,7 @@ public void testHLSSegmentFileName() { }); appSettings.setHlsMuxingEnabled(hlsEnabled); - appSettings.setHlsSegmentFileNameFormat(hlsSegmentFileNameFormat); + appSettings.setHlsSegmentFileSuffixFormat(hlsSegmentFileNameFormat); ConsoleAppRestServiceTest.callSetAppSettings("LiveApp", appSettings); } catch (Exception e) { e.printStackTrace(); diff --git a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java index 4fcac4d91..a16e0971a 100644 --- a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java +++ b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java @@ -648,7 +648,7 @@ public void testUnsetAppSettings(AppSettings appSettings) { assertFalse(appSettings.isWriteSubscriberEventsToDatastore()); assertEquals("%09d", appSettings.getHlsSegmentFileSuffixFormat()); - appSettings.setHlsSegmentFileNameFormat("%s"); + appSettings.setHlsSegmentFileSuffixFormat("%s"); assertEquals("%s", appSettings.getHlsSegmentFileSuffixFormat()); diff --git a/src/test/java/io/antmedia/test/MuxerUnitTest.java b/src/test/java/io/antmedia/test/MuxerUnitTest.java index 002553f8e..51e443810 100644 --- a/src/test/java/io/antmedia/test/MuxerUnitTest.java +++ b/src/test/java/io/antmedia/test/MuxerUnitTest.java @@ -4006,7 +4006,7 @@ public void testHLSNaming() { hlsMuxer.init(appScope, "test", 300, "", 400000); assertEquals("./webapps/junit/streams/test_300p400kbps%09d.ts", hlsMuxer.getSegmentFilename()); - getAppSettings().setHlsSegmentFileNameFormat("-%Y%m%d-%s"); + getAppSettings().setHlsSegmentFileSuffixFormat("-%Y%m%d-%s"); hlsMuxer = new HLSMuxer(vertx, Mockito.mock(StorageClient.class), "", 7, null, false); hlsMuxer.init(appScope, "test", 0, "", 0); assertEquals("./webapps/junit/streams/test-%Y%m%d-%s.ts", hlsMuxer.getSegmentFilename()); diff --git a/src/test/java/io/antmedia/test/StreamFetcherUnitTest.java b/src/test/java/io/antmedia/test/StreamFetcherUnitTest.java index 37ba9e3b7..26c0c14a3 100644 --- a/src/test/java/io/antmedia/test/StreamFetcherUnitTest.java +++ b/src/test/java/io/antmedia/test/StreamFetcherUnitTest.java @@ -973,7 +973,9 @@ public void testHLSSourceFmp4() { String[] filesInStreams = new File("webapps/junit/streams").list(); boolean initFileFound = false; - String regex = streamId + "_" + System.currentTimeMillis()/100000 + "\\d{5}_init.mp4"; + + //matches 13 digits because System.currentTimeMillis() is used in the file + String regex = streamId + "_\\d{13}_init.mp4"; System.out.println("regex:"+regex); for (int i = 0; i < filesInStreams.length; i++) { From bc0d1b34a214507e70f299d9eef7814c5431cb92 Mon Sep 17 00:00:00 2001 From: mekya Date: Tue, 31 Dec 2024 10:18:59 +0300 Subject: [PATCH 3/5] Increase code coverage --- .../io/antmedia/test/AppSettingsUnitTest.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java index a16e0971a..1c8753728 100644 --- a/src/test/java/io/antmedia/test/AppSettingsUnitTest.java +++ b/src/test/java/io/antmedia/test/AppSettingsUnitTest.java @@ -663,9 +663,22 @@ public void testUnsetAppSettings(AppSettings appSettings) { appSettings.setS3TransferBufferSizeInBytes(50000); assertEquals(50000, appSettings.getS3TransferBufferSizeInBytes()); - map = appSettings.getEncoderParameters(); - assertNotNull(map); - assertEquals(0, map.size()); + Map> mapEncoderParameters = appSettings.getEncoderParameters(); + assertNotNull(mapEncoderParameters); + assertEquals(0, mapEncoderParameters.size()); + + Map libopenH264 = new HashMap<>(); + libopenH264.put("rc_mode", "quality"); + mapEncoderParameters.put("libopenh264", libopenH264); + + + appSettings.setEncoderParameters(mapEncoderParameters); + + mapEncoderParameters = appSettings.getEncoderParameters(); + assertNotNull(mapEncoderParameters); + assertEquals(1, mapEncoderParameters.size()); + assertEquals("quality", mapEncoderParameters.get("libopenh264").get("rc_mode")); + //if we add a new field, we just need to check its default value in this test //When a new field is added or removed please update the number of fields and make this test pass From f5083a50a0277e8a779083ebae759a1ca92028fa Mon Sep 17 00:00:00 2001 From: mekya Date: Tue, 31 Dec 2024 13:33:25 +0300 Subject: [PATCH 4/5] Fix convention error --- src/main/java/io/antmedia/AppSettings.java | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/io/antmedia/AppSettings.java b/src/main/java/io/antmedia/AppSettings.java index f95ceabd4..0e87799da 100644 --- a/src/main/java/io/antmedia/AppSettings.java +++ b/src/main/java/io/antmedia/AppSettings.java @@ -1093,7 +1093,7 @@ public class AppSettings implements Serializable{ /** * The settings for accepting only time based token subscribers as connections to the streams - * @Deprecated. Please use {@link #enableTimeTokenForPlay} or {@link #enableTimeTokenForPublish} + * @deprecated. Please use {@link #enableTimeTokenForPlay} or {@link #enableTimeTokenForPublish} */ @Value( "${timeTokenSubscriberOnly:${"+SETTINGS_TIME_TOKEN_SUBSCRIBER_ONLY+":false}}" ) private boolean timeTokenSubscriberOnly; @@ -1161,7 +1161,7 @@ public class AppSettings implements Serializable{ /** * The path for manually saved used VoDs * Determines the directory to store VOD files. - * @Deprecated use {@link VoDRestService#importVoDs(String)} + * @deprecated use {@link VoDRestService#importVoDs(String)} */ @Value( "${vodFolder:${"+SETTINGS_VOD_FOLDER+":}}" ) private String vodFolder = ""; @@ -1380,7 +1380,7 @@ public class AppSettings implements Serializable{ * https://trac.ffmpeg.org/wiki/Encode/H.264 * Ant Media Server uses "veryfast" by default * - * @Deprecated use {@link #encoderParameters} + * @deprecated use {@link #encoderParameters} * */ @Value("${encoderPreset:${" + SETTINGS_ENCODING_PRESET +":}}") @@ -1390,7 +1390,7 @@ public class AppSettings implements Serializable{ /** * Encoder profile in adaptive bitrate, * It's baseline by default. - * @Deprecated use {@link #encoderParameters} + * @deprecated use {@link #encoderParameters} */ @Value( "${encoderProfile:${" + SETTINGS_ENCODING_PROFILE +":}}") @Deprecated @@ -1398,7 +1398,7 @@ public class AppSettings implements Serializable{ /** * Encoder level in adaptive bitrate - * @Deprecated use {@link #encoderParameters} + * @deprecated use {@link #encoderParameters} */ @Deprecated @Value( "${encoderLevel:${" + SETTINGS_ENCODING_LEVEL +":}}") @@ -1406,7 +1406,7 @@ public class AppSettings implements Serializable{ /** * Encoding rate control in adaptive bitrate - * @Deprecated use {@link #encoderParameters} + * @deprecated use {@link #encoderParameters} */ @Deprecated @Value( "${encoderRc:${" + SETTINGS_ENCODING_RC +":}}") @@ -1418,7 +1418,7 @@ public class AppSettings implements Serializable{ * Specific settings for selected encoder, * For libx264 please check https://trac.ffmpeg.org/wiki/Encode/H.264 * - * @Deprecated use {@link #encoderParameters} + * @deprecated use {@link #encoderParameters} */ @Deprecated @Value( "${encoderSpecific:${" + SETTINGS_ENCODING_SPECIFIC +":}}") @@ -1441,7 +1441,7 @@ public class AppSettings implements Serializable{ /** * Set quality/speed ratio modifier, Higher values speed up the encode at the cost of quality. - * @Deprecated use {@link #encoderParameters} + * @deprecated use {@link #encoderParameters} */ @Value( "${vp8EncoderSpeed:${" + SETTINGS_ENCODING_VP8_SPEED +":4}}") @Deprecated @@ -1757,31 +1757,31 @@ public class AppSettings implements Serializable{ private String dataChannelWebHookURL = ""; /** - * @Deprecated. Please use {@link #encoderParameters} + * @deprecated. Please use {@link #encoderParameters} */ @Deprecated private String h265EncoderPreset; /** - * @Deprecated. Please use {@link #encoderParameters} + * @deprecated. Please use {@link #encoderParameters} */ @Deprecated private String h265EncoderProfile; /** - * @Deprecated. Please use {@link #encoderParameters} + * @deprecated. Please use {@link #encoderParameters} */ @Deprecated private String h265EncoderRc; /** - * @Deprecated. Please use {@link #encoderParameters} + * @deprecated. Please use {@link #encoderParameters} */ @Deprecated private String h265EncoderSpecific; /** - * @Deprecated. Please use {@link #encoderParameters} + * @deprecated. Please use {@link #encoderParameters} */ @Deprecated private String h265EncoderLevel; @@ -1836,7 +1836,7 @@ public class AppSettings implements Serializable{ /** * Constant Rate Factor used by x264, x265, VP8, * Use values between 4-51 - * @Deprecated. Please use {@link #encoderParameters} + * @deprecated. Please use {@link #encoderParameters} */ @Value("${constantRateFactor:${"+SETTINGS_CONSTANT_RATE_FACTOR+":23}}") @Deprecated @@ -2792,7 +2792,7 @@ public void setPlayTokenControlEnabled(boolean playTokenControlEnabled) { } /** - * @Deprecated Please use {@link #isEnableTimeTokenForPlay()} or {@link #isEnableTimeTokenForPublish()} + * @deprecated Please use {@link #isEnableTimeTokenForPlay()} or {@link #isEnableTimeTokenForPublish()} * @return */ @Deprecated From bb14e840785ef1e9b7cc7cb9ea45f740713e54d0 Mon Sep 17 00:00:00 2001 From: mekya Date: Tue, 31 Dec 2024 16:07:50 +0300 Subject: [PATCH 5/5] Fix sonar quality gate issues --- src/main/java/io/antmedia/AppSettings.java | 4 +++- src/main/java/io/antmedia/plugin/api/IStreamListener.java | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/antmedia/AppSettings.java b/src/main/java/io/antmedia/AppSettings.java index 0e87799da..fd60fb271 100644 --- a/src/main/java/io/antmedia/AppSettings.java +++ b/src/main/java/io/antmedia/AppSettings.java @@ -1096,6 +1096,7 @@ public class AppSettings implements Serializable{ * @deprecated. Please use {@link #enableTimeTokenForPlay} or {@link #enableTimeTokenForPublish} */ @Value( "${timeTokenSubscriberOnly:${"+SETTINGS_TIME_TOKEN_SUBSCRIBER_ONLY+":false}}" ) + @Deprecated private boolean timeTokenSubscriberOnly; /** * The setting for accepting only time based token(TOTP) subscribers as connections to the streams @@ -1164,6 +1165,7 @@ public class AppSettings implements Serializable{ * @deprecated use {@link VoDRestService#importVoDs(String)} */ @Value( "${vodFolder:${"+SETTINGS_VOD_FOLDER+":}}" ) + @Deprecated private String vodFolder = ""; /** @@ -1453,7 +1455,7 @@ public class AppSettings implements Serializable{ * good * realtime * - * @Deprecated use {@link #encoderParameters} + * @deprecated use {@link #encoderParameters} */ @Value( "${vp8EncoderDeadline:${" + SETTINGS_ENCODING_VP8_DEADLINE +":realtime}}") @Deprecated diff --git a/src/main/java/io/antmedia/plugin/api/IStreamListener.java b/src/main/java/io/antmedia/plugin/api/IStreamListener.java index 2fe30c30e..d6fa3ceb3 100644 --- a/src/main/java/io/antmedia/plugin/api/IStreamListener.java +++ b/src/main/java/io/antmedia/plugin/api/IStreamListener.java @@ -10,7 +10,7 @@ public interface IStreamListener { * AMS inform the plugins when a stream is started with this method. * @param streamId is the id of the stream * - * @Deprecated use {@link #streamStarted(Broadcast)} because Broadcast object may be deleted when this method is called + * @deprecated use {@link #streamStarted(Broadcast)} because Broadcast object may be deleted when this method is called */ @Deprecated (since="3.0", forRemoval = true) public default void streamStarted(String streamId) { @@ -30,7 +30,7 @@ public default void streamStarted(Broadcast broadcast) { * AMS inform the plugins when a stream is finished with this method. * @param streamId is the id of the stream * - * @Deprecated use {@link #streamFinished(Broadcast)} because Broadcast object may be deleted when this method is called + * @deprecated use {@link #streamFinished(Broadcast)} because Broadcast object may be deleted when this method is called */ @Deprecated (since="3.0", forRemoval = true) public default void streamFinished(String streamId) {