This is an automated email from the ASF dual-hosted git repository. solomax pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/openmeetings.git
The following commit(s) were added to refs/heads/master by this push: new 5608cbf [OPENMEETINGS-2239] another attempt to make 'softphone -> browser' work 5608cbf is described below commit 5608cbfee7be52e625f0197f1dbad0d53f1421e9 Author: Maxim Solodovnik <solomax...@gmail.com> AuthorDate: Tue Dec 22 21:40:51 2020 +0700 [OPENMEETINGS-2239] another attempt to make 'softphone -> browser' work --- .../openmeetings/core/remote/AbstractStream.java | 12 +- .../org/apache/openmeetings/core/remote/KRoom.java | 26 ++-- .../apache/openmeetings/core/remote/KStream.java | 140 ++++++++++++--------- .../openmeetings/core/remote/KTestStream.java | 4 +- .../openmeetings/core/sip/ISipCallbacks.java | 4 +- .../apache/openmeetings/core/sip/SipManager.java | 47 ++++--- .../openmeetings/core/sip/SipStackProcessor.java | 18 +-- .../openmeetings/core/remote/BaseMockedTest.java | 3 +- .../src/site/markdown/AsteriskIntegration.md | 1 - .../web/admin/connection/KStreamDto.java | 40 +++--- .../apache/openmeetings/web/app/TimerService.java | 3 +- .../org/apache/openmeetings/web/room/raw-room.js | 28 +++-- 12 files changed, 181 insertions(+), 145 deletions(-) diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/AbstractStream.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/AbstractStream.java index cfc18d4..2dd7230 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/AbstractStream.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/AbstractStream.java @@ -48,8 +48,16 @@ public abstract class AbstractStream { public abstract void release(boolean remove); - public static WebRtcEndpoint createWebRtcEndpoint(MediaPipeline pipeline) { - return new WebRtcEndpoint.Builder(pipeline).build(); + public static WebRtcEndpoint createWebRtcEndpoint(MediaPipeline pipeline, Boolean send) { + WebRtcEndpoint.Builder builder = new WebRtcEndpoint.Builder(pipeline); + if (send != null) { + if (send) { + builder.sendonly(); + } else { + builder.recvonly(); + } + } + return builder.build(); } public static RecorderEndpoint createRecorderEndpoint(MediaPipeline pipeline, String path, MediaProfileSpecType profile) { diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java index 2062c5b..bc90f9b 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KRoom.java @@ -1,7 +1,4 @@ /* - * (C) Copyright 2014 Kurento (http://kurento.org/) - */ -/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -52,15 +49,12 @@ import org.slf4j.LoggerFactory; import com.github.openjson.JSONObject; /** - * Bean object dynamically created representing a conference room on the MediaServer + * Dynamically created object representing a conference room on the MediaServer * */ public class KRoom { private static final Logger log = LoggerFactory.getLogger(KRoom.class); - /** - * Not injected by annotation but by constructor. - */ private final StreamProcessor processor; private final RecordingChunkDao chunkDao; private final Room room; @@ -104,8 +98,6 @@ public class KRoom { .put("uid", stream.getUid()) .toString() ); - //FIXME TODO check close on stop sharing - //FIXME TODO permission can be removed, some listener might be required } public boolean isRecording() { @@ -251,8 +243,22 @@ public class KRoom { public void updateSipCount(final long count) { if (count != sipCount) { - sipCount = count; processor.getByRoom(room.getId()).forEach(stream -> stream.addSipProcessor(count)); + if (sipCount == 0) { + processor.getClientManager() + .streamByRoom(room.getId()) + .filter(Client::isSip) + .findAny() + .ifPresent(c -> { + StreamDesc sd = c.addStream(StreamType.WEBCAM, Activity.AUDIO, Activity.VIDEO); // TODO check this + sd.setWidth(120).setHeight(90); + c.restoreActivities(sd); + KStream stream = join(sd, processor.getHandler()); + stream.startBroadcast(sd, "", () -> {}); + processor.getClientManager().update(c); + }); + } + sipCount = count; } } diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java index c7fb37a..ffd91e1 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KStream.java @@ -40,6 +40,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import org.apache.openmeetings.core.sip.ISipCallbacks; import org.apache.openmeetings.core.sip.SipStackProcessor; @@ -52,6 +53,7 @@ import org.apache.openmeetings.db.entity.record.RecordingChunk.Type; import org.apache.openmeetings.db.util.ws.RoomMessage; import org.apache.openmeetings.db.util.ws.TextRoomMessage; import org.apache.openmeetings.util.OmFileHelper; +import org.kurento.client.BaseRtpEndpoint; import org.kurento.client.Continuation; import org.kurento.client.IceCandidate; import org.kurento.client.ListenerSubscription; @@ -60,6 +62,7 @@ import org.kurento.client.MediaObject; import org.kurento.client.MediaPipeline; import org.kurento.client.MediaProfileSpecType; import org.kurento.client.MediaType; +import org.kurento.client.OfferOptions; import org.kurento.client.RecorderEndpoint; import org.kurento.client.RtpEndpoint; import org.kurento.client.WebRtcEndpoint; @@ -79,7 +82,7 @@ public class KStream extends AbstractStream implements ISipCallbacks { private MediaProfileSpecType profile; private MediaPipeline pipeline; private RecorderEndpoint recorder; - private WebRtcEndpoint outgoingMedia = null; + private BaseRtpEndpoint outgoingMedia = null; private RtpEndpoint rtpEndpoint; private Optional<SipStackProcessor> sipProcessor = Optional.empty(); private final ConcurrentMap<String, WebRtcEndpoint> listeners = new ConcurrentHashMap<>(); @@ -143,7 +146,13 @@ public class KStream extends AbstractStream implements ISipCallbacks { pipeline = kHandler.createPipiline(Map.of(TAG_ROOM, String.valueOf(getRoomId()), TAG_STREAM_UID, sd.getUid()), new Continuation<Void>() { @Override public void onSuccess(Void result) throws Exception { - internalStartBroadcast(sd, sdpOffer); + if (sipClient) { + addSipProcessor(1); + } else { + outgoingMedia = createEndpoint(sd.getSid(), sd.getUid(), true); + internalStartBroadcast(sd, sdpOffer); + notifyOnNewStream(sd); + } then.run(); } @@ -155,10 +164,10 @@ public class KStream extends AbstractStream implements ISipCallbacks { } private void internalStartBroadcast(final StreamDesc sd, final String sdpOffer) throws Exception { - outgoingMedia = createEndpoint(sd.getSid(), sd.getUid()); outgoingMedia.addMediaSessionTerminatedListener(evt -> log.warn("Media stream terminated {}", sd)); flowoutSubscription = outgoingMedia.addMediaFlowOutStateChangeListener(evt -> { - log.info("Media Flow STATE :: {}, type {}, evt {}", evt.getState(), evt.getType(), evt.getMediaType()); + log.info("Media Flow OUT STATE :: {}, evt {}, source {}" + , evt.getState(), evt.getMediaType(), evt.getSource()); if (MediaFlowState.NOT_FLOWING == evt.getState()) { log.warn("FlowOut Future is created"); flowoutFuture = Optional.of(new CompletableFuture<>().completeAsync(() -> { @@ -173,12 +182,18 @@ public class KStream extends AbstractStream implements ISipCallbacks { dropFlowoutFuture(); } }); - outgoingMedia.addMediaFlowInStateChangeListener(evt -> log.warn("Media FlowIn :: {}", evt)); - addListener(sd.getSid(), sd.getUid(), sdpOffer); - addSipProcessor(kRoom.getSipCount()); + outgoingMedia.addMediaFlowInStateChangeListener(evt -> log.warn("Media Flow IN :: {}, {}, {}" + , evt.getState(), evt.getMediaType(), evt.getSource())); + if (!sipClient) { + addListener(sd.getSid(), sd.getUid(), sdpOffer); + addSipProcessor(kRoom.getSipCount()); + } if (kRoom.isRecording()) { startRecord(); } + } + + private void notifyOnNewStream(final StreamDesc sd) { Client c = sd.getClient(); WebSocketHelper.sendRoom(new TextRoomMessage(c.getRoomId(), c, RoomMessage.Type.RIGHT_UPDATED, c.getUid())); if (hasAudio || hasVideo || hasScreen) { @@ -213,11 +228,13 @@ public class KStream extends AbstractStream implements ISipCallbacks { return; } - final WebRtcEndpoint endpoint = getEndpointForUser(sid, uid); + final BaseRtpEndpoint endpoint = getEndpointForUser(sid, uid); final String sdpAnswer = endpoint.processOffer(sdpOffer); - log.debug("gather candidates"); - endpoint.gatherCandidates(); // this one might throw Exception + if (endpoint instanceof WebRtcEndpoint) { + log.debug("gather candidates"); + ((WebRtcEndpoint)endpoint).gatherCandidates(); // this one might throw Exception + } log.trace("USER {}: SdpAnswer is {}", this.uid, sdpAnswer); kHandler.sendClient(sid, newKurentoMsg() .put("id", "videoResponse") @@ -225,7 +242,7 @@ public class KStream extends AbstractStream implements ISipCallbacks { .put("sdpAnswer", sdpAnswer)); } - private WebRtcEndpoint getEndpointForUser(String sid, String uid) { + private BaseRtpEndpoint getEndpointForUser(String sid, String uid) { if (uid.equals(this.uid)) { log.debug("PARTICIPANT {}: configuring loopback", this.uid); return outgoingMedia; @@ -238,7 +255,7 @@ public class KStream extends AbstractStream implements ISipCallbacks { listener.release(); } log.debug("PARTICIPANT {}: creating new endpoint for {}", uid, this.uid); - listener = createEndpoint(sid, uid); + listener = createEndpoint(sid, uid, false); listeners.put(uid, listener); log.debug("PARTICIPANT {}: obtained endpoint for {}", uid, this.uid); @@ -266,14 +283,16 @@ public class KStream extends AbstractStream implements ISipCallbacks { endpoint.addTag("uid", uid); } - private RtpEndpoint getRtpEndpoint(MediaPipeline pipeline) { - RtpEndpoint endpoint = new RtpEndpoint.Builder(pipeline).build(); + private RtpEndpoint getRtpEndpoint(MediaPipeline pipeline, String direction) { + RtpEndpoint endpoint = new RtpEndpoint.Builder(pipeline) + //.withProperties(Properties.of(direction, Boolean.TRUE)) + .build(); setTags(endpoint, uid); return endpoint; } - private WebRtcEndpoint createEndpoint(String sid, String uid) { - WebRtcEndpoint endpoint = createWebRtcEndpoint(pipeline); + private WebRtcEndpoint createEndpoint(String sid, String uid, boolean send) { + WebRtcEndpoint endpoint = createWebRtcEndpoint(pipeline, send); setTags(endpoint, uid); endpoint.addIceCandidateFoundListener(evt -> kHandler.sendClient(sid @@ -475,10 +494,10 @@ public class KStream extends AbstractStream implements ISipCallbacks { public void addCandidate(IceCandidate candidate, String uid) { if (this.uid.equals(uid)) { - if (outgoingMedia == null) { + if (outgoingMedia == null || !(outgoingMedia instanceof WebRtcEndpoint)) { return; } - outgoingMedia.addIceCandidate(candidate); + ((WebRtcEndpoint)outgoingMedia).addIceCandidate(candidate); } else { WebRtcEndpoint endpoint = listeners.get(uid); log.debug("Add candidate for {}, listener found ? {}", uid, endpoint != null); @@ -488,46 +507,14 @@ public class KStream extends AbstractStream implements ISipCallbacks { } } - void addSipProcessor(long count) { - if (count > 0) { - if (sipProcessor.isEmpty()) { - try { - sipProcessor = kHandler.getSipManager().createSipStackProcessor( - randomUUID().toString() - , kRoom.getRoom() - , this); - sipProcessor.ifPresent(SipStackProcessor::register); - } catch (Exception e) { - log.error("Unexpected error while creating SipProcessor", e); - } - } - } else { - releaseRtp(); - } - } - private static JSONObject convert(com.google.gson.JsonObject o) { return new JSONObject(o.toString()); } - @Override - public String getSid() { - return sid; - } - - @Override - public String getUid() { - return uid; - } - public Date getConnectedSince() { return connectedSince; } - public KRoom getKRoom() { - return kRoom; - } - public Long getRoomId() { return kRoom.getRoom().getId(); } @@ -548,10 +535,6 @@ public class KStream extends AbstractStream implements ISipCallbacks { return recorder; } - public WebRtcEndpoint getOutgoingMedia() { - return outgoingMedia; - } - public Long getChunkId() { return chunkId; } @@ -571,26 +554,61 @@ public class KStream extends AbstractStream implements ISipCallbacks { + flowoutFuture + ", chunkId=" + chunkId + ", type=" + type + ", sid=" + sid + ", uid=" + uid + "]"; } + void addSipProcessor(long count) { + if (count > 0) { + if (sipProcessor.isEmpty()) { + try { + sipProcessor = kHandler.getSipManager().createSipStackProcessor( + randomUUID().toString() + , kRoom.getRoom() + , this); + sipProcessor.ifPresent(SipStackProcessor::register); + } catch (Exception e) { + log.error("Unexpected error while creating SipProcessor", e); + } + } + } else { + if (sipClient) { + release(); + } else { + releaseRtp(); + } + } + } + @Override public void onRegisterOk() { - if (sipClient) { - - } else { - rtpEndpoint = getRtpEndpoint(pipeline); + rtpEndpoint = getRtpEndpoint(pipeline, sipClient ? "recvonly" : "sendonly"); + OfferOptions options = new OfferOptions(); + options.setOfferToReceiveAudio(hasAudio); + options.setOfferToReceiveVideo(hasVideo); + String offer = null; + if (!sipClient) { + offer = rtpEndpoint.generateOffer(options); if (hasAudio) { outgoingMedia.connect(rtpEndpoint, MediaType.AUDIO); } if (hasVideo) { outgoingMedia.connect(rtpEndpoint, MediaType.VIDEO); } - sipProcessor.get().invite(kRoom.getRoom(), rtpEndpoint.generateOffer()); } + sipProcessor.get().invite(kRoom.getRoom(), offer); } @Override - public void onInviteOk(String sdp) { + public void onInviteOk(String sdp, Consumer<String> answerConsumer) { if (sipClient) { - + String answer = rtpEndpoint.processOffer(sdp); + answerConsumer.accept(answer); + log.debug(answer); + StreamDesc sd = kHandler.getStreamProcessor().getBySid(sid).getStream(uid); + try { + outgoingMedia = rtpEndpoint; + internalStartBroadcast(sd, sdp); + notifyOnNewStream(sd); + } catch (Exception e) { + log.error("Unexpected error"); + } } else { rtpEndpoint.processAnswer(sdp); } diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java index 6949528..741c1f6 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/remote/KTestStream.java @@ -72,7 +72,7 @@ public class KTestStream extends AbstractStream { } private void startTestRecording(IWsClient c, JSONObject msg) { - webRtcEndpoint = createWebRtcEndpoint(pipeline); + webRtcEndpoint = createWebRtcEndpoint(pipeline, null); webRtcEndpoint.connect(webRtcEndpoint); MediaProfileSpecType profile = getProfile(msg); @@ -134,7 +134,7 @@ public class KTestStream extends AbstractStream { public void play(final IWsClient inClient, JSONObject msg) { createPipeline(() -> { - webRtcEndpoint = createWebRtcEndpoint(pipeline); + webRtcEndpoint = createWebRtcEndpoint(pipeline, true); player = createPlayerEndpoint(pipeline, recPath); player.connect(webRtcEndpoint); webRtcEndpoint.addMediaSessionStartedListener(evt -> { diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/ISipCallbacks.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/ISipCallbacks.java index a04f275..b476c8a 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/ISipCallbacks.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/ISipCallbacks.java @@ -18,7 +18,9 @@ */ package org.apache.openmeetings.core.sip; +import java.util.function.Consumer; + public interface ISipCallbacks { void onRegisterOk(); - void onInviteOk(String sdp); + void onInviteOk(String sdp, Consumer<String> answerConsumer); } diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java index ac8fc06..a95e419 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipManager.java @@ -26,6 +26,7 @@ import java.util.Optional; import java.util.function.Function; import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; import org.apache.openmeetings.db.entity.room.Room; import org.apache.openmeetings.db.entity.user.User; @@ -35,6 +36,7 @@ import org.apache.wicket.util.string.Strings; import org.asteriskjava.manager.DefaultManagerConnection; import org.asteriskjava.manager.ManagerConnection; import org.asteriskjava.manager.ManagerConnectionFactory; +import org.asteriskjava.manager.ManagerConnectionState; import org.asteriskjava.manager.ResponseEvents; import org.asteriskjava.manager.action.ConfbridgeListAction; import org.asteriskjava.manager.action.DbDelAction; @@ -85,6 +87,7 @@ public class SipManager implements ISipManager { private int maxLocalWsPort = 7666; private ManagerConnectionFactory factory; + private ManagerConnection con; private String sipUserPicture; private BitSet ports; @@ -100,13 +103,23 @@ public class SipManager implements ISipManager { } } - private ManagerConnection getConnection() { - DefaultManagerConnection con = (DefaultManagerConnection)factory.createManagerConnection(); - con.setDefaultEventTimeout(managerTimeout); - con.setDefaultResponseTimeout(managerTimeout); - con.setSocketReadTimeout((int)managerTimeout); - con.setSocketTimeout((int)managerTimeout); - return con; + @PreDestroy + public void destroy() { + if (con != null) { + con.logoff(); + } + } + + private void connectManager() throws Exception { + if (con == null || ManagerConnectionState.CONNECTED != con.getState()) { + DefaultManagerConnection defCon = (DefaultManagerConnection)factory.createManagerConnection(); + defCon.setDefaultEventTimeout(managerTimeout); + defCon.setDefaultResponseTimeout(managerTimeout); + defCon.setSocketReadTimeout((int)managerTimeout); + defCon.setSocketTimeout((int)managerTimeout); + con = defCon; + con.login("on"); + } } private ManagerResponse exec(ManagerAction action) { @@ -114,9 +127,8 @@ public class SipManager implements ISipManager { log.warn("There is no Asterisk configured"); return null; } - ManagerConnection con = getConnection(); try { - con.login(); + connectManager(); ManagerResponse r = con.sendAction(action); if (r != null) { log.debug("{}", r); @@ -124,12 +136,6 @@ public class SipManager implements ISipManager { return (r instanceof ManagerError) ? null : r; } catch (Exception e) { log.error("Error while executing ManagerAction: {}", action, e); - } finally { - try { - con.logoff(); - } catch (Exception e) { - // no-op - } } return null; } @@ -139,22 +145,15 @@ public class SipManager implements ISipManager { log.warn("There is no Asterisk configured"); return null; } - ManagerConnection con = getConnection(); try { - con.login("on"); + connectManager(); ResponseEvents r = con.sendEventGeneratingAction(action); if (r != null) { - log.debug("{}", r.getResponse()); + log.trace("{}", r.getResponse()); } return (r == null || r.getResponse() instanceof ManagerError) ? null : r; } catch (Exception e) { log.error("Error while executing EventGeneratingAction: {}", action, e); - } finally { - try { - con.logoff(); - } catch (Exception e) { - // no-op - } } return null; } diff --git a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipStackProcessor.java b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipStackProcessor.java index 31a1941..dc22235 100644 --- a/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipStackProcessor.java +++ b/openmeetings-core/src/main/java/org/apache/openmeetings/core/sip/SipStackProcessor.java @@ -198,8 +198,7 @@ public class SipStackProcessor implements SipListenerExt { callbacks.onRegisterOk(); } else if (INVITE.equals(prevReq.getMethod())) { dialog = evt.getDialog(); - ack(evt); - callbacks.onInviteOk(new String((byte[])resp.getContent())); + callbacks.onInviteOk(new String((byte[])resp.getContent()), answer -> ack(evt, answer)); } else if (BYE.equals(prevReq.getMethod())) { doDestroy(); } @@ -212,12 +211,13 @@ public class SipStackProcessor implements SipListenerExt { } } - private void ack(ResponseEvent evt) { + private void ack(ResponseEvent evt, String answer) { try { Response resp = evt.getResponse(); Dialog dlg = evt.getDialog(); CSeqHeader cseqHead = (CSeqHeader)resp.getHeader(CSeqHeader.NAME); Request ack = dlg.createAck(cseqHead.getSeqNumber()); + addSdp(ack, answer); dlg.sendAck(ack); } catch (Exception e) { log.error("ack {}", evt, e); @@ -336,6 +336,13 @@ public class SipStackProcessor implements SipListenerExt { }); } + private void addSdp(Request req, String sdp) throws Exception { + if (sdp != null) { + req.addHeader(headerFactory.createContentLengthHeader(sdp.length())); + req.setContent(sdp, headerFactory.createContentTypeHeader("application", "sdp")); + } + } + public void invite(Room r, String sdp) { final String sipNumber = getSipNumber(r); if (sipNumber == null) { @@ -349,10 +356,7 @@ public class SipStackProcessor implements SipListenerExt { , req -> { try { addAllow(req); - if (sdp != null) { - req.addHeader(headerFactory.createContentLengthHeader(sdp.length())); - req.setContent(sdp, headerFactory.createContentTypeHeader("application", "sdp")); - } + addSdp(req, sdp); } catch (Exception e) { log.error("fail patch invite request", e); } diff --git a/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java b/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java index 7402754..3565a64 100644 --- a/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java +++ b/openmeetings-core/src/test/java/org/apache/openmeetings/core/remote/BaseMockedTest.java @@ -20,6 +20,7 @@ package org.apache.openmeetings.core.remote; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -94,7 +95,7 @@ public class BaseMockedTest { return null; } }); - streamMock.when(() -> AbstractStream.createWebRtcEndpoint(any(MediaPipeline.class))).thenReturn(mock(WebRtcEndpoint.class)); + streamMock.when(() -> AbstractStream.createWebRtcEndpoint(any(MediaPipeline.class), anyBoolean())).thenReturn(mock(WebRtcEndpoint.class)); streamMock.when(() -> AbstractStream.createRecorderEndpoint(any(MediaPipeline.class), anyString(), any(MediaProfileSpecType.class))).thenReturn(mock(RecorderEndpoint.class)); streamMock.when(() -> AbstractStream.createPlayerEndpoint(any(MediaPipeline.class), anyString())).thenReturn(mock(PlayerEndpoint.class)); diff --git a/openmeetings-server/src/site/markdown/AsteriskIntegration.md b/openmeetings-server/src/site/markdown/AsteriskIntegration.md index 0b98140..c6459d4 100644 --- a/openmeetings-server/src/site/markdown/AsteriskIntegration.md +++ b/openmeetings-server/src/site/markdown/AsteriskIntegration.md @@ -138,7 +138,6 @@ encryption=no avpf=yes icesupport=yes directmedia=no -disallow=all allow=!all,ulaw,opus,vp8 ``` diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/KStreamDto.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/KStreamDto.java index 90cc2b7..75265a7 100644 --- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/KStreamDto.java +++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/KStreamDto.java @@ -37,30 +37,26 @@ import org.apache.openmeetings.db.entity.record.RecordingChunk.Type; public class KStreamDto implements IDataProviderEntity { private static final long serialVersionUID = 1L; - private String sid; - private String uid; - private Long roomId; - private Date connectedSince; - private StreamType streamType; - private String profile; - private String recorder; - private Long chunkId; - private Type type; + private final String sid; + private final String uid; + private final Long roomId; + private final Date connectedSince; + private final StreamType streamType; + private final String profile; + private final String recorder; + private final Long chunkId; + private final Type type; public KStreamDto(KStream kStream) { - this.sid = kStream.getSid(); - this.uid = kStream.getUid(); - this.roomId = kStream.getRoomId(); - this.connectedSince = kStream.getConnectedSince(); - this.streamType = kStream.getStreamType(); - this.profile = kStream.getProfile().toString(); - this.recorder = (kStream.getRecorder() == null) ? null : kStream.getRecorder().toString(); - this.chunkId = kStream.getChunkId(); - this.type = kStream.getType(); - } - - public static long getSerialversionuid() { - return serialVersionUID; + sid = kStream.getSid(); + uid = kStream.getUid(); + roomId = kStream.getRoomId(); + connectedSince = kStream.getConnectedSince(); + streamType = kStream.getStreamType(); + profile = kStream.getProfile().toString(); + recorder = (kStream.getRecorder() == null) ? null : kStream.getRecorder().toString(); + chunkId = kStream.getChunkId(); + type = kStream.getType(); } public String getSid() { diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/TimerService.java b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/TimerService.java index 422755a..6829c0f 100644 --- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/TimerService.java +++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/app/TimerService.java @@ -102,7 +102,6 @@ public class TimerService { private void updateSipLastName(Optional<Client> sipClient, Room r) { long count = sipManager.countUsers(r.getConfno()); final String newLastName = "(" + count + ")"; - kHandler.updateSipCount(r, count); sipClient.ifPresentOrElse(c -> { if (!newLastName.equals(c.getUser().getLastname())) { c.getUser().setLastname(newLastName).resetDisplayName(); @@ -113,11 +112,13 @@ public class TimerService { User sipUser = sipManager.getSipUser(r); sipUser.setLastname(newLastName).resetDisplayName(); Client c = new Client("-- unique - sip - session --", 1, sipUser, sipUser.getPictureUri()); + c.allow(Right.VIDEO, Right.AUDIO); cm.add(c); c.setRoom(r); cm.addToRoom(c); WebSocketHelper.sendRoom(new TextRoomMessage(r.getId(), c, RoomMessage.Type.ROOM_ENTER, c.getUid())); }); + kHandler.updateSipCount(r, count); } public void scheduleModCheck(Room r) { diff --git a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js index b54fbf6..0d349c2 100644 --- a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js +++ b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/raw-room.js @@ -440,25 +440,27 @@ var Room = (function() { .css('background-image', 'url(' + c.user.pictureUri + ')') .find('.user.name').text(c.user.displayName); - const actions = le.find('.user.actions'); - __rightVideoIcon(c, actions); - __rightAudioIcon(c, actions); - __rightOtherIcons(c, actions); - __activityIcon(actions, '.kick' - , () => !self && _hasRight('MODERATOR') && !_hasRight('SUPER_MODERATOR', c.rights) - , null - , { - confirmationEvent: 'om-kick' - , placement: Settings.isRtl ? 'left' : 'right' - , onConfirm: () => OmUtil.roomAction({action: 'kick', uid: c.uid}) - }); - __activityIcon(actions, '.private-chat' + if (c.user.id !== -1) { + const actions = le.find('.user.actions'); + __rightVideoIcon(c, actions); + __rightAudioIcon(c, actions); + __rightOtherIcons(c, actions); + __activityIcon(actions, '.kick' + , () => !self && _hasRight('MODERATOR') && !_hasRight('SUPER_MODERATOR', c.rights) + , null + , { + confirmationEvent: 'om-kick' + , placement: Settings.isRtl ? 'left' : 'right' + , onConfirm: () => OmUtil.roomAction({action: 'kick', uid: c.uid}) + }); + __activityIcon(actions, '.private-chat' , () => options.userId !== c.user.id && $('#chatPanel').is(':visible') , function() { Chat.addTab('chatTab-u' + c.user.id, c.user.displayName); Chat.open(); $('#chatMessage .wysiwyg-editor').click(); }); + } if (self) { options.rights = c.rights; _setQuickPollRights();