/** * Adds a specific (RTP) SSRC to the list of SSRCs seen/received on this <tt>Channel</tt>. * Invoked by the Jitsi Videobridge server, not its clients. * * @param ssrc the (RTP) SSRC to be added to the list of SSRCs seen/received on this * <tt>Channel</tt> * @return <tt>true</tt> if the list of SSRCs seen/received on this <tt>Channel</tt> has been * modified as part of the method call; otherwise, <tt>false</tt> */ public synchronized boolean addSSRC(int ssrc) { // contains for (int i = 0; i < ssrcs.length; i++) if (ssrcs[i] == ssrc) return false; // add int[] newSSRCs = new int[ssrcs.length + 1]; System.arraycopy(ssrcs, 0, newSSRCs, 0, ssrcs.length); newSSRCs[ssrcs.length] = ssrc; ssrcs = newSSRCs; return true; }
/** * Removes a specific (RTP) SSRC from the list of SSRCs seen/received on this <tt>Channel</tt>. * Invoked by the Jitsi Videobridge server, not its clients. * * @param ssrc the (RTP) SSRC to be removed from the list of SSRCs seen/received on this * <tt>Channel</tt> * @return <tt>true</tt> if the list of SSRCs seen/received on this <tt>Channel</tt> has been * modified as part of the method call; otherwise, <tt>false</tt> */ public synchronized boolean removeSSRC(int ssrc) { if (ssrcs.length == 1) { if (ssrcs[0] == ssrc) { ssrcs = NO_SSRCS; return true; } else return false; } else { for (int i = 0; i < ssrcs.length; i++) { if (ssrcs[i] == ssrc) { int[] newSSRCs = new int[ssrcs.length - 1]; if (i != 0) System.arraycopy(ssrcs, 0, newSSRCs, 0, i); if (i != newSSRCs.length) { System.arraycopy(ssrcs, i + 1, newSSRCs, i, newSSRCs.length - i); } ssrcs = newSSRCs; return true; } } return false; } }
private void runOnDtlsTransport(StreamConnector connector) throws IOException { DtlsControlImpl dtlsControl = (DtlsControlImpl) getTransportManager().getDtlsControl(this); DtlsTransformEngine engine = dtlsControl.getTransformEngine(); final DtlsPacketTransformer transformer = (DtlsPacketTransformer) engine.getRTPTransformer(); byte[] receiveBuffer = new byte[SCTP_BUFFER_SIZE]; if (LOG_SCTP_PACKETS) { System.setProperty( ConfigurationService.PNAME_SC_HOME_DIR_LOCATION, System.getProperty("java.io.tmpdir")); System.setProperty( ConfigurationService.PNAME_SC_HOME_DIR_NAME, SctpConnection.class.getName()); } synchronized (this) { // FIXME local SCTP port is hardcoded in bridge offer SDP (Jitsi // Meet) sctpSocket = Sctp.createSocket(5000); assocIsUp = false; acceptedIncomingConnection = false; } // Implement output network link for SCTP stack on DTLS transport sctpSocket.setLink( new NetworkLink() { @Override public void onConnOut(SctpSocket s, byte[] packet) throws IOException { if (LOG_SCTP_PACKETS) { LibJitsi.getPacketLoggingService() .logPacket( PacketLoggingService.ProtocolName.ICE4J, new byte[] {0, 0, 0, (byte) debugId}, 5000, new byte[] {0, 0, 0, (byte) (debugId + 1)}, remoteSctpPort, PacketLoggingService.TransportName.UDP, true, packet); } // Send through DTLS transport transformer.sendApplicationData(packet, 0, packet.length); } }); if (logger.isDebugEnabled()) { logger.debug("Connecting SCTP to port: " + remoteSctpPort + " to " + getEndpoint().getID()); } sctpSocket.setNotificationListener(this); sctpSocket.listen(); // FIXME manage threads threadPool.execute( new Runnable() { @Override public void run() { SctpSocket sctpSocket = null; try { // sctpSocket is set to null on close sctpSocket = SctpConnection.this.sctpSocket; while (sctpSocket != null) { if (sctpSocket.accept()) { acceptedIncomingConnection = true; break; } Thread.sleep(100); sctpSocket = SctpConnection.this.sctpSocket; } if (isReady()) { notifySctpConnectionReady(); } } catch (Exception e) { logger.error("Error accepting SCTP connection", e); } if (sctpSocket == null && logger.isInfoEnabled()) { logger.info( "SctpConnection " + getID() + " closed" + " before SctpSocket accept()-ed."); } } }); // Notify that from now on SCTP connection is considered functional sctpSocket.setDataCallback(this); // Setup iceSocket DatagramSocket datagramSocket = connector.getDataSocket(); if (datagramSocket != null) { this.iceSocket = new IceUdpSocketWrapper(datagramSocket); } else { this.iceSocket = new IceTcpSocketWrapper(connector.getDataTCPSocket()); } DatagramPacket rcvPacket = new DatagramPacket(receiveBuffer, 0, receiveBuffer.length); // Receive loop, breaks when SCTP socket is closed try { do { iceSocket.receive(rcvPacket); RawPacket raw = new RawPacket(rcvPacket.getData(), rcvPacket.getOffset(), rcvPacket.getLength()); raw = transformer.reverseTransform(raw); // Check for app data if (raw == null) continue; if (LOG_SCTP_PACKETS) { LibJitsi.getPacketLoggingService() .logPacket( PacketLoggingService.ProtocolName.ICE4J, new byte[] {0, 0, 0, (byte) (debugId + 1)}, remoteSctpPort, new byte[] {0, 0, 0, (byte) debugId}, 5000, PacketLoggingService.TransportName.UDP, false, raw.getBuffer(), raw.getOffset(), raw.getLength()); } // Pass network packet to SCTP stack sctpSocket.onConnIn(raw.getBuffer(), raw.getOffset(), raw.getLength()); } while (true); } finally { // Eventually, close the socket although it should happen from // expire(). synchronized (this) { assocIsUp = false; acceptedIncomingConnection = false; if (sctpSocket != null) { sctpSocket.close(); sctpSocket = null; } } } }