/*
* Mobicents, Communications Middleware
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party
* contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program 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 Lesser General Public License
* for more details.
*
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
*
* Boston, MA 02110-1301 USA
*/
package org.mobicents.media.server.impl.rtp;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.mobicents.media.Buffer;
import org.mobicents.media.Format;
import org.mobicents.media.MediaSource;
import org.mobicents.media.server.spi.Timer;
/**
*
* @author Oleg Kulikov
*/
public class RtpSocket {
private int bufferSize = 8196;
private byte[] senderBuffer = new byte[bufferSize];
private int localPort;
private String localAddress;
protected InetSocketAddress remoteAddress = null; // holder for dynamic payloads.
private HashMap<Integer, Format> rtpMap = new HashMap<Integer, Format>();
private HashMap<Integer, Format> rtpMapOriginal = new HashMap<Integer, Format>(); // packet jitter in milliseconds
private int jitter = 60; // stun support
private ReceiveStream receiveStream;
private SendStream sendStream; // timer to synchronize from
protected Timer timer;
private RtpFactory rtpFactory = null;
private RtpSocketListener listener; // logger instance
private Transceiver transceiver;
private int period = 20;
private final static Logger logger = Logger.getLogger(RtpSocket.class);
/**
* Creates a new instance of RtpSocket
*
* @param timer
* used to synchronize receiver stream.
* @param rtpMap
* RTP payloads list.
*/
public RtpSocket(Transceiver transceiver, Timer timer, Map<Integer, Format> rtpMap, RtpFactory rtpFactory) {
this.transceiver = transceiver;
this.timer = timer;
this.jitter = rtpFactory.getJitter();
rtpMapOriginal.putAll(rtpMap);
this.rtpMap.putAll(rtpMap);
sendStream = new SendStream(this);
receiveStream = new ReceiveStream(this, jitter, period);
this.rtpFactory = rtpFactory;
this.localAddress = rtpFactory.publicAddress.getHostName();
this.localPort = rtpFactory.getLocalPort();
}
/**
* Gets address to which this socked is bound.
*
* @return either local address to which this socket is bound or public
* address in case of NAT translation.
*/
public String getLocalAddress() {
return localAddress;
}
/**
* Returns port number to which this socked is bound.
*
* @return port number or -1 if socket not bound.
*/
public int getLocalPort() {
return localPort;
}
/**
* Gets the jitter for time of packet arrival
*
* @return the value of jitter in milliseconds.
*/
public int getJitter() {
return this.jitter;
}
/**
* Assign new value of packet time arrival jitter.
*
* @param jitter
* the value of jitter in milliseconds.
*/
public void setJitter(int jitter) {
this.jitter = jitter;
}
/**
* Gets receiver stream.
*
* @return receiver stream instance.
*/
public MediaSource getReceiveStream() {
return receiveStream;
}
public void release() {
rtpFactory.releaseRTPSocket(this);
}
public RtpSocketListener getListener() {
return listener;
}
public void setListener(RtpSocketListener listener) {
this.listener = listener;
}
/**
* Assigns remote end.
*
* @param address
* the address of the remote party.
* @param port
* the port number of the remote party.
*/
public void setPeer(InetAddress address, int port) throws IOException {
remoteAddress = new InetSocketAddress(address, port);
rtpFactory.rtpSockets.put(remoteAddress, this);
}
/**
* Gets relations between payload number and format used by this socket.
*
* @return the map where keya are payload number and object stored under key
* is <code>Format</code> object
*/
public HashMap<Integer, Format> getRtpMap() {
return rtpMap;
}
public void setRtpMap(HashMap<Integer, Format> rtpMap) {
this.rtpMap = rtpMap;
if (sendStream != null) {
sendStream.formats = new Format[rtpMap.size()];
rtpMap.values().toArray(sendStream.formats);
}
}
public void resetRtpMap() {
this.rtpMap.clear();
this.rtpMap.putAll(rtpMapOriginal);
}
/**
* Determines payload type for specified format.
*
* @param format
* the object representing format.
* @return the integer identifier of the payload or -1 if specified format
* was not previously registered with addFormat().
*/
protected int getPayloadType(Format format) {
Collection<Integer> keys = rtpMap.keySet();
for (Integer key : keys) {
Format fmt = rtpMap.get(key);
if (fmt.matches(format)) {
return key;
}
}
return -1;
}
/**
* (Non Java-doc).
*
* @see org.mobicents.media.server.impl.rtp.RtpSocket#startSendStream(PushBufferDataSource);
*/
public SendStream getSendStream() {
return sendStream;
}
/**
* Sends media data to remote peer.
*
* This method uses blocking sending to make sure that data is out in time.
*
* @param buffer
* the buffer which contains media data
* @throws java.io.IOException
*/
public void send(Buffer buffer) throws IOException {
try {
RtpHeader h = (RtpHeader) buffer.getHeader();
byte[] headerByte = h.toByteArray();
int len = headerByte.length + buffer.getLength();
senderBuffer = new byte[len];
// combine RTP header and payload
System.arraycopy(headerByte, 0, senderBuffer, 0, headerByte.length);
System.arraycopy((byte[]) buffer.getData(), 0, senderBuffer, headerByte.length, buffer.getLength());
// construct datagram packet and send synchronously it out
// senderPacket.setData(senderBuffer, 0, len);
transceiver.send(senderBuffer, len, remoteAddress);
} finally {
buffer.dispose();
}
}
public void receive(RtpPacket rtpPacket) {
receiveStream.push(rtpPacket);
}
protected void notify(Exception e) {
if (listener != null) {
listener.error(e);
}
}
}