腾讯会议官网:视频会议_语音会议_远程会议软件_在线培训系统-腾讯会议
腾讯会议API文档:腾讯会议 简介 - API 文档 - 文档中心 - 腾讯云
腾讯会议(Tencent Meeting,TM)是一款基于腾讯21年音视频通讯经验积累的高清流畅、便捷易用、安全可靠的云视频会议产品,让您随时随地高效开会,全方位满足不同场景下的会议需求。您可以使用腾讯会议进行远程音视频会议、在线协作、会管会控、会议录制、指定邀请、布局管理等。在线下办公场景时,腾讯会议提供会议室连接器,让现有会议室设备连上云会议。同时,腾讯会议也推出了简单、上手即用的新一代智能协作会议室腾讯会议 Rooms,为企业提供更先进更智能的会议室解决方案。
腾讯会议覆盖 PC、移动客户端,分为免费版、商业版(付费)、企业版(付费)。
企业会议
PC 端、移动端、小程序随时随地一键开会,灵活扩容,提高企业会议质量与效率。支持与传统硬件视频会议系统对接,只需简单拨号,即可接入腾讯会议,突破企业设备的限制,降低远程视频会议的成本。
远程教学
利用在线文档协作与实时屏幕共享,为远程课堂营造专注、互动性强的教学氛围。
远程面试
高清音视频通话品质让交流更顺畅,背景虚化让交流更集中,AI 智能美颜让会议形象更美好。
腾讯会议 简介 - API 文档 - 文档中心 - 腾讯云
腾讯会议(Tencent Meeting,TM)Rest API 是为参与腾讯会议生态系统建设的合作方开发者接入并访问腾讯会议资源提供的一组工具,是访问腾讯会议 SaaS 服务的入口。合作伙伴可以通过腾讯会议 API 进行二次开发,例如创建一个会议,修改会议,查询会议信息等。
腾讯会议的鉴权方式有两种:
- 企业内部应用鉴权
- 第三方应用鉴权(OAuth2.0)
1)注册登录腾讯会议官网
视频会议_语音会议_远程会议软件_在线培训系统-腾讯会议
我们开发需要使用的四个参数:SecretKey,SecretID,AppID,SDKID
我在开发中使用的是腾讯会议的商业版和企业版,腾讯会议和obs都是一种推流方式,腾讯会议相比较多了一个会议的概念。
商业版需要跟腾讯官方付费购买账号用户,一个账号可以有多个用户,腾讯是按照用户标准收费的,一个用户有唯一的userId和手机号,腾讯会议API主要是通过userid作为唯一标志,用户可以创建会议,使用会议等等。
腾讯收费的标准是按照用户数量来收费的,但是不限制具体是某个用户,比如我一个账号买了三个用户,我只能在官网上配置三个用户,但是可以删除用户再新增用户。
一个用户可以同时建立多个同时间段内的会议,但是有直播并发数的限制。
还可以看到腾讯会议的会议信息和用户信息
2)公共参数
REST API 对每个访问请求进行身份验证,如未提供安全凭证和签名则无法调用 API 接口。则用户可以参考腾讯云 API 的鉴权规则计算签名。
API 调用方需申请或持有安全凭证。安全凭证包括 SecretId 和 SecretKey。
- SecretId:用于表示 API 调用者身份。
- SecretKey:用于加密签名字符串和服务器端验证签名字符串的密钥。
公共参数是用于标识用户和接口鉴权目的的参数,如非必要,在每个接口单独的接口文档中不再对这些参数进行说明,但每次请求均需要携带这些参数,才能正常发起请求。
API 采用 TC3-HMAC-SHA256 签名方法,公共参数需要统一放到 HTTP Header 请求头部中。
即:每次发送请求(除了生成签名),都需要这些公共参数,放在 HTTP Header 请求头部中.
看看这几个必填的参数,X-TC-Signature 是生成的签名,SdkId 如果存在的话必须填。
注意:构造请求头,需注意自定义字段名的大小写。签名验证以及服务器端读取字段值对大小写敏感。
3)生成签名串
参与签名的字符串包括:
String tobeSig = httpMethod + "\nX-TC-Key=" + secretId + "&X-TC-Nonce=" + headerNonce + "&X-TC-Timestamp=" + headerTimestamp + "\n" + requestUri + "\n" + requestBody;
参数解释:
httpMethod:是当前请求的请求方式,以取消会议接口为例,请求方式为POST
Header 请求头中参与签名的字段包含:X-TC-Nonce,X-TC-Timestamp,X-TC-Key。 组成 Header 签名串时,参与签名的参数按参数名做字典序升序排列。
requestUri:注意是URI,不是URL,取消会议的URL是 https://api.meeting.qq.com/v1/meetings/{meetingId}/cancel,
URI 是 /v1/meetings/{meetingId}/cancel,注意{meetingId} 是实际的meetingId,比如 /v1/meetings/123456789/cancel
requestBody:接口的请求体json串,注意如果没有请求体,比如是Get请求,用空串“ ”表示,不能以null表示。
拼接好待签名的字符串后,用 SecretKey 密钥生成待签名字符串的 Hmac-SHA256 签名,将签名转换为16进制字符串形式,然后进行 Base64 编码。
以Java代码为例,所有的生成签名串代码如下:
private static String HMAC_ALGORITHM = "HmacSHA256";
private static char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static String bytesToHex(byte[] bytes) {
char[] buf = new char[bytes.length * 2];
int index = 0;
for (byte b : bytes) {
buf[index++] = HEX_CHAR[b >>> 4 & 0xf];
buf[index++] = HEX_CHAR[b & 0xf];
}
return new String(buf);
}
/**
* 生成签名,开发版本oracle jdk 1.8.0_221
*
* @param secretId 邮件下发的secret_id
* @param secretKey 邮件下发的secret_key
* @param httpMethod http请求方法 GET/POST/PUT等
* @param headerNonce X-TC-Nonce请求头,随机数
* @param headerTimestamp X-TC-Timestamp请求头,当前时间的秒级时间戳
* @param requestUri 请求uri,eg:/v1/meetings
* @param requestBody 请求体,没有的设为空串
* @return 签名,需要设置在请求头X-TC-Signature中
* @throws NoSuchAlgorithmException e
* @throws InvalidKeyException e
*/
static String sign(String secretId, String secretKey, String httpMethod, String headerNonce, String headerTimestamp, String requestUri, String requestBody)
throws NoSuchAlgorithmException, InvalidKeyException {
String tobeSig =
httpMethod + "\nX-TC-Key=" + secretId + "&X-TC-Nonce=" + headerNonce + "&X-TC-Timestamp=" + headerTimestamp + "\n" + requestUri + "\n" + requestBody;
Mac mac = Mac.getInstance(HMAC_ALGORITHM);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm());
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(tobeSig.getBytes(StandardCharsets.UTF_8));
String hexHash = bytesToHex(hash);
return new String(Base64.getEncoder().encode(hexHash.getBytes(StandardCharsets.UTF_8)));
}
我的系统是PC端推流,没有做移动端推流,所以是以第一种鉴权方式企业内部鉴权,如果做移动端推流,可以使用第二种方式第三方应用鉴权,跟做微信小程序的授权方式类似,此处不做详解,以腾讯会议参考文档为准。
腾讯会议 第三方应用鉴权(OAuth2.0) - API 文档 - 文档中心 - 腾讯云
常用的API主要有以下四个模块,会议管理,直播管理,用户管理,录制管理,详情可以看API文档。
我以会议的增删改查为例,以及用户的查询的Java代码
package com.dayee.tnst.outside.tencentMeeting.api.client;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dayee.tnst.framework.response.Result;
import com.dayee.utilities.collection.CollectionUtil;
import com.dayee.utilities.lang.StringUtil;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
@Slf4j
public class TencentMeetingApiClient {
private static final String tencent_meeting_url = "https://api.meeting.qq.com";
private static final String POST = "POST";
private static final String GET = "GET";
private static final String PUT = "PUT";
private static final String DELETE = "DELETE";
private String secretId;
private String secretKey;
private String appId;
private String sdkId;
public TencentMeetingApiClient(String secretId, String secretKey, String appId, String sdkId) {
this.secretId = secretId;
this.secretKey = secretKey;
this.appId = appId;
this.sdkId = sdkId;
}
/**
* 创建会议
* @param userId 腾讯会议用户唯一标识
* @param subject 会议主题
* @param startDate 会议开始时间
* @param endDate 会议结束时间
* @return
*/
public Result createMeetings(String userId, String subject,
Date startDate, Date endDate) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
log.info("创建会议,userId:{},subject:{},startDate:{},endDate:{}",userId,subject,startDate,endDate);
// 开始日期和结束日期的秒级时间戳
int startTime = getSecondTimestamp(startDate);
int endTime = getSecondTimestamp(endDate);
// 六位数随机数
String password = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
// body参数
HashMap parameters = new HashMap<>();
parameters.put("userid",userId);//腾讯会议用户唯一标识
parameters.put("instanceid",1);//用户的终端设备类型 1:PC
parameters.put("subject",subject);//会议主题
parameters.put("start_time",String.valueOf(startTime));//会议开始时间戳(单位秒)
parameters.put("end_time",String.valueOf(endTime));//会议结束时间戳(单位秒)
parameters.put("type",0);// 会议类型:0:预约会议
parameters.put("meeting_type",0);// 0:普通会议
parameters.put("password",password); // 入会密码,自动生成随机密码,长度不能超过6个字符
parameters.put("enable_live",true);// 会议直播-开启会议直播
// 会议媒体参数配置
HashMap settings = new HashMap<>();
settings.put("mute_enable_join",true);//会议设置-成员加入时自动静音:是
settings.put("allow_in_before_host",false);//会议设置-允许成员在主持人进会前加入会议:否
settings.put("allow_screen_shared_watermark",true);//会议设置-开启屏幕水印:是
settings.put("auto_in_waiting_room",true);//会议设置-开启等候室:是
settings.put("only_enterprise_user_allowed",false);//入会成员限制,默认所有用户均可入会
parameters.put("settings",settings); // 会议的配置
// 创建会议uri
String requestUri= "/v1/meetings";
// 发送请求
return RequestUtil.requestPost(this,requestUri,parameters);
}
/**
* 修改会议
* @param meetingId 会议的唯一 ID
* @param userId 腾讯会议用户唯一标识
* @param subject 会议主题
* @param startDate 会议开始时间
* @param endDate 会议结束时间
* @return
*/
public Result updateMeetings(String meetingId,String userId, String subject,
Date startDate, Date endDate) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
log.info("修改会议,meetingId:{},userId:{},subject:{},startDate:{},endDate:{}",meetingId,userId,subject,startDate,endDate);
// 开始日期和结束日期的秒级时间戳
int startTime = getSecondTimestamp(startDate);
int endTime = getSecondTimestamp(endDate);
//body参数
HashMap parameters = new HashMap<>();
parameters.put("userid",userId);//腾讯会议用户唯一标识
parameters.put("instanceid",1);//用户的终端设备类型 1:PC
parameters.put("subject",subject);//会议主题
parameters.put("start_time",String.valueOf(startTime));//会议开始时间戳(单位秒)
parameters.put("end_time",String.valueOf(endTime));//会议结束时间戳(单位秒)
parameters.put("type",0);// 会议类型:0:预约会议
parameters.put("meeting_type",0);// 0:普通会议
parameters.put("enable_live",true);// 会议直播-开启会议直播
// 会议媒体参数配置
HashMap settings = new HashMap<>();
settings.put("mute_enable_join",true);//会议设置-成员加入时自动静音:是
settings.put("allow_in_before_host",false);//会议设置-允许成员在主持人进会前加入会议:否
settings.put("allow_screen_shared_watermark",true);//会议设置-开启屏幕水印:是
settings.put("auto_in_waiting_room",true);//会议设置-开启等候室:是
settings.put("only_enterprise_user_allowed",false);//入会成员限制,默认所有用户均可入会
parameters.put("settings",settings); // 会议的配置
// 修改会议地址
String requestUri= "/v1/meetings/{meetingId}";
requestUri = requestUri.replace("{meetingId}", meetingId);
// 发送请求
return RequestUtil.requestPut(this,requestUri,parameters);
}
/**
* 取消会议
* @param meetingId 会议的唯一 ID
* @param userId 腾讯会议用户唯一标识
* @return
*/
public Result cancelMeetings(String meetingId,String userId) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
log.info("取消会议,meetingId:{},userId:{}",meetingId,userId);
//body参数
HashMap parameters = new HashMap<>();
parameters.put("userid",userId);//腾讯会议用户唯一标识
parameters.put("instanceid",1);//用户的终端设备类型 1:PC
parameters.put("reason_code",0);// 原因代码,可为用户自定义
// 取消会议地址
String requestUri = "/v1/meetings/{meetingId}/cancel";
requestUri = requestUri.replace("{meetingId}", meetingId);
// 发送请求
return RequestUtil.requestPost(this,requestUri,parameters);
}
/**
* 查询会议
* @param meetingId 会议的唯一 ID
* @param userId 腾讯会议用户唯一标识
* @return
*/
public Result findMeetingsById(String meetingId,String userId) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
log.info("查询会议,meetingId:{},userId:{}",meetingId,userId);
// 通过会议ID查询地址uri
String requestUri = "/v1/meetings/{meetingId}?userid={userid}&instanceid={instanceid}";
requestUri = requestUri.replace("{meetingId}", meetingId).replace("{userid}", userId).replace("{instanceid}", "1");
// 发送请求
return RequestUtil.requestGet(this,requestUri);
}
private static final class RequestUtil {
static Result requestGet(TencentMeetingApiClient2 instance, String requestUri)
throws NoSuchAlgorithmException, InvalidKeyException, IOException {
return request(instance, GET, requestUri, null);
}
static Result requestDelete(TencentMeetingApiClient2 instance, String requestUri)
throws NoSuchAlgorithmException, InvalidKeyException, IOException {
return request(instance, DELETE, requestUri, null);
}
static Result requestPost(TencentMeetingApiClient2 instance, String requestUri,
Map parameters) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
return request(instance, POST, requestUri, parameters);
}
static Result requestPut(TencentMeetingApiClient2 instance, String requestUri,
Map parameters) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
return request(instance, PUT, requestUri, parameters);
}
private static Result request(TencentMeetingApiClient2 instance,
String httpMethod,
String requestUri,
Map parameters) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
log.info("操作腾讯会议信息,SecretId:{},SecretKey:{},APPID:{},SDKID:{}",instance.secretId,instance.secretKey,instance.appId,instance.sdkId);
// 当前时间的秒级时间戳
String timestamp=String.valueOf(System.currentTimeMillis()/1000);
// 随机数
String nonce=String.valueOf(new Random().nextInt(Integer.MAX_VALUE));
HashMap header = getHeader(nonce,timestamp,instance.secretId,instance.appId,instance.sdkId);
String parameterStr = "";
if (parameters != null) {
parameterStr = JSONArray.toJSONString(parameters);
}
// 签名
String sign = SignatureUtil.sign(instance.secretId, instance.secretKey, httpMethod, nonce, timestamp, requestUri, parameterStr);
header.put("X-TC-Signature", sign);
requestUri = tencent_meeting_url + requestUri;
String body = null;
switch (httpMethod){
case GET:
body = sendGet(requestUri,header);
break;
case POST:
body = sendPost(requestUri,header,parameterStr);
break;
case PUT:
body = sendPut(requestUri,header,parameterStr);
break;
case DELETE:
body = sendDelete(requestUri,header);
}
return checkRequestSuccess(body);
}
private static HashMap getHeader(String nonce, String timestamp, String secretId, String appId,String sdkId) {
HashMap header = new HashMap<>();
header.put("X-TC-Key",secretId);
header.put("AppId", appId);
header.put("X-TC-Nonce",nonce);
header.put("X-TC-Timestamp",timestamp);
header.put("content-type", "application/json");
header.put("SdkId", sdkId);//有就加,没有可以不加
header.put("X-TC-Registered", "1");
return header;
}
}
/**
* get请求
* */
public static String sendGet(String url,HashMap header){
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
String jsonStr = "";
try {
httpGet.setHeader("X-TC-Key",header.get("X-TC-Key"));
httpGet.setHeader("AppId", header.get("AppId"));
httpGet.setHeader("SdkId", header.get("SdkId"));//有就加,没有可以不加
httpGet.setHeader("X-TC-Nonce",header.get("X-TC-Nonce"));
httpGet.setHeader("X-TC-Timestamp",header.get("X-TC-Timestamp"));
httpGet.setHeader("X-TC-Signature", header.get("X-TC-Signature"));
httpGet.setHeader("content-type", header.get("content-type"));
httpGet.setHeader("X-TC-Registered", header.get("X-TC-Registered"));
CloseableHttpResponse httpResponse = null;
httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
jsonStr = EntityUtils.toString(httpEntity,"UTF-8");
}
} catch (IOException e) {
}finally{
httpGet.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
}
}
return jsonStr;
}
/**
* post请求
* */
public static String sendPost(String url,HashMap header,String parameter){
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
String jsonStr = "";
try {
httpPost.setHeader("X-TC-Key",header.get("X-TC-Key"));
httpPost.setHeader("AppId", header.get("AppId"));
httpPost.setHeader("SdkId", header.get("SdkId"));//有就加,没有可以不加
httpPost.setHeader("X-TC-Nonce",header.get("X-TC-Nonce"));
httpPost.setHeader("X-TC-Timestamp",header.get("X-TC-Timestamp"));
httpPost.setHeader("X-TC-Signature", header.get("X-TC-Signature"));
httpPost.setHeader("content-type", header.get("content-type"));
httpPost.setHeader("X-TC-Registered", header.get("X-TC-Registered"));
httpPost.setEntity(new StringEntity(parameter,"utf-8"));
CloseableHttpResponse httpResponse = null;
httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
jsonStr = EntityUtils.toString(httpEntity,"UTF-8");
}
} catch (IOException e) {
}finally{
httpPost.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
}
}
return jsonStr;
}
/**
* put请求
* */
public static String sendPut(String url,HashMap header,String parameter){
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPut httpPut = new HttpPut(url);
String jsonStr = "";
try {
httpPut.setHeader("X-TC-Key",header.get("X-TC-Key"));
httpPut.setHeader("AppId", header.get("AppId"));
httpPut.setHeader("SdkId", header.get("SdkId"));//有就加,没有可以不加
httpPut.setHeader("X-TC-Nonce",header.get("X-TC-Nonce"));
httpPut.setHeader("X-TC-Timestamp",header.get("X-TC-Timestamp"));
httpPut.setHeader("X-TC-Signature", header.get("X-TC-Signature"));
httpPut.setHeader("content-type", header.get("content-type"));
httpPut.setHeader("X-TC-Registered", header.get("X-TC-Registered"));
httpPut.setEntity(new StringEntity(parameter,"utf-8"));
CloseableHttpResponse httpResponse = null;
httpResponse = httpClient.execute(httpPut);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
jsonStr = EntityUtils.toString(httpEntity,"UTF-8");
}
} catch (IOException e) {
}finally{
httpPut.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
}
}
return jsonStr;
}
/**
* delete请求
* */
public static String sendDelete(String url,HashMap header){
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpDelete httpDelete = new HttpDelete(url);
String jsonStr = "";
try {
httpDelete.setHeader("X-TC-Key",header.get("X-TC-Key"));
httpDelete.setHeader("AppId", header.get("AppId"));
httpDelete.setHeader("SdkId", header.get("SdkId"));//有就加,没有可以不加
httpDelete.setHeader("X-TC-Nonce",header.get("X-TC-Nonce"));
httpDelete.setHeader("X-TC-Timestamp",header.get("X-TC-Timestamp"));
httpDelete.setHeader("X-TC-Signature", header.get("X-TC-Signature"));
httpDelete.setHeader("content-type", header.get("content-type"));
httpDelete.setHeader("X-TC-Registered", header.get("X-TC-Registered"));
CloseableHttpResponse httpResponse = null;
httpResponse = httpClient.execute(httpDelete);
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
jsonStr = EntityUtils.toString(httpEntity,"UTF-8");
}
} catch (IOException e) {
}finally{
httpDelete.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
}
}
return jsonStr;
}
/**
* 校验请求是否成功
*/
public static Result checkRequestSuccess(String responseBody){
if(StringUtil.isNotBlank(responseBody)){
JSONObject jsonObject = JSONObject.parseObject(responseBody);
String error_info = jsonObject.getString("error_info");
if(StringUtil.isNotBlank(error_info)){
jsonObject = JSONObject.parseObject(error_info);
return Result.fail(jsonObject.getString("message"));
}
}
return Result.ok(responseBody);
}
/**
* 获取日期时间戳(单位秒)
* @param date
* @return
*/
public static int getSecondTimestamp(Date date){
if (null == date) {
return 0;
}
String timestamp = String.valueOf(date.getTime());
int length = timestamp.length();
if (length > 3) {
return Integer.valueOf(timestamp.substring(0,length-3));
} else {
return 0;
}
}
private static final class SignatureUtil{
private static String HMAC_ALGORITHM = "HmacSHA256";
private static char[] HEX_CHAR = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static String bytesToHex(byte[] bytes) {
char[] buf = new char[bytes.length * 2];
int index = 0;
for (byte b : bytes) {
buf[index++] = HEX_CHAR[b >>> 4 & 0xf];
buf[index++] = HEX_CHAR[b & 0xf];
}
return new String(buf);
}
/**
* 生成签名,开发版本oracle jdk 1.8.0_221
*
* @param secretId 邮件下发的secret_id
* @param secretKey 邮件下发的secret_key
* @param httpMethod http请求方法 GET/POST/PUT等
* @param headerNonce X-TC-Nonce请求头,随机数
* @param headerTimestamp X-TC-Timestamp请求头,当前时间的秒级时间戳
* @param requestUri 请求uri,eg:/v1/meetings
* @param requestBody 请求体,没有的设为空串
* @return 签名,需要设置在请求头X-TC-Signature中
* @throws NoSuchAlgorithmException e
* @throws InvalidKeyException e
*/
static String sign(String secretId, String secretKey, String httpMethod, String headerNonce, String headerTimestamp, String requestUri, String requestBody)
throws NoSuchAlgorithmException, InvalidKeyException {
String tobeSig =
httpMethod + "\nX-TC-Key=" + secretId + "&X-TC-Nonce=" + headerNonce + "&X-TC-Timestamp=" + headerTimestamp + "\n" + requestUri + "\n" + requestBody;
Mac mac = Mac.getInstance(HMAC_ALGORITHM);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), mac.getAlgorithm());
mac.init(secretKeySpec);
byte[] hash = mac.doFinal(tobeSig.getBytes(StandardCharsets.UTF_8));
String hexHash = bytesToHex(hash);
return new String(Base64.getEncoder().encode(hexHash.getBytes(StandardCharsets.UTF_8)));
}
}
}
注意1:一定要严格按照文档给的请求参数,比如取消会议中,因为在请求体中多传了一个meetingId字段,导致有时候可以取消,有时候不能取消,所以一定要注意。
注意2:如果是主持人创建会议,用腾讯会议客户端登录进入会议,一定要传这个参数,默认传1,
否则在客户端列表中不能出现会议列表,且腾讯会议客户端无法根据你的登录手机号,匹配到对应的腾讯会议,识别出你是会议主持人
附:用户的增删改查操作
注:腾讯会议官方没有提供查询所有用户的api,只有分页查询,查询所有用户需要我们自己封装处理。
/**
* 根据用户ID查询用户
* @param userid
* @return
*/
public Result findUserByUserId(String userid) throws IOException, InvalidKeyException, NoSuchAlgorithmException {
log.info("根据用户ID查询用户,userid:{}",userid);
// 获取用户详情地址
String requestUri = "/v1/users/{userid}";
requestUri = requestUri.replace("{userid}",userid);
// 发送请求
return RequestUtil.requestGet(this,requestUri);
}
/**
* 查询所有用户列表
* @return Map<手机号,userId>
*/
public Result
单元测试类:
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dayee.tnst.framework.response.Result;
import com.dayee.tnst.outside.tencentMeeting.api.client.TencentMeetingApiClient;
import com.dayee.tnst.outside.tencentMeeting.api.client.TencentMeetingApiClient2;
import com.dayee.utilities.lang.DateUtil;
import com.dayee.utilities.lang.StringUtil;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest()
@Transactional
@Slf4j
public class TencentMeetingServiceTests {
public TencentMeetingApiClient tencentMeetingApiClient;
public static String SecretId = "你自己的SecretId";
public static String SecretKey = "你自己的SecretKey";
public static String APPID = "你自己的APPID";
public static String SDKID = "你自己的SDKID";
@Before
public void init() {
tencentMeetingApiClient = new TencentMeetingApiClient(SecretId,SecretKey,APPID,SDKID);
}
@Test
public void test() throws NoSuchAlgorithmException, InvalidKeyException, IOException {
// 测试新增/修改/删除/查询用户
// 将用户手机号作为userId
testOperateUser("12345678911","12345678911");
// 测试新增/修改/删除/查询会议
testOperateMeetings("12345678911");
}
/**
* 测试新增/修改/删除用户
* 测试根据用户ID查询用户
* 测试查询所有用户列表
*
* @param userid
* @param phone
*/
public void testOperateUser(String userid,String phone) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
Result result;
// 新增用户
String userName = "凤雏";
result = tencentMeetingApiClient.saveUser(userid, phone, userName);
System.out.println("=================测试新增用户: " + result.getResult());
// 根据用户ID查询用户
result = tencentMeetingApiClient.findUserByUserId(userid);
System.out.println("=================根据用户ID查询用户结果:" + result.getResult());
// 修改用户
String userName2 = "凤雏2";
result = tencentMeetingApiClient.updateUser(userid,phone,userName2);
System.out.println("=================测试修改用户:" + result.getResult());
// 根据用户ID查询用户
result = tencentMeetingApiClient.findUserByUserId(userid);
System.out.println("=================根据用户ID查询用户结果:" + result.getResult());
// 删除用户
result = tencentMeetingApiClient.deleteUser(userid);
System.out.println("=================测试删除用户:" + result.getResult());
// 根据用户ID查询用户
result = tencentMeetingApiClient.findUserByUserId(userid);
System.out.println("=================根据用户ID查询用户结果:" + result.getResult());
// 查询所有用户列表
Result