阿里云直播推流

先说背景:java

    项目中用到阿里云直播相关,经过阿里云提供接口判断流状态,验证部分代码比较绕,分享上来但愿能帮助他人;
算法

不说废话直接上干货:json

// 签名算法版本,目前版本是1.0
    private static final String SIGNATURE_VERSION = "1.0";
    // 签名方式,目前支持 HMAC-SHA1
    private static final String SIGNATURE_METHOD = "HMACSHA1";
    // API 版本号为日期形式:YYYY-MM-DD。本版本对应为:2016-11-01
    private static final String VERSION = "2016-11-01";
    // 请求类型(GET/POST)
    private static final String REQUEST_METHOD_TYPE = "GET";
    // 返回值类型(JSON/XML)
    private static final String RET_FORMAT_TYPE = "JSON";
    // 参数之间分隔符
    private static final Character SEPARATOR = '&';
    private static final String HOST = "https://live.aliyuncs.com";

    /**
     * 查询推流地址是否在推流
     * @return
     */
    @Override
    public Boolean steamIsOnline(String streamName) {
        logger.info("oooo 查询推流地址是否在推流");

        //构建请求参数
        Map<String, Object> params = Maps.newConcurrentMap();
        try {
            //接口参数
            params.put("Action", "DescribeLiveStreamsOnlineList");
            params.put("DomainName", ApplicationConfig.ali_live_domain_name);
            params.put("AppName", ApplicationConfig.ali_live_app_name);
            //公共参数
            buildPublicParams(params);
        }catch (Exception e) {
            logger.error("oooo 查询推流地址是否在推流, 参数构建出错", e);
        }

        //构建请求
        String request = null;
        try {
            request = buildRequest(HOST, params, ApplicationConfig.alimedia_accessKeySecret);
        } catch (UnsupportedEncodingException e) {
            logger.error("oooo 查询推流地址是否在推流, 【UTF-8】编码方式不支持", e);
        } catch (NoSuchAlgorithmException e) {
            logger.error("oooo 查询推流地址是否在推流, 签名加密【{}】失败", SIGNATURE_METHOD, e);
        } catch (InvalidKeyException e) {
            logger.error("oooo 查询推流地址是否在推流, secretKey: 【{}】无效", ApplicationConfig.alimedia_accessKeySecret, e);
        }

        //发送请求
        String result = "";
        try {
            result = send(request);
        } catch (IOException e) {
            logger.error("oooo 查询推流地址是否在推流, 请求接口失败", e);
        }

        //处理结果列表
        boolean isContainSteamName = false; //是否包含推流名称
        try {
            JSONObject resultJson = JSONObject.parseObject(result);
            JSONObject onlineInfo = resultJson.getJSONObject("OnlineInfo"); //正在推送的流信息
            JSONArray liveStreamOnlineInfo = onlineInfo.getJSONArray("LiveStreamOnlineInfo");
            for(Object obj : liveStreamOnlineInfo) {
                JSONObject jsonObject = (JSONObject)obj;
                String onlineStreamName = jsonObject.getString("StreamName"); //流名称
                if(StringUtils.equalsIgnoreCase(streamName, onlineStreamName)) {
                    isContainSteamName = true;
                    break;
                }
            }
        }catch (Exception e) {
            logger.error("oooo 查询推流地址是否在推流, 结果集解析出错, result: {}", result, e);
        }

        return isContainSteamName;
    }

    /**
     * 禁止直播流推送
     * @param streamName
     * @return
     */
    @Override
    public Boolean forbidLiveStream(String streamName) {
        logger.info("oooo 禁止直播流推送, streamName: {}", streamName);

        //构建请求参数
        Map<String, Object> params = Maps.newConcurrentMap();
        try {
            //接口参数
            params.put("Action", "ResumeLiveStream");
            params.put("DomainName", ApplicationConfig.ali_live_domain_name);
            params.put("AppName", ApplicationConfig.ali_live_app_name);
            params.put("StreamName", streamName);
            params.put("LiveStreamType", "publisher");//用于指定主播推流仍是客户端拉流,目前支持 “publisher”(主播推送)
            //公共参数
            buildPublicParams(params);
        }catch (Exception e) {
            logger.error("oooo 禁止直播流推送, 参数构建出错", e);
            return false;
        }

        //构建请求
        String request;
        try {
            request = buildRequest(HOST, params, ApplicationConfig.alimedia_accessKeySecret);
        } catch (UnsupportedEncodingException e) {
            logger.error("oooo 禁止直播流推送, 【UTF-8】编码方式不支持", e);
            return false;
        } catch (NoSuchAlgorithmException e) {
            logger.error("oooo 禁止直播流推送, 签名加密【{}】失败", SIGNATURE_METHOD, e);
            return false;
        } catch (InvalidKeyException e) {
            logger.error("oooo 禁止直播流推送, secretKey: 【{}】无效", ApplicationConfig.alimedia_accessKeySecret, e);
            return false;
        }

        //发送请求
        try {
            send(request);
        } catch (IOException e) {
            logger.error("oooo 禁止直播流推送, 请求接口失败", e);
            return false;
        }

        return true;
    }

    /**
     * 发送请求
     * @param request
     * @return
     * @throws IOException
     */
    private String send(String request) throws IOException {
        HttpClient client = new HttpClient();
        GetMethod method = new GetMethod(request);
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false));

        int statusCode = client.executeMethod(method);
        if (statusCode != HttpStatus.SC_OK) {
            logger.error("oooo 阿里云接口请求失败: request: {}, {}", request, method.getStatusLine());
        }

        byte[] responseBody = method.getResponseBody();

        return new String(responseBody);
    }

    /**
     * 构建公共参数
     * @param params
     * @return
     */
    private Map<String, Object> buildPublicParams(Map<String, Object> params) {
        final String timestamp = ParameterHelper.getISO8601Time(new Date());
        final String signatureNonce = new BigInteger(32, new SecureRandom()).toString(8);

        params.put("Format", RET_FORMAT_TYPE);
        params.put("SignatureMethod", "HMAC-SHA1");
        params.put("Timestamp", timestamp);
        params.put("AccessKeyId", ApplicationConfig.alimedia_accessKeyId);
        params.put("SignatureNonce", signatureNonce);
        params.put("Version", VERSION);
        params.put("SignatureVersion", SIGNATURE_VERSION);

        return params;
    }

    /**
     * 构建请求
     * @param host
     * @param params
     * @param secret
     * @return
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    private String buildRequest(String host, Map<String, Object> params, String secret) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        String paramsStr = "";
        List<String> sortedKeys = new ArrayList<>(params.keySet());
        Collections.sort(sortedKeys);
        for (String key : sortedKeys) {
            paramsStr += URLEncoder.encode(key, CharEncoding.UTF_8) + "=" + URLEncoder.encode(String.valueOf(params.get(key)), CharEncoding.UTF_8) + SEPARATOR;
        }

        return host + "/?" + paramsStr + "Signature=" + buildSignature(REQUEST_METHOD_TYPE, params, (secret + SEPARATOR));
    }

    /**
     * 构建签名
     * @param method
     * @param params
     * @param secretKey
     * @return
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    private String buildSignature(String method, Map<String, Object> params, String secretKey) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
        String paramsStr = "";
        List<String> sortedKeys = new ArrayList<>(params.keySet());
        Collections.sort(sortedKeys);
        for (String key : sortedKeys) {
            paramsStr += SEPARATOR + popEncode(key) + '=' + popEncode(String.valueOf(params.get(key)));
        }

        String stringToSign = method + SEPARATOR + popEncode("/") + SEPARATOR + popEncode(paramsStr.substring(1, paramsStr.length()));

        //按照 RFC2104 的定义,计算签名 HMAC 值
        Mac mac = Mac.getInstance(SIGNATURE_METHOD);
        mac.init(new SecretKeySpec(secretKey.getBytes(CharEncoding.UTF_8), SIGNATURE_METHOD));
        byte[] rawHmac = mac.doFinal(stringToSign.getBytes(CharEncoding.UTF_8));
        String sign = new BASE64Encoder().encode(rawHmac);

        return URLEncoder.encode(sign, CharEncoding.UTF_8);
    }

    /**
     * 编码
     * @param value
     * @return
     * @throws UnsupportedEncodingException
     */
    private static String popEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, CharEncoding.UTF_8).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
    }
    也没有啥技术难点刚开始上手可能须要搞清楚阿里的安全验证。帮助到您了就点个赞!谢谢!