请教:怎么释放一次RTP会话(RTP session)中的端口

shunshine988 2010-06-14 09:21:19
下面是基于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()方法中等待的线程
}
}
}
}
}
...全文
524 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
injuer 2010-06-19
  • 打赏
  • 举报
回复
RPT做媒体流的端口应该是独立的,换句话说应该P2P实现,不是理解为中转作用,域概念搞混了吧....

RPT需要自己实现CLIENT和SERVER,两者的端口应该独立.
colin_pxx 2010-06-19
  • 打赏
  • 举报
回复
这么长的代码看了就头晕
shunshine988 2010-06-19
  • 打赏
  • 举报
回复
JMF的东西我也不怎么懂,现在老师让解决这个问题,都不知道怎么解决。为了能再次发送媒体流,只能是用新的端口再次发送了。

[Quote=引用 3 楼 injuer 的回复:]
RTP貌似不是调用方法就会释放端口了,第一次调用是侦测端口,第二次调用则是使用端口,如果第一次的方法未结束,会是第二次的发送被阻断,不想端口被占用,应该是对线程进行处理,而不是一直去想怎么释放SESSION,RPT的SESSION在线程之间是共享的.
[/Quote]
zhanlang9075 2010-06-19
  • 打赏
  • 举报
回复
I'm Sorry,小弟目前还没接触过JMF,只得帮顶一下。
[Quote=引用 3 楼 injuer 的回复:]
RTP貌似不是调用方法就会释放端口了,第一次调用是侦测端口,第二次调用则是使用端口,如果第一次的方法未结束,会是第二次的发送被阻断,不想端口被占用,应该是对线程进行处理,而不是一直去想怎么释放SESSION,RPT的SESSION在线程之间是共享的.
[/Quote]
学习了
injuer 2010-06-19
  • 打赏
  • 举报
回复
RTP貌似不是调用方法就会释放端口了,第一次调用是侦测端口,第二次调用则是使用端口,如果第一次的方法未结束,会是第二次的发送被阻断,不想端口被占用,应该是对线程进行处理,而不是一直去想怎么释放SESSION,RPT的SESSION在线程之间是共享的.
shunshine988 2010-06-18
  • 打赏
  • 举报
回复
怎么没人理我啊,up
shunshine988 2010-06-15
  • 打赏
  • 举报
回复
有人懂JMF方面的东西吗,求助

67,549

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧