diff --git a/examples/rtp-receiver/README.md b/examples/rtp-receiver/README.md index 56567bf..e2b2885 100644 --- a/examples/rtp-receiver/README.md +++ b/examples/rtp-receiver/README.md @@ -8,7 +8,8 @@ Squawk WebSocket client implementation for connecting to squawk and receiving RT 2. [Maven](https://maven.apache.org/download.cgi) 3. API key for Benzinga Squawk. Contact Benzinga licensing team at  licensing@benzinga.com, if you don't have one. 4. Squawk WebSocket address. Contact Benzinga licensing team at  licensing@benzinga.com for that. -5. Publicly open and accessible IP:Port on your end. +5. Publicly open and accessible IP and few ports, 5 should be enough, on your end. Multiple ports needed in case there are more than one broadcaster is active +6. [ffmpeg](https://www.ffmpeg.org/) command-line utility. It is for saving the incoming audio stream in a file using [StreamingSessionListener](src/main/java/com/benzinga/squawk/StreamingSessionListener.java). You can comment/remove that part from [SquawkWSClient](src/main/java/com/benzinga/squawk/SquawkWSClient.java) if you want to consume the incoming RTP differently. ## Installing and Executing @@ -28,15 +29,13 @@ Please note that the execution is dependent on configuration, which can be done | bz.squawk.room      | BZ_SQUAWK_ROOM | Room to join. It must be `PRO` | bz.squawk.role      | BZ_SQUAWK_ROLE | Room to join. It must be `rtpreceiver` | receiver.ip      | RECEIVER_IP | The IP address where you want to receive RTP stream. It must be publicly accessible IP -| receiver.port      | RECEIVER_PORT | An open port to receive RTP stream. -| receiver.sdpoffer.file      | RECEIVER_SDP_OFFER_FILE | File path containing your custom SDP Offer. This SDP offer should have public IP and port. Please note that this configuration will be given precedence over  `receiver.ip` and `receiver.port`. So either set SDP file path or IP & port. +| receiver.ports      | RECEIVER_PORTS | Some open ports to receive RTP streams. It should be comma-separated int values and not consecutive ports. There should be some gap between ports because RTP uses the next available port for RTCP. Need multiple ports opened in case of more than one broadcaster is active. Max 5 ports should be more than enough. -  -Please note that if you set the environment variable for a config parameter, then the `application.conf` value will be overridden by the env value.  + Please note that if you set the environment variable for a config parameter, then the `application.conf` value will be overridden by the env values.  ## Verifying -Once the authentication and SDP negotiation is successful, you should start receiving stream at configured `IP:Port`. The generated SDP offer will be saved under `/Documents/bz-squawk-sdpoffer/inputAudio.sdp` You can use this file to verify the streaming. There are a couple of ways to do that: +Once the authenticated and joined the room, there should be SDP negotiation when any Benzinga broadcaster joins in or right away if any active after joined room. SDP offer will use any available port from configured receiver.ports. On successful SDP negotiation, the generated SDP offer will be saved in a file named `input_audio_.sdp` under `/Documents/bz-squawk-sdpoffer`. So if there are multiple active broadcasters, there will be multiple files per broadcaster's session. You can use this file to verify the streaming. There are a couple of ways to do that. - **Using ffmpeg:** This is the preferred way to verify the RTP stream. The idea is to dump the incoming RTP audio stream into the file and play it. @@ -48,6 +47,12 @@ And if you want an output file rotation with segments, for e.g. every 15 minutes ``` sudo ffmpeg -protocol_whitelist file,crypto,udp,rtp -acodec opus -i your-sdp-offer-file.sdp -acodec libopus -f segment -segment_atclocktime 1 -segment_time 900 -reset_timestamps 1 -strftime 1 out-%Y%m%dT%H%M.ogg -```Keep the streaming ON for few minutes to receive several squawks. And then play the output file in any supported player. +``` +Keep the streaming ON for few minutes to receive several squawks. And then play the output file in any supported player. - **Using VLC:**  Open the SDP offer file in the VLC player (Media > Open File) and wait for the next squawk from the Benzinga team. This option will probably work only if the VLC player is on the same machine where the stream is being delivered. + + +## Consuming the Incoming Streams + +Consuming incoming stream mostly include forward/rebroadcast. The squawk RTP client provides [StreamingSessionListener](src/main/java/com/benzinga/squawk/StreamingSessionListener.java), which has callbacks `onBroadcasterJoined` and `onBroadcasterLeft`. It provides the associated [StreamingSession](src/main/java/com/benzinga/squawk/models/StreamingSession.java) for the broadcaster. It contains all the information required to consume/cutoff the stream. diff --git a/examples/rtp-receiver/log4j.properties b/examples/rtp-receiver/log4j.properties deleted file mode 100644 index 5e8724f..0000000 --- a/examples/rtp-receiver/log4j.properties +++ /dev/null @@ -1,10 +0,0 @@ -# Set root category priority to INFO and its only appender to CONSOLE. -log4j.rootCategory=WARN, CONSOLE - -log4j.logger.bz=INFO -log4j.logger.market=INFO - -log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender -log4j.appender.CONSOLE.Threshold=TRACE -log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout -log4j.appender.CONSOLE.layout.ConversionPattern=%d [%t] %p %c:%L %x %m%n diff --git a/examples/rtp-receiver/pom.xml b/examples/rtp-receiver/pom.xml index c573c62..73fffa0 100644 --- a/examples/rtp-receiver/pom.xml +++ b/examples/rtp-receiver/pom.xml @@ -33,7 +33,7 @@ org.java-websocket Java-WebSocket - 1.4.0 + 1.5.1 diff --git a/examples/rtp-receiver/src/main/java/com/benzinga/squawk/SquawkWSClient.java b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/SquawkWSClient.java index a594966..50a34ed 100644 --- a/examples/rtp-receiver/src/main/java/com/benzinga/squawk/SquawkWSClient.java +++ b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/SquawkWSClient.java @@ -1,22 +1,26 @@ package com.benzinga.squawk; +import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStreamReader; import java.net.URI; import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.Paths; +import java.util.HashMap; import java.util.Map; +import java.util.Stack; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.java_websocket.client.WebSocketClient; -import org.java_websocket.drafts.Draft; import org.java_websocket.handshake.ServerHandshake; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.benzinga.squawk.models.ActiveBroadcastersResponse; +import com.benzinga.squawk.models.Broadcaster; +import com.benzinga.squawk.models.StreamingSession; import com.fasterxml.uuid.Generators; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -34,38 +38,72 @@ public class SquawkWSClient extends WebSocketClient { private static final Logger log = LoggerFactory.getLogger(SquawkWSClient.class); private final Gson gson = new GsonBuilder().create(); - private static Config conf; + private final Config conf; + + private final StreamingSessionListener sessionListener; private static final String MESSAGE_TYPE_AUTH = "auth"; - private static final String MESSAGE_TYPE_PING = "ping"; - private static final String MESSAGE_TYPE_SDP_OFFER = "sdp-offer"; + private static final String MESSAGE_TYPE_JOIN_ROOM = "joinRoom"; + private static final String MESSAGE_TYPE_PING = "ping"; + private static final String MESSAGE_TYPE_RECEIVE_MEDIA = "receiveMedia"; private static final String MESSAGE_TYPE_LOGOUT = "logout"; - private static final String MESSAGE_TYPE_MEDIA_OVERRIDE = "media-override"; + private static final String MESSAGE_TYPE_MEDIA_OVERRIDE = "mediaOverride"; + private static final String MESSAGE_TYPE_NEW_PRESENTER_ARRIVED = "newPresenterArrived"; + private static final String MESSAGE_TYPE_PRESENTER_LEFT = "presenterLeft"; + // The retry interval in seconds for reconnecting after WS connection closed unexpectedly. private static final long CONNECTION_RETRY_INTERVAL = 20L; // For what period of time the client should keep retrying at CONNECTION_RETRY_INTERVAL private static final long RETRY_PERIOD = 60L * 15L; ScheduledExecutorService scheduledExecutorService; + + private final Stack availablePorts = new Stack(); + + // Map of broadcasterId:associated StreamingSession + private Map activeStreams = new HashMap(); + + // Map of messageId:broadcasterId of sdp offer + private Map pendingSdpAnswers = new HashMap(); private boolean shouldRetryConnection = true; - public SquawkWSClient(String serverURI) throws URISyntaxException { + public SquawkWSClient(String serverURI, Config conf, StreamingSessionListener sessionListener) throws URISyntaxException { super(new URI(serverURI)); + this.conf = conf; + this.initAvailablePortsStack(conf.getString("receiver.ports").split(",")); + this.sessionListener = sessionListener; this.setConnectionLostTimeout(30); } - public SquawkWSClient( URI serverUri , Draft draft ) { - super( serverUri, draft ); - } - - public SquawkWSClient( URI serverURI ) { + public SquawkWSClient(URI serverURI, Config conf, StreamingSessionListener sessionListener) { super( serverURI ); + this.conf = conf; + this.initAvailablePortsStack(conf.getString("receiver.ports").split(",")); + this.sessionListener = sessionListener; + this.setConnectionLostTimeout(30); } - public SquawkWSClient( URI serverUri, Map httpHeaders ) { + public SquawkWSClient(URI serverUri, Map httpHeaders, Config conf, StreamingSessionListener sessionListener) { super(serverUri, httpHeaders); + this.conf = conf; + this.initAvailablePortsStack(conf.getString("receiver.ports").split(",")); + this.sessionListener = sessionListener; + this.setConnectionLostTimeout(30); } + + private void initAvailablePortsStack(String[] strPorts) { + for (int i = 0; i < strPorts.length; i++) { + try { + int p = Integer.parseInt(strPorts[i]); + this.availablePorts.push(p); + } catch (NumberFormatException e) { + log.error("Error parsing available ports from config", e); + log.info("RECEIVER_PORTS should be comma-separated integer values with no space in between"); + System.exit(0); + } + } + } @Override public void onOpen( ServerHandshake handshakedata ) { @@ -83,36 +121,71 @@ public void onMessage( String message ) { log.info("Message Received {}", message); JsonObject msg = gson.fromJson(message, JsonObject.class); switch (msg.get("type").getAsString()) { - case MESSAGE_TYPE_AUTH: + case MESSAGE_TYPE_AUTH + "Response": if (msg.has("error")) { log.error("Authentication failed {}", msg.get("error").getAsString()); this.closeWS(); } else { - this.sendSdpOffer(sdpOffer()); - log.error("Authentication successful. Sending SDP Offer"); + log.info("Authentication successful. Joining Room."); + this.sendJoinRoomMessage(); } break; - case MESSAGE_TYPE_SDP_OFFER: + case MESSAGE_TYPE_JOIN_ROOM + "Response": + if (msg.has("error")) { + log.error("Joining Room failed {}", msg.get("error").getAsString()); + this.closeWS(); + } else { + log.info("Joined Room successful. Should connect if any active broadcaster found."); + ActiveBroadcastersResponse activeBcasterResp = gson.fromJson(msg, ActiveBroadcastersResponse.class); + activeBcasterResp.getExistingBroadcasters().forEach((broadcaster) -> { + this.sendSdpOffer(generateSdpOffer(broadcaster), broadcaster); + }); + } + break; + case MESSAGE_TYPE_RECEIVE_MEDIA + "Response": if (msg.has("error")) { log.error("Failed to negotiate SDP. Error: {}", msg.get("error").getAsString()); this.closeWS(); } else { + String userId = this.pendingSdpAnswers.remove(msg.get("id").getAsString()); + this.activeStreams.get(userId).setSdpAnswer(msg.get("sdpAnswer").getAsString()); + sessionListener.onBroadcasterJoined(this.activeStreams.get(userId)); log.info("SDP negitiation successfull"); } break; + case MESSAGE_TYPE_NEW_PRESENTER_ARRIVED: + Broadcaster broadcaster = gson.fromJson(msg.get("user").getAsJsonObject(), Broadcaster.class); + this.sendSdpOffer(generateSdpOffer(broadcaster), broadcaster); + break; + case MESSAGE_TYPE_PRESENTER_LEFT: + String userId = msg.get("userId").getAsString(); + StreamingSession endedSession = this.activeStreams.remove(userId); + this.endSession(endedSession); + break; case MESSAGE_TYPE_MEDIA_OVERRIDE: - log.info("Received media-override message. Session ended. Looks like signed in from another session using same API key."); + log.info("Received media-override message. Session ended. Looks like signed in from another session using same API key/token."); this.closeWS(); break; - case MESSAGE_TYPE_PING: + case MESSAGE_TYPE_PING + "Response": log.info("Pong Received"); break; } } + + private void endSession(StreamingSession streamingSession) { + sessionListener.onBroadcasterLeft(streamingSession); + streamingSession.getSdpOfferFile().delete(); + availablePorts.push(streamingSession.getReceiverPort()); + } @Override public void onClose( int code, String reason, boolean remote ) { - log.info( "Connection closed by " + ( remote ? "remote peer" : "us" ) + " Code: " + code + " Reason: " + reason ); + log.info("Connection closed by " + ( remote ? "remote peer" : "us" ) + " Code: " + code + " Reason: " + reason ); + log.info("Cleaning up: Closing active streaming sesions..."); + this.activeStreams.forEach((broadcasterId, streamingSession) -> { + this.endSession(streamingSession); + }); + this.activeStreams.clear(); if (this.shouldRetryConnection) { scheduledExecutorService = Executors.newScheduledThreadPool(1); scheduledExecutorService.scheduleAtFixedRate( @@ -150,7 +223,7 @@ public void sendPing() { private void closeWS() { log.info("Closing WebSocket connection."); - this.shouldRetryConnection= false; + this.shouldRetryConnection= false; this.close(); } @@ -160,17 +233,29 @@ private void sendAuthMessage() { authObj.addProperty("id", Generators.timeBasedGenerator().generate().toString()); authObj.addProperty("role", conf.getString("bz.squawk.role")); authObj.addProperty("type", MESSAGE_TYPE_AUTH); - authObj.addProperty("apikey", conf.getString("bz.squawk.apiKey")); - authObj.addProperty("room", conf.getString("bz.squawk.room")); + authObj.addProperty("apikey", conf.getString("bz.squawk.apiKey")); this.send(authObj.toString()); } - private void sendSdpOffer(String sdpOffer) { + private void sendJoinRoomMessage() { + String room = conf.getString("bz.squawk.room"); + log.info("Joining Room: {}" , room); + JsonObject authObj = new JsonObject(); + authObj.addProperty("id", Generators.timeBasedGenerator().generate().toString()); + authObj.addProperty("type", MESSAGE_TYPE_JOIN_ROOM); + authObj.addProperty("room", conf.getString("bz.squawk.room")); + this.send(authObj.toString()); + } + + private void sendSdpOffer(String sdpOffer, Broadcaster broadcaster) { log.info("Sending SDP Offer"); JsonObject receiveMediaMessage = new JsonObject(); - receiveMediaMessage.addProperty("id", Generators.timeBasedGenerator().generate().toString()); - receiveMediaMessage.addProperty("type", MESSAGE_TYPE_SDP_OFFER); + String messageId = Generators.timeBasedGenerator().generate().toString(); + receiveMediaMessage.addProperty("id", messageId); + receiveMediaMessage.addProperty("type", MESSAGE_TYPE_RECEIVE_MEDIA); receiveMediaMessage.addProperty("sdpOffer", sdpOffer); + receiveMediaMessage.addProperty("userId", broadcaster.getUserId()); + this.pendingSdpAnswers.put(messageId, broadcaster.getUserId()); this.send(receiveMediaMessage.toString()); } @@ -182,28 +267,34 @@ private void sendLogoutMessage() { this.send(logoutMessage.toString()); } - private String sdpOffer() { - if (conf.hasPath("receiver.sdpoffer.file") && !"".equals(conf.getString("receiver.sdpoffer.file"))) { - return this.getSDPOffer(conf.getString("receiver.sdpoffer.file")); - } else { - log.info("Generating a sample SDP Offer using IP {} and Port {}", conf.getString("receiver.ip"), conf.getString("receiver.port")); - log.info("If you want to use your SDP offer, then please set env RECEIVER_SDP_OFFER_FILE"); - String rtpSdpOffer = "v=0\n" + - "t=0 0\n" + - "m=audio " + conf.getString("receiver.port") + " RTP/AVP 98\n" + - "c=IN IP4 " + conf.getString("receiver.ip") + "\n" + - "a=recvonly\n" + - "a=rtpmap:98 opus/48000/2\n" + - "a=fmtp:98 stereo=0; sprop-stereo=0; useinbandfec=1"; - log.info("SDP Offer \n{}", rtpSdpOffer); - this.writeSdpOffertoFile(rtpSdpOffer); - return rtpSdpOffer; - } + private String generateSdpOffer(Broadcaster broadcaster) { + int port = availablePorts.pop(); + log.info("Generating an SDP Offer using IP {} and Port {} for connecting to broadcaster {}", conf.getString("receiver.ip"), port, broadcaster.getUsername()); + String rtpSdpOffer = "v=0\n" + + "t=0 0\n" + + "m=audio " + port + " RTP/AVP 98\n" + + "c=IN IP4 " + conf.getString("receiver.ip") + "\n" + + "a=recvonly\n" + + "a=rtpmap:98 opus/48000/2\n" + + "a=fmtp:98 stereo=0; sprop-stereo=0; useinbandfec=1"; + log.info("SDP Offer \n{}", rtpSdpOffer); + File sdpOfferFile = this.writeSdpOffertoFile(rtpSdpOffer, broadcaster.getUserId()); + StreamingSession streamingSession = new StreamingSession(broadcaster, port, rtpSdpOffer, sdpOfferFile); + activeStreams.put(broadcaster.getUserId(), streamingSession); + return rtpSdpOffer; } - private void writeSdpOffertoFile(String rtpSdpOffer) { + + /** + * + * Write the SDP offer to a file with appending broadcaster id to file name + * @param rtpSdpOffer + * @param broadcasterId + * @return File path + */ + private File writeSdpOffertoFile(String rtpSdpOffer, String broadcasterId) { String path = System.getProperty("user.home") + File.separator + "Documents"; - path += File.separator + "bz-squawk-sdpoffer"; + path += File.separator + "bz-squawk-sdpoffers"; File customDir = new File(path); if (!customDir.exists()) { @@ -211,7 +302,7 @@ private void writeSdpOffertoFile(String rtpSdpOffer) { customDir.mkdirs(); } - File sdpOfferfile = new File(customDir.getPath() + File.separator + "inputAudio.sdp"); + File sdpOfferfile = new File(customDir.getPath() + File.separator + "input_audio_" + broadcasterId + ".sdp"); BufferedWriter writer; try { writer = new BufferedWriter(new FileWriter(sdpOfferfile)); @@ -221,27 +312,65 @@ private void writeSdpOffertoFile(String rtpSdpOffer) { log.info("You can open this file in VLC to play live squawk audio stream"); } catch (IOException e) { log.error("Error occured while writting the SDP offer to file" , e); - } - } - - private String getSDPOffer(String filePath) { - String rtpSdpOffer = ""; - try - { - rtpSdpOffer = new String ( Files.readAllBytes( Paths.get(filePath) ) ); - log.info("SDP Offer from file \n{}", rtpSdpOffer); - } - catch (IOException e) - { - log.error("Error occured while reading the SDP offer from file" , e); - } - return rtpSdpOffer; + } + return sdpOfferfile; } - + public static void main( String[] args ) throws URISyntaxException { - conf = ConfigFactory.load(); + Map activeFfpmegProcesses = new HashMap(); + Config conf = ConfigFactory.load(); log.info("Squawk Address : {}", conf.getString("bz.squawk.addr")); - SquawkWSClient c = new SquawkWSClient(conf.getString("bz.squawk.addr")); // more about drafts here: http://github.com/TooTallNate/Java-WebSocket/wiki/Drafts + SquawkWSClient c = new SquawkWSClient(conf.getString("bz.squawk.addr"), conf, new StreamingSessionListener(){ + + @Override + public void onBroadcasterLeft(StreamingSession streamingSession) { + + // disconnect the stream + log.info("Broadcaster: {} left. Incoming stream on port {} cutoff.", streamingSession.getBroadcaster().getUsername(), streamingSession.getReceiverPort()); + + // stopping ffmpeg to save the stream + Process p =activeFfpmegProcesses.remove(streamingSession.getBroadcaster().getUserId()); + p.destroy(); + + } + + @Override + public void onBroadcasterJoined(StreamingSession streamingSession) { + + // connect stream further + log.info("New broadcaster: {} joined. Incoming stream on port {}", streamingSession.getBroadcaster().getUsername(), streamingSession.getReceiverPort()); + + // starting ffmpeg to save the stream + String outputFile = System.getProperty("user.home") + "/out_" + streamingSession.getBroadcaster().getUsername() + "_" + System.currentTimeMillis() +".ogg"; + String ffmpegCmd = "ffmpeg -protocol_whitelist file,crypto,udp,rtp -acodec opus -i " + + streamingSession.getSdpOfferFile().getPath() + + " -acodec libopus " + + outputFile; + + log.info("Running command > {} ", ffmpegCmd); + + try { + Process p = Runtime.getRuntime().exec(ffmpegCmd); + activeFfpmegProcesses.put(streamingSession.getBroadcaster().getUserId(), p); + log.info("Incoming stream being saved into file {}", outputFile); + + new Thread(new Runnable() { + @Override + public void run() { + BufferedReader lineReader = new BufferedReader(new InputStreamReader(p.getInputStream())); + lineReader.lines().forEach(log::info); + + BufferedReader errorReader = new BufferedReader(new InputStreamReader(p.getErrorStream())); + errorReader.lines().forEach(log::error); + } + }).start(); + + } catch (IOException e) { + log.error("Unable to record and save incoming RTP stream", e); + } + + } + }); c.connect(); Runtime.getRuntime().addShutdownHook(new Thread() { @@ -250,7 +379,7 @@ public void run() if (c.isOpen()) { log.info("Shutting down WebSocket Client!"); c.sendLogoutMessage(); - c.close(); + c.closeWS(); } } }); diff --git a/examples/rtp-receiver/src/main/java/com/benzinga/squawk/StreamingSessionListener.java b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/StreamingSessionListener.java new file mode 100644 index 0000000..74466ea --- /dev/null +++ b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/StreamingSessionListener.java @@ -0,0 +1,21 @@ +package com.benzinga.squawk; + +import com.benzinga.squawk.models.StreamingSession; + +/** + * Callbacks on event of a new Broadcaster joins or leave * + */ +public interface StreamingSessionListener { + + /** + * + * @param streamingSession {@link StreamingSession} of new broadcaster + */ + public void onBroadcasterJoined(StreamingSession streamingSession); + + /** + * + * @param streamingSession {@link StreamingSession} of broadcaster left + */ + public void onBroadcasterLeft(StreamingSession streamingSession); +} diff --git a/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/ActiveBroadcastersResponse.java b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/ActiveBroadcastersResponse.java new file mode 100644 index 0000000..0c3bedf --- /dev/null +++ b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/ActiveBroadcastersResponse.java @@ -0,0 +1,20 @@ +package com.benzinga.squawk.models; + +import java.util.List; +import com.google.gson.annotations.SerializedName; + +public class ActiveBroadcastersResponse extends Response { + + @SerializedName("existingPresenters") + private List broadcasters; + + public ActiveBroadcastersResponse(String id, String type, List broadcasters) { + super(id, type); + this.broadcasters = broadcasters; + } + + public List getExistingBroadcasters() { + return broadcasters; + } + +} \ No newline at end of file diff --git a/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/Broadcaster.java b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/Broadcaster.java new file mode 100644 index 0000000..01509e8 --- /dev/null +++ b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/Broadcaster.java @@ -0,0 +1,20 @@ +package com.benzinga.squawk.models; + +public class Broadcaster { + private String userId; + private String username; + + public Broadcaster(String userId, String username) { + this.userId = userId; + this.username = username; + } + + public String getUserId() { + return userId; + } + + public String getUsername() { + return username; + } + +} diff --git a/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/Response.java b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/Response.java new file mode 100644 index 0000000..0831cf7 --- /dev/null +++ b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/Response.java @@ -0,0 +1,20 @@ +package com.benzinga.squawk.models; + +public class Response { + private String id; + private String type; + + public Response(String id, String type) { + this.id = id; + this.type = type + "Response"; + } + + public String getId() { + return id; + } + + public String getType() { + return type; + } + +} diff --git a/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/StreamingSession.java b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/StreamingSession.java new file mode 100644 index 0000000..f0d33b4 --- /dev/null +++ b/examples/rtp-receiver/src/main/java/com/benzinga/squawk/models/StreamingSession.java @@ -0,0 +1,47 @@ +package com.benzinga.squawk.models; + +import java.io.File; + +public class StreamingSession { + private Broadcaster broadcaster; + private int receiverPort; + private String sdpOffer; + private String sdpAnswer; + private File sdpOfferFile; + + public StreamingSession(Broadcaster broadcaster, int receiverPort, String sdpOffer, File sdpOfferFile) { + this.broadcaster = broadcaster; + this.receiverPort = receiverPort; + this.sdpOffer = sdpOffer; + this.sdpOfferFile = sdpOfferFile; + } + + public String getSdpOffer() { + return sdpOffer; + } + + public void setSdpOffer(String sdpOffer) { + this.sdpOffer = sdpOffer; + } + + public String getSdpAnswer() { + return sdpAnswer; + } + + public void setSdpAnswer(String sdpAnswer) { + this.sdpAnswer = sdpAnswer; + } + + public Broadcaster getBroadcaster() { + return broadcaster; + } + + public int getReceiverPort() { + return receiverPort; + } + + public File getSdpOfferFile() { + return sdpOfferFile; + } + +} diff --git a/examples/rtp-receiver/src/main/resources/application.conf b/examples/rtp-receiver/src/main/resources/application.conf index 9625b96..73bf94a 100644 --- a/examples/rtp-receiver/src/main/resources/application.conf +++ b/examples/rtp-receiver/src/main/resources/application.conf @@ -8,7 +8,5 @@ bz.squawk.addr = "" bz.squawk.addr = ${?BZ_SQUAWK_ADDR} receiver.ip = 127.0.0.1 receiver.ip = ${?RECEIVER_IP} -receiver.port = 8449 -receiver.port = ${?RECEIVER_PORT} -receiver.sdpoffer.file = "" -receiver.sdpoffer.file = ${?RECEIVER_SDP_OFFER_FILE} \ No newline at end of file +receiver.ports = "8245,8345,8445,8545,8645" +receiver.ports = ${?RECEIVER_PORTS} \ No newline at end of file diff --git a/examples/rtp-receiver/src/main/resources/log4j.properties b/examples/rtp-receiver/src/main/resources/log4j.properties index d8bd1e4..a2897e2 100644 --- a/examples/rtp-receiver/src/main/resources/log4j.properties +++ b/examples/rtp-receiver/src/main/resources/log4j.properties @@ -1,7 +1,7 @@ # Set root category priority to INFO and its only appender to CONSOLE. #log4j.rootCategory=WARN, CONSOLE, INFO -log4j.rootCategory=INFO, console +log4j.rootCategory=DEBUG, console log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.Target=System.out