请教:怎么释放一次RTP会话(RTP session)中的端口
下面是基于JMF的一个媒体流发送类。有个问题:为什么调用一次这个类建立一次RTP session并发送完一个媒体流(如一个视频)后,(打印结果如一),再用同样的本地发送端口localPort就不能再发送了(打印结果如二),换成其他端口号后就可以了,我怀疑是上次RTP session的端口没有释放(相关语句为程序中标红的部分)。哪位高手帮忙看下是不是这个问题,怎么解决 或是怎么在一次媒体流发送完毕后释放掉占用的端口? 再此先谢过!
调用方法如下
RTPTransmit t=new RTPTransmit(filePath, localPort, destIP, destPort, beginMediaTime);
t.start();
打印下面语句为程序中标蓝的部分
一:
第一次可以发送媒体流时打印输出如下:
20:21:12,140 ERROR [STDERR] Track 0 is set to transmit as:
20:21:12,140 ERROR [STDERR] MPEG/RTP
20:21:12,140 ERROR [STDERR] Track 1 is set to transmit as:
20:21:12,140 ERROR [STDERR] mpegaudio/rtp, 44100.0 Hz, 16-bit, Stereo, LittleEndian, Signed, 8000.0 frame rate, FrameSize=32768 bits
20:21:12,156 ERROR [STDERR] Created RTP session: 192.168.100.107 6666 8000
20:21:12,171 ERROR [STDERR] Created RTP session: 192.168.100.107 6668 8002
二:
再用同样的本地发送端口发送时打印输出如下:
20:21:12,140 ERROR [STDERR] Track 0 is set to transmit as:
20:21:12,140 ERROR [STDERR] MPEG/RTP
20:21:12,140 ERROR [STDERR] Track 1 is set to transmit as:
20:21:12,140 ERROR [STDERR] mpegaudio/rtp, 44100.0 Hz, 16-bit, Stereo, LittleEndian, Signed, 8000.0 frame rate, FrameSize=32768 bits
即没有了Created RTP session: 192.168.100.107 6666 8000
Created RTP session: 192.168.100.107 6666 8002
public class RTPTransmit //用RTP协议传输数据的类
{
private MediaLocator locator;
private int localPort;
private String filePath;
private String destIP;
private int destPort;
private double beginMediaTime = 0.00;
private Processor processor = null;
private RTPManager rtpMgrs[];
private DataSource dataOutput = null;
public RTPTransmit(String filePath, int localPort, String destIP, int destPort, double beginMediaTime)
{
this.filePath = filePath;
this.localPort = localPort;
this.destIP = destIP;
this.destPort = destPort;
this.beginMediaTime = beginMediaTime;
}
public boolean setFilePath(String filepath)
{
if (filepath == "")
{
return false;
}
try
{
filepath = "file:/" + filepath;
this.locator = new MediaLocator(filepath);
}
catch (Exception e)
{
return false;
}
return true;
}
public synchronized String start()
{
this.setFilePath(this.filePath);
String result;
result = createProcessor();
if (result != null)
return result;
result = createTransmitter();
this.processor.setMediaTime(new Time(this.beginMediaTime));
if (result != null)
{
processor.close();
processor = null;
return result;
}
processor.start();
return null;
}
private String createProcessor() //为指定的媒体定位器产生一个处理器
{
if (locator == null)
return "Locator is null";
DataSource ds;
try
{
ds = javax.media.Manager.createDataSource(locator); //为定义的MediaLocator定位并 实例化一个适当的数据源
}
catch (Exception e)
{
return "Couldn't create DataSource";
}
try
{
processor = javax.media.Manager.createProcessor(ds); // 通过数据源产生一个处理器
}
catch (NoProcessorException npe)
{
return "Couldn't create processor";
}
catch (IOException ioe)
{
return "IOException creating processor";
}
boolean result = waitForState(processor, Processor.Configured); //等待处理器配置好
if (result == false)
return "Couldn't configure processor";
TrackControl[] tracks = processor.getTrackControls(); // 为媒体流中的每一个轨迹获取一个控制器
if (tracks == null || tracks.length < 1) // 确保至少有一个可用的轨迹
return "Couldn't find tracks in processor";
ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
processor.setContentDescriptor(cd); //设置输出的内容描述为RAW_RTP
Track.getSupportedFormats()
Format supported[];
Format chosen = null;
boolean atLeastOneTrack = false;
for (int i = 0; i < tracks.length; i++)
{ //对于每一个轨迹
Format format = tracks[i].getFormat();
if (tracks[i].isEnabled())
{ //如果轨迹可用
supported = tracks[i].getSupportedFormats();
if (supported.length > 0)
{ //如果存在支持的格式
if (supported[0] instanceof VideoFormat)
{
chosen = checkForVideoSizes(tracks[i].getFormat(),
supported[0]); //检查视频格式的尺寸,以确保正常工作
}
else
chosen = supported[0]; // 选择第一种支持的格式即可
tracks[i].setFormat(chosen);
System.err.println("Track " + i + " is set to transmit as:");
System.err.println(" " + chosen); atLeastOneTrack = true;
}
else
tracks[i].setEnabled(false);
}
else
tracks[i].setEnabled(false);
}
if (!atLeastOneTrack) //如果每个轨迹都不存在合适的格式
return "Couldn't set any of the tracks to a valid RTP format";
result = waitForState(processor, Controller.Realized); // 等待处理器实现
if (result == false)
return "Couldn't realize processor";
dataOutput = processor.getDataOutput(); // 从处理器获取输出的数据源
return null;
}
private String createTransmitter() //产生RTP会话传输
{
PushBufferDataSource pbds = (PushBufferDataSource) dataOutput; // 将数据源转化成“Push”(推)数据源
PushBufferStream pbss[] = pbds.getStreams(); // 获取“Push”数据流
rtpMgrs = new RTPManager[pbss.length]; // 为每个轨迹产生一个RTP会话管理器
for (int i = 0; i < pbss.length; i++)
{
try
{
rtpMgrs[i] = RTPManager.newInstance();
int localport = this.localPort + 2 * i; //每增加一个轨迹,端口号加2
int destPort = this.destPort + 2 * i;
InetAddress ipAddr = InetAddress.getByName(this.destIP); //获取发送目的地的IP地址
SessionAddress localAddr = new SessionAddress(InetAddress
.getLocalHost(), localport); //获取本机的会话地址
SessionAddress destAddr = new SessionAddress(ipAddr, destPort);//获取目的机器(接收端)的会话地址
rtpMgrs[i].initialize(localAddr); //将本机会话地址传给RTP管理器
rtpMgrs[i].addTarget(destAddr); // 加入目的会话地址
System.err.println("Created RTP session: " + this.destIP + " "
+ destPort+" "localport);
SendStream sendStream = rtpMgrs[i].createSendStream(dataOutput,
i); // 产生数据源的RTP传输流
sendStream.start(); //开始RTP数据流传输
}
catch (Exception e)
{
return e.getMessage();
}
}
return null;
}
// 内部监听类:处理器的状态监听器
class StateListener implements ControllerListener
{
public void controllerUpdate(ControllerEvent ce)
{
if (ce instanceof ControllerClosedEvent) // 控制器关闭
setFailed();
if (ce instanceof ControllerEvent)
{ //对于所有的控制事件
synchronized (getStateLock())
{
getStateLock().notifyAll();
//通知在waitForState()方法中等待的线程
}
}
}
}
}