/**
     * 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;
      }
    }
예제 #3
0
  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;
        }
      }
    }
  }