SRS流媒体服务(三)SRS服务http(s) api操作SRS服务-程序员宅基地

技术标签: srs  vue  SRS流媒体  uni-app  

SRS流媒体服务器提供了强大的API,供开发者根据自己的业务场景定制自己的流媒体服务。

本机环境:

虚拟机VMPRO15安装Linux系统:CentOS7

SRS服务版本:SRSv4-b2-4.0.215(SRSv4已于2021年12月正式发布稳定版本)

Linux开启端口与服务:

 Linux网络环境:192.168.5.104 

物理机本地网络环境:192.168.5.101

一、 测试SRS服务提供的http api首先需要在SRS配置文件中开启对应服务:

二、访问API:

2.1、SRS提供了api的面包屑,可以从根目录开始导航,不需要任何记忆。一般的字段包括:

  • code表示错误码,按照linux惯例,0表示成功。
  • urls表示是面包屑导航,该api下面的子api(链接)。
  • data表示最后一级提供服务的api,返回的数据。

2.2、使用Postman请求SRS提供的最顶级API(http://192.168.5.104:1985):

2.3、再次访问下一级API(http://192.168.5.104:1985/api):

 2.4、继续看(http://192.168.5.104:1985/api/v1):

2.5、尝试获取SRS服务器已连接的客户端信息(http://192.168.5.104:1985/api/v1/clients): 

 

 

2.6、SRS HTTP API支持跨域,js可以直接调用srs的http api。

SRS支持两种跨域方式:

  • OPTIONS: jquery可以直接跨域请求API,浏览器会发送一个OPTIONS跨域请求,SRS允许跨域后,浏览器再次发起API请求。
  • JSONP: jquery/angularjs可以发起JSONP跨域请求,服务器会将响应作为js文件,内容是调用一个函数,函数名由QueryString中的callback指定。
  • JSONP-DELETE: JSONP只能GET,因此DELETE方法是由QueryString的method指定的。

2.7、SRS内置支持https_api,只需要在配置开启https(将证书换成自己的证书)

http_api {
    enabled         on;
    listen          1985;
    https {
        #是否开启https
        enabled on;
        #监听端口号
        listen 1990;
        #SSL私钥文件
        #       openssl genrsa -out server.key 2048
        # default: ./conf/server.key
        key ./conf/server.key;
        # SSL公共证书
        #       openssl req -new -x509 -key server.key -out server.crt -days 3650 -subj "/C=CN/ST=Beijing/L=Beijing/O=Me/OU=Me/CN=ossrs.net"
        # default: ./conf/server.crt
        cert ./conf/server.crt;
    }
}

2.8、SRS提供的所有API及描述(由于版本持续更新,可能不准确):

三、接口测试踢掉连接到SRS服务器的客户端

 测试通过SRS提供的API踢掉连接到SRS的客户端,首先需要GET请求(http://192.168.5.104:1985/api/v1/clients)获取所有客户端信息,拿到客户端ID,再通过DELETE请求(http://192.168.5.104:1985/api/v1/clients/clientID)踢掉客户端,如果只踢推流客户端可通过API获取推流端(http://192.168.5.104:1985/api/v1/streams),其中streams.publish.cid即是推流客户端ID号。

3.1、使用HBuilderX创建一个uniapp项目,新建index和live2个页面,使用了uniapp官方UI组件uni-table和uni-popop,直接通过HBuilderX插件商城安装即可直接使用,使用uniapp官方推流插件live-pusher实现视频采集和推流

UI组件如下:

 

index.vue

<template>
    <view>
        <live-pusher class="livePusher-top" id="livePusher" @statechange="statechange"  :beauty="beauty" :whiteness="whiteness"  :url="url" :enable-camera="enableCamera" mode="FHD"></live-pusher>
        <button v-if="flag" @click="startLive">开始直播</button>
        <button v-if="!flag" @click="stopLive">结束直播</button>
		<button  @click="pauseLive">暂停直播</button>
		<button  @click="resumeLive">恢复直播</button>
		<view class="uni-title">美颜</view>
		<slider min="0" max="9" value="0" @change="sliderChangeBeauty" activeColor="#FFCC33" backgroundColor="#000000" block-color="#8A6DE9" block-size="20" show-value />
		<view class="uni-title">美白</view>
		<slider min="0" max="9" value="0" @change="sliderChangeWhiteness" activeColor="#FFCC33" backgroundColor="#000000" block-color="#8A6DE9" block-size="20" show-value />
		
		<uni-popup ref="popup" :mask-click="false" type="message">
			<uni-popup-message  type="warn" :message="message" :duration="0"></uni-popup-message>
		</uni-popup>
	</view>
</template>

<script>
	export default {
        data() {
            return {
                url: 'rtmp://192.168.5.104/live/1',//推流地址
                enableCamera: true,//开启摄像头
                context: null,
				beauty : 0,//美颜值
				whiteness : 0 ,//美白值
				flag : true,
				message : null,//提示消息
				date : null,//定义时间
				dateStr : null
            };
        },
        onReady() {
            this.context = uni.createLivePusherContext('livePusher', this);
            // this.context.switchCamera() // 摄像头切换(切换为后置)
			setTimeout(()=>{
				this.context.startPreview() // 摄像头预览 (不加会黑屏)
			},1000);
            
        },
        methods: {
			//开始推流
            startLive() {
                this.context.start({
                    success: (res) => {
						this.flag=!this.flag;
                        console.log('livePusher.start:' + JSON.stringify(res));
                    },
					fail: (err)=>{
						console.log("livePusher失败:"+JSON.stringify(err));
					},
					complete:(res)=>{
						console.log("livePusher执行完成:"+JSON.stringify(res));
					}
                });
            },
			//停止推流
            stopLive() {
                this.context.stop({
                    success: (res) => {
						this.flag=!this.flag;
                        console.log('livePusher.stop:'+JSON.stringify(res));
						this.context.stopPreview(); // 关闭摄像头预览
                    }
                });
            },
			//暂停推流
			pauseLive(){
				this.context.pause({
					success: (res)=>{
						console.log('livePusher.pause:'+JSON.stringify(res));
					}
				});
				
			},
			//恢复推流
			resumeLive(){
				this.context.resume({
					success: (res)=>{
						console.log('livePusher.resume:'+JSON.stringify(res));
					}
				});
			},
			//设置美颜
			sliderChangeBeauty(e){
				this.beauty = e.detail.value;
				console.log("美颜值改变"+e.detail.value);
			},
			//设置美白
			sliderChangeWhiteness(e){
				this.whiteness = e.detail.value;
				console.log("美白值改变"+e.detail.value);
			},
			//状态改变数据,部分状态码如下:
			//1001:连接RTMP服务器成功
			//1002:RTMP开始推流
			//1003:打开摄像头成功
			//1007:首帧画面采集完成
			//1008:启动硬编
			//1101:上行带宽不足,数据发送不及时
			//1102:启动网络重连
			//3004:UNKNOWN
			//3005:tcp通道发送失败 错误码[-4]
			//-1307:所有IP都已经尝试失败,可以放弃治疗
			statechange(e){
				console.log("状态"+e.detail.code+e.detail.message);
				if(e.detail.code==3005){//TCP通道断开
				this.date = new Date();
				this.dateStr = this.date.getFullYear()+":"
							+this.date.getMonth()+1+":"
							+this.date.getDate()+":"
							+this.date.getHours()+":"
							+this.date.getMinutes()+":"
							+this.date.getSeconds();
					this.flag = true;
					this.message = this.dateStr+"网络断开,正在重新连接";
					this.open();
				}if(e.detail.code==1102){//启动网络重连
					
				}if(e.detail.code==1001){//已经连接RTMO服务器
					// this.close();
					// this.message = "已连接服务器";
					// this.open();
					
				}if(e.detail.code==1002){//RTMP开始推流
					this.flag = false;
					this.close();
				}if(e.detail.code==-1307){//重连失败
					this.close();
					this.message = "重连失败";
					this.open();
				}
			},
			open() {
			        this.$refs.popup.open('top')
			},
			close() {
			        this.$refs.popup.close()
			}
			
        }
	}

</script>

<style>
.livePusher-top{
	background-color:white;
	
}
</style>

live.vue

<template>
	<view>
		<uni-table border stripe emptyText="暂无更多数据" >
		    <!-- 表头行 -->
		    <uni-tr>
		        <uni-th  align="center">客户端ID</uni-th>
		        <uni-th  align="center">客户端IP</uni-th>
		        <uni-th  align="center">类型</uni-th>
				<uni-th  align="center">操作</uni-th>
		    </uni-tr>
		    <!-- 表格数据行 -->
		    <uni-tr v-for="(list,index) in liveList">
		        <uni-td align="center">{
   {list.id}}</uni-td>
		        <uni-td align="center">{
   {list.ip}}</uni-td>
		        <uni-td align="center">{
   {list.type}}</uni-td>
				<uni-td align="center">
					<button @click="tichu(list.id,index)" class="mini-btn" type="warn" size="mini">踢出</button>
				</uni-td>
		    </uni-tr>
		    
		
		</uni-table>
		
	</view>
</template>

<script>
	
	export default {
		data() {
			return {
				//定义客户端列表
				liveList : null,
			}
		},
		onReady() {
			// 每秒更新客户端列表数据
			setInterval(()=>{
				uni.request({
					url:"http://192.168.5.104:1985/api/v1/clients",
					success: (res) => {
							this.liveList = res.data.clients;
					    },
					fail: (err) =>{
						console.log(err.data);
						console.log("失败");
					}
				})
			},1000)
			
		},
		methods: {
			tichu(clientID,index){
				uni.request({
					url:"http://192.168.5.104:1985/api/v1/clients/"+clientID,
					method:'DELETE',
					success: (res) => {
							if(res.data.code==0){
								this.liveList.splice(index,1);
							}
					    },
					fail: (err) =>{
						console.log(err.data);
						console.log("失败");
					}
				})
			}
		}
	}
</script>

<style>

</style>

3.2、SRS服务配置,开启了http_api服务,开启了RTC服务,开启RTMP转RTC流,稍后使用RTMP协议推流,RTC协议拉流(播放)

 

 

 

3.3、页面编写完可直接运行,打开HBuilderX 连接手机,真机运行,开始直播(推流)。

 

 3.4、使用谷歌浏览器打开http://192.168.5.104:8080使用RTC播放器拉流(RTC协议播放延迟低)

 3.5、使用HBuilderX运行到浏览器--Chrome,打开直播中心,踢出客户端。

 页面展示了2个客户端(GET请求 http://192.168.5.104:1985/api/v1/clients),一个推流端,一个拉流端。

PC端GIF截图(画质一言难尽,奈何CSDN不支持视频上传),在32秒左右踢流,手机端推流有断开重连,所以踢出推流端后会自动重新连接上,踢出推流端后画面静止,重连后再次动起来。

 

 手机端截图

 从上面可以看到通过http_api操作SRS服务踢出客户端成功。

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44341110/article/details/122516644

智能推荐

matlab 调速系统试验,实验三 开环直流调速系统Matlab仿真-程序员宅基地

文章浏览阅读1.2k次。开环直流调速系统Matlab仿真实训三 晶闸管开环直流调速系统的MATLAB仿真实训一、实验实训目的1.学习并掌握晶闸管开环直流调速系统模型建立及模型参数设置的方法和步骤。2.熟悉并掌握系统仿真参数设置的方法和步骤。3.学会利用MATLAB软件对系统进行稳态与动态计算与仿真。4.巩固并加深对晶闸管开环直流调速系统理论知识的理解。二、实验实训原理及知识准备1. 晶闸管开环直流调速系统的原理图..._开环直流调速系统的matlab仿真

iscroll部分机型高度计算错误原因--transform属性_iscroll transform-程序员宅基地

文章浏览阅读1.7k次。iscroll在部分手机上做下拉刷新的时候,高度会计算错误,显示为顶部部分高度被隐藏。当时使用版本是4.2.2。通过调试发现是iscroll源码的bug,在此Mark下,懒得提交Issue。iscroll4均有这个错误,在iscroll5里面已改正,但是只是在计算高度时做了防御式编程,根本原因估计还是没找到。图方便可以直接使用iscroll5,只是api变了。不想升级,可以按我的方式稍微修改下_iscroll transform

graphql----java使用_graphql.field-程序员宅基地

文章浏览阅读1.6k次。前言前一篇,已经讲了go语言中的使用。那么java端如何使用。1.定义用户结构public class User { private int id; private int age; private int sex; private String name; private String pic; // get set方法}_graphql.field

Linux的进程查看命令ps与top详解_psr top-程序员宅基地

文章浏览阅读1w次。1、ps -eFHUID进程所有者的用户标识、PID进程的进程标识、PPID父进程的进程标识、SZ进程的核心映像的页面大小、RSS进程的实际内存(驻留集)大小(单位是 1KB)、PSR绑定内核线程的处理器(如果有)的逻辑处理器号,对一个进程来说,如果它的线程全都绑定到同一处理器上,则显示该字段、STIME进程的启动时间、TTY进程的控制工作站、TIME进程的执行时间总和、CMD包含命令名_psr top

java.lang.ClassNotFoundException: ${jdbc.driverClassName}_caused by: java.lang.classnotfoundexception: ${jdb-程序员宅基地

文章浏览阅读3.4k次,点赞3次,收藏6次。错误日志错误分析一 . 配置文件中 <context:property-placeholder location=“classpath:db.properties” /> 标签没有写这个错误相信看完错误日志大家都能找的到, 就不多赘述了. 错误的原因就是, 如果没有加上面的标签, 那么下面配置文件代码中的property标签中的value属性的值就仅仅是一个string类型的..._caused by: java.lang.classnotfoundexception: ${jdbc.driverclassname}

h5页面引入java,H5页面调用原生activity-程序员宅基地

文章浏览阅读931次。原生的项目页面调用了第三方控件,并且访问页面都正常。现在将H5嵌入原生后,apk入口访问H5页面,从H5页面点击菜单调用原生activity,没有第三方控件的页面可以打开,有第三方控件的页面打开应用白屏闪退。调用原生activity代码如下:var activity = plus.android.runtimeMainActivity();var Intent = plus.android.imp...

随便推点

层级重音分析与预测方法研究_crf预测重音-程序员宅基地

文章浏览阅读357次。语音合成技术主要有三部分:1、文本分析;2、韵律建模;3语音合成文本分析文本分析处理流程:输入文本→文本预处理→文本规范化→分词→词性标注→字音转换→韵律预测→输出拼音节奏等信息文本预处理包括删除无效符号,断句,内码转换等。文本规范化的任务就是将文本中的这些特殊字符识别出来,并转化为一种规范化的表达。字音转换的任务是将待合成的文字序列转换为对应的拼音序列,即告诉后端合成器应_crf预测重音

在Python里的字符串、列表、元组、集合之间转换的一个不为人知的细节和bug_python list转化为set时长度发生变化-程序员宅基地

文章浏览阅读536次。首先看如下代码:a = ['0234','abcd']seta = set(a)b = ['0234']setb = set(b)c = ('0234','abcd')setc = set(c)d = ('0234')setd = set(d)e= tuple(b)sete = set(e)print(type(a), ' , ', a,' , ',seta)..._python list转化为set时长度发生变化

计算机专业专业课代号408,计算机专业考研你一定要知道的事情!-程序员宅基地

文章浏览阅读4.3k次。1.计算机专业专业课比较难,建议考研最好是本专业或者相关专业,有一定的基础,跨考有一定的难度。2.计算机考研主要分为学硕和专硕两个方向。学硕为计算机技术应用,专硕为计算机应用和软件工程。3.考试科目我这里只说学硕(专硕每个学校规定不同):一般情况下,初试为公共课+专业课。公共课考英语(学硕为英语一,难度较大)和政治,各占100分。专业课一考数学一,相对较难。专业课二考计算机专业基础。计算机专业基础..._408是哪个专业

使用uedior关于iframe,样式问题【已解决】-程序员宅基地

文章浏览阅读117次。网站需要主题切换,但是iframe里读取不到改变后的css变量看文件只有一个我需要一个js的位置,能添加js到ifram

大话:边缘计算、雾计算、云计算_云计算 雾计算-程序员宅基地

文章浏览阅读7.8k次,点赞9次,收藏50次。云计算一种利用互联网实现随时随地、按需、便捷地使用共享计算设施、存储设备、应用程序等资源的计算模式。云计算系统由云平台、云存储、云终端、云安全四个基本部分组成,云平台从用户的角度可分为公有云、私有云、混合云等。通过从提供服务的层次可分为:基础设施即服务(Iaas)、平台即服务(Paas)和软件即服务(Saas)通过将应用部署到云端后,可以不必再关注那些令人头疼的硬件和软件问题,它们会由云服务商去解..._云计算 雾计算

STM32-自学笔记(10.使用GPIO和SysTick定时器实现按键扫描)_stm32定时器扫描按键-程序员宅基地

文章浏览阅读5.5k次,点赞3次,收藏23次。按键抖动的原因:通常按键所用的开关都是机械弹性开关。当按键触点闭合或者断开时,由于机械触点的弹性特点,一个按键开关在闭合时不会马上就稳定的接通。在断开时也不会一下子就彻底断开。而是在闭合和断开时伴随了一系列抖动。按键消抖的方法:硬件消抖和软件消抖硬件消抖:利用电容的充放电特性对抖动过程中产生的电压毛刺进行平滑处理。软件消抖:通过延迟程序过滤,通过延迟来过滤掉抖动时间。..._stm32定时器扫描按键