github.com/qiniu/go-sdk/v7@v7.27.0/qvs/stream.go (about) 1 package qvs 2 3 import ( 4 "context" 5 "io" 6 "net/http" 7 "net/url" 8 ) 9 10 const ( 11 DomainPublishRTMP string = "publishRtmp" 12 DomainLiveRTMP string = "liveRtmp" 13 DomainLiveHLS string = "liveHls" 14 DomainLiveHDL string = "liveHdl" 15 ) 16 17 type Stream struct { 18 StreamID string `json:"streamId"` // 流名称, 流名称在空间中唯一,可包含 字母、数字、中划线、下划线;1 ~ 100 个字符长;创建后将不可修改 19 Desc string `json:"desc,omitempty"` // 关于流的描述信息 20 21 NamespaceId string `json:"nsId"` // 所属的空间ID 22 Namespace string `json:"nsName"` // 所属的空间名称 23 24 RecordTemplateId string `json:"recordTemplateId"` // 录制模版ID,配置流维度的录制模板 25 SnapShotTemplateId string `json:"snapshotTemplateId"` // 截图模版ID,配置流维度的截图模板 26 27 Status bool `json:"status"` // 设备是否在线 28 Disabled bool `json:"disabled"` // 流是否被禁用 29 LastPushedAt int64 `json:"lastPushedAt"` // 最后一次推流时间,0:表示没有推流 30 31 CreatedAt int64 `json:"createdAt,omitempty"` // 流创建时间 32 UpdatedAt int64 `json:"updatedAt,omitempty"` // 流更新时间 33 34 // 以下字段只有在设备在线是才会出现 35 UserCount int `json:"userCount"` 36 ClientIp string `json:"clientIp,omitempty"` 37 AudioFrameRate int64 `json:"audioFrameRate,omitempty"` 38 BitRate int64 `json:"bitRate,omitempty"` 39 VideoFrameRate int64 `json:"videoFrameRate,omitempty"` 40 } 41 42 /* 43 创建流API 44 */ 45 func (manager *Manager) AddStream(nsId string, stream *Stream) (*Stream, error) { 46 var ret Stream 47 err := manager.client.CallWithJson(context.Background(), &ret, "POST", manager.url("/namespaces/%s/streams", nsId), nil, stream) 48 if err != nil { 49 return nil, err 50 } 51 return &ret, nil 52 } 53 54 /* 55 查询流API 56 */ 57 func (manager *Manager) QueryStream(nsId string, streamId string) (*Stream, error) { 58 var ret Stream 59 err := manager.client.Call(context.Background(), &ret, "GET", manager.url("/namespaces/%s/streams/%s", nsId, streamId), nil) 60 if err != nil { 61 return nil, err 62 } 63 return &ret, nil 64 } 65 66 /* 67 更新流API 68 */ 69 func (manager *Manager) UpdateStream(nsId string, streamId string, ops []PatchOperation) (*Stream, error) { 70 req := M{"operations": ops} 71 var ret Stream 72 err := manager.client.CallWithJson(context.Background(), &ret, "PATCH", manager.url("/namespaces/%s/streams/%s", nsId, streamId), nil, req) 73 if err != nil { 74 return nil, err 75 } 76 return &ret, nil 77 } 78 79 /* 80 删除流API 81 */ 82 func (manager *Manager) DeleteStream(nsId string, streamId string) error { 83 return manager.client.Call(context.Background(), nil, "DELETE", manager.url("/namespaces/%s/streams/%s", nsId, streamId), nil) 84 } 85 86 /* 87 查询流列表API 88 */ 89 func (manager *Manager) ListStream(nsId string, offset, line int, prefix, sortBy string, qType int) ([]Stream, int64, error) { 90 ret := struct { 91 Items []Stream `json:"items"` 92 Total int64 `json:"total"` 93 }{} 94 95 query := url.Values{} 96 setQuery(query, "offset", offset) 97 setQuery(query, "line", line) 98 setQuery(query, "sortBy", sortBy) 99 setQuery(query, "prefix", prefix) 100 setQuery(query, "qtype", qType) 101 102 err := manager.client.Call(context.Background(), &ret, "GET", manager.url("/namespaces/%s/streams?%v", nsId, query.Encode()), nil) 103 return ret.Items, ret.Total, err 104 } 105 106 type DynamicLiveRoute struct { 107 PublishIP string `json:"publishIP"` // 推流端对外IP地址 108 PlayIP string `json:"playIP"` // 拉流端对外IP地址 109 UrlExpireSec int64 `json:"urlExpireSec"` // 地址过期时间,urlExpireSec:100代表100秒后过期; 默认urlExpireSec:0,永不过期. 110 PlayExpireSec int64 `json:"playExpireSec"` // 播放过期时间(单位为秒) 111 } 112 113 type StaticLiveRoute struct { 114 Domain string `json:"domain"` // 域名 115 DomainType string `json:"domainType"` // 域名类型 116 UrlExpireSec int64 `json:"urlExpireSec"` // 地址过期时间,urlExpireSec:100代表100秒后过期; 默认urlExpireSec:0,永不过期. 117 PlayExpireSec int64 `json:"playExpireSec"` // 播放过期时间(单位为秒) 118 } 119 120 type RouteRet struct { 121 PublishUrl string `json:"publishUrl"` // rtmp推流地址 122 PlayUrls RoutePlayUrls `json:"playUrls"` // 拉流URLs 123 PublishUrlExpired int64 `json:"publishUrlExpired"` // 推拉流地址过期时间点(unix时间戳,单位second) 124 } 125 126 type RoutePlayUrls struct { 127 Rtmp string `json:"rtmp"` // rtmp播放地址 128 Flv string `json:"flv"` // flv播放地址 129 Hls string `json:"hls"` // hls播放地址 130 } 131 132 /* 133 动态获取流地址API:推拉流IP地址计算最合适的设备端推拉流地址 134 */ 135 func (manager *Manager) DynamicPublishPlayURL(nsId string, streamId string, route *DynamicLiveRoute) (*RouteRet, error) { 136 var ret RouteRet 137 err := manager.client.CallWithJson(context.Background(), &ret, "POST", manager.url("/namespaces/%s/streams/%s/urls", nsId, streamId), nil, route) 138 if err != nil { 139 return nil, err 140 } 141 return &ret, nil 142 } 143 144 /* 145 静态获取流地址API:根据domain生成推拉流地址 146 */ 147 func (manager *Manager) StaticPublishPlayURL(nsId, streamId string, route *StaticLiveRoute) (string, error) { 148 var ret RouteRet 149 err := manager.client.CallWithJson(context.Background(), &ret, "POST", manager.url("/namespaces/%s/streams/%s/domain", nsId, streamId), nil, route) 150 if err != nil { 151 return "", err 152 } 153 switch route.DomainType { 154 case DomainPublishRTMP: 155 return ret.PublishUrl, nil 156 case DomainLiveRTMP: 157 return ret.PlayUrls.Rtmp, nil 158 case DomainLiveHLS: 159 return ret.PlayUrls.Hls, nil 160 case DomainLiveHDL: 161 return ret.PlayUrls.Flv, nil 162 } 163 return "", nil 164 } 165 166 // 禁用流 167 func (manager *Manager) DisableStream(nsId string, streamId string) error { 168 err := manager.client.CallWithJson(context.Background(), nil, "POST", manager.url("/namespaces/%s/streams/%s/disabled", nsId, streamId), nil, nil) 169 return err 170 } 171 172 // 恢复流 173 func (manager *Manager) EnableStream(nsId string, streamId string) error { 174 err := manager.client.CallWithJson(context.Background(), nil, "POST", manager.url("/namespaces/%s/streams/%s/enabled", nsId, streamId), nil, nil) 175 return err 176 } 177 178 // 停止推流 179 func (manager *Manager) StopStream(nsId string, streamId string) error { 180 err := manager.client.CallWithJson(context.Background(), nil, "POST", manager.url("/namespaces/%s/streams/%s/stop", nsId, streamId), nil, nil) 181 return err 182 } 183 184 type StreamPublishHistory struct { 185 StreamId string `json:"streamId"` 186 NsId string `json:"nsId"` 187 Start int64 `json:"start"` 188 End int64 `json:"end"` 189 Duration int64 `json:"duration"` 190 Snap string `json:"snap"` 191 Fmt string `json:"format,omitempty"` 192 } 193 194 // 查询推流历史记录 195 func (manager *Manager) QueryStreamPubhistories(nsId string, streamId string, start, end int, line, offset int) ([]StreamPublishHistory, int64, error) { 196 ret := struct { 197 Items []StreamPublishHistory `json:"items"` 198 Total int64 `json:"total"` 199 }{} 200 201 query := url.Values{} 202 setQuery(query, "start", start) 203 setQuery(query, "end", end) 204 setQuery(query, "offset", offset) 205 setQuery(query, "line", line) 206 207 err := manager.client.Call(context.Background(), &ret, "GET", manager.url("/namespaces/%s/streams/%s/pubhistories?%v", nsId, streamId, query.Encode()), nil) 208 return ret.Items, ret.Total, err 209 } 210 211 // 按需截图 212 func (manager *Manager) OndemandSnap(nsId, streamId string) error { 213 return manager.client.CallWithJson(context.Background(), nil, "POST", manager.url("/namespaces/%s/streams/%s/snap", nsId, streamId), nil, nil) 214 } 215 216 // 删除截图 217 func (manager *Manager) DeleteSnapshots(nsId, streamId string, files []string) error { 218 return manager.client.CallWithJson(context.Background(), nil, "DELETE", manager.url("/namespaces/%s/streams/%s/snapshots", nsId, streamId), nil, M{"files": files}) 219 } 220 221 // 查询截图列表 222 func (manager *Manager) StreamsSnapshots(nsId string, streamId string, start, end int, qtype int, line int, marker string) ([]byte, error) { 223 query := url.Values{} 224 setQuery(query, "start", start) 225 setQuery(query, "end", end) 226 setQuery(query, "type", qtype) 227 setQuery(query, "line", line) 228 setQuery(query, "marker", marker) 229 230 req, err := http.NewRequest("GET", manager.url("/namespaces/%s/streams/%s/snapshots?%v", nsId, streamId, query.Encode()), nil) 231 if err != nil { 232 return nil, err 233 } 234 resp, err := manager.client.Do(context.Background(), req) 235 if err != nil { 236 return nil, err 237 } 238 body, err := io.ReadAll(resp.Body) 239 if err != nil { 240 return nil, err 241 } 242 return body, nil 243 } 244 245 type RecordHistory struct { 246 Url string `json:"url"` 247 Start int `json:"start"` 248 End int `json:"end"` 249 Duration int `json:"duration"` 250 Format int `json:"format"` 251 Snap string `json:"snap"` 252 File string `json:"file"` 253 } 254 255 // 查询视频流的录制记录 256 func (manager *Manager) QueryStreamRecordHistories(nsId string, streamId string, start, end int, marker string, line int, format string) ([]RecordHistory, string, error) { 257 ret := struct { 258 Items []RecordHistory `json:"items"` 259 Marker string `json:"marker"` 260 }{} 261 262 query := url.Values{} 263 setQuery(query, "start", start) 264 setQuery(query, "end", end) 265 setQuery(query, "marker", marker) 266 setQuery(query, "line", line) 267 setQuery(query, "format", format) 268 269 err := manager.client.Call(context.Background(), &ret, "GET", manager.url("/namespaces/%s/streams/%s/recordhistories?%v", nsId, streamId, query.Encode()), nil) 270 return ret.Items, ret.Marker, err 271 } 272 273 // 查询流封面 274 func (manager *Manager) QueryStreamCover(nsId string, streamId string) (string, error) { 275 ret := struct { 276 Url string `json:"url"` 277 }{} 278 err := manager.client.Call(context.Background(), &ret, "GET", manager.url("/namespaces/%s/streams/%s/cover", nsId, streamId), nil) 279 return ret.Url, err 280 }