package com.team.zhuoke.danmu.client;
import android.util.Log;
import com.team.zhuoke.danmu.msg.DyMessage;
import com.team.zhuoke.danmu.msg.MsgView;
import com.team.zhuoke.danmu.utils.KeepAlive;
import com.team.zhuoke.danmu.utils.KeepGetMsg;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Map;
public class DyBulletScreenClient {
private static final String TAG = "DyBulletScreenClient";
private static DyBulletScreenClient instance;
//第三方弹幕协议服务器地址
private static final String hostName = "openbarrage.douyutv.com";
//第三方弹幕协议服务器端口
private static final int port = 8601;
//设置字节获取buffer的最大值
private static final int MAX_BUFFER_LENGTH = 8192;
//socket相关配置
private Socket sock;
private BufferedOutputStream bos;
private BufferedInputStream bis;
//获取弹幕线程及心跳线程运行和停止标记
private boolean readyFlag = false;
private DyBulletScreenClient() {
}
/**
* 单例获取方法,客户端单例模式访问
*
* @return
*/
public static DyBulletScreenClient getInstance() {
if (null == instance) {
instance = new DyBulletScreenClient();
}
return instance;
}
public interface HandleMsgListener {
void handleMessage(String txt);
}
private HandleMsgListener mHandleMsgListener = null;
public void setmHandleMsgListener(HandleMsgListener mHandleMsgListener) {
this.mHandleMsgListener = mHandleMsgListener;
}
private boolean isHandleMsgListenerNull() {
return mHandleMsgListener == null;
}
public void start(int roomId, int groupId) {
init(roomId, groupId);
KeepAlive keepAlive = new KeepAlive();
keepAlive.start();
KeepGetMsg keepGetMsg = new KeepGetMsg();
keepGetMsg.start();
}
/**
* 客户端初始化,连接弹幕服务器并登陆房间及弹幕池
*
* @param roomId 房间ID
* @param groupId 弹幕池分组ID
*/
public void init(int roomId, int groupId) {
//连接弹幕服务器
this.connectServer();
//登陆指定房间
this.loginRoom(roomId);
//加入指定的弹幕池
this.joinGroup(roomId, groupId);
//设置客户端就绪标记为就绪状态
readyFlag = true;
}
public void stop() {
unInit();
}
public void unInit() {
readyFlag = false;
}
/**
* 获取弹幕客户端就绪标记
*
* @return
*/
public boolean getReadyFlag() {
return readyFlag;
}
/**
* 连接弹幕服务器
*/
private void connectServer() {
try {
//获取弹幕服务器访问host
String host = InetAddress.getByName(hostName).getHostAddress();
//建立socke连接
sock = new Socket(host, port);
//设置socket输入及输出
bos = new BufferedOutputStream(sock.getOutputStream());
bis = new BufferedInputStream(sock.getInputStream());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 登录指定房间
*
* @param roomId
*/
private void loginRoom(int roomId) {
//获取弹幕服务器登陆请求数据包
byte[] loginRequestData = DyMessage.getLoginRequestData(roomId);
try {
//发送登陆请求数据包给弹幕服务器
bos.write(loginRequestData, 0, loginRequestData.length);
bos.flush();
//初始化弹幕服务器返回值读取包大小
byte[] recvByte = new byte[MAX_BUFFER_LENGTH];
//获取弹幕服务器返回值
bis.read(recvByte, 0, recvByte.length);
//解析服务器返回的登录信息
if (DyMessage.parseLoginRespond(recvByte)) {
Log.d(TAG, "loginRoom: Receive login response successfully!");
} else {
Log.d(TAG, "loginRoom: Receive login response failed!!");
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 加入弹幕分组池
*
* @param roomId
* @param groupId
*/
private void joinGroup(int roomId, int groupId) {
//获取弹幕服务器加弹幕池请求数据包
byte[] joinGroupRequest = DyMessage.getJoinGroupRequest(roomId, groupId);
try {
//想弹幕服务器发送加入弹幕池请求数据
bos.write(joinGroupRequest, 0, joinGroupRequest.length);
bos.flush();
Log.d(TAG, "joinGroup: Send join group request successfully!");
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "joinGroup: Send join group request failed!");
}
}
/**
* 服务器心跳连接
*/
public void keepAlive() {
//获取与弹幕服务器保持心跳的请求数据包
byte[] keepAliveRequest = DyMessage.getKeepAliveData((int) (System.currentTimeMillis() / 1000));
try {
//向弹幕服务器发送心跳请求数据包
bos.write(keepAliveRequest, 0, keepAliveRequest.length);
bos.flush();
Log.d(TAG, "keepAlive: Send keep alive request successfully!");
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "keepAlive: Send keep alive request failed!");
}
}
/**
* 获取服务器返回信息
*/
public void getServerMsg() {
//初始化获取弹幕服务器返回信息包大小
byte[] recvByte = new byte[MAX_BUFFER_LENGTH];
//定义服务器返回信息的字符串
String dataStr;
try {
//读取服务器返回信息,并获取返回信息的整体字节长度
int recvLen = bis.read(recvByte, 0, recvByte.length);
//根据实际获取的字节数初始化返回信息内容长度
byte[] realBuf = new byte[recvLen];
//按照实际获取的字节长度读取返回信息
System.arraycopy(recvByte, 0, realBuf, 0, recvLen);
//根据TCP协议获取返回信息中的字符串信息
dataStr = new String(realBuf, 12, realBuf.length - 12);
// //循环处理socekt黏包情况
// while(dataStr.lastIndexOf("type@=") > 5){
// //对黏包中最后一个数据包进行解析
// MsgView msgView = new MsgView(TextUtils.substring(dataStr, 0, dataStr.lastIndexOf("type@=") - 1));
// //分析该包的数据类型,以及根据需要进行业务操作
// parseServerMsg(msgView.getMessageList());
// //处理黏包中的剩余部分
// dataStr = TextUtils.substring(dataStr, 0, dataStr.lastIndexOf("type@=") - 12);
// }
//对单一数据包进行解析
MsgView msgView = new MsgView(dataStr);
//分析该包的数据类型,以及根据需要进行业务操作
parseServerMsg(msgView.getMessageList());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 解析从服务器接受的协议,并根据需要订制业务需求
*
* @param msg
*/
private void parseServerMsg(Map<String, Object> msg) {
if (msg.get("type") != null) {
//服务器反馈错误信息
if (msg.get("type").equals("error")) {
Log.d(TAG, "parseServerMsg: msg.toString()=" + msg.toString());
//结束心跳和获取弹幕线程
this.readyFlag = false;
}
/***@TODO 根据业务需求来处理获取到的所有弹幕及礼物信息***********/
//判断消息类型
if (msg.get("type").equals("chatmsg")) {//弹幕消息
if (msg.containsKey("txt")) {
if (!isHandleMsgListenerNull()) {
mHandleMsgListener.handleMessage(msg.get("txt").toString());
}
}
}
//@TODO 其他业务信息根据需要进行添加
/*************************************************************/
}
}
}