Commit 2d89322b by lyg1949 Committed by GitHub

Merge pull request #5 from xiongziliang/master

update from origin
parents ade89bdb c507e8a7
Subproject commit ed47015f92cc79dfe3344b3666aafb54f1bbc2f4 Subproject commit 60aab3b9f6230312c882b9d3d360ed27c94ebd9f
Subproject commit 7f7906b05d84c5efeceecb8d6f540a71c8153431 Subproject commit 43facc343afc2b5b70bbbc3c177f20dfa936f2bf
{
"id": "95afe791-f716-426e-99c4-a797e112ab2c",
"name": "127.0.0.1",
"values": [
{
"key": "ZLMediaKit_URL",
"value": "127.0.0.1",
"enabled": true
},
{
"key": "ZLMediaKit_secret",
"value": "035c73f7-bb6b-4889-a715-d9eb2d1925cc",
"enabled": true
},
{
"key": "defaultVhost",
"value": "__defaultVhost__",
"enabled": true
}
],
"_postman_variable_scope": "environment",
"_postman_exported_at": "2020-07-11T15:16:04.479Z",
"_postman_exported_using": "Postman/7.27.1"
}
\ No newline at end of file
{
"info": {
"_postman_id": "ff20487b-d269-40c3-b811-44bc643a3b74",
"name": "ZLMediaKit",
"description": "媒体服务器",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "获取服务器api列表(getApiList)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getApiList?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getApiList"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
}
]
}
},
"response": []
},
{
"name": "获取网络线程负载(getThreadsLoad)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getThreadsLoad?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getThreadsLoad"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
}
]
}
},
"response": []
},
{
"name": "获取后台线程负载(getWorkThreadsLoad)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getWorkThreadsLoad?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getWorkThreadsLoad"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
}
]
}
},
"response": []
},
{
"name": "获取服务器配置(getServerConfig)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getServerConfig?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getServerConfig"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
}
]
}
},
"response": []
},
{
"name": "设置服务器配置(setServerConfig)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/setServerConfig?secret={{ZLMediaKit_secret}}&api.apiDebug=0",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"setServerConfig"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "api.apiDebug",
"value": "0",
"description": "配置键与配置项值"
}
]
}
},
"response": []
},
{
"name": "重启服务器(restartServer)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/restartServer?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"restartServer"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
}
]
}
},
"response": []
},
{
"name": "获取流列表(getMediaList)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getMediaList?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getMediaList"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "schema",
"value": "rtmp",
"description": "筛选协议,例如 rtsp或rtmp",
"disabled": true
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "筛选虚拟主机,例如__defaultVhost__",
"disabled": true
},
{
"key": "app",
"value": null,
"description": "筛选应用名,例如 live",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "关断单个流(close_stream)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/close_stream?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=test",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"close_stream"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "schema",
"value": "rtsp",
"description": "协议,例如 rtsp或rtmp"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "live",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "test",
"description": "流id,例如 test"
},
{
"key": "force",
"value": "1",
"description": "是否强制关闭(有人在观看是否还关闭)",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "批量关断流(close_streams)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/close_streams?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=test",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"close_streams"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "schema",
"value": "rtsp",
"description": "协议,例如 rtsp或rtmp"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "live",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "test",
"description": "流id,例如 test"
},
{
"key": "force",
"value": "1",
"description": "是否强制关闭(有人在观看是否还关闭)",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "获取TcpSession列表(getAllSession)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getAllSession?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getAllSession"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "local_port",
"value": "",
"description": "筛选本机端口,例如筛选rtsp链接:554",
"disabled": true
},
{
"key": "peer_ip",
"value": null,
"description": "筛选客户端ip",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "断开tcp连接(kick_session)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/kick_session?secret={{ZLMediaKit_secret}}&id=123456",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"kick_session"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "id",
"value": "123456",
"description": "客户端唯一id,可以通过getAllSession接口获取"
}
]
}
},
"response": []
},
{
"name": "批量断开tcp连接(kick_sessions)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/kick_sessions?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"kick_sessions"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "local_port",
"value": "",
"description": "筛选本机端口,例如筛选rtsp链接:554",
"disabled": true
},
{
"key": "peer_ip",
"value": null,
"description": "筛选客户端ip",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "添加rtsp/rtmp/hls拉流代理(addStreamProxy)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/addStreamProxy?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=live&stream=test&url=rtmp://live.hkstv.hk.lxdns.com/live/hks2&enable_rtsp=1&enable_rtmp=1",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"addStreamProxy"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "添加的流的虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "live",
"description": "添加的流的应用名,例如live"
},
{
"key": "stream",
"value": "test",
"description": "添加的流的id名,例如test"
},
{
"key": "url",
"value": "rtmp://live.hkstv.hk.lxdns.com/live/hks2",
"description": "拉流地址,例如rtmp://live.hkstv.hk.lxdns.com/live/hks2"
},
{
"key": "enable_rtsp",
"value": "1",
"description": "是否转rtsp"
},
{
"key": "enable_rtmp",
"value": "1",
"description": "是否转rtmp"
},
{
"key": "enable_hls",
"value": null,
"description": "是否转hls",
"disabled": true
},
{
"key": "enable_mp4",
"value": null,
"description": "是否mp4录制",
"disabled": true
},
{
"key": "rtp_type",
"value": null,
"description": "rtsp拉流时,拉流方式,0:tcp,1:udp,2:组播",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "关闭拉流代理(delStreamProxy)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/delStreamProxy?secret={{ZLMediaKit_secret}}&key=__defaultVhost__/live/1",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"delStreamProxy"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "key",
"value": "__defaultVhost__/live/1",
"description": "addStreamProxy接口返回的key"
}
]
}
},
"response": []
},
{
"name": "添加FFmpeg拉流代理(addFFmpegSource)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/addFFmpegSource?secret={{ZLMediaKit_secret}}&src_url=http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8&dst_url=rtmp://10.8.9.115:8554/live/hks2&timeout_ms=10000",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"addFFmpegSource"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "src_url",
"value": "http://live.hkstv.hk.lxdns.com/live/hks2/playlist.m3u8",
"description": "FFmpeg拉流地址,支持任意协议或格式(只要FFmpeg支持即可)"
},
{
"key": "dst_url",
"value": "rtmp://10.8.9.115:8554/live/hks2",
"description": "FFmpeg rtmp推流地址,一般都是推给自己,例如rtmp://127.0.0.1/live/stream_form_ffmpeg"
},
{
"key": "timeout_ms",
"value": "10000",
"description": "FFmpeg推流成功超时时间,单位毫秒"
}
]
}
},
"response": []
},
{
"name": "关闭FFmpeg拉流代理(delFFmpegSource)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/delFFmpegSource?secret={{ZLMediaKit_secret}}&key=5f748d2ef9712e4b2f6f970c1d44d93a",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"delFFmpegSource"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "key",
"value": "5f748d2ef9712e4b2f6f970c1d44d93a"
}
]
}
},
"response": []
},
{
"name": "流是否在线(isMediaOnline)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/isMediaOnline?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=proxy&stream=1",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"isMediaOnline"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "schema",
"value": "rtsp",
"description": "协议,例如 rtsp或rtmp"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "proxy",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "1",
"description": "流id,例如 test"
}
]
}
},
"response": []
},
{
"name": "获取流信息(getMediaInfo)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getMediaInfo?secret={{ZLMediaKit_secret}}&schema=rtsp&vhost={{defaultVhost}}&app=live&stream=mym9",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getMediaInfo"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "schema",
"value": "rtsp",
"description": "协议,例如 rtsp或rtmp"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "live",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "mym9",
"description": "流id,例如 test"
}
]
}
},
"response": []
},
{
"name": "获取流信息(getMp4RecordFile)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getMp4RecordFile?secret={{ZLMediaKit_secret}}&vhost={{defaultVhost}}&app=proxy&stream=2&period=2020-05-26",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getMp4RecordFile"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "proxy",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "2",
"description": "流id,例如 test"
},
{
"key": "period",
"value": "2020-05-26",
"description": "流的录像日期,格式为2020-02-01,如果不是完整的日期,那么是搜索录像文件夹列表,否则搜索对应日期下的mp4文件列表"
}
]
}
},
"response": []
},
{
"name": "开始录制(startRecord)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/startRecord?secret={{ZLMediaKit_secret}}&type=1&vhost={{defaultVhost}}&app=live&stream=obs&customized_path",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"startRecord"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "type",
"value": "1",
"description": "0为hls,1为mp4"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "live",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "obs",
"description": "流id,例如 obs"
},
{
"key": "customized_path",
"value": null,
"description": "录像保存目录"
}
]
}
},
"response": []
},
{
"name": "停止录制(stopRecord)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/stopRecord?secret={{ZLMediaKit_secret}}&type=1&vhost={{defaultVhost}}&app=live&stream=obs",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"stopRecord"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "type",
"value": "1",
"description": "0为hls,1为mp4"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "live",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "obs",
"description": "流id,例如 obs"
}
]
}
},
"response": []
},
{
"name": "是否正在录制(isRecording)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/isRecording?secret={{ZLMediaKit_secret}}&type=1&vhost={{defaultVhost}}&app=live&stream=obs",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"isRecording"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "type",
"value": "1",
"description": "0为hls,1为mp4"
},
{
"key": "vhost",
"value": "{{defaultVhost}}",
"description": "虚拟主机,例如__defaultVhost__"
},
{
"key": "app",
"value": "live",
"description": "应用名,例如 live"
},
{
"key": "stream",
"value": "obs",
"description": "流id,例如 obs"
}
]
}
},
"response": []
},
{
"name": "获取截图(getSnap)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getSnap?secret={{ZLMediaKit_secret}}&url=rtsp://www.mym9.com/101065?from=2019-06-28/01:12:13&timeout_sec=10&expire_sec=1",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getSnap"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "url",
"value": "rtsp://www.mym9.com/101065?from=2019-06-28/01:12:13",
"description": "需要截图的url,可以是本机的,也可以是远程主机的"
},
{
"key": "timeout_sec",
"value": "10",
"description": "截图失败超时时间,防止FFmpeg一直等待截图"
},
{
"key": "expire_sec",
"value": "1",
"description": "截图的过期时间,该时间内产生的截图都会作为缓存返回"
}
]
}
},
"response": []
},
{
"name": "获取rtp推流信息(getRtpInfo)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/getRtpInfo?secret={{ZLMediaKit_secret}}&stream_id=test",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"getRtpInfo"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "stream_id",
"value": "test",
"description": "流id"
}
]
}
},
"response": []
},
{
"name": "创建RTP服务器(openRtpServer)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/openRtpServer?secret={{ZLMediaKit_secret}}&port=0&enable_tcp=1&stream_id=test",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"openRtpServer"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "port",
"value": "0",
"description": "绑定的端口,0时为随机端口"
},
{
"key": "enable_tcp",
"value": "1",
"description": "创建 udp端口时是否同时监听tcp端口"
},
{
"key": "stream_id",
"value": "test",
"description": "该端口绑定的流id\n"
}
]
}
},
"response": []
},
{
"name": "关闭RTP服务器(closeRtpServer)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/closeRtpServer?secret={{ZLMediaKit_secret}}&stream_id=test",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"closeRtpServer"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
},
{
"key": "stream_id",
"value": "test",
"description": "该端口绑定的流id"
}
]
}
},
"response": []
},
{
"name": "获取RTP服务器列表(listRtpServer)",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{ZLMediaKit_URL}}/index/api/listRtpServer?secret={{ZLMediaKit_secret}}",
"host": [
"{{ZLMediaKit_URL}}"
],
"path": [
"index",
"api",
"listRtpServer"
],
"query": [
{
"key": "secret",
"value": "{{ZLMediaKit_secret}}",
"description": "api操作密钥(配置文件配置),如果操作ip是127.0.0.1,则不需要此参数"
}
]
}
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"id": "90757ea3-58c0-4f84-8000-513ed7088bbc",
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"id": "0ddf2b8e-9932-409d-a055-1ab3b7765600",
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"id": "0e272976-965b-4f25-8b9e-5916c59234d7",
"key": "ZLMediaKit_URL",
"value": "zlmediakit.com:8880"
},
{
"id": "321374c3-3357-4405-915e-9cb524d95fbc",
"key": "ZLMediaKit_secret",
"value": "035c73f7-bb6b-4889-a715-d9eb2d1925cc"
},
{
"id": "468ce1f6-ec79-44d2-819e-5cb9f42cd396",
"key": "defaultVhost",
"value": "__defaultVhost__"
}
],
"protocolProfileBehavior": {}
}
\ No newline at end of file
把这两个json文件导入postman就可以愉快的测试ZLMediaKit的restful接口了
\ No newline at end of file
...@@ -257,7 +257,7 @@ static recursive_mutex s_ffmpegMapMtx; ...@@ -257,7 +257,7 @@ static recursive_mutex s_ffmpegMapMtx;
#if defined(ENABLE_RTPPROXY) #if defined(ENABLE_RTPPROXY)
//rtp服务器列表 //rtp服务器列表
static unordered_map<uint16_t, RtpServer::Ptr> s_rtpServerMap; static unordered_map<string, RtpServer::Ptr> s_rtpServerMap;
static recursive_mutex s_rtpServerMapMtx; static recursive_mutex s_rtpServerMapMtx;
#endif #endif
...@@ -753,44 +753,53 @@ void installWebApi() { ...@@ -753,44 +753,53 @@ void installWebApi() {
val["exist"] = true; val["exist"] = true;
val["peer_ip"] = process->get_peer_ip(); val["peer_ip"] = process->get_peer_ip();
val["peer_port"] = process->get_peer_port(); val["peer_port"] = process->get_peer_port();
val["local_port"] = process->get_local_port();
val["local_ip"] = process->get_local_ip();
}); });
api_regist1("/index/api/openRtpServer",[](API_ARGS1){ api_regist1("/index/api/openRtpServer",[](API_ARGS1){
CHECK_SECRET(); CHECK_SECRET();
CHECK_ARGS("port", "enable_tcp", "stream_id"); CHECK_ARGS("port", "enable_tcp", "stream_id");
RtpServer::Ptr server = std::make_shared<RtpServer>(); auto stream_id = allArgs["stream_id"];
server->start(allArgs["port"], allArgs["stream_id"], allArgs["enable_tcp"].as<bool>());
lock_guard<recursive_mutex> lck(s_rtpServerMapMtx);
if(s_rtpServerMap.find(stream_id) != s_rtpServerMap.end()) {
//为了防止RtpProcess所有权限混乱的问题,不允许重复添加相同的stream_id
throw InvalidArgsException("该stream_id已存在");
}
auto port = server->getPort(); RtpServer::Ptr server = std::make_shared<RtpServer>();
server->setOnDetach([port]() { server->start(allArgs["port"], stream_id, allArgs["enable_tcp"].as<bool>());
server->setOnDetach([stream_id]() {
//设置rtp超时移除事件 //设置rtp超时移除事件
lock_guard<recursive_mutex> lck(s_rtpServerMapMtx); lock_guard<recursive_mutex> lck(s_rtpServerMapMtx);
s_rtpServerMap.erase(port); s_rtpServerMap.erase(stream_id);
}); });
//保存对象 //保存对象
lock_guard<recursive_mutex> lck(s_rtpServerMapMtx); s_rtpServerMap.emplace(stream_id, server);
s_rtpServerMap.emplace(port, server);
//回复json //回复json
val["port"] = port; val["port"] = server->getPort();
}); });
api_regist1("/index/api/closeRtpServer",[](API_ARGS1){ api_regist1("/index/api/closeRtpServer",[](API_ARGS1){
CHECK_SECRET(); CHECK_SECRET();
CHECK_ARGS("port"); CHECK_ARGS("stream_id");
lock_guard<recursive_mutex> lck(s_rtpServerMapMtx); lock_guard<recursive_mutex> lck(s_rtpServerMapMtx);
val["hit"] = (int)s_rtpServerMap.erase(allArgs["port"].as<uint16_t>()); val["hit"] = (int) s_rtpServerMap.erase(allArgs["stream_id"]);
}); });
api_regist1("/index/api/listRtpServer",[](API_ARGS1){ api_regist1("/index/api/listRtpServer",[](API_ARGS1){
CHECK_SECRET(); CHECK_SECRET();
lock_guard<recursive_mutex> lck(s_rtpServerMapMtx); lock_guard<recursive_mutex> lck(s_rtpServerMapMtx);
for(auto &pr : s_rtpServerMap){ for (auto &pr : s_rtpServerMap) {
val["data"].append(pr.first); Value obj;
obj["stream_id"] = pr.first;
obj["port"] = pr.second->getPort();
val["data"].append(obj);
} }
}); });
......
...@@ -118,7 +118,7 @@ RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) { ...@@ -118,7 +118,7 @@ RtpCodec::Ptr Factory::getRtpEncoderBySdp(const Sdp::Ptr &sdp) {
case CodecH265 : return std::make_shared<H265RtpEncoder>(ssrc,mtu,sample_rate,pt,interleaved); case CodecH265 : return std::make_shared<H265RtpEncoder>(ssrc,mtu,sample_rate,pt,interleaved);
case CodecAAC : return std::make_shared<AACRtpEncoder>(ssrc,mtu,sample_rate,pt,interleaved); case CodecAAC : return std::make_shared<AACRtpEncoder>(ssrc,mtu,sample_rate,pt,interleaved);
case CodecG711A : case CodecG711A :
case CodecG711U : return std::make_shared<G711RtpEncoder>(ssrc, mtu, sample_rate, pt, interleaved); case CodecG711U : return std::make_shared<G711RtpEncoder>(codec_id, ssrc, mtu, sample_rate, pt, interleaved);
default : WarnL << "暂不支持该CodecId:" << codec_id; return nullptr; default : WarnL << "暂不支持该CodecId:" << codec_id; return nullptr;
} }
} }
...@@ -129,7 +129,7 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) { ...@@ -129,7 +129,7 @@ RtpCodec::Ptr Factory::getRtpDecoderByTrack(const Track::Ptr &track) {
case CodecH265 : return std::make_shared<H265RtpDecoder>(); case CodecH265 : return std::make_shared<H265RtpDecoder>();
case CodecAAC : return std::make_shared<AACRtpDecoder>(track->clone()); case CodecAAC : return std::make_shared<AACRtpDecoder>(track->clone());
case CodecG711A : case CodecG711A :
case CodecG711U : return std::make_shared<G711RtpDecoder>(track->clone()); case CodecG711U : return std::make_shared<G711RtpDecoder>(track->getCodecId());
default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr; default : WarnL << "暂不支持该CodecId:" << track->getCodecName(); return nullptr;
} }
} }
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
namespace mediakit{ namespace mediakit{
G711RtpDecoder::G711RtpDecoder(const Track::Ptr &track){ G711RtpDecoder::G711RtpDecoder(CodecId codecid){
_codecid = track->getCodecId(); _codecid = codecid;
_frame = obtainFrame(); _frame = obtainFrame();
} }
...@@ -59,16 +59,10 @@ void G711RtpDecoder::onGetG711(const G711Frame::Ptr &frame) { ...@@ -59,16 +59,10 @@ void G711RtpDecoder::onGetG711(const G711Frame::Ptr &frame) {
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
G711RtpEncoder::G711RtpEncoder(uint32_t ui32Ssrc, G711RtpEncoder::G711RtpEncoder(CodecId codecid, uint32_t ui32Ssrc, uint32_t ui32MtuSize,
uint32_t ui32MtuSize, uint32_t ui32SampleRate, uint8_t ui8PayloadType, uint8_t ui8Interleaved) :
uint32_t ui32SampleRate, G711RtpDecoder(codecid),
uint8_t ui8PayloadType, RtpInfo(ui32Ssrc, ui32MtuSize, ui32SampleRate, ui8PayloadType, ui8Interleaved) {
uint8_t ui8Interleaved) :
RtpInfo(ui32Ssrc,
ui32MtuSize,
ui32SampleRate,
ui8PayloadType,
ui8Interleaved) {
} }
void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) { void G711RtpEncoder::inputFrame(const Frame::Ptr &frame) {
......
...@@ -21,7 +21,7 @@ class G711RtpDecoder : public RtpCodec , public ResourcePoolHelper<G711Frame> { ...@@ -21,7 +21,7 @@ class G711RtpDecoder : public RtpCodec , public ResourcePoolHelper<G711Frame> {
public: public:
typedef std::shared_ptr<G711RtpDecoder> Ptr; typedef std::shared_ptr<G711RtpDecoder> Ptr;
G711RtpDecoder(const Track::Ptr &track); G711RtpDecoder(CodecId codecid);
~G711RtpDecoder() {} ~G711RtpDecoder() {}
/** /**
...@@ -35,9 +35,6 @@ public: ...@@ -35,9 +35,6 @@ public:
return _codecid; return _codecid;
} }
protected:
G711RtpDecoder() {}
private: private:
void onGetG711(const G711Frame::Ptr &frame); void onGetG711(const G711Frame::Ptr &frame);
G711Frame::Ptr obtainFrame(); G711Frame::Ptr obtainFrame();
...@@ -61,7 +58,8 @@ public: ...@@ -61,7 +58,8 @@ public:
* @param ui8PayloadType pt类型 * @param ui8PayloadType pt类型
* @param ui8Interleaved rtsp interleaved 值 * @param ui8Interleaved rtsp interleaved 值
*/ */
G711RtpEncoder(uint32_t ui32Ssrc, G711RtpEncoder(CodecId codecid,
uint32_t ui32Ssrc,
uint32_t ui32MtuSize, uint32_t ui32MtuSize,
uint32_t ui32SampleRate, uint32_t ui32SampleRate,
uint8_t ui8PayloadType = 0, uint8_t ui8PayloadType = 0,
......
...@@ -80,7 +80,9 @@ void RtpSelector::delProcess(const string &stream_id,const RtpProcess *ptr) { ...@@ -80,7 +80,9 @@ void RtpSelector::delProcess(const string &stream_id,const RtpProcess *ptr) {
if (it->second->getProcess().get() != ptr) { if (it->second->getProcess().get() != ptr) {
return; return;
} }
auto process = it->second->getProcess();
_map_rtp_process.erase(it); _map_rtp_process.erase(it);
process->onDetach();
} }
void RtpSelector::onManager() { void RtpSelector::onManager() {
......
...@@ -56,29 +56,29 @@ static unordered_map<string, weak_ptr<RtspSession> > g_mapGetter; ...@@ -56,29 +56,29 @@ static unordered_map<string, weak_ptr<RtspSession> > g_mapGetter;
//对g_mapGetter上锁保护 //对g_mapGetter上锁保护
static recursive_mutex g_mtxGetter; static recursive_mutex g_mtxGetter;
RtspSession::RtspSession(const Socket::Ptr &pSock) : TcpSession(pSock) { RtspSession::RtspSession(const Socket::Ptr &sock) : TcpSession(sock) {
DebugP(this); DebugP(this);
GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond); GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond);
pSock->setSendTimeOutSecond(keep_alive_sec); sock->setSendTimeOutSecond(keep_alive_sec);
//起始接收buffer缓存设置为4K,节省内存 //起始接收buffer缓存设置为4K,节省内存
pSock->setReadBuffer(std::make_shared<BufferRaw>(4 * 1024)); sock->setReadBuffer(std::make_shared<BufferRaw>(4 * 1024));
} }
RtspSession::~RtspSession() { RtspSession::~RtspSession() {
DebugP(this); DebugP(this);
} }
void RtspSession::onError(const SockException& err) { void RtspSession::onError(const SockException &err) {
bool isPlayer = !_pushSrc; bool isPlayer = !_push_src;
uint64_t duration = _ticker.createdTime()/1000; uint64_t duration = _alive_ticker.createdTime() / 1000;
WarnP(this) << (isPlayer ? "RTSP播放器(" : "RTSP推流器(") WarnP(this) << (isPlayer ? "RTSP播放器(" : "RTSP推流器(")
<< _mediaInfo._vhost << "/" << _media_info._vhost << "/"
<< _mediaInfo._app << "/" << _media_info._app << "/"
<< _mediaInfo._streamid << _media_info._streamid
<< ")断开:" << err.what() << ")断开:" << err.what()
<< ",耗时(s):" << duration; << ",耗时(s):" << duration;
if (_rtpType == Rtsp::RTP_MULTICAST) { if (_rtp_type == Rtsp::RTP_MULTICAST) {
//取消UDP端口监听 //取消UDP端口监听
UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this); UDPServer::Instance().stopListenPeer(get_peer_ip().data(), this);
} }
...@@ -91,8 +91,8 @@ void RtspSession::onError(const SockException& err) { ...@@ -91,8 +91,8 @@ void RtspSession::onError(const SockException& err) {
//流量统计事件广播 //流量统计事件广播
GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold); GET_CONFIG(uint32_t,iFlowThreshold,General::kFlowThreshold);
if(_ui64TotalBytes > iFlowThreshold * 1024){ if(_bytes_usage > iFlowThreshold * 1024){
NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _mediaInfo, _ui64TotalBytes, duration, isPlayer, static_cast<SockInfo &>(*this)); NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastFlowReport, _media_info, _bytes_usage, duration, isPlayer, static_cast<SockInfo &>(*this));
} }
} }
...@@ -101,30 +101,28 @@ void RtspSession::onManager() { ...@@ -101,30 +101,28 @@ void RtspSession::onManager() {
GET_CONFIG(uint32_t,handshake_sec,Rtsp::kHandshakeSecond); GET_CONFIG(uint32_t,handshake_sec,Rtsp::kHandshakeSecond);
GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond); GET_CONFIG(uint32_t,keep_alive_sec,Rtsp::kKeepAliveSecond);
if (_ticker.createdTime() > handshake_sec * 1000) { if (_alive_ticker.createdTime() > handshake_sec * 1000) {
if (_strSession.size() == 0) { if (_sessionid.size() == 0) {
shutdown(SockException(Err_timeout,"illegal connection")); shutdown(SockException(Err_timeout,"illegal connection"));
return; return;
} }
} }
if ((_rtp_type == Rtsp::RTP_UDP || _push_src ) && _alive_ticker.elapsedTime() > keep_alive_sec * 1000) {
if ((_rtpType == Rtsp::RTP_UDP || _pushSrc ) && _ticker.elapsedTime() > keep_alive_sec * 1000) {
//如果是推流端或者rtp over udp类型的播放端,那么就做超时检测 //如果是推流端或者rtp over udp类型的播放端,那么就做超时检测
shutdown(SockException(Err_timeout,"rtp over udp session timeouted")); shutdown(SockException(Err_timeout,"rtp over udp session timeouted"));
return; return;
} }
} }
void RtspSession::onRecv(const Buffer::Ptr &pBuf) { void RtspSession::onRecv(const Buffer::Ptr &buf) {
_ticker.resetTime(); _alive_ticker.resetTime();
_ui64TotalBytes += pBuf->size(); _bytes_usage += buf->size();
if (_onRecv) { if (_on_recv) {
//http poster的请求数据转发给http getter处理 //http poster的请求数据转发给http getter处理
_onRecv(pBuf); _on_recv(buf);
} else { } else {
// TraceP(this) << pBuf->size() << "\r\n" << pBuf->data(); input(buf->data(), buf->size());
input(pBuf->data(),pBuf->size());
} }
} }
...@@ -132,15 +130,15 @@ void RtspSession::onRecv(const Buffer::Ptr &pBuf) { ...@@ -132,15 +130,15 @@ void RtspSession::onRecv(const Buffer::Ptr &pBuf) {
static inline bool end_of(const string &str, const string &substr){ static inline bool end_of(const string &str, const string &substr){
auto pos = str.rfind(substr); auto pos = str.rfind(substr);
return pos != string::npos && pos == str.size() - substr.size(); return pos != string::npos && pos == str.size() - substr.size();
}; }
void RtspSession::onWholeRtspPacket(Parser &parser) { void RtspSession::onWholeRtspPacket(Parser &parser) {
string strCmd = parser.Method(); //提取出请求命令字 string method = parser.Method(); //提取出请求命令字
_iCseq = atoi(parser["CSeq"].data()); _cseq = atoi(parser["CSeq"].data());
if(_strContentBase.empty() && strCmd != "GET"){ if(_content_base.empty() && method != "GET"){
_strContentBase = parser.Url(); _content_base = parser.Url();
_mediaInfo.parse(parser.FullUrl()); _media_info.parse(parser.FullUrl());
_mediaInfo._schema = RTSP_SCHEMA; _media_info._schema = RTSP_SCHEMA;
} }
typedef void (RtspSession::*rtsp_request_handler)(const Parser &parser); typedef void (RtspSession::*rtsp_request_handler)(const Parser &parser);
...@@ -160,10 +158,10 @@ void RtspSession::onWholeRtspPacket(Parser &parser) { ...@@ -160,10 +158,10 @@ void RtspSession::onWholeRtspPacket(Parser &parser) {
s_cmd_functions.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER); s_cmd_functions.emplace("GET_PARAMETER",&RtspSession::handleReq_SET_PARAMETER);
}, []() {}); }, []() {});
auto it = s_cmd_functions.find(strCmd); auto it = s_cmd_functions.find(method);
if (it == s_cmd_functions.end()) { if (it == s_cmd_functions.end()) {
sendRtspResponse("403 Forbidden"); sendRtspResponse("403 Forbidden");
shutdown(SockException(Err_shutdown,StrPrinter << "403 Forbidden:" << strCmd)); shutdown(SockException(Err_shutdown,StrPrinter << "403 Forbidden:" << method));
return; return;
} }
...@@ -181,24 +179,22 @@ void RtspSession::onWholeRtspPacket(Parser &parser) { ...@@ -181,24 +179,22 @@ void RtspSession::onWholeRtspPacket(Parser &parser) {
} }
void RtspSession::onRtpPacket(const char *data, uint64_t len) { void RtspSession::onRtpPacket(const char *data, uint64_t len) {
if(!_pushSrc){ if(!_push_src){
return; return;
} }
int trackIdx = -1;
uint8_t interleaved = data[1]; uint8_t interleaved = data[1];
if(interleaved %2 == 0){ if(interleaved %2 == 0){
trackIdx = getTrackIndexByInterleaved(interleaved); auto track_idx = getTrackIndexByInterleaved(interleaved);
handleOneRtp(trackIdx, _aTrackInfo[trackIdx]->_type, _aTrackInfo[trackIdx]->_samplerate, (unsigned char *) data + 4, len - 4); handleOneRtp(track_idx, _sdp_track[track_idx]->_type, _sdp_track[track_idx]->_samplerate, (unsigned char *) data + 4, len - 4);
}else{ }else{
trackIdx = getTrackIndexByInterleaved(interleaved - 1); auto track_idx = getTrackIndexByInterleaved(interleaved - 1);
onRtcpPacket(trackIdx, _aTrackInfo[trackIdx], (unsigned char *) data + 4, len - 4); onRtcpPacket(track_idx, _sdp_track[track_idx], (unsigned char *) data + 4, len - 4);
} }
} }
void RtspSession::onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen){ void RtspSession::onRtcpPacket(int track_idx, SdpTrack::Ptr &track, unsigned char *data, unsigned int len){}
}
int64_t RtspSession::getContentLength(Parser &parser) { int64_t RtspSession::getContentLength(Parser &parser) {
if(parser.Method() == "POST"){ if(parser.Method() == "POST"){
//http post请求的content数据部分是base64编码后的rtsp请求信令包 //http post请求的content数据部分是base64编码后的rtsp请求信令包
...@@ -207,7 +203,6 @@ int64_t RtspSession::getContentLength(Parser &parser) { ...@@ -207,7 +203,6 @@ int64_t RtspSession::getContentLength(Parser &parser) {
return RtspSplitter::getContentLength(parser); return RtspSplitter::getContentLength(parser);
} }
void RtspSession::handleReq_Options(const Parser &parser) { void RtspSession::handleReq_Options(const Parser &parser) {
//支持这些命令 //支持这些命令
sendRtspResponse("200 OK",{"Public" , "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, ANNOUNCE, RECORD, SET_PARAMETER, GET_PARAMETER"}); sendRtspResponse("200 OK",{"Public" , "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, ANNOUNCE, RECORD, SET_PARAMETER, GET_PARAMETER"});
...@@ -215,16 +210,16 @@ void RtspSession::handleReq_Options(const Parser &parser) { ...@@ -215,16 +210,16 @@ void RtspSession::handleReq_Options(const Parser &parser) {
void RtspSession::handleReq_ANNOUNCE(const Parser &parser) { void RtspSession::handleReq_ANNOUNCE(const Parser &parser) {
auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA, auto src = dynamic_pointer_cast<RtspMediaSource>(MediaSource::find(RTSP_SCHEMA,
_mediaInfo._vhost, _media_info._vhost,
_mediaInfo._app, _media_info._app,
_mediaInfo._streamid)); _media_info._streamid));
if(src){ if(src){
sendRtspResponse("406 Not Acceptable", {"Content-Type", "text/plain"}, "Already publishing."); sendRtspResponse("406 Not Acceptable", {"Content-Type", "text/plain"}, "Already publishing.");
string err = StrPrinter << "ANNOUNCE:" string err = StrPrinter << "ANNOUNCE:"
<< "Already publishing:" << "Already publishing:"
<< _mediaInfo._vhost << " " << _media_info._vhost << " "
<< _mediaInfo._app << " " << _media_info._app << " "
<< _mediaInfo._streamid << endl; << _media_info._streamid << endl;
throw SockException(Err_shutdown,err); throw SockException(Err_shutdown,err);
} }
...@@ -232,30 +227,30 @@ void RtspSession::handleReq_ANNOUNCE(const Parser &parser) { ...@@ -232,30 +227,30 @@ void RtspSession::handleReq_ANNOUNCE(const Parser &parser) {
if(end_of(full_url,".sdp")){ if(end_of(full_url,".sdp")){
//去除.sdp后缀,防止EasyDarwin推流器强制添加.sdp后缀 //去除.sdp后缀,防止EasyDarwin推流器强制添加.sdp后缀
full_url = full_url.substr(0,full_url.length() - 4); full_url = full_url.substr(0,full_url.length() - 4);
_mediaInfo.parse(full_url); _media_info.parse(full_url);
} }
if(_mediaInfo._app.empty() || _mediaInfo._streamid.empty()){ if(_media_info._app.empty() || _media_info._streamid.empty()){
//推流rtsp url必须最少两级(rtsp://host/app/stream_id),不允许莫名其妙的推流url //推流rtsp url必须最少两级(rtsp://host/app/stream_id),不允许莫名其妙的推流url
sendRtspResponse("403 Forbidden", {"Content-Type", "text/plain"}, "rtsp推流url非法,最少确保两级rtsp url"); sendRtspResponse("403 Forbidden", {"Content-Type", "text/plain"}, "rtsp推流url非法,最少确保两级rtsp url");
throw SockException(Err_shutdown,StrPrinter << "rtsp推流url非法:" << full_url); throw SockException(Err_shutdown,StrPrinter << "rtsp推流url非法:" << full_url);
} }
SdpParser sdpParser(parser.Content()); SdpParser sdpParser(parser.Content());
_strSession = makeRandStr(12); _sessionid = makeRandStr(12);
_aTrackInfo = sdpParser.getAvailableTrack(); _sdp_track = sdpParser.getAvailableTrack();
_pushSrc = std::make_shared<RtspMediaSourceImp>(_mediaInfo._vhost,_mediaInfo._app,_mediaInfo._streamid); _push_src = std::make_shared<RtspMediaSourceImp>(_media_info._vhost, _media_info._app, _media_info._streamid);
_pushSrc->setListener(dynamic_pointer_cast<MediaSourceEvent>(shared_from_this())); _push_src->setListener(dynamic_pointer_cast<MediaSourceEvent>(shared_from_this()));
_pushSrc->setSdp(sdpParser.toString()); _push_src->setSdp(sdpParser.toString());
sendRtspResponse("200 OK",{"Content-Base",_strContentBase + "/"}); sendRtspResponse("200 OK",{"Content-Base", _content_base + "/"});
} }
void RtspSession::handleReq_RECORD(const Parser &parser){ void RtspSession::handleReq_RECORD(const Parser &parser){
if (_aTrackInfo.empty() || parser["Session"] != _strSession) { if (_sdp_track.empty() || parser["Session"] != _sessionid) {
send_SessionNotFound(); send_SessionNotFound();
throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any availabe track when record" : "session not found when record"); throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any availabe track when record" : "session not found when record");
} }
auto onRes = [this](const string &err,bool enableRtxp,bool enableHls,bool enableMP4){ auto onRes = [this](const string &err,bool enableRtxp,bool enableHls,bool enableMP4){
bool authSuccess = err.empty(); bool authSuccess = err.empty();
...@@ -266,21 +261,21 @@ void RtspSession::handleReq_RECORD(const Parser &parser){ ...@@ -266,21 +261,21 @@ void RtspSession::handleReq_RECORD(const Parser &parser){
} }
//设置转协议 //设置转协议
_pushSrc->setProtocolTranslation(enableRtxp,enableHls,enableMP4); _push_src->setProtocolTranslation(enableRtxp, enableHls, enableMP4);
_StrPrinter rtp_info; _StrPrinter rtp_info;
for(auto &track : _aTrackInfo){ for(auto &track : _sdp_track){
if (track->_inited == false) { if (track->_inited == false) {
//还有track没有setup //还有track没有setup
shutdown(SockException(Err_shutdown,"track not setuped")); shutdown(SockException(Err_shutdown,"track not setuped"));
return; return;
} }
rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ","; rtp_info << "url=" << _content_base << "/" << track->_control_surffix << ",";
} }
rtp_info.pop_back(); rtp_info.pop_back();
sendRtspResponse("200 OK", {"RTP-Info",rtp_info}); sendRtspResponse("200 OK", {"RTP-Info",rtp_info});
if(_rtpType == Rtsp::RTP_TCP){ if(_rtp_type == Rtsp::RTP_TCP){
//如果是rtsp推流服务器,并且是TCP推流,那么加大TCP接收缓存,这样能提升接收性能 //如果是rtsp推流服务器,并且是TCP推流,那么加大TCP接收缓存,这样能提升接收性能
_sock->setReadBuffer(std::make_shared<BufferRaw>(256 * 1024)); _sock->setReadBuffer(std::make_shared<BufferRaw>(256 * 1024));
setSocketFlags(); setSocketFlags();
...@@ -303,7 +298,7 @@ void RtspSession::handleReq_RECORD(const Parser &parser){ ...@@ -303,7 +298,7 @@ void RtspSession::handleReq_RECORD(const Parser &parser){
}; };
//rtsp推流需要鉴权 //rtsp推流需要鉴权
auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish,_mediaInfo,invoker,static_cast<SockInfo &>(*this)); auto flag = NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPublish, _media_info, invoker, static_cast<SockInfo &>(*this));
if(!flag){ if(!flag){
//该事件无人监听,默认不鉴权 //该事件无人监听,默认不鉴权
GET_CONFIG(bool,toRtxp,General::kPublishToRtxp); GET_CONFIG(bool,toRtxp,General::kPublishToRtxp);
...@@ -341,7 +336,7 @@ void RtspSession::emitOnPlay(){ ...@@ -341,7 +336,7 @@ void RtspSession::emitOnPlay(){
}; };
//广播通用播放url鉴权事件 //广播通用播放url鉴权事件
auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _mediaInfo, invoker, static_cast<SockInfo &>(*this)); auto flag = _emit_on_play ? false : NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastMediaPlayed, _media_info, invoker, static_cast<SockInfo &>(*this));
if (!flag) { if (!flag) {
//该事件无人监听,默认不鉴权 //该事件无人监听,默认不鉴权
onRes(""); onRes("");
...@@ -381,7 +376,7 @@ void RtspSession::handleReq_Describe(const Parser &parser) { ...@@ -381,7 +376,7 @@ void RtspSession::handleReq_Describe(const Parser &parser) {
if(_rtsp_realm.empty()){ if(_rtsp_realm.empty()){
//广播是否需要rtsp专属认证事件 //广播是否需要rtsp专属认证事件
if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _mediaInfo, invoker, static_cast<SockInfo &>(*this))) { if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnGetRtspRealm, _media_info, invoker, static_cast<SockInfo &>(*this))) {
//无人监听此事件,说明无需认证 //无人监听此事件,说明无需认证
invoker(""); invoker("");
} }
...@@ -389,10 +384,11 @@ void RtspSession::handleReq_Describe(const Parser &parser) { ...@@ -389,10 +384,11 @@ void RtspSession::handleReq_Describe(const Parser &parser) {
invoker(_rtsp_realm); invoker(_rtsp_realm);
} }
} }
void RtspSession::onAuthSuccess() { void RtspSession::onAuthSuccess() {
TraceP(this); TraceP(this);
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this()); weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
MediaSource::findAsync(_mediaInfo,weakSelf.lock(),[weakSelf](const MediaSource::Ptr &src){ MediaSource::findAsync(_media_info, weakSelf.lock(), [weakSelf](const MediaSource::Ptr &src){
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf){ if(!strongSelf){
return; return;
...@@ -400,43 +396,44 @@ void RtspSession::onAuthSuccess() { ...@@ -400,43 +396,44 @@ void RtspSession::onAuthSuccess() {
auto rtsp_src = dynamic_pointer_cast<RtspMediaSource>(src); auto rtsp_src = dynamic_pointer_cast<RtspMediaSource>(src);
if (!rtsp_src) { if (!rtsp_src) {
//未找到相应的MediaSource //未找到相应的MediaSource
string err = StrPrinter << "no such stream:" << strongSelf->_mediaInfo._vhost << " " << strongSelf->_mediaInfo._app << " " << strongSelf->_mediaInfo._streamid; string err = StrPrinter << "no such stream:" << strongSelf->_media_info._vhost << " " << strongSelf->_media_info._app << " " << strongSelf->_media_info._streamid;
strongSelf->send_StreamNotFound(); strongSelf->send_StreamNotFound();
strongSelf->shutdown(SockException(Err_shutdown,err)); strongSelf->shutdown(SockException(Err_shutdown,err));
return; return;
} }
//找到了相应的rtsp流 //找到了相应的rtsp流
strongSelf->_aTrackInfo = SdpParser(rtsp_src->getSdp()).getAvailableTrack(); strongSelf->_sdp_track = SdpParser(rtsp_src->getSdp()).getAvailableTrack();
if (strongSelf->_aTrackInfo.empty()) { if (strongSelf->_sdp_track.empty()) {
//该流无效 //该流无效
DebugL << "无trackInfo,该流无效"; DebugL << "无trackInfo,该流无效";
strongSelf->send_StreamNotFound(); strongSelf->send_StreamNotFound();
strongSelf->shutdown(SockException(Err_shutdown,"can not find any available track in sdp")); strongSelf->shutdown(SockException(Err_shutdown,"can not find any available track in sdp"));
return; return;
} }
strongSelf->_strSession = makeRandStr(12); strongSelf->_sessionid = makeRandStr(12);
strongSelf->_pMediaSrc = rtsp_src; strongSelf->_play_src = rtsp_src;
for(auto &track : strongSelf->_aTrackInfo){ for(auto &track : strongSelf->_sdp_track){
track->_ssrc = rtsp_src->getSsrc(track->_type); track->_ssrc = rtsp_src->getSsrc(track->_type);
track->_seq = rtsp_src->getSeqence(track->_type); track->_seq = rtsp_src->getSeqence(track->_type);
track->_time_stamp = rtsp_src->getTimeStamp(track->_type); track->_time_stamp = rtsp_src->getTimeStamp(track->_type);
} }
strongSelf->sendRtspResponse("200 OK", strongSelf->sendRtspResponse("200 OK",
{"Content-Base",strongSelf->_strContentBase + "/", {"Content-Base", strongSelf->_content_base + "/",
"x-Accept-Retransmit","our-retransmit", "x-Accept-Retransmit","our-retransmit",
"x-Accept-Dynamic-Rate","1" "x-Accept-Dynamic-Rate","1"
},rtsp_src->getSdp()); },rtsp_src->getSdp());
}); });
} }
void RtspSession::onAuthFailed(const string &realm,const string &why,bool close) { void RtspSession::onAuthFailed(const string &realm,const string &why,bool close) {
GET_CONFIG(bool,authBasic,Rtsp::kAuthBasic); GET_CONFIG(bool,authBasic,Rtsp::kAuthBasic);
if (!authBasic) { if (!authBasic) {
//我们需要客户端优先以md5方式认证 //我们需要客户端优先以md5方式认证
_strNonce = makeRandStr(32); _auth_nonce = makeRandStr(32);
sendRtspResponse("401 Unauthorized", sendRtspResponse("401 Unauthorized",
{"WWW-Authenticate", {"WWW-Authenticate",
StrPrinter << "Digest realm=\"" << realm << "\",nonce=\"" << _strNonce << "\"" }); StrPrinter << "Digest realm=\"" << realm << "\",nonce=\"" << _auth_nonce << "\"" });
}else { }else {
//当然我们也支持base64认证,但是我们不建议这样做 //当然我们也支持base64认证,但是我们不建议这样做
sendRtspResponse("401 Unauthorized", sendRtspResponse("401 Unauthorized",
...@@ -448,56 +445,56 @@ void RtspSession::onAuthFailed(const string &realm,const string &why,bool close) ...@@ -448,56 +445,56 @@ void RtspSession::onAuthFailed(const string &realm,const string &why,bool close)
} }
} }
void RtspSession::onAuthBasic(const string &realm,const string &strBase64){ void RtspSession::onAuthBasic(const string &realm,const string &auth_base64){
//base64认证 //base64认证
char user_pwd_buf[512]; char user_pwd_buf[512];
av_base64_decode((uint8_t *)user_pwd_buf,strBase64.data(),strBase64.size()); av_base64_decode((uint8_t *) user_pwd_buf, auth_base64.data(), auth_base64.size());
auto user_pwd_vec = split(user_pwd_buf,":"); auto user_pwd_vec = split(user_pwd_buf, ":");
if(user_pwd_vec.size() < 2){ if (user_pwd_vec.size() < 2) {
//认证信息格式不合法,回复401 Unauthorized //认证信息格式不合法,回复401 Unauthorized
onAuthFailed(realm,"can not find user and passwd when basic64 auth"); onAuthFailed(realm, "can not find user and passwd when basic64 auth");
return; return;
} }
auto user = user_pwd_vec[0]; auto user = user_pwd_vec[0];
auto pwd = user_pwd_vec[1]; auto pwd = user_pwd_vec[1];
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this()); weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
onAuth invoker = [pwd,realm,weakSelf](bool encrypted,const string &good_pwd){ onAuth invoker = [pwd, realm, weakSelf](bool encrypted, const string &good_pwd) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf){ if (!strongSelf) {
//本对象已经销毁 //本对象已经销毁
return; return;
} }
//切换到自己的线程执行 //切换到自己的线程执行
strongSelf->async([weakSelf,good_pwd,pwd,realm](){ strongSelf->async([weakSelf, good_pwd, pwd, realm]() {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf){ if (!strongSelf) {
//本对象已经销毁 //本对象已经销毁
return; return;
} }
//base64忽略encrypted参数,上层必须传入明文密码 //base64忽略encrypted参数,上层必须传入明文密码
if(pwd == good_pwd){ if (pwd == good_pwd) {
//提供的密码且匹配正确 //提供的密码且匹配正确
strongSelf->onAuthSuccess(); strongSelf->onAuthSuccess();
return; return;
} }
//密码错误 //密码错误
strongSelf->onAuthFailed(realm,StrPrinter << "password mismatch when base64 auth:" << pwd << " != " << good_pwd); strongSelf->onAuthFailed(realm, StrPrinter << "password mismatch when base64 auth:" << pwd << " != " << good_pwd);
}); });
}; };
//此时必须提供明文密码 //此时必须提供明文密码
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,_mediaInfo,realm,user, true,invoker,static_cast<SockInfo &>(*this))){ if (!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth, _media_info, realm, user, true, invoker, static_cast<SockInfo &>(*this))) {
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之 //表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
WarnP(this) << "请监听kBroadcastOnRtspAuth事件!"; WarnP(this) << "请监听kBroadcastOnRtspAuth事件!";
//但是我们还是忽略认证以便完成播放 //但是我们还是忽略认证以便完成播放
//我们输入的密码是明文 //我们输入的密码是明文
invoker(false,pwd); invoker(false, pwd);
} }
} }
void RtspSession::onAuthDigest(const string &realm,const string &strMd5){ void RtspSession::onAuthDigest(const string &realm,const string &auth_md5){
DebugP(this) << strMd5; DebugP(this) << auth_md5;
auto mapTmp = Parser::parseArgs(strMd5,",","="); auto mapTmp = Parser::parseArgs(auth_md5, ",", "=");
decltype(mapTmp) map; decltype(mapTmp) map;
for(auto &pr : mapTmp){ for(auto &pr : mapTmp){
map[trim(string(pr.first)," \"")] = trim(pr.second," \""); map[trim(string(pr.first)," \"")] = trim(pr.second," \"");
...@@ -509,8 +506,8 @@ void RtspSession::onAuthDigest(const string &realm,const string &strMd5){ ...@@ -509,8 +506,8 @@ void RtspSession::onAuthDigest(const string &realm,const string &strMd5){
} }
//check nonce //check nonce
auto nonce = map["nonce"]; auto nonce = map["nonce"];
if(_strNonce != nonce){ if(_auth_nonce != nonce){
onAuthFailed(realm,StrPrinter << "nonce not mached:" << nonce << " != " << _strNonce); onAuthFailed(realm,StrPrinter << "nonce not mached:" << nonce << " != " << _auth_nonce);
return ; return ;
} }
//check username and uri //check username and uri
...@@ -570,7 +567,7 @@ void RtspSession::onAuthDigest(const string &realm,const string &strMd5){ ...@@ -570,7 +567,7 @@ void RtspSession::onAuthDigest(const string &realm,const string &strMd5){
}; };
//此时可以提供明文或md5加密的密码 //此时可以提供明文或md5加密的密码
if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth,_mediaInfo,realm,username, false,invoker,static_cast<SockInfo &>(*this))){ if(!NoticeCenter::Instance().emitEvent(Broadcast::kBroadcastOnRtspAuth, _media_info, realm, username, false, invoker, static_cast<SockInfo &>(*this))){
//表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之 //表明该流需要认证却没监听请求密码事件,这一般是大意的程序所为,警告之
WarnP(this) << "请监听kBroadcastOnRtspAuth事件!"; WarnP(this) << "请监听kBroadcastOnRtspAuth事件!";
//但是我们还是忽略认证以便完成播放 //但是我们还是忽略认证以便完成播放
...@@ -602,9 +599,11 @@ void RtspSession::onAuthUser(const string &realm,const string &authorization){ ...@@ -602,9 +599,11 @@ void RtspSession::onAuthUser(const string &realm,const string &authorization){
onAuthFailed(realm,StrPrinter << "unsupported auth type:" << authType); onAuthFailed(realm,StrPrinter << "unsupported auth type:" << authType);
} }
} }
inline void RtspSession::send_StreamNotFound() { inline void RtspSession::send_StreamNotFound() {
sendRtspResponse("404 Stream Not Found",{"Connection","Close"}); sendRtspResponse("404 Stream Not Found",{"Connection","Close"});
} }
inline void RtspSession::send_UnsupportedTransport() { inline void RtspSession::send_UnsupportedTransport() {
sendRtspResponse("461 Unsupported Transport",{"Connection","Close"}); sendRtspResponse("461 Unsupported Transport",{"Connection","Close"});
} }
...@@ -614,36 +613,36 @@ inline void RtspSession::send_SessionNotFound() { ...@@ -614,36 +613,36 @@ inline void RtspSession::send_SessionNotFound() {
} }
void RtspSession::handleReq_Setup(const Parser &parser) { void RtspSession::handleReq_Setup(const Parser &parser) {
//处理setup命令,该函数可能进入多次 //处理setup命令,该函数可能进入多次
auto controlSuffix = split(parser.FullUrl(),"/").back();// parser.FullUrl().substr(_strContentBase.size()); auto controlSuffix = split(parser.FullUrl(),"/").back();
if(controlSuffix.front() == '/'){ if(controlSuffix.front() == '/'){
controlSuffix = controlSuffix.substr(1); controlSuffix = controlSuffix.substr(1);
} }
int trackIdx = getTrackIndexByControlSuffix(controlSuffix); int trackIdx = getTrackIndexByControlSuffix(controlSuffix);
SdpTrack::Ptr &trackRef = _aTrackInfo[trackIdx]; SdpTrack::Ptr &trackRef = _sdp_track[trackIdx];
if (trackRef->_inited) { if (trackRef->_inited) {
//已经初始化过该Track //已经初始化过该Track
throw SockException(Err_shutdown, "can not setup one track twice"); throw SockException(Err_shutdown, "can not setup one track twice");
} }
trackRef->_inited = true; //现在初始化 trackRef->_inited = true; //现在初始化
if(_rtpType == Rtsp::RTP_Invalid){ if(_rtp_type == Rtsp::RTP_Invalid){
auto &strTransport = parser["Transport"]; auto &strTransport = parser["Transport"];
if(strTransport.find("TCP") != string::npos){ if(strTransport.find("TCP") != string::npos){
_rtpType = Rtsp::RTP_TCP; _rtp_type = Rtsp::RTP_TCP;
}else if(strTransport.find("multicast") != string::npos){ }else if(strTransport.find("multicast") != string::npos){
_rtpType = Rtsp::RTP_MULTICAST; _rtp_type = Rtsp::RTP_MULTICAST;
}else{ }else{
_rtpType = Rtsp::RTP_UDP; _rtp_type = Rtsp::RTP_UDP;
} }
} }
//允许接收rtp、rtcp包 //允许接收rtp、rtcp包
RtspSplitter::enableRecvRtp(_rtpType == Rtsp::RTP_TCP); RtspSplitter::enableRecvRtp(_rtp_type == Rtsp::RTP_TCP);
switch (_rtpType) { switch (_rtp_type) {
case Rtsp::RTP_TCP: { case Rtsp::RTP_TCP: {
if(_pushSrc){ if(_push_src){
//rtsp推流时,interleaved由推流者决定 //rtsp推流时,interleaved由推流者决定
auto key_values = Parser::parseArgs(parser["Transport"],";","="); auto key_values = Parser::parseArgs(parser["Transport"],";","=");
int interleaved_rtp = -1 , interleaved_rtcp = -1; int interleaved_rtp = -1 , interleaved_rtcp = -1;
...@@ -657,14 +656,16 @@ void RtspSession::handleReq_Setup(const Parser &parser) { ...@@ -657,14 +656,16 @@ void RtspSession::handleReq_Setup(const Parser &parser) {
trackRef->_interleaved = 2 * trackRef->_type; trackRef->_interleaved = 2 * trackRef->_type;
} }
sendRtspResponse("200 OK", sendRtspResponse("200 OK",
{"Transport",StrPrinter << "RTP/AVP/TCP;unicast;" {"Transport", StrPrinter << "RTP/AVP/TCP;unicast;"
<< "interleaved=" << (int)trackRef->_interleaved << "-" << (int)trackRef->_interleaved + 1 << ";" << "interleaved=" << (int) trackRef->_interleaved << "-"
<< (int) trackRef->_interleaved + 1 << ";"
<< "ssrc=" << printSSRC(trackRef->_ssrc), << "ssrc=" << printSSRC(trackRef->_ssrc),
"x-Transport-Options" , "late-tolerance=1.400000", "x-Transport-Options", "late-tolerance=1.400000",
"x-Dynamic-Rate" , "1" "x-Dynamic-Rate", "1"
}); });
} }
break; break;
case Rtsp::RTP_UDP: { case Rtsp::RTP_UDP: {
std::pair<Socket::Ptr, Socket::Ptr> pr; std::pair<Socket::Ptr, Socket::Ptr> pr;
try{ try{
...@@ -675,8 +676,8 @@ void RtspSession::handleReq_Setup(const Parser &parser) { ...@@ -675,8 +676,8 @@ void RtspSession::handleReq_Setup(const Parser &parser) {
throw SockException(Err_shutdown, ex.what()); throw SockException(Err_shutdown, ex.what());
} }
_apRtpSock[trackIdx] = pr.first; _rtp_socks[trackIdx] = pr.first;
_apRtcpSock[trackIdx] = pr.second; _rtcp_socks[trackIdx] = pr.second;
//设置客户端内网端口信息 //设置客户端内网端口信息
string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL); string strClientPort = FindField(parser["Transport"].data(), "client_port=", NULL);
...@@ -705,14 +706,15 @@ void RtspSession::handleReq_Setup(const Parser &parser) { ...@@ -705,14 +706,15 @@ void RtspSession::handleReq_Setup(const Parser &parser) {
sendRtspResponse("200 OK", sendRtspResponse("200 OK",
{"Transport", StrPrinter << "RTP/AVP/UDP;unicast;" {"Transport", StrPrinter << "RTP/AVP/UDP;unicast;"
<< "client_port=" << strClientPort << ";" << "client_port=" << strClientPort << ";"
<< "server_port=" << pr.first->get_local_port() << "-" << pr.second->get_local_port() << ";" << "server_port=" << pr.first->get_local_port() << "-"
<< pr.second->get_local_port() << ";"
<< "ssrc=" << printSSRC(trackRef->_ssrc) << "ssrc=" << printSSRC(trackRef->_ssrc)
}); });
} }
break; break;
case Rtsp::RTP_MULTICAST: { case Rtsp::RTP_MULTICAST: {
if(!_multicaster){ if(!_multicaster){
_multicaster = RtpMultiCaster::get(getPoller(),get_local_ip(),_mediaInfo._vhost, _mediaInfo._app, _mediaInfo._streamid); _multicaster = RtpMultiCaster::get(getPoller(), get_local_ip(), _media_info._vhost, _media_info._app, _media_info._streamid);
if (!_multicaster) { if (!_multicaster) {
send_NotAcceptable(); send_NotAcceptable();
throw SockException(Err_shutdown, "can not get a available udp multicast socket"); throw SockException(Err_shutdown, "can not get a available udp multicast socket");
...@@ -739,7 +741,7 @@ void RtspSession::handleReq_Setup(const Parser &parser) { ...@@ -739,7 +741,7 @@ void RtspSession::handleReq_Setup(const Parser &parser) {
GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL); GET_CONFIG(uint32_t,udpTTL,MultiCast::kUdpTTL);
sendRtspResponse("200 OK", sendRtspResponse("200 OK",
{"Transport",StrPrinter << "RTP/AVP;multicast;" {"Transport", StrPrinter << "RTP/AVP;multicast;"
<< "destination=" << _multicaster->getIP() << ";" << "destination=" << _multicaster->getIP() << ";"
<< "source=" << get_local_ip() << ";" << "source=" << get_local_ip() << ";"
<< "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";" << "port=" << iSrvPort << "-" << pSockRtcp->get_local_port() << ";"
...@@ -754,19 +756,19 @@ void RtspSession::handleReq_Setup(const Parser &parser) { ...@@ -754,19 +756,19 @@ void RtspSession::handleReq_Setup(const Parser &parser) {
} }
void RtspSession::handleReq_Play(const Parser &parser) { void RtspSession::handleReq_Play(const Parser &parser) {
if (_aTrackInfo.empty() || parser["Session"] != _strSession) { if (_sdp_track.empty() || parser["Session"] != _sessionid) {
send_SessionNotFound(); send_SessionNotFound();
throw SockException(Err_shutdown,_aTrackInfo.empty() ? "can not find any available track when play" : "session not found when play"); throw SockException(Err_shutdown, _sdp_track.empty() ? "can not find any available track when play" : "session not found when play");
} }
auto pMediaSrc = _pMediaSrc.lock(); auto play_src = _play_src.lock();
if(!pMediaSrc){ if(!play_src){
send_StreamNotFound(); send_StreamNotFound();
shutdown(SockException(Err_shutdown,"rtsp stream released")); shutdown(SockException(Err_shutdown,"rtsp stream released"));
return; return;
} }
bool useBuf = true; bool useGOP = true;
_enableSendRtp = false; _enable_send_rtp = false;
float iStartTime = 0; float iStartTime = 0;
auto strRange = parser["Range"]; auto strRange = parser["Range"];
if (strRange.size()) { if (strRange.size()) {
...@@ -777,53 +779,53 @@ void RtspSession::handleReq_Play(const Parser &parser) { ...@@ -777,53 +779,53 @@ void RtspSession::handleReq_Play(const Parser &parser) {
} }
iStartTime = 1000 * atof(strStart.data()); iStartTime = 1000 * atof(strStart.data());
InfoP(this) << "rtsp seekTo(ms):" << iStartTime; InfoP(this) << "rtsp seekTo(ms):" << iStartTime;
useBuf = !pMediaSrc->seekTo(iStartTime); useGOP = !play_src->seekTo(iStartTime);
} else if (pMediaSrc->totalReaderCount() == 0) { } else if (play_src->totalReaderCount() == 0) {
//第一个消费者 //第一个消费者
pMediaSrc->seekTo(0); play_src->seekTo(0);
} }
_StrPrinter rtp_info; _StrPrinter rtp_info;
for (auto &track : _aTrackInfo) { for (auto &track : _sdp_track) {
if (track->_inited == false) { if (track->_inited == false) {
//还有track没有setup //还有track没有setup
shutdown(SockException(Err_shutdown, "track not setuped")); shutdown(SockException(Err_shutdown, "track not setuped"));
return; return;
} }
track->_ssrc = pMediaSrc->getSsrc(track->_type); track->_ssrc = play_src->getSsrc(track->_type);
track->_seq = pMediaSrc->getSeqence(track->_type); track->_seq = play_src->getSeqence(track->_type);
track->_time_stamp = pMediaSrc->getTimeStamp(track->_type); track->_time_stamp = play_src->getTimeStamp(track->_type);
rtp_info << "url=" << _strContentBase << "/" << track->_control_surffix << ";" rtp_info << "url=" << _content_base << "/" << track->_control_surffix << ";"
<< "seq=" << track->_seq << ";" << "seq=" << track->_seq << ";"
<< "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ","; << "rtptime=" << (int) (track->_time_stamp * (track->_samplerate / 1000)) << ",";
} }
rtp_info.pop_back(); rtp_info.pop_back();
sendRtspResponse("200 OK", sendRtspResponse("200 OK",
{"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useBuf? pMediaSrc->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000), {"Range", StrPrinter << "npt=" << setiosflags(ios::fixed) << setprecision(2) << (useGOP ? play_src->getTimeStamp(TrackInvalid) / 1000.0 : iStartTime / 1000),
"RTP-Info",rtp_info "RTP-Info",rtp_info
}); });
_enableSendRtp = true; _enable_send_rtp = true;
setSocketFlags(); setSocketFlags();
if (!_pRtpReader && _rtpType != Rtsp::RTP_MULTICAST) { if (!_play_reader && _rtp_type != Rtsp::RTP_MULTICAST) {
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this()); weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
_pRtpReader = pMediaSrc->getRing()->attach(getPoller(), useBuf); _play_reader = play_src->getRing()->attach(getPoller(), useGOP);
_pRtpReader->setDetachCB([weakSelf]() { _play_reader->setDetachCB([weakSelf]() {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if (!strongSelf) { if (!strongSelf) {
return; return;
} }
strongSelf->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached")); strongSelf->shutdown(SockException(Err_shutdown, "rtsp ring buffer detached"));
}); });
_pRtpReader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) { _play_reader->setReadCB([weakSelf](const RtspMediaSource::RingDataType &pack) {
auto strongSelf = weakSelf.lock(); auto strongSelf = weakSelf.lock();
if (!strongSelf) { if (!strongSelf) {
return; return;
} }
if (strongSelf->_enableSendRtp) { if (strongSelf->_enable_send_rtp) {
strongSelf->sendRtpPacket(pack); strongSelf->sendRtpPacket(pack);
} }
}); });
...@@ -831,13 +833,13 @@ void RtspSession::handleReq_Play(const Parser &parser) { ...@@ -831,13 +833,13 @@ void RtspSession::handleReq_Play(const Parser &parser) {
} }
void RtspSession::handleReq_Pause(const Parser &parser) { void RtspSession::handleReq_Pause(const Parser &parser) {
if (parser["Session"] != _strSession) { if (parser["Session"] != _sessionid) {
send_SessionNotFound(); send_SessionNotFound();
throw SockException(Err_shutdown,"session not found when pause"); throw SockException(Err_shutdown,"session not found when pause");
} }
sendRtspResponse("200 OK"); sendRtspResponse("200 OK");
_enableSendRtp = false; _enable_send_rtp = false;
} }
void RtspSession::handleReq_Teardown(const Parser &parser) { void RtspSession::handleReq_Teardown(const Parser &parser) {
...@@ -873,7 +875,7 @@ void RtspSession::handleReq_Post(const Parser &parser) { ...@@ -873,7 +875,7 @@ void RtspSession::handleReq_Post(const Parser &parser) {
g_mapGetter.erase(sessioncookie); g_mapGetter.erase(sessioncookie);
//http poster收到请求后转发给http getter处理 //http poster收到请求后转发给http getter处理
_onRecv = [this,httpGetterWeak](const Buffer::Ptr &pBuf){ _on_recv = [this,httpGetterWeak](const Buffer::Ptr &buf){
auto httpGetterStrong = httpGetterWeak.lock(); auto httpGetterStrong = httpGetterWeak.lock();
if(!httpGetterStrong){ if(!httpGetterStrong){
shutdown(SockException(Err_shutdown,"http getter released")); shutdown(SockException(Err_shutdown,"http getter released"));
...@@ -881,18 +883,18 @@ void RtspSession::handleReq_Post(const Parser &parser) { ...@@ -881,18 +883,18 @@ void RtspSession::handleReq_Post(const Parser &parser) {
} }
//切换到http getter的线程 //切换到http getter的线程
httpGetterStrong->async([pBuf,httpGetterWeak](){ httpGetterStrong->async([buf,httpGetterWeak](){
auto httpGetterStrong = httpGetterWeak.lock(); auto httpGetterStrong = httpGetterWeak.lock();
if(!httpGetterStrong){ if(!httpGetterStrong){
return; return;
} }
httpGetterStrong->onRecv(std::make_shared<BufferString>(decodeBase64(string(pBuf->data(),pBuf->size())))); httpGetterStrong->onRecv(std::make_shared<BufferString>(decodeBase64(string(buf->data(), buf->size()))));
}); });
}; };
if(!parser.Content().empty()){ if(!parser.Content().empty()){
//http poster后面的粘包 //http poster后面的粘包
_onRecv(std::make_shared<BufferString>(parser.Content())); _on_recv(std::make_shared<BufferString>(parser.Content()));
} }
sendRtspResponse("200 OK", sendRtspResponse("200 OK",
...@@ -911,82 +913,82 @@ inline void RtspSession::send_NotAcceptable() { ...@@ -911,82 +913,82 @@ inline void RtspSession::send_NotAcceptable() {
sendRtspResponse("406 Not Acceptable",{"Connection","Close"}); sendRtspResponse("406 Not Acceptable",{"Connection","Close"});
} }
void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtp, int) {
void RtspSession::onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) { _push_src->onWrite(rtp, false);
_pushSrc->onWrite(rtppt, false);
} }
inline void RtspSession::onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr& addr) {
inline void RtspSession::onRcvPeerUdpData(int interleaved, const Buffer::Ptr &buf, const struct sockaddr &addr) {
//这是rtcp心跳包,说明播放器还存活 //这是rtcp心跳包,说明播放器还存活
_ticker.resetTime(); _alive_ticker.resetTime();
if(intervaled % 2 == 0){ if (interleaved % 2 == 0) {
if(_pushSrc){ if (_push_src) {
//这是rtsp推流上来的rtp包 //这是rtsp推流上来的rtp包
auto &ref = _aTrackInfo[intervaled / 2]; auto &ref = _sdp_track[interleaved / 2];
handleOneRtp(intervaled / 2, ref->_type, ref->_samplerate, (unsigned char *) pBuf->data(), pBuf->size()); handleOneRtp(interleaved / 2, ref->_type, ref->_samplerate, (unsigned char *) buf->data(), buf->size());
}else if(!_udpSockConnected.count(intervaled)){ } else if (!_udp_connected_flags.count(interleaved)) {
//这是rtsp播放器的rtp打洞包 //这是rtsp播放器的rtp打洞包
_udpSockConnected.emplace(intervaled); _udp_connected_flags.emplace(interleaved);
_apRtpSock[intervaled / 2]->setSendPeerAddr(&addr); _rtp_socks[interleaved / 2]->setSendPeerAddr(&addr);
} }
}else{ } else {
//rtcp包 //rtcp包
if(!_udpSockConnected.count(intervaled)){ if (!_udp_connected_flags.count(interleaved)) {
_udpSockConnected.emplace(intervaled); _udp_connected_flags.emplace(interleaved);
_apRtcpSock[(intervaled - 1) / 2]->setSendPeerAddr(&addr); _rtcp_socks[(interleaved - 1) / 2]->setSendPeerAddr(&addr);
} }
onRtcpPacket((intervaled - 1) / 2, _aTrackInfo[(intervaled - 1) / 2], (unsigned char *) pBuf->data(),pBuf->size()); onRtcpPacket((interleaved - 1) / 2, _sdp_track[(interleaved - 1) / 2], (unsigned char *) buf->data(),
buf->size());
} }
} }
inline void RtspSession::startListenPeerUdpData(int track_idx) {
inline void RtspSession::startListenPeerUdpData(int trackIdx) {
weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this()); weak_ptr<RtspSession> weakSelf = dynamic_pointer_cast<RtspSession>(shared_from_this());
auto srcIP = inet_addr(get_peer_ip().data()); auto srcIP = inet_addr(get_peer_ip().data());
auto onUdpData = [weakSelf,srcIP](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr,int intervaled){ auto onUdpData = [weakSelf,srcIP](const Buffer::Ptr &buf, struct sockaddr *peer_addr, int interleaved){
auto strongSelf=weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if (!strongSelf) {
return false; return false;
} }
if (((struct sockaddr_in *) pPeerAddr)->sin_addr.s_addr != srcIP) { if (((struct sockaddr_in *) peer_addr)->sin_addr.s_addr != srcIP) {
WarnP(strongSelf.get()) << ((intervaled % 2 == 0) ? "收到其他地址的rtp数据:" : "收到其他地址的rtcp数据:") WarnP(strongSelf.get()) << ((interleaved % 2 == 0) ? "收到其他地址的rtp数据:" : "收到其他地址的rtcp数据:")
<< SockUtil::inet_ntoa(((struct sockaddr_in *) pPeerAddr)->sin_addr); << SockUtil::inet_ntoa(((struct sockaddr_in *) peer_addr)->sin_addr);
return true; return true;
} }
struct sockaddr addr=*pPeerAddr; struct sockaddr addr = *peer_addr;
strongSelf->async([weakSelf,pBuf,addr,intervaled]() { strongSelf->async([weakSelf, buf, addr, interleaved]() {
auto strongSelf=weakSelf.lock(); auto strongSelf = weakSelf.lock();
if(!strongSelf) { if (!strongSelf) {
return; return;
} }
strongSelf->onRcvPeerUdpData(intervaled,pBuf,addr); strongSelf->onRcvPeerUdpData(interleaved, buf, addr);
}); });
return true; return true;
}; };
switch (_rtpType){ switch (_rtp_type){
case Rtsp::RTP_MULTICAST:{ case Rtsp::RTP_MULTICAST:{
//组播使用的共享rtcp端口 //组播使用的共享rtcp端口
UDPServer::Instance().listenPeer(get_peer_ip().data(), this, [onUdpData]( UDPServer::Instance().listenPeer(get_peer_ip().data(), this,
int intervaled, const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr) { [onUdpData]( int interleaved, const Buffer::Ptr &buf, struct sockaddr *peer_addr) {
return onUdpData(pBuf,pPeerAddr,intervaled); return onUdpData(buf, peer_addr, interleaved);
}); });
} }
break; break;
case Rtsp::RTP_UDP:{ case Rtsp::RTP_UDP:{
auto setEvent = [&](Socket::Ptr &sock,int intervaled){ auto setEvent = [&](Socket::Ptr &sock,int interleaved){
if(!sock){ if(!sock){
WarnP(this) << "udp端口为空:" << intervaled; WarnP(this) << "udp端口为空:" << interleaved;
return; return;
} }
sock->setOnRead([onUdpData,intervaled](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr , int addr_len){ sock->setOnRead([onUdpData,interleaved](const Buffer::Ptr &pBuf, struct sockaddr *pPeerAddr , int addr_len){
onUdpData(pBuf,pPeerAddr,intervaled); onUdpData(pBuf, pPeerAddr, interleaved);
}); });
}; };
setEvent(_apRtpSock[trackIdx], 2*trackIdx ); setEvent(_rtp_socks[track_idx], 2 * track_idx );
setEvent(_apRtcpSock[trackIdx], 2*trackIdx + 1 ); setEvent(_rtcp_socks[track_idx], 2 * track_idx + 1 );
} }
break; break;
...@@ -1003,14 +1005,11 @@ static string dateStr(){ ...@@ -1003,14 +1005,11 @@ static string dateStr(){
return buf; return buf;
} }
bool RtspSession::sendRtspResponse(const string &res_code, bool RtspSession::sendRtspResponse(const string &res_code, const StrCaseMap &header_const, const string &sdp, const char *protocol){
const StrCaseMap &header_const,
const string &sdp,
const char *protocol){
auto header = header_const; auto header = header_const;
header.emplace("CSeq",StrPrinter << _iCseq); header.emplace("CSeq",StrPrinter << _cseq);
if(!_strSession.empty()){ if(!_sessionid.empty()){
header.emplace("Session",_strSession); header.emplace("Session", _sessionid);
} }
header.emplace("Server",SERVER_NAME); header.emplace("Server",SERVER_NAME);
...@@ -1040,14 +1039,11 @@ int RtspSession::send(const Buffer::Ptr &pkt){ ...@@ -1040,14 +1039,11 @@ int RtspSession::send(const Buffer::Ptr &pkt){
// if(!_enableSendRtp){ // if(!_enableSendRtp){
// DebugP(this) << pkt->data(); // DebugP(this) << pkt->data();
// } // }
_ui64TotalBytes += pkt->size(); _bytes_usage += pkt->size();
return TcpSession::send(pkt); return TcpSession::send(pkt);
} }
bool RtspSession::sendRtspResponse(const string &res_code, bool RtspSession::sendRtspResponse(const string &res_code, const std::initializer_list<string> &header, const string &sdp, const char *protocol) {
const std::initializer_list<string> &header,
const string &sdp,
const char *protocol) {
string key; string key;
StrCaseMap header_map; StrCaseMap header_map;
int i = 0; int i = 0;
...@@ -1062,43 +1058,44 @@ bool RtspSession::sendRtspResponse(const string &res_code, ...@@ -1062,43 +1058,44 @@ bool RtspSession::sendRtspResponse(const string &res_code,
} }
inline int RtspSession::getTrackIndexByTrackType(TrackType type) { inline int RtspSession::getTrackIndexByTrackType(TrackType type) {
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { for (unsigned int i = 0; i < _sdp_track.size(); i++) {
if (type == _aTrackInfo[i]->_type) { if (type == _sdp_track[i]->_type) {
return i; return i;
} }
} }
if(_aTrackInfo.size() == 1){ if(_sdp_track.size() == 1){
return 0; return 0;
} }
throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type); throw SockException(Err_shutdown, StrPrinter << "no such track with type:" << (int) type);
} }
inline int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix) { inline int RtspSession::getTrackIndexByControlSuffix(const string &controlSuffix) {
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { for (unsigned int i = 0; i < _sdp_track.size(); i++) {
if (controlSuffix == _aTrackInfo[i]->_control_surffix) { if (controlSuffix == _sdp_track[i]->_control_surffix) {
return i; return i;
} }
} }
if(_aTrackInfo.size() == 1){ if(_sdp_track.size() == 1){
return 0; return 0;
} }
throw SockException(Err_shutdown, StrPrinter << "no such track with suffix:" << controlSuffix); throw SockException(Err_shutdown, StrPrinter << "no such track with suffix:" << controlSuffix);
} }
inline int RtspSession::getTrackIndexByInterleaved(int interleaved){ inline int RtspSession::getTrackIndexByInterleaved(int interleaved){
for (unsigned int i = 0; i < _aTrackInfo.size(); i++) { for (unsigned int i = 0; i < _sdp_track.size(); i++) {
if (_aTrackInfo[i]->_interleaved == interleaved) { if (_sdp_track[i]->_interleaved == interleaved) {
return i; return i;
} }
} }
if(_aTrackInfo.size() == 1){ if(_sdp_track.size() == 1){
return 0; return 0;
} }
throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved); throw SockException(Err_shutdown, StrPrinter << "no such track with interleaved:" << interleaved);
} }
bool RtspSession::close(MediaSource &sender,bool force) { bool RtspSession::close(MediaSource &sender, bool force) {
//此回调在其他线程触发 //此回调在其他线程触发
if(!_pushSrc || (!force && _pushSrc->totalReaderCount())){ if(!_push_src || (!force && _push_src->totalReaderCount())){
return false; return false;
} }
string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force; string err = StrPrinter << "close media:" << sender.getSchema() << "/" << sender.getVhost() << "/" << sender.getApp() << "/" << sender.getId() << " " << force;
...@@ -1107,17 +1104,34 @@ bool RtspSession::close(MediaSource &sender,bool force) { ...@@ -1107,17 +1104,34 @@ bool RtspSession::close(MediaSource &sender,bool force) {
} }
int RtspSession::totalReaderCount(MediaSource &sender) { int RtspSession::totalReaderCount(MediaSource &sender) {
return _pushSrc ? _pushSrc->totalReaderCount() : sender.readerCount(); return _push_src ? _push_src->totalReaderCount() : sender.readerCount();
}
inline void RtspSession::onSendRtpPacket(const RtpPacket::Ptr &pkt){
#if RTSP_SERVER_SEND_RTCP
int track_index = getTrackIndexByTrackType(pkt->type);
RtcpCounter &counter = _rtcp_counter[track_index];
counter.pktCnt += 1;
counter.octCount += (pkt->size() - pkt->offset);
auto &ticker = _rtcp_send_tickers[track_index];
if (ticker.elapsedTime() > 5 * 1000) {
//send rtcp every 5 second
ticker.resetTime();
//直接保存网络字节序
memcpy(&counter.timeStamp, pkt->data() + 8, 4);
sendSenderReport(_rtp_type == Rtsp::RTP_TCP, track_index);
}
#endif
} }
void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
//InfoP(this) <<(int)pkt.Interleaved; switch (_rtp_type) {
switch (_rtpType) {
case Rtsp::RTP_TCP: { case Rtsp::RTP_TCP: {
int i = 0; int i = 0;
int size = pkt->size(); int size = pkt->size();
setSendFlushFlag(false); setSendFlushFlag(false);
pkt->for_each([&](const RtpPacket::Ptr &rtp) { pkt->for_each([&](const RtpPacket::Ptr &rtp) {
onSendRtpPacket(rtp);
if (++i == size) { if (++i == size) {
setSendFlushFlag(true); setSendFlushFlag(true);
} }
...@@ -1129,15 +1143,15 @@ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { ...@@ -1129,15 +1143,15 @@ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
int i = 0; int i = 0;
int size = pkt->size(); int size = pkt->size();
pkt->for_each([&](const RtpPacket::Ptr &rtp) { pkt->for_each([&](const RtpPacket::Ptr &rtp) {
int iTrackIndex = getTrackIndexByTrackType(rtp->type); onSendRtpPacket(rtp);
auto &pSock = _apRtpSock[iTrackIndex]; int track_index = getTrackIndexByTrackType(rtp->type);
auto &pSock = _rtp_socks[track_index];
if (!pSock) { if (!pSock) {
shutdown(SockException(Err_shutdown, "udp sock not opened yet")); shutdown(SockException(Err_shutdown, "udp sock not opened yet"));
return; return;
} }
BufferRtp::Ptr buffer(new BufferRtp(rtp, 4)); BufferRtp::Ptr buffer(new BufferRtp(rtp, 4));
_ui64TotalBytes += buffer->size(); _bytes_usage += buffer->size();
pSock->send(buffer, nullptr, 0, ++i == size); pSock->send(buffer, nullptr, 0, ++i == size);
}); });
} }
...@@ -1145,42 +1159,27 @@ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) { ...@@ -1145,42 +1159,27 @@ void RtspSession::sendRtpPacket(const RtspMediaSource::RingDataType &pkt) {
default: default:
break; break;
} }
#if RTSP_SERVER_SEND_RTCP
int iTrackIndex = getTrackIndexByTrackType(pkt->type);
RtcpCounter &counter = _aRtcpCnt[iTrackIndex];
counter.pktCnt += 1;
counter.octCount += (pkt->length - pkt->offset);
auto &ticker = _aRtcpTicker[iTrackIndex];
if (ticker.elapsedTime() > 5 * 1000) {
//send rtcp every 5 second
ticker.resetTime();
//直接保存网络字节序
memcpy(&counter.timeStamp, pkt->payload + 8 , 4);
sendSenderReport(_rtpType == Rtsp::RTP_TCP,iTrackIndex);
}
#endif
} }
void RtspSession::sendSenderReport(bool overTcp,int iTrackIndex) { void RtspSession::sendSenderReport(bool over_tcp, int track_index) {
static const char s_cname[] = "ZLMediaKitRtsp"; static const char s_cname[] = "ZLMediaKitRtsp";
uint8_t aui8Rtcp[4 + 28 + 10 + sizeof(s_cname) + 1] = {0}; uint8_t rtcp_buf[4 + 28 + 10 + sizeof(s_cname) + 1] = {0};
uint8_t *pui8Rtcp_SR = aui8Rtcp + 4, *pui8Rtcp_SDES = pui8Rtcp_SR + 28; uint8_t *rtcp_sr = rtcp_buf + 4, *rtcp_sdes = rtcp_sr + 28;
auto &track = _aTrackInfo[iTrackIndex]; auto &track = _sdp_track[track_index];
auto &counter = _aRtcpCnt[iTrackIndex]; auto &counter = _rtcp_counter[track_index];
aui8Rtcp[0] = '$'; rtcp_buf[0] = '$';
aui8Rtcp[1] = track->_interleaved + 1; rtcp_buf[1] = track->_interleaved + 1;
aui8Rtcp[2] = (sizeof(aui8Rtcp) - 4) >> 8; rtcp_buf[2] = (sizeof(rtcp_buf) - 4) >> 8;
aui8Rtcp[3] = (sizeof(aui8Rtcp) - 4) & 0xFF; rtcp_buf[3] = (sizeof(rtcp_buf) - 4) & 0xFF;
pui8Rtcp_SR[0] = 0x80; rtcp_sr[0] = 0x80;
pui8Rtcp_SR[1] = 0xC8; rtcp_sr[1] = 0xC8;
pui8Rtcp_SR[2] = 0x00; rtcp_sr[2] = 0x00;
pui8Rtcp_SR[3] = 0x06; rtcp_sr[3] = 0x06;
uint32_t ssrc=htonl(track->_ssrc); uint32_t ssrc = htonl(track->_ssrc);
memcpy(&pui8Rtcp_SR[4], &ssrc, 4); memcpy(&rtcp_sr[4], &ssrc, 4);
uint64_t msw; uint64_t msw;
uint64_t lsw; uint64_t lsw;
...@@ -1190,35 +1189,35 @@ void RtspSession::sendSenderReport(bool overTcp,int iTrackIndex) { ...@@ -1190,35 +1189,35 @@ void RtspSession::sendSenderReport(bool overTcp,int iTrackIndex) {
lsw = (uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6); lsw = (uint32_t) ((double) tv.tv_usec * (double) (((uint64_t) 1) << 32) * 1.0e-6);
msw = htonl(msw); msw = htonl(msw);
memcpy(&pui8Rtcp_SR[8], &msw, 4); memcpy(&rtcp_sr[8], &msw, 4);
lsw = htonl(lsw); lsw = htonl(lsw);
memcpy(&pui8Rtcp_SR[12], &lsw, 4); memcpy(&rtcp_sr[12], &lsw, 4);
//直接使用网络字节序 //直接使用网络字节序
memcpy(&pui8Rtcp_SR[16], &counter.timeStamp, 4); memcpy(&rtcp_sr[16], &counter.timeStamp, 4);
uint32_t pktCnt = htonl(counter.pktCnt); uint32_t pktCnt = htonl(counter.pktCnt);
memcpy(&pui8Rtcp_SR[20], &pktCnt, 4); memcpy(&rtcp_sr[20], &pktCnt, 4);
uint32_t octCount = htonl(counter.octCount); uint32_t octCount = htonl(counter.octCount);
memcpy(&pui8Rtcp_SR[24], &octCount, 4); memcpy(&rtcp_sr[24], &octCount, 4);
pui8Rtcp_SDES[0] = 0x81; rtcp_sdes[0] = 0x81;
pui8Rtcp_SDES[1] = 0xCA; rtcp_sdes[1] = 0xCA;
pui8Rtcp_SDES[2] = 0x00; rtcp_sdes[2] = 0x00;
pui8Rtcp_SDES[3] = 0x06; rtcp_sdes[3] = 0x06;
memcpy(&pui8Rtcp_SDES[4], &ssrc, 4); memcpy(&rtcp_sdes[4], &ssrc, 4);
pui8Rtcp_SDES[8] = 0x01; rtcp_sdes[8] = 0x01;
pui8Rtcp_SDES[9] = 0x0f; rtcp_sdes[9] = 0x0f;
memcpy(&pui8Rtcp_SDES[10], s_cname, sizeof(s_cname)); memcpy(&rtcp_sdes[10], s_cname, sizeof(s_cname));
pui8Rtcp_SDES[10 + sizeof(s_cname)] = 0x00; rtcp_sdes[10 + sizeof(s_cname)] = 0x00;
if(overTcp){ if (over_tcp) {
send(obtainBuffer((char *) aui8Rtcp, sizeof(aui8Rtcp))); send(obtainBuffer((char *) rtcp_buf, sizeof(rtcp_buf)));
}else { } else {
_apRtcpSock[iTrackIndex]->send((char *) aui8Rtcp + 4, sizeof(aui8Rtcp) - 4); _rtcp_socks[track_index]->send((char *) rtcp_buf + 4, sizeof(rtcp_buf) - 4);
} }
} }
...@@ -1234,4 +1233,3 @@ void RtspSession::setSocketFlags(){ ...@@ -1234,4 +1233,3 @@ void RtspSession::setSocketFlags(){
} }
/* namespace mediakit */ /* namespace mediakit */
...@@ -59,51 +59,31 @@ public: ...@@ -59,51 +59,31 @@ public:
//在请求明文密码时如果提供md5密码者则会导致认证失败 //在请求明文密码时如果提供md5密码者则会导致认证失败
typedef std::function<void(bool encrypted,const string &pwd_or_md5)> onAuth; typedef std::function<void(bool encrypted,const string &pwd_or_md5)> onAuth;
RtspSession(const Socket::Ptr &pSock); RtspSession(const Socket::Ptr &sock);
virtual ~RtspSession(); virtual ~RtspSession();
////TcpSession override//// ////TcpSession override////
void onRecv(const Buffer::Ptr &pBuf) override; void onRecv(const Buffer::Ptr &buf) override;
void onError(const SockException &err) override; void onError(const SockException &err) override;
void onManager() override; void onManager() override;
protected: protected:
//RtspSplitter override /////RtspSplitter override/////
/** //收到完整的rtsp包回调,包括sdp等content数据
* 收到完整的rtsp包回调,包括sdp等content数据
* @param parser rtsp包
*/
void onWholeRtspPacket(Parser &parser) override; void onWholeRtspPacket(Parser &parser) override;
//收到rtp包回调
/** void onRtpPacket(const char *data, uint64_t len) override;
* 收到rtp包回调 //从rtsp头中获取Content长度
* @param data
* @param len
*/
void onRtpPacket(const char *data,uint64_t len) override;
/**
* 从rtsp头中获取Content长度
* @param parser
* @return
*/
int64_t getContentLength(Parser &parser) override; int64_t getContentLength(Parser &parser) override;
////RtpReceiver override////
//RtpReceiver override void onRtpSorted(const RtpPacket::Ptr &rtp, int track_idx) override;
void onRtpSorted(const RtpPacket::Ptr &rtppt, int trackidx) override; ////MediaSourceEvent override////
//MediaSourceEvent override bool close(MediaSource &sender, bool force) override ;
bool close(MediaSource &sender,bool force) override ;
int totalReaderCount(MediaSource &sender) override; int totalReaderCount(MediaSource &sender) override;
/////TcpSession override////
//TcpSession override
int send(const Buffer::Ptr &pkt) override; int send(const Buffer::Ptr &pkt) override;
//收到RTCP包回调
virtual void onRtcpPacket(int track_idx, SdpTrack::Ptr &track, unsigned char *data, unsigned int len);
/**
* 收到RTCP包回调
* @param iTrackidx
* @param track
* @param pucData
* @param uiLen
*/
virtual void onRtcpPacket(int iTrackidx, SdpTrack::Ptr &track, unsigned char *pucData, unsigned int uiLen);
private: private:
//处理options方法,获取服务器能力 //处理options方法,获取服务器能力
void handleReq_Options(const Parser &parser); void handleReq_Options(const Parser &parser);
...@@ -127,101 +107,100 @@ private: ...@@ -127,101 +107,100 @@ private:
void handleReq_Post(const Parser &parser); void handleReq_Post(const Parser &parser);
//处理SET_PARAMETER、GET_PARAMETER方法,一般用于心跳 //处理SET_PARAMETER、GET_PARAMETER方法,一般用于心跳
void handleReq_SET_PARAMETER(const Parser &parser); void handleReq_SET_PARAMETER(const Parser &parser);
//rtsp资源未找到 //rtsp资源未找到
void inline send_StreamNotFound(); void send_StreamNotFound();
//不支持的传输模式 //不支持的传输模式
void inline send_UnsupportedTransport(); void send_UnsupportedTransport();
//会话id错误 //会话id错误
void inline send_SessionNotFound(); void send_SessionNotFound();
//一般rtsp服务器打开端口失败时触发 //一般rtsp服务器打开端口失败时触发
void inline send_NotAcceptable(); void send_NotAcceptable();
//获取track下标 //获取track下标
inline int getTrackIndexByTrackType(TrackType type); int getTrackIndexByTrackType(TrackType type);
inline int getTrackIndexByControlSuffix(const string &controlSuffix); int getTrackIndexByControlSuffix(const string &control_suffix);
inline int getTrackIndexByInterleaved(int interleaved); int getTrackIndexByInterleaved(int interleaved);
//一般用于接收udp打洞包,也用于rtsp推流 //一般用于接收udp打洞包,也用于rtsp推流
inline void onRcvPeerUdpData(int intervaled, const Buffer::Ptr &pBuf, const struct sockaddr &addr); void onRcvPeerUdpData(int interleaved, const Buffer::Ptr &buf, const struct sockaddr &addr);
//配合onRcvPeerUdpData使用 //配合onRcvPeerUdpData使用
inline void startListenPeerUdpData(int iTrackIdx); void startListenPeerUdpData(int track_idx);
////rtsp专有认证相关//// ////rtsp专有认证相关////
//认证成功 //认证成功
void onAuthSuccess(); void onAuthSuccess();
//认证失败 //认证失败
void onAuthFailed(const string &realm,const string &why,bool close = true); void onAuthFailed(const string &realm, const string &why, bool close = true);
//开始走rtsp专有认证流程 //开始走rtsp专有认证流程
void onAuthUser(const string &realm,const string &authorization); void onAuthUser(const string &realm, const string &authorization);
//校验base64方式的认证加密 //校验base64方式的认证加密
void onAuthBasic(const string &realm,const string &strBase64); void onAuthBasic(const string &realm, const string &auth_base64);
//校验md5方式的认证加密 //校验md5方式的认证加密
void onAuthDigest(const string &realm,const string &strMd5); void onAuthDigest(const string &realm, const string &auth_md5);
//触发url鉴权事件 //触发url鉴权事件
void emitOnPlay(); void emitOnPlay();
//发送rtp给客户端 //发送rtp给客户端
void sendRtpPacket(const RtspMediaSource::RingDataType &pkt); void sendRtpPacket(const RtspMediaSource::RingDataType &pkt);
//触发rtcp发送
void onSendRtpPacket(const RtpPacket::Ptr &rtp);
//回复客户端 //回复客户端
bool sendRtspResponse(const string &res_code,const std::initializer_list<string> &header, const string &sdp = "" , const char *protocol = "RTSP/1.0"); bool sendRtspResponse(const string &res_code, const std::initializer_list<string> &header, const string &sdp = "", const char *protocol = "RTSP/1.0");
bool sendRtspResponse(const string &res_code,const StrCaseMap &header = StrCaseMap(), const string &sdp = "",const char *protocol = "RTSP/1.0"); bool sendRtspResponse(const string &res_code, const StrCaseMap &header = StrCaseMap(), const string &sdp = "", const char *protocol = "RTSP/1.0");
//服务器发送rtcp //服务器发送rtcp
void sendSenderReport(bool overTcp,int iTrackIndex); void sendSenderReport(bool over_tcp, int track_idx);
//设置socket标志 //设置socket标志
void setSocketFlags(); void setSocketFlags();
private: private:
//用于判断客户端是否超时 //是否已经触发on_play事件
Ticker _ticker; bool _emit_on_play = false;
//是否开始发送rtp
bool _enable_send_rtp;
//推流或拉流客户端采用的rtp传输方式
Rtsp::eRtpType _rtp_type = Rtsp::RTP_Invalid;
//收到的seq,回复时一致 //收到的seq,回复时一致
int _iCseq = 0; int _cseq = 0;
//消耗的总流量
uint64_t _bytes_usage = 0;
//ContentBase //ContentBase
string _strContentBase; string _content_base;
//Session号 //Session号
string _strSession; string _sessionid;
//记录是否需要rtsp专属鉴权,防止重复触发事件 //记录是否需要rtsp专属鉴权,防止重复触发事件
string _rtsp_realm; string _rtsp_realm;
//是否已经触发on_play事件 //登录认证
bool _emit_on_play = false; string _auth_nonce;
//用于判断客户端是否超时
Ticker _alive_ticker;
//url解析后保存的相关信息 //url解析后保存的相关信息
MediaInfo _mediaInfo; MediaInfo _media_info;
//rtsp推流相关绑定的源
RtspMediaSourceImp::Ptr _push_src;
//rtsp播放器绑定的直播源 //rtsp播放器绑定的直播源
std::weak_ptr<RtspMediaSource> _pMediaSrc; std::weak_ptr<RtspMediaSource> _play_src;
//直播源读取器 //直播源读取器
RtspMediaSource::RingType::RingReader::Ptr _pRtpReader; RtspMediaSource::RingType::RingReader::Ptr _play_reader;
//推流或拉流客户端采用的rtp传输方式
Rtsp::eRtpType _rtpType = Rtsp::RTP_Invalid;
//sdp里面有效的track,包含音频或视频 //sdp里面有效的track,包含音频或视频
vector<SdpTrack::Ptr> _aTrackInfo; vector<SdpTrack::Ptr> _sdp_track;
//rtcp统计,trackid idx 为数组下标
RtcpCounter _rtcp_counter[2];
//rtcp发送时间,trackid idx 为数组下标
Ticker _rtcp_send_tickers[2];
////////RTP over udp//////// ////////RTP over udp////////
//RTP端口,trackid idx 为数组下标 //RTP端口,trackid idx 为数组下标
Socket::Ptr _apRtpSock[2]; Socket::Ptr _rtp_socks[2];
//RTCP端口,trackid idx 为数组下标 //RTCP端口,trackid idx 为数组下标
Socket::Ptr _apRtcpSock[2]; Socket::Ptr _rtcp_socks[2];
//标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号 //标记是否收到播放的udp打洞包,收到播放的udp打洞包后才能知道其外网udp端口号
unordered_set<int> _udpSockConnected; unordered_set<int> _udp_connected_flags;
////////RTP over udp_multicast//////// ////////RTP over udp_multicast////////
//共享的rtp组播对象 //共享的rtp组播对象
RtpMultiCaster::Ptr _multicaster; RtpMultiCaster::Ptr _multicaster;
////////RTSP over HTTP ////////
//登录认证
string _strNonce;
//消耗的总流量
uint64_t _ui64TotalBytes = 0;
//RTSP over HTTP
//quicktime 请求rtsp会产生两次tcp连接, //quicktime 请求rtsp会产生两次tcp连接,
//一次发送 get 一次发送post,需要通过x-sessioncookie关联起来 //一次发送 get 一次发送post,需要通过x-sessioncookie关联起来
string _http_x_sessioncookie; string _http_x_sessioncookie;
function<void(const Buffer::Ptr &pBuf)> _onRecv; function<void(const Buffer::Ptr &)> _on_recv;
//是否开始发送rtp
bool _enableSendRtp;
//rtsp推流相关
RtspMediaSourceImp::Ptr _pushSrc;
//rtcp统计,trackid idx 为数组下标
RtcpCounter _aRtcpCnt[2];
//rtcp发送时间,trackid idx 为数组下标
Ticker _aRtcpTicker[2];
}; };
/** /**
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论