腾讯实时音视频(TRTC)研究技术文档
腾讯实时音视频(TRTC)研究技术文档整体流程用户同步签名调用:返回类封装前端测试代码总结整体流程根据业务逻辑在service里签名传到前台,前台根据userId,和签名,房间号(房间号后台管理,每进入房间默认创建房间号,返回前端)进入房间,然后根据前台操作开启视频直播,此房间号后台记录后广播到用户展示的房间列表,其他用户通过点击房间号,进入各个房间,根据操作开启关闭摄像头通讯。用户同步...
·
整体流程
根据业务逻辑在service里签名传到前台,前台根据userId,和签名,房间号(房间号后台管理,每进入房间默认创建房间号,返回前端)进入房间,然后根据前台操作开启视频直播,此房间号后台记录后广播到用户展示的房间列表,其他用户通过点击房间号,进入各个房间,根据操作开启关闭摄像头通讯。
用户同步
2 .0 接口调用说明
2.1 请求URL
https://console.tim.qq.com/v4/im_open_login_svc/account_import?usersig=xxx&identifier=admin&sdkappid=88888888&random=99999999&contenttype=json
2.2 请求参数
URL中各参数的含义以及填写方式参见REST API简介。
2.3 最高调用频率
100次/秒。如需提升调用频率,请根据工单模板提交工单申请处理。
2.4 HTTP请求方式
POST
2.5 HTTP请求包体格式
JSON
2.6 请求包示例
{
"Identifier":"test",
"Nick":"test",
"FaceUrl":"http://www.qq.com"
}
2.7 请求包字段说明
字段 | 类型 | 属性 | 说明 |
---|---|---|---|
Identifier | String | 必填 | 用户名,长度不超过 32 字节 |
Nick | String | 选填 | 用户昵称 |
FaceUrl | String | 选填 | 用户昵称 |
Type | Integer | 选填 | 帐号类型,开发者默认无需填写,值0表示普通帐号,1表示机器人帐号。 |
2.8 应答包体示例
{
"ActionStatus":"OK",
"ErrorInfo":"",
"ErrorCode":0
}
2.9 应答包字段说明
字段 | 类型 | 说明 |
---|---|---|
ActionStatus | String | 请求处理的结果,OK表示处理成功,FAIL表示失败。 |
ErrorCode | Integer | 错误码。 |
ErrorInfo | String | 错误信息。 |
签名调用:
package com.example.demo.utils.tls_sigature;
import com.example.demo.utils.base64_url.base64_url;
import com.example.demo.utils.tls_dto.GenTLSSignatureResult;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.json.JSONObject;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.Charset;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.util.Arrays;
import java.util.zip.Deflater;
/**
* Created by liwenbin on 2018/9/17.
*/
public class Sigature {
/**
* @brief 生成 tls 票据,精简参数列表
* @param skdAppid 应用的 sdkappid
* @param identifier 用户 id
* @param privStr 私钥文件内容
* @param expire 有效期,以秒为单位,推荐时长一个月
* @return
* @throws IOException
*/
public static GenTLSSignatureResult GenTLSSignatureEx(
long skdAppid,
String identifier,
String privStr,
long expire) throws IOException {
GenTLSSignatureResult result = new GenTLSSignatureResult();
Security.addProvider(new BouncyCastleProvider());
Reader reader = new CharArrayReader(privStr.toCharArray());
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
PEMParser parser = new PEMParser(reader);
Object obj = parser.readObject();
parser.close();
PrivateKey privKeyStruct = converter.getPrivateKey((PrivateKeyInfo) obj);
String jsonString = "{"
+ "\"TLS.account_type\":\"" + 0 +"\","
+"\"TLS.identifier\":\"" + identifier +"\","
+"\"TLS.appid_at_3rd\":\"" + 0 +"\","
+"\"TLS.sdk_appid\":\"" + skdAppid +"\","
+"\"TLS.expire_after\":\"" + expire +"\","
+"\"TLS.version\": \"201512300000\""
+"}";
String time = String.valueOf(System.currentTimeMillis()/1000);
String SerialString =
"TLS.appid_at_3rd:" + 0 + "\n" +
"TLS.account_type:" + 0 + "\n" +
"TLS.identifier:" + identifier + "\n" +
"TLS.sdk_appid:" + skdAppid + "\n" +
"TLS.time:" + time + "\n" +
"TLS.expire_after:" + expire +"\n";
try {
//Create Signature by SerialString
Signature signature = Signature.getInstance("SHA256withECDSA", "BC");
signature.initSign(privKeyStruct);
signature.update(SerialString.getBytes(Charset.forName("UTF-8")));
byte[] signatureBytes = signature.sign();
String sigTLS = Base64.encodeBase64String(signatureBytes);
//Add TlsSig to jsonString
JSONObject jsonObject= new JSONObject(jsonString);
jsonObject.put("TLS.sig", (Object)sigTLS);
jsonObject.put("TLS.time", (Object)time);
jsonString = jsonObject.toString();
//compression
Deflater compresser = new Deflater();
compresser.setInput(jsonString.getBytes(Charset.forName("UTF-8")));
compresser.finish();
byte [] compressBytes = new byte [512];
int compressBytesLength = compresser.deflate(compressBytes);
compresser.end();
String userSig = new String(base64_url.base64EncodeUrl(Arrays.copyOfRange(compressBytes,0,compressBytesLength)));
result.urlSig = userSig;
}
catch(Exception e)
{
e.printStackTrace();
result.errMessage = "generate usersig failed";
}
return result;
}
}
返回类封装
package com.example.demo.utils.tls_dto;
/**
* Created by liwenbin on 2018/9/17.
*/
public class GenTLSSignatureResult {
//错误信息
public String errMessage;
//签名
public String urlSig;
public int expireTime;
public int initTime;
public String getErrMessage() {
return errMessage;
}
public void setErrMessage(String errMessage) {
this.errMessage = errMessage;
}
public String getUrlSig() {
return urlSig;
}
public void setUrlSig(String urlSig) {
this.urlSig = urlSig;
}
public int getExpireTime() {
return expireTime;
}
public void setExpireTime(int expireTime) {
this.expireTime = expireTime;
}
public int getInitTime() {
return initTime;
}
public void setInitTime(int initTime) {
this.initTime = initTime;
}
}
前端测试代码
客户一:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试</title>
</head>
<body >
<!-- 音视频 -->
<!--
本地视频流
muted:
本地视频流的video必须置为静音(muted),否则会出现啸叫/回声等问题
Mac / iPhone / iPad 需要用js设置muted属性
autoplay:必须为激活状态
playsinline:保证在ios safari中不全屏播放
-->
<video id="localVideo" muted autoplay playsinline></video>
<!-- 远端视频流 -->
<video id="remoteVideo" autoplay playsinline></video>
<!-- 纯音频 -->
<!-- 本地音频流 / 这种场景下,localaudio 其实没有播放的必要了,可以用来调试 -->
<!-- <audio id="localAudioMedia" muted autoplay></audio> -->
<!-- 远端音频流 -->
<!-- <audio id="remoteAudioMedia" autoplay ></audio> -->
<script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
<script src="https://sqimg.qq.com/expert_qq/webrtc/3.0/WebRTCAPI.min.js"></script>
<script>
//调试模式
var RTC = new WebRTCAPI( {
"userId": "sootower",
"sdkAppId": 1400134005,
"userSig": "eJxFkF1vgjAUhv8Lt1uWlloMuyOoodlQh7gEb5qOFuyEtkL92Jb991Wm8ebk5Hly8ua8P17*unpixkhOmaWo496zB7zHAYuzkZ2grLKic9jHoQ-ATR5F10utLhxADH0EwF1KLpSVlRzueq2tPrn13-WydjCdFjF5iyMe1knOkzrOyNyocfOSrILZUS2-dQpFThpQ6E62abM4kW205G02*fxA5cGgAodRsN8tZuspO6Nqv8m27Xvsbx5yMsf9*hbGd3T4zkXCEQAQuYGv0spWXDhGYxhgMAqunJWlPihL7ZcRQx2-fwBhWS0_",
"debug":{
"log": true, //是否在控制台打印调试日志 ,默认为false
"vconsole": true, //是否展示 vconsole (方便在移动端查看日志)
"uploadLog": true //是否上报日志
}
} );
RTC.getLocalStream({
video:true,
audio:true,
attributes:{
width:640,
height:480,
frameRate:20
}
},function( info ){
// info { stream }
var stream = info.stream;
document.getElementById("localVideo").srcObject = stream
RTC.enterRoom( {
roomid : 123456,
role: 'user'
// privateMapKey: "xxxxxxxxxxxxx" //不必须
}, function(){
//进房房间成功
console.info( "==进入房间成功==" )
RTC.startRTC({
role: 'user',
stream: stream
}, function(){
console.info( "==开始推流==" )
//成功
},function(){
console.info( "==推流失败==" )
//失败
});
} , function(data){
console.info( "==进入房间失败==" )
//进入房间失败
} );
},function ( error ){
console.error( error )
});
RTC.on( 'onRemoteStreamUpdate' , function( data ){
if( data && data.stream){
var stream1 = data.stream
console.debug( data.userId + 'enter this room with unique videoId '+ data.videoId )
document.querySelector("#remoteVideo").srcObject = stream1
// document.getElementById("localVideo").srcObject = stream
// RTC.updateStream({
// role: "user",
// stream: stream
// }, function(){
// console.debug('updateStream succ')
// }, function(){
// console.debug('updateStream failed')
// });
}else{
console.debug( 'somebody enter this room without stream' )
}
})
</script>
</body>
</html>
客户二:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>标题</title>
</head>
<body >
<!-- 音视频 -->
<!--
本地视频流
muted:
本地视频流的video必须置为静音(muted),否则会出现啸叫/回声等问题
Mac / iPhone / iPad 需要用js设置muted属性
autoplay:必须为激活状态
playsinline:保证在ios safari中不全屏播放
-->
<video id="localVideo" muted autoplay playsinline></video>
<!-- 远端视频流 -->
<video id="remoteVideo" autoplay playsinline></video>
<!-- 纯音频 -->
<!-- 本地音频流 / 这种场景下,localaudio 其实没有播放的必要了,可以用来调试 -->
<!-- <audio id="localAudioMedia" muted autoplay></audio> -->
<!-- 远端音频流 -->
<!-- <audio id="remoteAudioMedia" autoplay ></audio> -->
<script src="https://cdn.bootcss.com/jquery/1.10.2/jquery.min.js"></script>
<script src="https://sqimg.qq.com/expert_qq/webrtc/3.0/WebRTCAPI.min.js"></script>
<script>
//调试模式
var RTC = new WebRTCAPI( {
"userId": "liwenbin",
"sdkAppId": 1400134005,
"userSig": "eJxFkF1PgzAUhv8Ltxhp6Sqbd06aCPNjuGUKN02hnZwIpYG6yYz-XUZYvDkXz5M3b97z42wfN9fCGJBcWE5a6dw6yLkasfo20Cou9la1A-bpwkfoIg*q7aDRZ44wxT5B6F*CVNrCHsZcBUelc9CT6*BjgE8svY*SsKEbGr95D7UqA5uxU3gQxF3jfk1e4z7GK-c9ZC-ecrvaJVF59zzPauMtWZJSM8vBREnVz4*4ZK5X4DyvK*i6LE3lDhaXMvnJx3VDJZ4hhMlw6CQt1OrMKQnwDUV*MHFRFM2Xttz2Ro3v*P0DHgVXxg__",
"debug":{
"log": true, //是否在控制台打印调试日志 ,默认为false
"vconsole": true, //是否展示 vconsole (方便在移动端查看日志)
"uploadLog": true //是否上报日志
}
} );
RTC.getLocalStream({
video:true,
audio:true,
attributes:{
width:640,
height:480,
frameRate:20
}
},function( info ){
// info { stream }
var stream = info.stream;
document.getElementById("localVideo").srcObject = stream
RTC.enterRoom( {
roomid : 123456,
role: 'user'
// privateMapKey: "xxxxxxxxxxxxx" //不必须
}, function(){
//进房房间成功
console.info( "==进入房间成功==" )
RTC.startRTC({
role: 'user',
stream: stream
}, function(){
console.info( "==开始推流==" )
//成功
},function(){
console.info( "==推流失败==" )
//失败
});
} , function(data){
console.info( "==进入房间失败==" )
//进入房间失败
} );
},function ( error ){
console.error( error )
});
RTC.on( 'onRemoteStreamUpdate' , function( data ){
if( data && data.stream){
var stream1 = data.stream
console.debug( data.userId + 'enter this room with unique videoId '+ data.videoId )
document.querySelector("#remoteVideo").srcObject = stream1
// document.getElementById("localVideo").srcObject = stream
// RTC.updateStream({
// role: "user",
// stream: stream
// }, function(){
// console.debug('updateStream succ')
// }, function(){
// console.debug('updateStream failed')
// });
}else{
console.debug( 'somebody enter this room without stream' )
}
})
</script>
</body>
</html>
总结
经测试,h5端IOS微信内置浏览器不支持调用,Android浏览器允许打开摄像头情况下调用正常。
更多推荐
已为社区贡献1条内容
所有评论(0)