/* * Copyright 2007 Sun Microsystems, Inc. * * This file is part of jVoiceBridge. * * jVoiceBridge is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation and distributed hereunder * to you. * * jVoiceBridge is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Sun designates this particular file as subject to the "Classpath" * exception as provided by Sun in the License file that accompanied this * code. */ package com.sun.voip; /* * Packet for sending RTP data */ public class RtpSenderPacket extends RtpPacket { private static boolean comfortNoise = true; private long packetsSent = 0; private long comfortPayloadSentCount = 0; private long timeComfortPayloadSent; /** * Initialize an Rtp sender packet. */ public RtpSenderPacket(int encoding, int sampleRate, int channels) { super(encoding, sampleRate, channels); // // Initialize RTP header // buffer[0] = (byte)0x80; // version 2 buffer[1] = (byte)MARK_BIT | PCMU_PAYLOAD; // MARK bit and payload buffer[2] = (byte)0; // sequence # buffer[3] = (byte)1; buffer[4] = (byte)0; // rtpTimestamp buffer[5] = (byte)0; buffer[6] = (byte)0; buffer[7] = (byte)0; long now = System.currentTimeMillis(); buffer[8] = (byte)((now >> 24) & 0xff); // Synchronization Source SSRC id buffer[9] = (byte)((now >> 16) & 0xff); buffer[10] = (byte)((now >> 8) & 0xff); buffer[11] = (byte)(now & 0xff); } /** * set the header fields for a comfort payload change * * After sending a comfort noise payload, * we keep track of how much time has passed until we start * sending data again. We then update the rtpTimestamp * with the number of PACKET_PERIOD samples (rounded up). */ public void setComfortPayload() { buffer[1] = COMFORT_PAYLOAD; setLength(RtpPacket.HEADER_SIZE + 1); comfortPayloadSentCount++; timeComfortPayloadSent = System.currentTimeMillis(); } public void setComfortNoiseLevel(byte comfortNoiseLevel) { buffer[RtpPacket.DATA] = comfortNoiseLevel; } /** * increment the RTP sequence number */ public void incrementRtpSequenceNumber() { rtpSequenceNumber++; buffer[2] = (byte)((rtpSequenceNumber >> 8) & 0xff); buffer[3] = (byte)(rtpSequenceNumber & 0xff); } /** * Update the RTP sequence number and timestamp. This method is called * after sending a packet of data. The reason this isn't done automatically * is because the mixer sends packets with the same sequence # and * time stamp to multiple members. */ public void updateRtpHeader(int size) { rtpSequenceNumber++; buffer[0] = (byte)0x80; // version 2 buffer[1] &= ~MARK_BIT; // clear MARK bit buffer[2] = (byte)((rtpSequenceNumber >> 8) & 0xff); buffer[3] = (byte)(rtpSequenceNumber & 0xff); /* * adjust RTP header time stamp */ adjustRtpTimestamp(size - HEADER_SIZE); } /** * Adjust the RTP Timestamp. This method is called when we are about * to resume sending data after sending a COMFORT_PAYLOAD. * * Calulate the number of samples that would have been * sent during the time between when the comfort payload * was sent and now. * * The timestamp is adjusted by the amount of time we stopped sending data. * * @param adjustment long to add to the RTP timestamp. */ public void adjustRtpTimestamp() { /* * Elapsed time since comfort payload sent multiplied * by the number of samples per second gives the * number of samples by which the RTP timestamp must * be adjusted. */ if (timeComfortPayloadSent == 0) { Logger.error("RtpSenderPacket: timeComfortPayloadSent is 0!"); return; } adjustRtpTimestamp(System.currentTimeMillis() - timeComfortPayloadSent); timeComfortPayloadSent = 0; } /* * Adjust the RTP timestamp by the specified amount. * This adjustment is necessary after a comfort payload change * or when there is a long pause. */ public void adjustRtpTimestamp(long elapsed) { int adjustment = (int) (elapsed * (getDataSize() / RtpPacket.PACKET_PERIOD)); adjustment = ((adjustment + getDataSize() - 1) / getDataSize()) * getDataSize(); buffer[1] |= MARK_BIT; adjustRtpTimestamp(adjustment); } private void adjustRtpTimestamp(int adjustment) { rtpTimestamp += adjustment; buffer[4] = (byte)((rtpTimestamp >> 24) & 0xff); buffer[5] = (byte)((rtpTimestamp >> 16) & 0xff); buffer[6] = (byte)((rtpTimestamp >> 8) & 0xff); buffer[7] = (byte)(rtpTimestamp & 0xff); } public void incrementPacketsSent() { packetsSent++; } public long getPacketsSent() { return packetsSent; } public long getComfortPayloadSentCount() { return comfortPayloadSentCount; } /* * Make sure sequence number wraps properly. */ public static void main(String[] args) { RtpSenderPacket packet = new RtpSenderPacket( PCM_ENCODING, 8000, 1); Logger.logLevel = 5; short expected = packet.rtpSequenceNumber; while (true) { if (packet.rtpSequenceNumber != expected) { Logger.println("expected " + expected + " got " + packet.rtpSequenceNumber); } packet.rtpSequenceNumber++; expected = packet.rtpSequenceNumber; } } }