//获取设备
Vector deviceList = DeviceList(null);
CaptureDeviceInfo di = (CaptureDeviceInfo) deviceList.elementAt(i);
videoFormats = di.getFormats();
MediaLocator ml = di.getLocator();
//获取数据源
1.CaptureDialog dialogCapture = new CaptureDialog(this, null);
2.CaptureDeviceInfo cdi = AudioDevice();
3.String nameCaptureDeviceAudio = Name();
4.cdi = VideoDevice();
5.String nameCaptureDeviceVideo = Name();createprocessa
6.DataSource dataSource = ateCaptureDataSource(
nameCaptureDeviceAudio,
nameCaptureDeviceVideo,
7.DataSource cdswrapper = new CDSWrapper((PushBufferDataSource) dataSource);
8.dataSource = cdswrapper;
t();
10.open(dataSource);
//打开
/
/关闭
13.dataSource.disconnect();
it(0);
6.2.1 客户端
1.采集音频、视频信号
要进行语音、视频聊天,首先需要从麦克风和摄像头采集音频、视频信号,本功能模块所完成的功能是,取得采集设备列表,取第一个可用的设备,并从设备中获得信号。流程图如6-1所示。
图6-1 采集音频、视频信号流程图
过程:
①由CaptureDeviceManager类的getDeviceList(Format)方法得到Vector类的deviceList[15]。
②若设备列表为空,则结束,若不为空,用Vector类的elementAt(int)方法获得第一个可用的设备的名字,然后强制转换为CaptureDeviceInfo类。
③调用CaptureDeviceInfo类的getLocator( )方法,便能得到该设备的定位器MediaLocator。
④由获得的MediaLocator创建DataSource,便得到设备采集到的语音、视频信号。
核心代码:
Vector audioCapDevList = DeviceList(new AudioFormat(
AudioFormat.LINEAR));
CaptureDeviceInfo audioCapDevInfo = (CaptureDeviceInfo)
audioCapDevList.elementAt(0);
MediaLocator audioCapDevLoc = Locator();
DataSource audioDataSource = ateDataSource(audioCapDevLoc);
2.处理音频、视频信号
从采集设备获得的原始信号不适合在网络上直接传输,需要对原始信号进行格式编码转换。本功能模块完成对原始信号的格式编码转换功能。处理音频、视频信号,主要是处理信号的Content Type(类似于文件类型File Type)和Format,用Processor的setContentDescriptor(ContentDescriptor)可设置Content Type,用轨道控制器(TrackControl,由Processor的getTrackControls()方法所得)的setFormat(Format)方法可设置Format。流程图如6-2所示。
图6-2 处理音频、视频信号流程图
过程:
①用上面所得的DataSource构造Processor,Processor便能得到从麦克风或摄像头中采集到的信号。
②Processor的setContentDescriptor(ContentDescripto
r)可设置Content Type。
③由Processor的getTrackControls( )方法,得到一个TrackControl类的数组。
④分别为每个TrackControl类用setFormat(Format)方法设备每个轨道的编码格式。
⑤所有的TrackControl设置完毕后,由Processor的getDataOutput( )得已处理完毕的DataSource。
核心代码:
Processor audioProcessor = ateProcessor(audioDataSource);
audioProcessor.setContentDescriptor(new ContentDescriptor(
ContentDescriptor.RAW_RTP));
TrackControl audioTracks = TrackControls();
Format supported = audioTracks[0].getSupportedFormats();
audioTracks[0].setFormat(supported[0]);
DataSource audioDataOutput = DataOutput();
3.传输音频、视频信号
有两种传输方式:TCP和UDP。UDP适合音频/视频等实时信号的传输。本功能模块用RTP实现对信号的传输,RTP是针对Internet上多媒体数据流的一个传输协议,它建立在UDP之上。流程图如6-3所示。
图6-3 传输音频、视频信号流程图
过程:
①创建一个RTPManager,并用RTPManager的静态方法newInstance( )使该RTPManager实例化。
②用该RTPManager的initialize(RTPConnector)方法设置该会话的本地地址及端口,和目的地址及端口。
③用该RTPManager的createSendStream(DataSource dataSource, int streamIndex)方法创建输出流(Stream)。
④调用输出流的start( )方法,开始发送数据流。
核心代码:
RTPManager audioRTPMgr = wInstance();
audioRTPMgr.initialize(new RTPSocketAdapter(audioDataSock, audioCtrlSock,
ipAddr, destAudioDataPort, destAudioCtrlPort));
SendStream sendStream = ateSendStream(audioDataOutput, 0);
sendStream.start();
4.接收并播放音频、视频信号
本模块用RTP完成对信号的接收和播放,并用RTCP对会话进行管理。流程图如图6-4,图6-5,图6-6所示
过程:
1)设置RTP管理器:
①创建并初始化RTP管理器。
②用addReceiveStreamListener(ReceiveStreamListener)方法,为RTPManager添加RTP事件监视器。
③设置本地和目的地的地址及端口。
2)RTP事件处理:
①监视器监视到RTP管理器的NewReceiveStreamEvent事件。
②由getReceiveStream方法获得输入流(ReceiveStream)。
③由该流的getDataSource( )方法获得接收到的数据源。
④由接收到的数据源,创建播放器(Player)。
⑤用addControllerListener(ControllerListener)为播放器添加监视器,监视播放器状态的改变。
⑥实例化播放器,使播放器的状态由unrealized变为realized。
3)Player事件处理:
①监视器监视到播放器的RealizeCompleteEvent事件。
②由该事件的getSourceController( )得到播放器。
③由播放器的getVisualComponent( )得到可视化组件,并判断该组件是否为空。
④若不为空,则显示该组件并播放
若为空,则直接播放。视频信号有可化组件,音频信号无可视化组件。
核心代码:
1)设置RTPManager
RTPManager audioRTPMgr = wInstance();
audioRTPMgr.addReceiveStreamListener(this);
audioRTPMgr.initialize(new RTPSocketAdapter(audioDataSock, audioCtrlSock,
ipAddr, destAudioDataPort, destAudioCtrlPort));
2)RTP事件处理
public synchronized void update(ReceiveStreamEvent evt){
if (evt instanceof NewReceiveStreamEvent) {
ReceiveStream stream = (
(NewReceiveStreamEvent) evt).getReceiveStream();
DataSource ds = DataSource();
Player p = atePlayer(ds);
p.addControllerListener(this);
}
}
3)Player事件处理
public synchronized void controllerUpdate(ControllerEvent ce) {
Player p = (Player) ce.getSourceController();
if (p.getVisualComponent() != null) {
chatFrame.videoPanel.add(new PlayerPanel(p));
}
p.start();
}
5.穿透NAT
分别位于两NAT后面的客户端,要进行通信,需要借助服务器进行NAT的穿透。由第五章穿透NAT的相关知识得知,目前比较常用的NAT类型是完全锥型NAT,故本软件只实现这一类型NAT的穿透。
图6-7 穿透NAT
如图6-7所示,步骤如下:
① 客户端A发UDP数据报经NAT A,把数据发送到服务器。NAT A分配端口给客户端A。服务器接收到信息后,把客户端A经NAT A后的地址及端口信息记录下来。
② 客户端B发UDP数据报经NAT B,把数据发送到服务器。NAT B分配端口给客户端B。服务器接收到
信息后,把客户端B经NAT B后的地址及端口信息记录下来。
③ 服务器把客户端B的地址及端口信息发送给客户端A,把客户端A的地址及端口信息发送给客户端B,客户端A、B就可以通过所获得的对方的地址及端口号进行通信了。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。