Пример #1
0
  /**
   * Loads the list of enabled and disabled encryption protocols with their priority.
   *
   * @param enabledEncryptionProtocols The list of enabled encryption protocol available for this
   *     account.
   * @param disabledEncryptionProtocols The list of disabled encryption protocol available for this
   *     account.
   */
  private void loadEncryptionProtocols(
      Map<String, Integer> encryptionProtocols, Map<String, Boolean> encryptionProtocolStatus) {
    int nbEncryptionProtocols = ENCRYPTION_PROTOCOLS.length;
    String[] encryptions = new String[nbEncryptionProtocols];
    boolean[] selectedEncryptions = new boolean[nbEncryptionProtocols];

    // Load stored values.
    int prefixeLength = ProtocolProviderFactory.ENCRYPTION_PROTOCOL.length() + 1;
    String encryptionProtocolPropertyName;
    String name;
    int index;
    boolean enabled;
    Iterator<String> encryptionProtocolNames = encryptionProtocols.keySet().iterator();
    while (encryptionProtocolNames.hasNext()) {
      encryptionProtocolPropertyName = encryptionProtocolNames.next();
      index = encryptionProtocols.get(encryptionProtocolPropertyName);
      // If the property is set.
      if (index != -1) {
        name = encryptionProtocolPropertyName.substring(prefixeLength);
        if (isExistingEncryptionProtocol(name)) {
          enabled =
              encryptionProtocolStatus.get(
                  ProtocolProviderFactory.ENCRYPTION_PROTOCOL_STATUS + "." + name);
          encryptions[index] = name;
          selectedEncryptions[index] = enabled;
        }
      }
    }

    // Load default values.
    String encryptionProtocol;
    boolean set;
    int j = 0;
    for (int i = 0; i < ENCRYPTION_PROTOCOLS.length; ++i) {
      encryptionProtocol = ENCRYPTION_PROTOCOLS[i];
      // Specify a default value only if there is no specific value set.
      if (!encryptionProtocols.containsKey(
          ProtocolProviderFactory.ENCRYPTION_PROTOCOL + "." + encryptionProtocol)) {
        set = false;
        // Search for the first empty element.
        while (j < encryptions.length && !set) {
          if (encryptions[j] == null) {
            encryptions[j] = encryptionProtocol;
            // By default only ZRTP is set to true.
            selectedEncryptions[j] = encryptionProtocol.equals("ZRTP");
            set = true;
          }
          ++j;
        }
      }
    }

    this.encryptionConfigurationTableModel.init(encryptions, selectedEncryptions);
  }
Пример #2
0
  /**
   * Returns default <tt>WebRtcDataStream</tt> if it's ready or <tt>null</tt> otherwise.
   *
   * @return <tt>WebRtcDataStream</tt> if it's ready or <tt>null</tt> otherwise.
   * @throws IOException
   */
  public WebRtcDataStream getDefaultDataStream() throws IOException {
    WebRtcDataStream def;

    synchronized (this) {
      if (sctpSocket == null) {
        def = null;
      } else {
        // Channel that runs on sid 0
        def = channels.get(0);
        if (def == null) {
          def = openChannel(0, 0, 0, 0, "default");
        }
        // Pawel Domas: Must be acknowledged before use
        /*
         * XXX Lyubomir Marinov: We're always sending ordered. According
         * to "WebRTC Data Channel Establishment Protocol", we can start
         * sending messages containing user data after the
         * DATA_CHANNEL_OPEN message has been sent without waiting for
         * the reception of the corresponding DATA_CHANNEL_ACK message.
         */
        //                if (!def.isAcknowledged())
        //                    def = null;
      }
    }
    return def;
  }
Пример #3
0
  /**
   * Returns the sequence number to use for a specific RTX packet, which is based on the packet's
   * original sequence number.
   *
   * <p>Because we terminate the RTX format, and with simulcast we might translate RTX packets from
   * multiple SSRCs into the same SSRC, we keep count of the RTX packets (and their sequence
   * numbers) which we sent for each SSRC.
   *
   * @param ssrc the SSRC of the RTX stream for the packet.
   * @param defaultSeq the default sequence number to use in case we don't (yet) have any
   *     information about <tt>ssrc</tt>.
   * @return the sequence number which should be used for the next RTX packet sent using SSRC
   *     <tt>ssrc</tt>.
   */
  private int getNextRtxSequenceNumber(long ssrc, int defaultSeq) {
    Integer seq;
    synchronized (rtxSequenceNumbers) {
      seq = rtxSequenceNumbers.get(ssrc);
      if (seq == null) seq = defaultSeq;
      else seq++;

      rtxSequenceNumbers.put(ssrc, seq);
    }

    return seq;
  }
Пример #4
0
  /**
   * Returns the sequence number to use for a specific RTX packet, which is based on the packet's
   * original sequence number.
   *
   * <p>Because we terminate the RTX format, and with simulcast we might translate RTX packets from
   * multiple SSRCs into the same SSRC, we keep count of the RTX packets (and their sequence
   * numbers) which we sent for each SSRC.
   *
   * @param ssrc the SSRC of the RTX stream for the packet.
   * @return the sequence number which should be used for the next RTX packet sent using SSRC
   *     <tt>ssrc</tt>.
   */
  private int getNextRtxSequenceNumber(long ssrc) {
    Integer seq;
    synchronized (rtxSequenceNumbers) {
      seq = rtxSequenceNumbers.get(ssrc);
      if (seq == null) seq = new Random().nextInt(0xffff);
      else seq++;

      rtxSequenceNumbers.put(ssrc, seq);
    }

    return seq;
  }
  /**
   * Returns, the <tt>TransportManager</tt> instance for the channel-bundle with ID
   * <tt>channelBundleId</tt>. If no instance exists and <tt>create</tt> is <tt>true</tt>, one will
   * be created.
   *
   * @param channelBundleId the ID of the channel-bundle for which to return the
   *     <tt>TransportManager</tt>.
   * @param create whether to create a new instance, if one doesn't exist.
   * @return the <tt>TransportManager</tt> instance for the channel-bundle with ID
   *     <tt>channelBundleId</tt>.
   */
  IceUdpTransportManager getTransportManager(String channelBundleId, boolean create) {
    IceUdpTransportManager transportManager;

    synchronized (transportManagers) {
      transportManager = transportManagers.get(channelBundleId);
      if (transportManager == null && create && !isExpired()) {
        try {
          // FIXME: the initiator is hard-coded
          // We assume rtcp-mux when bundle is used, so we make only
          // one component.
          transportManager = new IceUdpTransportManager(this, true, 1);
        } catch (IOException ioe) {
          throw new UndeclaredThrowableException(ioe);
        }
        transportManagers.put(channelBundleId, transportManager);
      }
    }

    return transportManager;
  }
Пример #6
0
  /**
   * {@inheritDoc}
   *
   * <p>SCTP input data callback.
   */
  @Override
  public void onSctpPacket(
      byte[] data, int sid, int ssn, int tsn, long ppid, int context, int flags) {
    if (ppid == WEB_RTC_PPID_CTRL) {
      // Channel control PPID
      try {
        onCtrlPacket(data, sid);
      } catch (IOException e) {
        logger.error("IOException when processing ctrl packet", e);
      }
    } else if (ppid == WEB_RTC_PPID_STRING || ppid == WEB_RTC_PPID_BIN) {
      WebRtcDataStream channel;

      synchronized (this) {
        channel = channels.get(sid);
      }

      if (channel == null) {
        logger.error("No channel found for sid: " + sid);
        return;
      }
      if (ppid == WEB_RTC_PPID_STRING) {
        // WebRTC String
        String str;
        String charsetName = "UTF-8";

        try {
          str = new String(data, charsetName);
        } catch (UnsupportedEncodingException uee) {
          logger.error("Unsupported charset encoding/name " + charsetName, uee);
          str = null;
        }
        channel.onStringMsg(str);
      } else {
        // WebRTC Binary
        channel.onBinaryMsg(data);
      }
    } else {
      logger.warn("Got message on unsupported PPID: " + ppid);
    }
  }
    /**
     * Estimate the <tt>RemoteClock</tt> of a given RTP stream (identified by its SSRC) at a given
     * time.
     *
     * @param ssrc the SSRC of the RTP stream whose <tt>RemoteClock</tt> we want to estimate.
     * @param time the local time that will be mapped to a remote time.
     * @return An estimation of the <tt>RemoteClock</tt> at time "time".
     */
    public RemoteClock estimate(int ssrc, long time) {
      ReceivedRemoteClock receivedRemoteClock = receivedClocks.get(ssrc);
      if (receivedRemoteClock == null || receivedRemoteClock.getFrequencyHz() == -1) {
        // We can't continue if we don't have NTP and RTP timestamps
        // and/or the original sender frequency, so move to the next
        // one.
        return null;
      }

      long delayMillis = time - receivedRemoteClock.getReceivedTime();

      // Estimate the remote wall clock.
      long remoteTime = receivedRemoteClock.getRemoteClock().getRemoteTime();
      long estimatedRemoteTime = remoteTime + delayMillis;

      // Drift the RTP timestamp.
      int rtpTimestamp =
          receivedRemoteClock.getRemoteClock().getRtpTimestamp()
              + ((int) delayMillis) * (receivedRemoteClock.getFrequencyHz() / 1000);
      return new RemoteClock(estimatedRemoteTime, rtpTimestamp);
    }
Пример #8
0
  /**
   * Handles control packet.
   *
   * @param data raw packet data that arrived on control PPID.
   * @param sid SCTP stream id on which the data has arrived.
   */
  private synchronized void onCtrlPacket(byte[] data, int sid) throws IOException {
    ByteBuffer buffer = ByteBuffer.wrap(data);
    int messageType = /* 1 byte unsigned integer */ 0xFF & buffer.get();

    if (messageType == MSG_CHANNEL_ACK) {
      if (logger.isDebugEnabled()) {
        logger.debug(getEndpoint().getID() + " ACK received SID: " + sid);
      }
      // Open channel ACK
      WebRtcDataStream channel = channels.get(sid);
      if (channel != null) {
        // Ack check prevents from firing multiple notifications
        // if we get more than one ACKs (by mistake/bug).
        if (!channel.isAcknowledged()) {
          channel.ackReceived();
          notifyChannelOpened(channel);
        } else {
          logger.warn("Redundant ACK received for SID: " + sid);
        }
      } else {
        logger.error("No channel exists on sid: " + sid);
      }
    } else if (messageType == MSG_OPEN_CHANNEL) {
      int channelType = /* 1 byte unsigned integer */ 0xFF & buffer.get();
      int priority = /* 2 bytes unsigned integer */ 0xFFFF & buffer.getShort();
      long reliability = /* 4 bytes unsigned integer */ 0xFFFFFFFFL & buffer.getInt();
      int labelLength = /* 2 bytes unsigned integer */ 0xFFFF & buffer.getShort();
      int protocolLength = /* 2 bytes unsigned integer */ 0xFFFF & buffer.getShort();
      String label;
      String protocol;

      if (labelLength == 0) {
        label = "";
      } else {
        byte[] labelBytes = new byte[labelLength];

        buffer.get(labelBytes);
        label = new String(labelBytes, "UTF-8");
      }
      if (protocolLength == 0) {
        protocol = "";
      } else {
        byte[] protocolBytes = new byte[protocolLength];

        buffer.get(protocolBytes);
        protocol = new String(protocolBytes, "UTF-8");
      }

      if (logger.isDebugEnabled()) {
        logger.debug(
            "!!! "
                + getEndpoint().getID()
                + " data channel open request on SID: "
                + sid
                + " type: "
                + channelType
                + " prio: "
                + priority
                + " reliab: "
                + reliability
                + " label: "
                + label
                + " proto: "
                + protocol);
      }

      if (channels.containsKey(sid)) {
        logger.error("Channel on sid: " + sid + " already exists");
      }

      WebRtcDataStream newChannel = new WebRtcDataStream(sctpSocket, sid, label, true);
      channels.put(sid, newChannel);

      sendOpenChannelAck(sid);

      notifyChannelOpened(newChannel);
    } else {
      logger.error("Unexpected ctrl msg type: " + messageType);
    }
  }
    /**
     * Inspect an <tt>RTCPCompoundPacket</tt> and build-up the state for future estimations.
     *
     * @param pkt
     */
    public void apply(RTCPCompoundPacket pkt) {
      if (pkt == null || pkt.packets == null || pkt.packets.length == 0) {
        return;
      }

      for (RTCPPacket rtcpPacket : pkt.packets) {
        switch (rtcpPacket.type) {
          case RTCPPacket.SR:
            RTCPSRPacket srPacket = (RTCPSRPacket) rtcpPacket;

            // The media sender SSRC.
            int ssrc = srPacket.ssrc;

            // Convert 64-bit NTP timestamp to Java standard time.
            // Note that java time (milliseconds) by definition has
            // less precision then NTP time (picoseconds) so
            // converting NTP timestamp to java time and back to NTP
            // timestamp loses precision. For example, Tue, Dec 17
            // 2002 09:07:24.810 EST is represented by a single
            // Java-based time value of f22cd1fc8a, but its NTP
            // equivalent are all values ranging from
            // c1a9ae1c.cf5c28f5 to c1a9ae1c.cf9db22c.

            // Use round-off on fractional part to preserve going to
            // lower precision
            long fraction = Math.round(1000D * srPacket.ntptimestamplsw / 0x100000000L);
            /*
             * If the most significant bit (MSB) on the seconds
             * field is set we use a different time base. The
             * following text is a quote from RFC-2030 (SNTP v4):
             *
             * If bit 0 is set, the UTC time is in the range
             * 1968-2036 and UTC time is reckoned from 0h 0m 0s UTC
             * on 1 January 1900. If bit 0 is not set, the time is
             * in the range 2036-2104 and UTC time is reckoned from
             * 6h 28m 16s UTC on 7 February 2036.
             */
            long msb = srPacket.ntptimestampmsw & 0x80000000L;
            long remoteTime =
                (msb == 0)
                    // use base: 7-Feb-2036 @ 06:28:16 UTC
                    ? msb0baseTime + (srPacket.ntptimestampmsw * 1000) + fraction
                    // use base: 1-Jan-1900 @ 01:00:00 UTC
                    : msb1baseTime + (srPacket.ntptimestampmsw * 1000) + fraction;

            // Estimate the clock rate of the sender.
            int frequencyHz = -1;
            if (receivedClocks.containsKey(ssrc)) {
              // Calculate the clock rate.
              ReceivedRemoteClock oldStats = receivedClocks.get(ssrc);
              RemoteClock oldRemoteClock = oldStats.getRemoteClock();
              frequencyHz =
                  Math.round(
                      (float)
                              (((int) srPacket.rtptimestamp - oldRemoteClock.getRtpTimestamp())
                                  & 0xffffffffl)
                          / (remoteTime - oldRemoteClock.getRemoteTime()));
            }

            // Replace whatever was in there before.
            receivedClocks.put(
                ssrc,
                new ReceivedRemoteClock(
                    ssrc, remoteTime, (int) srPacket.rtptimestamp, frequencyHz));
            break;
          case RTCPPacket.SDES:
            break;
        }
      }
    }