Skip to content

Commit

Permalink
added hangup
Browse files Browse the repository at this point in the history
  • Loading branch information
olofkallander committed Dec 3, 2024
1 parent f901dee commit a27d12f
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 55 deletions.
1 change: 1 addition & 0 deletions examples/simpleclient/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<table>
<tr>
<td id="joincell"><button id="join">Join</button></td>
<td><button id="hangup">Hangup</button></td>
</tr>
<tr>
<td>My endpoint id: <label id="endpointId"></label></td>
Expand Down
154 changes: 132 additions & 22 deletions examples/simpleclient/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,20 @@ let peerConnection: RTCPeerConnection|undefined = undefined
let localMediaStream: MediaStream|undefined = undefined;
let localDataChannel: RTCDataChannel|undefined = undefined;
let endpointId: string|undefined = undefined;
let conferenceId: string|undefined = undefined;
let remoteMediaStreams: Set<string> = new Set();

const serverUrl = 'https://localhost:8081/conferences/';

interface UserVideoMapItem
{
ssrc: number;
ssrc: Number;
msid: String;
element: HTMLVideoElement;
}

let receivers = new Map<string, UserVideoMapItem>();
let keepPolling = true;

// Keeps a long-poll running for simpleserver to simpleclient communication
async function startPoll()
Expand All @@ -41,7 +43,10 @@ async function startPoll()
return;
}

startPoll();
if (keepPolling)
{
startPoll();
}
}

async function onPollMessage(resultJson: any)
Expand Down Expand Up @@ -121,12 +126,71 @@ function onTrack(event: RTCTrackEvent)
videoElement.height = 180;
videoElement.muted = false;
videoElementsDiv.appendChild(videoElement);
receivers.set(event.track.id, {ssrc : 0, msid : event.track.id as String, element : videoElement});
var mapItem: UserVideoMapItem = {
ssrc : 0, // not available anyway
msid : event.track.id as String,
element : videoElement
};

receivers.set(event.track.id, mapItem);
console.log('Added video element ' + stream.id);
}
}
}

function getSsrcOfVideoMsid(trackId: String): Number
{
var rtpReceivers = peerConnection.getReceivers();
for (var rtpReceiver of rtpReceivers)
{
var ssrcs = rtpReceiver.getSynchronizationSources();
if (ssrcs.length == 0 || rtpReceiver.track.kind != "video")
{
continue;
}

if (rtpReceiver.track.label == trackId)
{
return ssrcs[0].source;
}
}
return null;
}

function getVideoElementBySsrc(ssrc: Number): HTMLVideoElement
{
var rtpReceivers = peerConnection.getReceivers();
for (var rtpReceiver of rtpReceivers)
{
var ssrcs = rtpReceiver.getSynchronizationSources();
if (ssrcs.length == 0 || rtpReceiver.track.kind != "video")
{
continue;
}

if (ssrcs[0].source == ssrc)
{
var mapItem = receivers.get(rtpReceiver.track.label);
return mapItem.element;
}
}
return null;
}

function getAllUserMapSsrcs(umap: any): Set<Number>
{
var s = new Set<Number>();
for (var endpoint of umap.endpoints)
{
for (var ssrc of endpoint.ssrcs)
{
s.add(ssrc);
}
}

return s;
}

function onDataChannelMessage(event: MessageEvent<any>)
{
console.log('onDataChannelMessage ' + event.data);
Expand All @@ -147,31 +211,41 @@ function onDataChannelMessage(event: MessageEvent<any>)
}
else if (message.type === 'UserMediaMap')
{
/* var activeUsers = getAllUserMapSsrcs(message);
for (var v of videoElementsDiv.children)
{
const ssrc = v.getAttribute("custom_ssrc");
if (ssrc != null && !(ssrc in activeUsers))
{
var videoElem = v as HTMLVideoElement;
videoElem.currentTime = 0;
}
}*/

for (const endpoint of message.endpoints)
{
for (var ssrc of endpoint.ssrcs)
{
console.log("ssrc {} speaking", ssrc)
console.log("ssrc speaking", ssrc)

var rtpReceivers = peerConnection.getReceivers();
for (var rtpReceiver of rtpReceivers)
var videoElement = getVideoElementBySsrc(ssrc);
/*if (videoElement.getAttribute("custom_ssrc") == null)
{
var ssrcs = rtpReceiver.getSynchronizationSources();
if (ssrcs.length == 0 || rtpReceiver.track.kind != "video")
{
continue;
}

if (ssrcs[0].source == ssrc)
{
var mapItem = receivers.get(rtpReceiver.track.label);
if (videoElementsDiv.firstChild != mapItem.element)
{
videoElementsDiv.removeChild(mapItem.element);
videoElementsDiv.insertBefore(mapItem.element, videoElementsDiv.firstChild);
}
return;
}
videoElement.setAttribute("custom_ssrc", ssrc.toString());
}*/

if (videoElement && videoElementsDiv.firstChild != videoElement)
{
videoElementsDiv.removeChild(videoElement);
var speaker = videoElementsDiv.firstChild as HTMLVideoElement
speaker.width = 320;
speaker.height = 180;
videoElementsDiv.insertBefore(videoElement, videoElementsDiv.firstChild);
var speaker = videoElementsDiv.firstChild as HTMLVideoElement
speaker.width = 640;
speaker.height = 360;

return;
}
}

Expand Down Expand Up @@ -224,7 +298,9 @@ async function joinClicked()
console.log('Join result ' + JSON.stringify(resultJson));

endpointId = resultJson.endpointId;
conferenceId = resultJson
endpointIdLabel.innerText = endpointId;
keepPolling = true;
startPoll()
}

Expand Down Expand Up @@ -287,11 +363,45 @@ async function listVideoDevices()
}
}

async function hangupClicked()
{
keepPolling = false;
const url = serverUrl + 'endpoints/' + endpointId + '/actions';
const body = {type : 'hangup'};

const requestInit: RequestInit = {method : 'POST', mode : 'cors', cache : 'no-store', body : JSON.stringify(body)};
const request = new Request(url, requestInit);
const result = await fetch(request);

console.log('hangup result ' + result.status);

localMediaStream.getTracks().forEach(function(track) { track.stop() })
localMediaStream = null;
localDataChannel.close();
localDataChannel.onmessage = null;
localDataChannel = null;
peerConnection.ontrack = null;
peerConnection.onicegatheringstatechange = null;
peerConnection.ondatachannel = null;
remoteMediaStreams.clear();
peerConnection.close();
peerConnection = null;

const localVideo = document.getElementById("localVideo") as HTMLVideoElement;
localVideo.srcObject = null;

audioElementsDiv.textContent = '';
videoElementsDiv.textContent = '';
}

async function main()
{
var joinButton = document.getElementById('join') as HTMLButtonElement;
joinButton.onclick = joinClicked;

var hangupButton = document.getElementById('hangup') as HTMLButtonElement;
hangupButton.onclick = hangupClicked;

await listAudioDevices();
await listVideoDevices();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ public synchronized boolean message(String endpointId, String messageString)
{
return onAnswer(endpointId, message);
}
else if (message.type.equals("hangup"))
{
return onHangup(endpointId);
}

return false;
}
Expand Down Expand Up @@ -170,6 +174,28 @@ else if (mediaDescription.type == MediaDescription.Type.VIDEO)
return true;
}

private boolean onHangup(String endpointId)
throws ParserFailedException, IOException, InterruptedException, ParseException
{
final var endpoint = endpoints.get(endpointId);
if (endpoint == null)
{
return false;
}
endpoints.remove(endpointId);
messageQueues.remove(endpointId);
try
{
symphonyMediaBridge.deleteEndpoint(conferenceId, endpointId);
return true;
}
catch (IOException | ParseException e)
{
LOGGER.error("Error deleting endpoint ", e);
return false;
}
}

public String poll(String endpointId) throws InterruptedException
{
final var queue = messageQueues.get(endpointId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,48 @@
package com.symphony.simpleserver.httpClient;

import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.hc.client5.http.classic.methods.HttpDelete;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class HttpClient {
public static class ResponsePair {
public class HttpClient
{
public static class ResponsePair
{
public final int statusCode;
public final String body;

public ResponsePair(int statusCode, String body) {
public ResponsePair(int statusCode, String body)
{
this.statusCode = statusCode;
this.body = body;
}
}

private final CloseableHttpClient httpClient;

HttpClient(CloseableHttpClient httpClient) {
this.httpClient = httpClient;
}
HttpClient(CloseableHttpClient httpClient) { this.httpClient = httpClient; }

public ResponsePair post(String url, JsonNode data) throws IOException, ParseException {
public ResponsePair post(String url, JsonNode data) throws IOException, ParseException
{
final var request = new HttpPost(url);
request.addHeader("Content-Type", "application/json");

final var stringEntity = new StringEntity(data.toString(), StandardCharsets.UTF_8);
request.setEntity(stringEntity);

try {
try (var httpResponse = httpClient.execute(request)) {
try
{
try (var httpResponse = httpClient.execute(request))
{
final var statusCode = httpResponse.getCode();
if (statusCode == 204) {
if (statusCode == 204)
{
return new ResponsePair(statusCode, null);
}

Expand All @@ -46,9 +51,31 @@ public ResponsePair post(String url, JsonNode data) throws IOException, ParseExc
EntityUtils.consumeQuietly(httpEntity);
return new ResponsePair(statusCode, responseBody);
}

} finally {
}
finally
{
EntityUtils.consumeQuietly(stringEntity);
}
}

public ResponsePair delete(String url)throws IOException, ParseException
{
final var request = new HttpDelete(url);

try (var httpResponse = httpClient.execute(request))
{
final var statusCode = httpResponse.getCode();
if (statusCode == 204)
{
return new ResponsePair(statusCode, null);
}

final var httpEntity = httpResponse.getEntity();
EntityUtils.consumeQuietly(httpEntity);
return new ResponsePair(statusCode, null);
}
finally
{
}
}
}
Loading

0 comments on commit a27d12f

Please sign in to comment.