/**
*
*/
package video.clientProxy;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import video.lib.RtcpPacket;
import video.lib.RtpPacket;
import video.lib.Statistic;
import video.lib.TrackStatistic;
import video.lib.UnsignedInt;
import video.transport.TransportService;
/**
* @author yuezhu
*
*/
public class ClientTrack {
private static final Logger LOGGER = LoggerFactory.getLogger(ClientTrack.class);
private static TransportService service;
/** Maps a proxy SSRC id to a Track */
private static Map<UnsignedInt, ClientTrack> proxySsrcMap = new ConcurrentHashMap<UnsignedInt, ClientTrack>();
/** Maps a client address to a Track */
private static Map<InetSocketAddress, ClientTrack> clientAddressMap = new ConcurrentHashMap<InetSocketAddress, ClientTrack>();
private Statistic trackStatistic;
/**
* Control Url of the track. This is the url handle given by the server to
* control different tracks in a RTSP session.
*/
private URI uri;
/** SSRC id given by the server side proxy*/
private UnsignedInt proxySsrc = new UnsignedInt(0);
/**
* Cached references to IoSession objects used to send packets to the client.
*/
private IoSession rtpClientSession = null;
private IoSession rtcpClientSession = null;
/**
* IP address and RTP/RTCP ports for the client.
* <p>
* TODO: When using reflection, there will be more than one connected client
* at a time to the same Track. So the track should keep a list of connected
* clients and forward packets to each of them.
*/
private InetAddress clientAddress;
private int clientRtpPort;
private int clientRtcpPort;
/**
* Construct a new Track.
*
* @param uri
* the control name for this track.
*/
public ClientTrack(TransportService transportService, URI uri) {
service = transportService;
this.uri = uri;
trackStatistic = new TrackStatistic("[client]" + uri.toString().replaceAll("\\/", "-"));
try {
trackStatistic.start();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Get the track by looking at client socket address.
*
* @return a Track instance if a matching pair is found or null
*/
public static ClientTrack getByClientSocketAddress(InetSocketAddress clientSocketAddress) {
return clientAddressMap.get(clientSocketAddress);
}
/**
* Get the track by looking at proxy SSRC id.
*
* @return a Track instance if a matching SSRC is found or null
*/
public static ClientTrack getByProxySsrc(UnsignedInt proxySsrc) {
return proxySsrcMap.get(proxySsrc);
}
// /// Member methods
/**
* @return the proxy SSRC id
*/
public UnsignedInt getProxySsrc() {
return proxySsrc;
}
/**
* Sets the proxy SSRC id.
*
* @param proxySsrc
*/
public void setProxySsrc(String proxySsrc) {
this.proxySsrc = UnsignedInt.fromString(proxySsrc, 16);
proxySsrcMap.put(this.proxySsrc, this);
}
/**
* Sets the proxy SSRC id.
*
* @param proxySsrc
*/
public void setProxySsrc(UnsignedInt proxySsrc) {
this.proxySsrc = proxySsrc;
proxySsrcMap.put(this.proxySsrc, this);
}
public URI getUri() {
return uri;
}
public void setUrl(URI uri) {
this.uri = uri;
}
public void setRtcpClientSession(IoSession rtcpClientSession) {
this.rtcpClientSession = rtcpClientSession;
}
public void setRtpClientSession(IoSession rtpClientSession) {
this.rtpClientSession = rtpClientSession;
}
/**
* Forwards a RTP packet to server. The packet will be set to the address
* indicated by the server at RTP (eve n) port.
*
* @param packet
* a RTP packet
*/
public void forwardRtpToServer(RtpPacket packet) {
try {
service.getRTPTransportChannel().send(packet.toIoBuffer().array());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Forwards a RTCP packet to server. The packet will be set to the address
* indicated by the server at RTCP (odd) port.
*
* @param packet
* a RTCP packet
*/
public void forwardRtcpToServer(RtcpPacket packet) {
// modify the SSRC for the server
packet.setSsrc( proxySsrc );
try {
service.getRTCPTransportChannel().send(packet.toIoBuffer().array());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Forwards a RTP packet to client. The packet will be set to the address
* indicated by the client at RTP (even) port.
* <p>
* TODO: This will be changed to support multiple clients connected to the
* same (live) track.
*
* @param packet
* a RTP packet
*/
public void forwardRtpToClient(RtpPacket packet) {
if (rtpClientSession == null) {
rtpClientSession = RtpClientService.newRtpSession(new InetSocketAddress(clientAddress, clientRtpPort));
}
rtpClientSession.write(packet.toIoBuffer());
trackStatistic.doStatistic(packet);
}
/**
* Forwards a RTCP packet to client. The packet will be set to the address
* indicated by the client at RTCP (odd) port.
* <p>
* TODO: This will be changed to support multiple clients connected to the
* same (live) track.
*
* @param packet
* a RTCP packet
*/
public void forwardRtcpToClient(RtcpPacket packet) {
if (rtcpClientSession == null) {
rtcpClientSession = RtpClientService.newRtcpSession(new InetSocketAddress(clientAddress, clientRtcpPort));
}
rtcpClientSession.write(packet.toIoBuffer());
}
/**
* Set the address of the server associated with this track.
* <p>
* TODO: This will be changed to support multiple clients connected to the
* same (live) track.
*
* @param clientAddress
* The client address to set.
* @param rtpPort
* the port number used for RTP packets
* @param rtcpPort
* the port number used for RTCP packets
*/
public void setClientSocketAddress(InetAddress clientAddress, int rtpPort, int rtcpPort) {
this.clientAddress = clientAddress;
this.clientRtpPort = rtpPort;
this.clientRtcpPort = rtcpPort;
clientAddressMap.put(new InetSocketAddress(clientAddress, rtpPort), this);
clientAddressMap.put(new InetSocketAddress(clientAddress, rtcpPort), this);
}
public synchronized void close() {
if (proxySsrc != null) {
proxySsrcMap.remove(proxySsrc);
}
clientAddressMap.remove(new InetSocketAddress(clientAddress, clientRtpPort));
clientAddressMap.remove(new InetSocketAddress(clientAddress, clientRtcpPort));
try {
trackStatistic.stop();
} catch (IOException e) {
e.printStackTrace();
}
LOGGER.debug("Closed track " + uri);
}
public String toString() {
return "Track(url=\"" + uri + "\"";
}
}