Servicio multimedia de transmisión SRS (2) Uso del mecanismo de devolución de llamada Http_CallBack del servicio SRS

SRS proporciona una serie de devoluciones de llamada http. De acuerdo con los diferentes estados del cliente que se conecta al servidor, se activa la solicitud http especificada por el usuario en este estado. El servicio definido por el usuario recibe la información transmitida por el servicio SRS y realiza una serie de operaciones Por ejemplo, cuando el cliente se conecta al servidor, juzga de acuerdo con los datos de devolución de llamada, si permite que los clientes se conecten al servidor.

El servicio SRS proporciona las siguientes devoluciones de llamada:

Versión del servicio SRS: 4.0.166

on_connect: se activa cuando el cliente se conecta al host virtual y la aplicación especificados

{
"action": "on_connect",
"client_id": 1985,
"ip": "192.168.1.10",
"vhost": "video.test.com", 
"app": "live",
"tcUrl": "rtmp://video.test.com/live?key=d2fa801d08e3f90ed1e1670e6e52651a",
"pageUrl": "http://www.test.com/live.html", 
"server_id": "vid-werty"
}

on_close: se activa cuando el cliente cierra la conexión o SRS cierra activamente la conexión

{
"action": "on_close",
"client_id": 1985,
"ip": "192.168.1.10", 
"vhost": "video.test.com", 
"app": "live",
"send_bytes": 10240, 
"recv_bytes": 10240, 
"server_id": "vid-werty"
}

on_publish: se activa cuando el cliente publica la transmisión, como enviar la transmisión al servidor en modo flash/FMLE

{
"action": "on_publish",
"client_id": 1985,
"ip": "192.168.1.10", 
"vhost": "video.test.com", 
"app": "live",
"stream": "livestream", 
"param":"?token=xxx&salt=yyy", 
"server_id": "vid-werty"
}

on_unpublish: se activa cuando el cliente deja de publicar la transmisión

{
"action": "on_unpublish",
"client_id": 1985,
"ip": "192.168.1.10", 
"vhost": "video.test.com", 
"app": "live",
"stream": "livestream", 
"param":"?token=xxx&salt=yyy", 
"server_id": "vid-werty"
}

on_play: se activa cuando el cliente comienza a reproducir la transmisión

{
"action": "on_play",
"client_id": 1985,
"ip": "192.168.1.10", 
"vhost": "video.test.com", 
"app": "live",
"stream": "livestream", 
"param":"?token=xxx&salt=yyy",
"pageUrl": "http://www.test.com/live.html", 
"server_id": "vid-werty"
}

on_stop: se activa cuando el cliente deja de jugar. Observaciones: Es posible que detener la reproducción no cierre la conexión y continúe la reproducción.

{
"action": "on_stop",
"client_id": 1985,
"ip": "192.168.1.10", 
"vhost": "video.test.com", 
"app": "live",
"stream": "livestream", 
"param":"?token=xxx&salt=yyy", 
"server_id": "vid-werty"
}

on_dvr: se activa cuando la grabación de DVR cierra un archivo flv

{
"action": "on_dvr",
"client_id": 1985,
"ip": "192.168.1.10", 
"vhost": "video.test.com", 
"app": "live",
"stream": "livestream", 
"param":"?token=xxx&salt=yyy",
"cwd": "/usr/local/srs",
"file": "./objs/nginx/html/live/livestream.1420254068776.flv", 
"server_id": "vid-werty"
}

on_hls: se activa cuando SRS obtiene archivos HLS ts

{
"action": "on_hls",
"client_id": 1985,
"ip": "192.168.1.10", 
"vhost": "video.test.com", 
"app": "live",
"stream": "livestream", 
"param":"?token=xxx&salt=yyy",
"duration": 9.36, // in seconds
"cwd": "/usr/local/srs",
"file": "./objs/nginx/html/live/livestream/2015-04-23/01/476584165.ts",
"url": "live/livestream/2015-04-23/01/476584165.ts",
"m3u8": "./objs/nginx/html/live/livestream/live.m3u8",
"m3u8_url": "live/livestream/live.m3u8",
"seq_no": 100, "server_id": "vid-werty"
}

on_hls_notify: se activa cuando SRS obtiene el archivo HLS ts, que se usa para enviar el archivo a la red CDN, al obtener el archivo ts de la red CDN. La solicitud es una solicitud GET y la dirección de la solicitud tiene el formato:

http://127.0.0.1:8085/api/v1/hls/[server_id]/[app]/[stream]/[ts_url][param];

[server_id]服务器ID替换
[app]应用名称替换
[stream]流名称替换
[ts_url]url替换
[param]参数替换
  • Evento: cuando ocurre el evento, se llamará a la dirección HTTP especificada por la devolución de llamada.
  • Dirección HTTP: se pueden admitir varias direcciones, separadas por espacios, y SRS devolverá la llamada a estas interfaces a su vez.
  • Datos: SRS envía datos POST a la interfaz HTTP. La última devolución de llamada on_hls_notify es una solicitud GET y los parámetros de la solicitud se empalman en la URL.
  • Valor devuelto: SRS requiere que el servidor HTTP devuelva HTTP200 y el contenido de la respuesta es un código de error entero (0 significa éxito); otros códigos de error desconectarán al cliente.
  • La información de transferencia de devolución de llamada anterior es proporcionada por la información de solicitud de devolución de llamada http_hooks en el GitHub oficial , que puede ser diferente de parte de la información realmente obtenida. Puede imprimirla y verla en la interfaz de servicio personalizada, habilitar la devolución de llamada y especificar la URL de solicitud Consulte la configuración de solicitud de devolución de llamada de SRS

Formato de solicitud de devolución de llamada, múltiples interfaces están separadas por espacios y terminan con un punto y coma:

on_connect http(https)://ip:puerto/api http(https)://ip:puerto/api;

demostración de prueba

Sistema de servidor: CentOS7.4

Modo de red de máquina virtual VM15Pro: puente

Dirección IP del servidor: 192.168.5.105

Puerto del servidor y servicio:

 Dirección IP de la máquina local: 192.168.5.104

1. Inicie el servicio SRS e ingrese al directorio de instalación

1.1 Ver el archivo de configuración y establecer la función de devolución de llamada

# main config for srs.
# @see full.conf for detail config.

listen              1935; //RTMP默认监听1935 TCP端口
max_connections     1000;  //最大连接数
#srs_log_tank        file;
#srs_log_file        ./objs/srs.log;
daemon              on;   //开启后台模式
http_api {
    enabled         on;   //支持外部程序管理SRS服务器,支持跨域请求,请求和响应数据只支持JSON
    listen          1985; //
}
http_server {
    enabled         on;   //开启SRS服务可视化界面查看系统信息和播放器推流器
    listen          8080;
    dir             ./objs/nginx/html;
}
rtc_server {
    enabled on;    //开启RTC服务器

    listen 8000;   //RTC默认监听8000端口为UDP端口

    candidate $CANDIDATE; //服务器提供服务的IP地址。开启RTC服务,这里一定不能错,云服务器这里可能读取不到可访问的外网IP或者错误IP地址,需要手动指定
}
vhost __defaultVhost__ {
    hls {
        enabled         on; 
    }
    http_remux {
        enabled     on;  //RTMP流转封装为http flv流分发
        mount       [vhost]/[app]/[stream].flv;
    }
    rtc {
        enabled     on;   

        #rtmp_to_rtc off; //RTMP推流转RTC拉流 

        #rtc_to_rtmp off;  //RTC推流转RTMP拉流
    }
    http_hooks {
        enabled          on;
        on_connect       https://192.168.5.102:400/connect;
        on_close         https://192.168.5.102:400/close;
        on_publish       https://192.168.5.102:400/publish;
        on_unpublish     https://192.168.5.102:400/unpublish;
        on_play          https://192.168.5.102:400/play;
        on_stop          https://192.168.5.102:400/stop;
    }
}

SRS4.0.166 no puede configurar rtmp_to_rtc, de lo contrario, el servicio de inicio informará un error ilegal, pero puede presionar RTMP y extraer RTC. No hay informes de errores al configurar este elemento en versiones posteriores, y la versión SRS4.0.X es actualmente una versión de desarrollo

1.2 Inicie el servicio y especifique la configuración de srs.conf para iniciar

cd  /usr/local/srs/SRS4.0/trunk   //进入安装目录

./objs/srs -c conf/srs.conf    //启动服务指定配置文件为srs.conf

./etc/init.d/srs status   //查看运行状态
./objs/srs -v   //查看安装版本号

 2. Cree un proyecto springboot y escriba una interfaz

clase de configuración

package com.example.live.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


/*
 * 配置类
 * @author jiang
 * @date 2021.10.17
 * */
@Configuration
public class WebConfig implements WebMvcConfigurer {
    //解决  No mapping for GET  访问静态资源
    public void addResourceHandlers(ResourceHandlerRegistry registry){
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/");

    }
    //http(https)://ip:port/访问本地址
    public void addViewControllers(ViewControllerRegistry registry){
        registry.addViewController("/").setViewName("client");
    }
}

generación de tokens y clase de verificación

package com.example.live.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.live.constant.Constant;
import java.io.UnsupportedEncodingException;
import java.util.Date;

/*
 * token生成、验证工具类
 * @author jiang
 * @date 2021.10.17
 * */
public class TokenUtils {
    //有效期  1000为1秒
    private static final long EXPIRE_TIME = 60*60*1000;
    //密钥
    private static final String SECRET = Constant.SECRET;

    /*
     * 校验token是否正确
     */
    public static boolean verify(String token, String username) {
        try {
            //根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm).withClaim("username", username).build();
            //效验token
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }


    /*
     * 获得token中的用户名
     */
    public static String getUsername(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("username").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /*
     * 生成签名
     */
    public static String sign(String username) throws UnsupportedEncodingException {
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        Algorithm algorithm = Algorithm.HMAC256(SECRET);
        Date date1 = new Date();
        return JWT.create()
                .withIssuer("auth0")//签发人
                .withClaim("username", username)//载体数据
                .withIssuedAt(date1)//签发时间
                .withExpiresAt(date)//过期时间
                .sign(algorithm);//生成新的JWT
    }
}

clase constante

package com.example.live.constant;


/*
 * 常量累
 * @author jiang
 * @date 2021.10.17
 * */
public class Constant {
    //token加密密钥
    public static final String SECRET="live";
}

Clase de encapsulación de datos de devolución de llamada SRS

package com.example.live.callbackbean;

/*
 * SRS回调数据
 * @author jiang
 * @date 2021.10.17
 * */
public class CallBackDataOnConnect {
    String action;
    String client_id;
    String ip;
    String vhost;
    String app;
    String stream;
    String tcUrl;
    String pageUrl;
    String param;

    public String getStream() {
        return stream;
    }

    public void setStream(String stream) {
        this.stream = stream;
    }

    public String getParam() {
        return param;
    }

    public void setParam(String param) {
        this.param = param;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public void setClient_id(String client_id) {
        this.client_id = client_id;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public void setVhost(String vhost) {
        this.vhost = vhost;
    }

    public void setApp(String app) {
        this.app = app;
    }

    public void setTcUrl(String tcUrl) {
        this.tcUrl = tcUrl;
    }

    public void setPageUrl(String pageUrl) {
        this.pageUrl = pageUrl;
    }

    public String getAction() {
        return action;
    }

    public String getClient_id() {
        return client_id;
    }

    public String getIp() {
        return ip;
    }

    public String getVhost() {
        return vhost;
    }

    public String getApp() {
        return app;
    }

    public String getTcUrl() {
        return tcUrl;
    }

    public String getPageUrl() {
        return pageUrl;
    }
}
package com.example.live.callbackbean;

/*
 * SRS回调数据
 * @author jiang
 * @date 2021.10.17
 * */
public class CallBackDataOnPublish {
            String server_id;
            String action ;
            String client_id ;
            String ip ;
            String vhost ;
            String app ;
            String tcUrl ;
            String stream ;
            String param ;

    public String getServer_id() {
        return server_id;
    }

    public void setServer_id(String server_id) {
        this.server_id = server_id;
    }

    public String getTcUrl() {
        return tcUrl;
    }

    public void setTcUrl(String tcUrl) {
        this.tcUrl = tcUrl;
    }

    public String getParam() {
        return param;
    }

    public void setParam(String param) {
        this.param = param;
    }

    public String getAction() {
        return action;
    }

    public String getClient_id() {
        return client_id;
    }

    public String getIp() {
        return ip;
    }

    public String getVhost() {
        return vhost;
    }

    public String getApp() {
        return app;
    }

    public String getStream() {
        return stream;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public void setClient_id(String client_id) {
        this.client_id = client_id;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public void setVhost(String vhost) {
        this.vhost = vhost;
    }

    public void setApp(String app) {
        this.app = app;
    }

    public void setStream(String stream) {
        this.stream = stream;
    }
}
package com.example.live.callbackbean;

/**
 * SRS回调数据
 * @author jiang
 * @date 2021/10/21 21:26
 */
public class CallBackDataOnPlay {
    String server_id;
    String action ;
    String client_id ;
    String ip ;
    String vhost ;
    String app ;
    String pageUrl ;
    String stream ;
    String param ;

    public String getServer_id() {
        return server_id;
    }

    public void setServer_id(String server_id) {
        this.server_id = server_id;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }

    public String getClient_id() {
        return client_id;
    }

    public void setClient_id(String client_id) {
        this.client_id = client_id;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public String getVhost() {
        return vhost;
    }

    public void setVhost(String vhost) {
        this.vhost = vhost;
    }

    public String getApp() {
        return app;
    }

    public void setApp(String app) {
        this.app = app;
    }

    public String getPageUrl() {
        return pageUrl;
    }

    public void setPageUrl(String pageUrl) {
        this.pageUrl = pageUrl;
    }

    public String getStream() {
        return stream;
    }

    public void setStream(String stream) {
        this.stream = stream;
    }

    public String getParam() {
        return param;
    }

    public void setParam(String param) {
        this.param = param;
    }
}

Interfaz e implementación de clase de servicio

package com.example.live.service;

public interface StreamService {
    public String generateURL();
}
package com.example.live.service.serviceImpl;

import com.example.live.service.StreamService;
import com.example.live.utils.TokenUtils;
import org.springframework.stereotype.Service;
import java.util.UUID;

@Service
public class StreamServiceImpl implements StreamService {
    @Override
    public String generateURL() {
        String token = null;
        String stream = null;
        try{
            token = TokenUtils.sign("jx");
            stream= UUID.randomUUID().toString();
        }catch (Exception e){
            e.getStackTrace();
        }
        String url="rtmp://192.168.5.105/live/"+stream+"?token="+token;
        return url;
    }
}

Procese la página de inicio para obtener la interfaz de solicitud de dirección push

package com.example.live.controllers;

import com.example.live.service.StreamService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/*
 * 
 * @author jiang
 * @date 2021.10.17
 * */
@Controller()
public class StreamController {
    @Autowired
    private StreamService streamService;
    @ResponseBody
    @RequestMapping("/getUrl")
    public String getUrl(){
        return streamService.generateURL();
    }

}

Interfaz de devolución de llamada SRS

package com.example.live.controllers;

import com.example.live.callbackbean.CallBackDataOnConnect;
import com.example.live.callbackbean.CallBackDataOnPlay;
import com.example.live.callbackbean.CallBackDataOnPublish;
import com.example.live.utils.TokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/*
 * 操作SRS流媒体服务回调函数
 * @author jiang
 * @date 2021.10.17
 *
 * 该类所有方法返回值均为int类型,根据SRS回调返回值要求
 * 含义:0成功,非0失败
 * */

@Controller
public class SRSCallBackController {
    private Logger log = LoggerFactory.getLogger(this.getClass());
    @ResponseBody
    @RequestMapping("/connect")
    /*
    * 客户端连接SRS服务器时回调函数请求此接口
    *返回0表示校验成功,非0为失败
    * */
    public int on_connect(@RequestBody CallBackDataOnConnect data){
        int code = 1;
            if(data.getApp()!=""&&data.getApp()!=null&&!data.getApp().isEmpty()&&"live".equals(data.getApp())){
                code = 0;
                log.info("推流应用名称正确...客户端连接成功...");
                return  code;
            }else {
                log.info("推流应用名称错误...客户端连接失败...");
                return code;
            }

    }
    @ResponseBody
    @RequestMapping("/close")
    /*
     * 客户端断开连接时触发
     * 客户端断开包括客户端主动断开和客户端被动断开(服务器主动停止客户端推流断开)
     * */
    public int on_close(@RequestBody String data){
        log.info("客户端断开连接"+data);
        return 0;
    }
    @ResponseBody
    @RequestMapping("/publish")
    /*
    * 用户推流(即直播)时触发
    * 返回0允许推流,返回非0拒绝推流
    * */
    public int on_publish(@RequestBody CallBackDataOnPublish data){
        int code = 1;
        if(data.getApp()!=""&&data.getApp()!=null&&!data.getApp().isEmpty()&&"live".equals(data.getApp())){
            //携带url验证格式为?token=....携带参数应为大于7个字符且问号在第一位
            if (data.getParam().length()>7&&data.getParam().indexOf("?")==0){
                Boolean flag = false;
                //截取?后面5个字符判断是否为token
                String str = data.getParam().substring(data.getParam().indexOf("?")+1,6);
                if("token".equals(str)){
                    //截取=后面字符串校验token是否有效
                    String token = data.getParam().substring(data.getParam().indexOf("=")+1,data.getParam().length());
                    flag = TokenUtils.verify(token,"jx");
                    if(flag){
                        code = 0;
                        String username = TokenUtils.getUsername(token);
                        log.info("token验证成功...客户端开始推流...,用户名为:"+username);
                        return  code;
                    }else {
                        log.info("token验证失败...禁止客户端推流...");
                        return code;
                    }
                }else {
                    log.info("请求未携带token...禁止客户端推流");
                    return code;
                }
            }else {
                log.info("请求未携带token...禁止客户端推流");
                return code;
            }
        }else {
            log.info("推流应用名称错误...禁止客户端推流");
            return code;
        }

    }
    @ResponseBody
    @RequestMapping("/unpublish")
    /*
    * 客户端停止推流时触发
    * 包括客户端主动停止推流和客户端被动停止推流(服务器主动停止客户端推流)
    * */
    public int on_unpublish(@RequestBody String data){
        log.info("客户端停止推流"+data);
        return 0;
    }

    @ResponseBody
    @RequestMapping("/play")
    /*
    * 客户端拉流(播放)时触发
    * 0表示允许拉流,非0表示拒绝拉流
    *
    * */
    public int on_play(@RequestBody CallBackDataOnPlay data) {
        int code = 1;

        if (data.getApp() != "" && data.getApp() != null && !data.getApp().isEmpty() && "live".equals(data.getApp())) {
            //携带url验证格式为?token=....携带参数应为大于7个字符且问号在第一位
            if (data.getParam().length()>7&&data.getParam().indexOf("?")==0){
                //截取?后面5个字符判断是否为token
                String str = data.getParam().substring(data.getParam().indexOf("?") + 1, 6);
                if ("token".equals(str)) {
                    Boolean flag = false;
                    //截取=后面字符串校验token是否有效
                    String token = data.getParam().substring(data.getParam().indexOf("=") + 1, data.getParam().length());
                    flag = TokenUtils.verify(token, "jx");
                    if (flag) {
                        code = 0;
                        String username = TokenUtils.getUsername(token);
                        log.info("token验证成功...客户端开始播放...,用户名为:" + username);
                        return code;
                    } else {
                        log.info("token验证失败...禁止客户端播放...");
                        return code;
                    }
                } else {
                    log.info("请求未携带token...禁止客户端播放");
                    return code;
                }
            }else {
                log.info("请求未携带token...禁止客户端播放");
                return code;
            }

        } else {
            log.info("推流应用名称错误...禁止客户端播放");
            return code;
        }
    }
    @ResponseBody
    @RequestMapping("/stop")
    /*
    * 客户端停止播放时触发
    * 官方介绍客户端停止播放时触发,可再次播放,实际通过PC端和移动端谷歌/火狐浏览器(webRTC协议拉流仅支持这俩浏览器)测试貌似仅服务器主动踢流时会触发此回调,
    * 客户端端主动暂停后可再播放,不会触发此回调,客户端关闭窗口会触发此回调
    * */
    public int on_stop(@RequestBody String data){
        log.info("客户端停止播放"+data);
        return 0;
    }
}

clase de inicio

package com.example.live;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LiveApplication {

    public static void main(String[] args) {
        SpringApplication.run(LiveApplication.class, args);
    }

}

página delantera

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主播端</title>

    <style>

        .stream{
            width: 100%;
            height: 50px;
            line-height: 50px;
            text-align: center;
            background-color: #0e90d2;
        }
        .div_btn{
            width: 100%;
            height: 30px;
            margin-top: 30px;
        }
        .btn{
            background-color: #2f96b4;
            width: 20%;
            height: 100%;
            text-align: center;
            margin-left: 40%;;
        }
        .push_url{
            width: 100%;
            height: 30px;
            margin-top: 50px;

        }
        span{
            display: inline-block;
            width: 20%;
            height: 30px;
            line-height: 30px;
            font-size: 18px;
            text-align: right;
            margin-left: 15%;
            margin-right: 0;
        }
        .input{

            display: inline-block;
            width: 50%;
            height: 29px;
            line-height: 29px;
            padding: 0;
            margin:0;
            border-width: 1px;
        }
        .tips{
            width: 100%;
            height: 50px;
        }
        .tips>div{
            width: 80%;
            height: 100%;
            margin: 0 10%;
        }
        .tips>div>span{
            width: 100%;
            height: 100%;
            font-size: 18px;
            line-height: 50px;
            text-align: center;
            margin-left: 0;
            color: red;
        }
    </style>
</head>
<body>
    <div class="stream">主播推流端</div>
    <div class="div_btn">
        <button class="btn" onclick="getURL()">点击获取推流地址</button>
    </div>
    <div class="push_url">
        <span>推流地址:</span><input class="input" value=""/>
    </div>
    <div class="tips">
        <div>
            <span class="tips_span"></span>
        </div>
    </div>

</body>
<script type="text/javascript" src="/static/js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" >
    $(function(){
        $("input").val("");
        var str = null;

    })
    /*
    * 请求获取推流地址
    * */
    function getURL() {
        var url="https://localhost:400/getUrl";
        $.get(
            url,
            (data)=>{
                $("input").val(data);
                str = data;
                var str1 = str.toString().substring(0,25);
                var str2 = str.toString().substring(26,str.toString().length);
                if(str2.toString().length>10){
                    var text = "温馨提示:PC端请使用OBS软件推流,其中推流地址为:"+str1+",密钥为:"
                                +str2.toString().substring(0,10)+"...";
                }else {
                    var text = "温馨提示:PC端请使用OBS软件推流,其中推流地址为:"+str1+",密钥为:"+str2;
                }
                $(".tips_span").hide();
                $(".tips_span").text(text);
                $(".tips_span").fadeIn(2000);
            }
        )
    }

</script>
</html>

configuración de las propiedades de la aplicación

# 应用名称
spring.application.name=live
# 应用服务 WEB 访问端口
#server.port=8080
#端口号HTTPS默认端口号为443,本机443端口被占用
server.port=400
#你生成的证书名字
server.ssl.key-store=tomcat.keystore
#密钥库密码
server.ssl.key-store-password=123456
server.ssl.keyStoreType=JKS
#别名
server.ssl.keyAlias=tomcat

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>live</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>live</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
       <!-- <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>-->

        <!--jwt依赖-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.example.live.LiveApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

3. Inicie springboot

Visite https://192.168.5.104:400 para obtener transmisión en vivo

 Transmisión de herramientas OBS

 La función de devolución de llamada entra en vigor

 

flujo de tracción 

Cierra el reproductor, OBS deja de transmitir

 Modifique el token incorrecto, autenticación de intento de transmisión de OBS 

 RTMP push stream HTTP_FLV pull stream, el retraso da miedo

 RTMP push stream RTC pull stream es mucho más rápido. . . Um. . Está relacionado con el entorno del servidor. . .

Supongo que te gusta

Origin blog.csdn.net/weixin_44341110/article/details/120829847
Recomendado
Clasificación