需求:APP作为服务端的程序。主动接收来自终端推送过来的码流视频信息,并且播放。
过程:
1、app发送一条信令协议,告知终端,请给我推送数据
2、同时app开始开启服务端程序开始监听一个端口号
3、终端收到了这条协议后开始推送数据。
4、app接收数据,并且完成数据的渲染显示。
在前几篇文章里说道的信令链路是
app端拿到端口号和IP进行socket连接
//实例化一个Socket对象
socket = new Socket();
//与对应的ip、端口进行连接,先要把桥建好
socket.connect(new InetSocketAddress(ip, port), 3000);
在这个基础上,同时还需要app作为服务端
public class ServerSocketThreadTM extends Thread {
/**
*
* 使用TCP协议,连接访问
* @param port 端口
* @param mMessageListener 收到服务器端数据时将回调该接口内的
* public void Message(String msg)方法
*/
public ServerSocketThreadTM(ServerSocket sSocket, int port,
MessageListener mMessageListener, ConnectedState connectedState) {
// this.ip = ip;
Log.i(TAG,"@@@server init");
this.port = port;
this.mMessageListener = mMessageListener;
this.connectedState=connectedState;
this.serverSocket=sSocket;
}
public void run() {
Log.v("socketThread", "@@@server run");
try {
Log.v("socketThread", "@@@server socket ok");
clientSocket = serverSocket.accept();
if (clientSocket.isConnected()) {
Log.d(TAG, "@@@server建立连接");
client = new ServerSocketThreadTM.Client(clientSocket,mMessageListener);
//打开对应的输入/输出流监听
client.start();
isStart=true;
connectedState.IsConnected(true);
}else{
Log.d(TAG, "@@@server未建立连接");
isStart=false;
// try {
// Thread.sleep(500);
// }catch (Exception e){
//
// }
connectedState.IsConnected(false);
}
} catch (Exception e) {
Log.v("socketThread", "@@@server Except");
e.printStackTrace();
isStart=false;
connectedState.IsConnected(false);
}
}
}
Client封装了输入输出的两个线程
public class Client {
private SClientInputThreadTM in;
private SClientOutputThreadTM out;
public Client(Socket socket, MessageListener mMessageListener) {
//用这个监听输入流线程来接收信息
in = new SClientInputThreadTM(socket);
in.setMessageListener(mMessageListener);
//以后就用这个监听输出流的线程来发送信息了
out = new SClientOutputThreadTM(socket);
}
public void start() {
in.setStart(true);
out.setStart(true);
in.start();
// out.start();
}
// 得到读消息线程
public SClientInputThreadTM getIn() {
return in;
}
// 得到写消息线程
public SClientOutputThreadTM getOut() {
return out;
}
}
这里是开启码流链路的线程
server=new ServerSocketThreadTM(serverSocket,port_server, new MessageListener() {
@Override
public void Message(String msg) {
if(msg.equals("outOline")){//流媒体链路断开
Log.i(TAG,"@@@server connected "+"流媒体链路断开");
}
}
}, new ConnectedState() {
@Override
public void IsConnected(boolean conn) {
Log.i(TAG,"@@@server connected "+conn);
if (conn==false) {
stopvideo();
showtip("网络异常");
}
// if (!conn){
// startServer();
// }
}
});
server.start();
Client中这两个线程用于收发数据
SClientInputThreadTM in;
SClientOutputThreadTM out;
重点:本项目建立码流的过程,和文章开篇的那个过程相互对应。(注释:实际情况下会添加各种处理,比如一些音频播放的一些初始化。是否别的摄像头正在请求开启终端视频的判断,这些暂时不做考虑,只是先有个流程)
1、Activity文件 PlayRealAV.java
2、播放器(一个自定义的控件,包含开始暂停、恢复、拖动、快进快退等功能)MySurfaceView.java
3、播放器控件对应的操作类 MyVideoOperate.java
4、信令链路TCP线程(SocketThread.java(开启)、ClientInputThread.java(输入线程)、ClientOutputThread.java(输出线程))
5、码流链路RTP线程(ServerSocketThread.java(开启码流),SClientInputThread.java(输入线程),SClientOutputThread.java(输出线程))。
1、Activity加载几个SurfaceView(本项目有多个摄像头)
one_mysurfaceview = (MySurfaceViewTM)findViewById(R.id.one_mysurfaceview);
two_mysurfaceview = (MySurfaceViewTM)findViewById(R.id.two_mysurfaceview);
......
当点击播放按钮,
会建立TCP连接,同时主界面会有tcp连接状态的监听,当然如果TCP连接已经存在了就会直接开始请求实时视频了。
MySurfaceView----->VideoOperateTM------->PlayRealAV
PlayRealAV
{
public void TCPConnect() {
// 初始化
android.util.Log.i(TAG,"ip:"+ip+"--port:"+port);
client = new SocketThreadTM(ip,port, new MessageListener() {
// 收到消息后调用此方法
@Override
public void Message(String msg) {
// TODO Auto-generated method stub
// tvMessage.append(msg);
if (msg.equals("2424")) {
// if (msg.equals(sendmsg)){
android.util.Log.i(TAG,"@@@::request success");
myHandler.sendEmptyMessage(MESSAGE_SUCCESS);
} else if (msg.equals("0000")) {
myHandler.sendEmptyMessage(MESSAGE_FAILED);
} else if (msg.equals("outTime")) {
myHandler.sendEmptyMessage(OUT_TIME);
}
}
}, new ConnectedState() {
@Override
public void IsConnected(boolean conn) {
if (conn) {
myHandler.sendEmptyMessage(CONN_SUCCESS);
android.util.Log.i(TAG,"@@@:conn succs");
} else {
android.util.Log.i(TAG,"@@@a:conn faild");
myHandler.sendEmptyMessage(CONN_FAIL);
}
}
});
// 正式启动线程
client.start();
}
}
把监听的信息传给了Activity,通过Handler了告知用户。
TCP连接上了根据协议发一条16进制的的数据,告知终端,app在请求实时视频了。
这部分代码是在VideoOperate.java类中
VideoOperate
{
byte[] data = comunication.reqRealVandAudio(channel,mContext);
client.sendMsg(data);//这个client是在界面文件实例化的tcp链路控制者
}
发生成功后,终端会返回一串数据给app。在Activity里的client线程会监听她,最终的处理回到了Operate类。就是会开启服务端程序,在这篇文章的整体介绍时已经说明了。
到此为止,码流链路建立完毕,接下来的重点就是app的解析了。