这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
今天学习的内容为直播推流项目
今天完善我的基于环信SDK的推流直播+coplay项目, 主要是coplay部分, 虽然主要是写react, 但也算是巩固学习rtc相关内容吧.
coplay的需求可以简化为如下,
- 客户端A开启游戏直播, 订阅通信信道
- 客户端B加入通信信道.
- 客户端B检测用户输入, 以一定频率发送给客户端A
- 客户端A接收输入消息, 发送给游戏作为2p信号.
环信直接没有提供RTC接口, 但我找到了类似可用的协议 MQTT.
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
首先做好准备工作, 注册/开通MQTT服务, 获取 appId, host, apiUrl 等信息.
具体的, 使用sdk的流程如下
- getAppToken , 携带appClientId与secret 获取app级别access_token
- getUserToken, 用户名+cid+app token验证, 获取usertoken. 这里的cid建议是 deviceId@appID, 我这里deviceId直接使用用户名
- 建立client (host+port+cid), 并填入配置参数 + 验证信息
- 建立连接后 subscribe 你关注的 topic
- 在onMessage回调中处理信息
包装了一层useEffect 封装成react hook
class MQTT {
constructor(isClient, token, uname, onMessage, clientId, topic) {
this.client = null;
this.host = MqttConfig.host;
this.port = MqttConfig.port;
this.appClientId = MqttConfig.appClientId;
this.appClientSecret = MqttConfig.appClientSecret;
this.appId = MqttConfig.appId;
this.reconnTimeout = MqttConfig.reconnTimeout;
this.cleanSession = MqttConfig.cleanSession;
this.useSSL = MqttConfig.useSSL;
this.apiUrl = MqttConfig.apiUrl;
this.clientId = clientId;
this.username = uname;
this.password = token;
this.topic = topic;
this.onMessage = onMessage;
this.isClient = isClient;
this.queueMes = [];
this.connecting = false;
}
connect = () => {
console.log("[MQTT] conn", this.clientId);
this.connecting = false;
this.client = new Client(this.host, this.port, this.clientId);
const options = {
timeout: 3,
onSuccess: () => {
// console.log("[MQTT] connected, go subscribe ", this.topic);
if (!this.client || !this.client.isConnected()) {
// console.log("mqttClient is not connected");
// return;
}
// if (!this.isClient) {
this.client.subscribe(this.topic, { qos: 0 });
// }
if (this.queueMes.length > 0) {
this.queueMes.forEach((mes) => {
this.send(mes);
});
this.queueMes = [];
}
},
mqttVersion: 4,
useSSL: this.useSSL,
cleanSession: this.cleanSession,
onFailure: (res) => {
if (!this.isClient && !this.connecting) {
this.connecting = setTimeout(this.connect(), this.reconnTimeout);
// console.log("[MQTT] connect failed", res);
}
},
reconnect: true,
keepAliveInterval: 60,
userName: this.username,
password: this.password,
};
this.client.onConnectionLost = (res) => {
if (!this.isClient && !this.connecting) {
// console.log("[MQTT] connection lost", res);
this.connecting = setTimeout(this.connect(), this.reconnTimeout);
}
};
this.client.onMessageArrived = (message) => {
console.log("[MQTT] message arrived", message);
this.onMessage(message.payloadString);
};
this.client.connect(options);
};
disconnect = () => {
if (this.connecting) {
clearTimeout(this.connecting);
this.connecting = false;
}
if (this.client && this.client.isConnected()) {
try {
this.client.unsubscribe(this.topic);
this.client.disconnect();
} catch (e) {
console.log("mqttClient disconnect error", e);
}
}
};
send = (data) => {
if (this.client && this.client.isConnected()) {
const message = new Message(data);
message.destinationName = this.topic;
this.client.send(message);
} else {
this.queueMes.push(data);
this.connect();
}
};
isConnected = () => {
return this.client && this.client.isConnected();
};
}
const useMqtt = (topic, uname, onMessage = () => {}, isClient = true) => {
const { apiUrl, appClientId, appClientSecret, appId } = MqttConfig;
const [mqttClient, setMqttClient] = useState(null);
const clientId = `${uname}@${appId}`;
// console.log("client id is ", clientId, topic);
let mqtt = null;
useEffect(() => {
const getAppToken = async () => {
http("post", `${apiUrl}/openapi/rm/app/token`, {
appClientId: appClientId,
appClientSecret: appClientSecret,
})
.then((res) => {
const access_token = res.body.access_token;
// console.log("[MQTT] access token ", res);
getUserToken(access_token);
})
.catch(console.error);
};
const getUserToken = async (access_token) => {
axios
.post(
`${apiUrl}/openapi/rm/user/token`,
{
username: uname,
expires_in: 86400,
cid: clientId,
},
{
headers: {
"Content-Type": "application/json",
Authorization: `${access_token}`,
},
}
)
.then((res) => {
// console.log("[MQTT] user token ", res);
const token = res.data.body.access_token;
// mqttConnect(token);
mqtt = new MQTT(isClient, token, uname, onMessage, clientId, topic);
mqtt.connect();
setMqttClient(mqtt);
})
.catch(console.error);
};
getAppToken();
return () => {
if (mqtt) {
mqtt.disconnect();
}
};
}, []);
return mqttClient;
};
export default useMqtt;
使用第三方接口最快的方式还是直接调通demo在上面改造, 自己手动魔改还是需要一步步填坑的, bug还没修完, 继续写代码