直播工具类(生成流地址、云直播签名、云直播IM签名、云直播IM解散群组)
1.导入jar包
<!--直播IM获取签名-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>kisso</artifactId>
<version>3.7.0</version>
</dependency>
2.工具类,仅供参考
package com.es.biz.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.es.biz.modules.userlive.entity.LiveAddressEntity;
import net.sf.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.zip.Deflater;
/**
* 直播工具类
*/
public class LiveUtils {
private static Logger log = LoggerFactory.getLogger(LiveUtils.class);
//--------------------------------------------------生成流地址(开始)--------------------------------
private static final char[] DIGITS_LOWER =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
private static final String pushKey = "xxxxxxxxx"; //域名管理中点击推流域名-->推流配置-->鉴权配置-->主KEY
private static final String playKey = "xxxxxxxxx"; //域名管理中点击推流域名-->推流配置-->鉴权配置-->主KEY
private static final String pushDomain = "xxxxxxxxx.com"; //云直播控制台配置的推流域名
private static final String playDomain = "xxxxxxxxx.com";//云直播控制台配置的播放域名
/**
* 推流地址
* @param appName
* @param streamName
* @return
*/
public static LiveAddressEntity getAddressUrl(String appName, String streamName) {
long txTime = getTxTime();
String safeUrl = getSafeUrl(pushKey, streamName, txTime);
LiveAddressEntity liveAddress = new LiveAddressEntity();
liveAddress.setPushRtmpUrl("rtmp://" + pushDomain + "/" + appName + "/" + streamName + "?" + safeUrl);
return liveAddress;
}
/**
* 播放地址
* @param appName
* @param streamName
* @return
*/
public static LiveAddressEntity getPlayAddressUrl(String appName, String streamName) {
long txTime = getTxTime();
String safeUrl = getSafeUrl(playKey, streamName, txTime);
LiveAddressEntity liveAddress = new LiveAddressEntity();
liveAddress.setPlayRtmpUrl("rtmp://" + playDomain + "/" + appName + "/" + streamName + "?" + safeUrl);
liveAddress.setFlvUrl("http://" + playDomain + "/" + appName + "/" + streamName + ".flv?" + safeUrl);
liveAddress.setHlsUrl("http://" + playDomain + "/" + appName + "/" + streamName + ".m3u8?" + safeUrl);
liveAddress.setUdpUrl("webrtc://" + playDomain + "/" + appName + "/" + streamName + "?" + safeUrl);
return liveAddress;
}
/**
* 过期时间戳
* @return
*/
private static long getTxTime() {
LocalDateTime localDateTime = LocalDateTime.now();
long nowTime = localDateTime.toEpochSecond(ZoneOffset.of("+8"));
return nowTime + 60 * 60 * 24;
}
/*
* KEY+ streamName + txTime
*/
private static String getSafeUrl(String key, String streamName, long txTime) {
String input = new StringBuilder().
append(key).
append(streamName).
append(Long.toHexString(txTime).toUpperCase()).toString();
String txSecret = null;
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
txSecret = byteArrayToHexString(
messageDigest.digest(input.getBytes("UTF-8")));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return txSecret == null ? "" :
new StringBuilder().
append("txSecret=").
append(txSecret).
append("&").
append("txTime=").
append(Long.toHexString(txTime).toUpperCase()).
toString();
}
private static String byteArrayToHexString(byte[] data) {
char[] out = new char[data.length << 1];
for (int i = 0, j = 0; i < data.length; i++) {
out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
out[j++] = DIGITS_LOWER[0x0F & data[i]];
}
return new String(out);
}
//--------------------------------------------------生成流地址(结束)----------------------------------------
//--------------------------------------------------云直播签名(开始)----------------------------------------
private final static Charset UTF8 = StandardCharsets.UTF_8;
private final static String SECRET_ID = "xxxxxxxxx";
private final static String SECRET_KEY = "xxxxxxxxx";
private final static String CT_JSON = "application/json; charset=utf-8";
public static byte[] hmac256(byte[] key, String msg) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
mac.init(secretKeySpec);
return mac.doFinal(msg.getBytes(UTF8));
}
public static String sha256Hex(String s) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] d = md.digest(s.getBytes(UTF8));
return DatatypeConverter.printHexBinary(d).toLowerCase();
}
/**
* 获取云直播签名
* @return
* @throws Exception
*/
public static String getUserSign() throws Exception {
String service = "cvm";
String host = "cvm.tencentcloudapi.com";
// String region = "ap-guangzhou";
// String action = "DescribeInstances";
// String version = "2017-03-12";
String algorithm = "TC3-HMAC-SHA256";
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 注意时区,否则容易出错
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(Long.valueOf(timestamp + "000")));
// ************* 步骤 1:拼接规范请求串 *************
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" + "host:" + host + "\n";
String signedHeaders = "content-type;host";
String payload = "{\"Limit\": 1, \"Filters\": [{\"Values\": [\"\\u672a\\u547d\\u540d\"], \"Name\": \"instance-name\"}]}";
String hashedRequestPayload = sha256Hex(payload);
String canonicalRequest = httpRequestMethod + "\n" + canonicalUri + "\n" + canonicalQueryString + "\n"
+ canonicalHeaders + "\n" + signedHeaders + "\n" + hashedRequestPayload;
System.out.println(canonicalRequest);
// ************* 步骤 2:拼接待签名字符串 *************
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = algorithm + "\n" + timestamp + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
System.out.println(stringToSign);
// ************* 步骤 3:计算签名 *************
byte[] secretDate = hmac256(("TC3" + SECRET_KEY).getBytes(UTF8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
String signature = DatatypeConverter.printHexBinary(hmac256(secretSigning, stringToSign)).toLowerCase();
System.out.println(signature);
// ************* 步骤 4:拼接 Authorization *************
String authorization = algorithm + " " + "Credential=" + SECRET_ID + "/" + credentialScope + ", "
+ "SignedHeaders=" + signedHeaders + ", " + "Signature=" + signature;
System.out.println(authorization);
TreeMap<String, String> headers = new TreeMap<String, String>();
headers.put("Authorization", authorization);
headers.put("Content-Type", CT_JSON);
headers.put("Host", host);
// headers.put("X-TC-Action", action);
headers.put("X-TC-Timestamp", timestamp);
// headers.put("X-TC-Version", version);
// headers.put("X-TC-Region", region);
StringBuilder sb = new StringBuilder();
sb.append("curl -X POST https://").append(host)
.append(" -H \"Authorization: ").append(authorization).append("\"")
.append(" -H \"Content-Type: application/json; charset=utf-8\"")
.append(" -H \"Host: ").append(host).append("\"")
// .append(" -H \"X-TC-Action: ").append(action).append("\"")
.append(" -H \"X-TC-Timestamp: ").append(timestamp).append("\"");
// .append(" -H \"X-TC-Version: ").append(version).append("\"")
// .append(" -H \"X-TC-Region: ").append(region).append("\"")
// .append(" -d '").append(payload).append("'");
System.out.println(sb.toString());
return sb.toString();
}
//--------------------------------------------------云直播签名(结束)--------------------------------
//--------------------------------------------------云直播IM签名(开始)-----------------------------
private final static Long sdkappid = xxxxxxxxxL;//腾讯云appid
private final static String key = "xxxxxxxxx";//腾讯云私钥
private final static long expire = 3600 * 24 * 180 ;// 签名有效时长 180天
private static String hmacsha256(String identifier, long currTime, String base64Userbuf) {
String contentToBeSigned = "TLS.identifier:" + identifier + "\n" + "TLS.sdkappid:" + sdkappid + "\n"
+ "TLS.time:" + currTime + "\n" + "TLS.expire:" + expire + "\n";
if (null != base64Userbuf) {
contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
}
try {
byte[] byteKey = key.getBytes("UTF-8");
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
hmac.init(keySpec);
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8"));
return (new BASE64Encoder().encode(byteSig)).replaceAll("\\s*", "");
} catch (UnsupportedEncodingException e) {
return "";
} catch (NoSuchAlgorithmException e) {
return "";
} catch (InvalidKeyException e) {
return "";
}
}
private static String genSig(String identifier, byte[] userbuf) {
long currTime = System.currentTimeMillis() / 1000;
JSONObject sigDoc = new JSONObject();
sigDoc.put("TLS.ver", "2.0");
sigDoc.put("TLS.identifier", identifier);
sigDoc.put("TLS.sdkappid", sdkappid);
sigDoc.put("TLS.expire", expire);
sigDoc.put("TLS.time", currTime);
String base64UserBuf = null;
if (null != userbuf) {
base64UserBuf = new BASE64Encoder().encode(userbuf);
sigDoc.put("TLS.userbuf", base64UserBuf);
}
String sig = hmacsha256(identifier, currTime, base64UserBuf);
if (sig.length() == 0) {
return "";
}
sigDoc.put("TLS.sig", sig);
Deflater compressor = new Deflater();
compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8")));
compressor.finish();
byte[] compressedBytes = new byte[2048];
int compressedBytesLength = compressor.deflate(compressedBytes);
compressor.end();
return (new String(Base64Url.base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength)))).replaceAll("\\s*", "");
}
public static String genSig(String identifier) {
return genSig(identifier, null);
}
public static String genSigWithUserBuf(String identifier, byte[] userbuf) {
return genSig(identifier, userbuf);
}
//--------------------------------------------------云直播IM签名(结束)----------------------------
//--------------------------------------------------云直播IM解散群组(开始)----------------------
private final static String destroyGroupUrl = "https://console.tim.qq.com/v4/group_open_http_svc/destroy_group?sdkappid=SDKAPPID&identifier=IDENTIFIER&usersig=USERSIG&random=RANDOM&contenttype=json";
private final static String identifier = "admin";
public static void main(String[] args) {
destroyGroup("9459064");
}
/**
* 解散群组
* @param groupId IM群组id
*/
public static String destroyGroup(String groupId){
String userSig = genSig(identifier);
//获取32位随机数字
StringBuilder stringBuilder = new StringBuilder();
String ran = String.valueOf(new Random().nextInt(899999999) + 10000000);
String rand = String.valueOf(new Random().nextInt(899999999) + 10000000);
String rando = String.valueOf(new Random().nextInt(899999999) + 10000000);
String random = String.valueOf(new Random().nextInt(899999999) + 10000000);
stringBuilder.append(ran).append(rand).append(rando).append(random);
String requestUrl = destroyGroupUrl.replace("SDKAPPID", sdkappid.toString()).replace("IDENTIFIER", identifier)
.replace("USERSIG", userSig).replace("RANDOM", stringBuilder);
JSONObject jsonObject = new JSONObject();
jsonObject.put("GroupId", groupId);
String s = "";
try {
s = HttpClientUtil.postParameters(requestUrl, jsonObject.toJSONString());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(s);
return s;
}
//--------------------------------------------------云直播IM解散群组(结束)--------------------------
}