package org.red5.app.sip.stream; import local.net.RtpPacket; import local.net.RtpSocket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import org.slf4j.Logger; import org.red5.app.sip.trancoders.Transcoder; import org.red5.logging.Red5LoggerFactory; public class RtpStreamSender { private static Logger log = Red5LoggerFactory.getLogger(RtpStreamSender.class, "sip"); private static final int RTP_HEADER_SIZE = 12; private RtpSocket rtpSocket = null; private byte[] packetBuffer; private RtpPacket rtpPacket; private int startPayloadPos; private int dtmf2833Type = 101; private int sequenceNum = 0; private long timestamp = 0; private Transcoder transcoder; public RtpStreamSender(Transcoder transcoder, DatagramSocket srcSocket, String destAddr, int destPort) throws UnknownHostException { this.transcoder = transcoder; rtpSocket = new RtpSocket(srcSocket, InetAddress.getByName(destAddr), destPort); } public void start() { packetBuffer = new byte[transcoder.getOutgoingEncodedFrameSize() + RTP_HEADER_SIZE]; rtpPacket = new RtpPacket(packetBuffer, 0); rtpPacket.setPayloadType(transcoder.getCodecId()); startPayloadPos = rtpPacket.getHeaderLength(); sequenceNum = 0; timestamp = 0; } public void queueSipDtmfDigits(String dtmfDigits) { byte[] dtmfbuf = new byte[transcoder.getOutgoingEncodedFrameSize() + RTP_HEADER_SIZE]; RtpPacket dtmfpacket = new RtpPacket(dtmfbuf, 0); dtmfpacket.setPayloadType(dtmf2833Type); dtmfpacket.setPayloadLength(transcoder.getOutgoingEncodedFrameSize()); byte[] blankbuf = new byte[transcoder.getOutgoingEncodedFrameSize() + RTP_HEADER_SIZE]; RtpPacket blankpacket = new RtpPacket(blankbuf, 0); blankpacket.setPayloadType(transcoder.getCodecId()); blankpacket.setPayloadLength(transcoder.getOutgoingEncodedFrameSize()); for (int d = 0; d < dtmfDigits.length(); d++) { char digit = dtmfDigits.charAt(d); if (digit == '*') { dtmfbuf[startPayloadPos] = 10; } else if (digit == '#') { dtmfbuf[startPayloadPos] = 11; } else if (digit >= 'A' && digit <= 'D') { dtmfbuf[startPayloadPos] = (byte) (digit - 53); } else { dtmfbuf[startPayloadPos] = (byte) (digit - 48); } // notice we are bumping times/seqn just like audio packets try { // send start event packet 3 times dtmfbuf[startPayloadPos + 1] = 0; // start event flag // and volume dtmfbuf[startPayloadPos + 2] = 1; // duration 8 bits dtmfbuf[startPayloadPos + 3] = -32; // duration 8 bits for (int r = 0; r < 3; r++) { dtmfpacket.setSequenceNumber(sequenceNum++); dtmfpacket.setTimestamp(transcoder.getOutgoingEncodedFrameSize()); doRtpDelay(); rtpSocketSend(dtmfpacket); } // send end event packet 3 times dtmfbuf[startPayloadPos + 1] = -128; // end event flag dtmfbuf[startPayloadPos + 2] = 3; // duration 8 bits dtmfbuf[startPayloadPos + 3] = 116; // duration 8 bits for (int r = 0; r < 3; r++) { dtmfpacket.setSequenceNumber(sequenceNum++); dtmfpacket.setTimestamp(transcoder.getOutgoingEncodedFrameSize() ); doRtpDelay(); rtpSocketSend(dtmfpacket); } // send 200 ms of blank packets for (int r = 0; r < 200 / transcoder.getOutgoingPacketization(); r++) { blankpacket.setSequenceNumber(sequenceNum++); blankpacket.setTimestamp(transcoder.getOutgoingEncodedFrameSize()); doRtpDelay(); rtpSocketSend(blankpacket); } } catch (Exception e) { log.warn("queueSipDtmfDigits", e.getLocalizedMessage()); } } } public void send(byte[] asaoBuffer, int offset, int num) { // System.out.println("Transcoding from Nelly to PCM"); transcoder.transcode(asaoBuffer, offset, num, packetBuffer, RTP_HEADER_SIZE, this); } public void sendTranscodedData() { rtpPacket.setSequenceNumber( sequenceNum++ ); timestamp += transcoder.getOutgoingEncodedFrameSize(); rtpPacket.setTimestamp( timestamp ); rtpPacket.setPayloadLength( transcoder.getOutgoingEncodedFrameSize() ); // System.out.println("Sending rtpPacket " + timestamp); rtpSocketSend(rtpPacket); } public void stop() { rtpSocket.close(); log.debug(" Stopping Rtp sender." ); } private void doRtpDelay() { try { Thread.sleep(transcoder.getOutgoingPacketization() - 2); } catch ( Exception e ) { } } private synchronized void rtpSocketSend(RtpPacket rtpPacket) { try { rtpSocket.send( rtpPacket ); timestamp += rtpPacket.getPayloadLength(); } catch (Exception e) { log.error("Exception while sending packet"); } } }