服务端开发说明
服务端职能
虽然实时音视频云已经提供了云端的音视频通话服务,但是想让这个服务和您的实际业务耦合还是需要您自己搭建一些业务服务的,其中主要分以下 2 块:
- RoomToken 签发服务
- 房间及 App 管理服务
RoomToken 签发服务
在进入一个实时音视频房间之前,您需要通过自己七牛云账户的 AK/SK 签算出一个 roomToken。roomToken 是一个包含了一次连麦所需要的主要信息的 token,这些信息包括 七牛的账户标识、连麦的应用 ID(appId)、连麦的房间号 (roomName)、连麦的用户名(userId)、有效期等等。这个 token 通过自己七牛账户的私钥进行加密,因为涉及到私钥加密,所以您需要自己搭建一个业务服务来向您的实时音视频应用提供 roomToken。
RoomToken 的签算逻辑可以参考以下流程,当然,您也可以选择使用我们的 服务端 SDK 来完成这些操作。
生成 roomToken 作为一个基本功能,各个语言版本的服务端 SDK 都提供了生成它的方法,具体参见各个 SDK 的文档。这里说明一下手动生成 roomToken 的计算方法。
// 1. 定义房间管理凭证,并对凭证字符做URL安全的Base64编码
roomAccess = {
"appId": "<AppID>"
"roomName": "<RoomName>",
"userId": "<UserID>",
"expireAt": <ExpireAt>,
"permission": "<Permission>"
}
roomAccessString = json_to_string(roomAccess)
encodedRoomAccess = urlsafe_base64_encode(roomAccessString)
// 2. 计算HMAC-SHA1签名,并对签名结果做URL安全的Base64编码
sign = hmac_sha1(encodedRoomAccess, <SecretKey>)
encodedSign = urlsafe_base64_encode(sign)
// 3. 将AccessKey与以上两者拼接得到房间鉴权
roomToken = "<AccessKey>" + ":" + encodedSign + ":" + encodedRoomAccess
AppID: 房间所属帐号的 app 。
RoomName: 房间名称,需满足规格 ^[a-zA-Z0-9_-]{3,64}$
UserID: 请求加入房间的用户 ID,需满足规格 ^[a-zA-Z0-9_-]{3,50}$
ExpireAt: int64 类型,鉴权的有效时间,传入以秒为单位的 64 位 Unix 绝对时间,token 将在该时间后失效。
Permission: 该用户的房间管理权限,"admin" 或 "user",默认为 "user" 。当权限角色为 "admin" 时,拥有将其他用户移除出房间等特权.
房间及 App 管理服务
这一部分服务是为了让您的业务后台能够自动地完成一些在控制台上需要完成的操作,比如 创建/修改 app,查看房间成员列表,踢出指定用户等。
对于这些服务,我们统一封装了 Restful 的接口方便给您调用,在调用各个接口之前,您还需要在 http headers 中添加鉴权头以识别您的权限。
同样,这些服务都可以通过服务端 SDK 来完成,以下都是介绍手动请求的情况。
HTTP 请求鉴权
Qiniu RTC Server API 通过 Qiniu Authorization 方式进行鉴权,每个房间管理 HTTP 请求头部需增加一个 Authorization 字段:
Authorization: "<QiniuToken>"
QiniuToken: 管理凭证,用于鉴权。
使用七牛颁发的AccessKey
和SecretKey
,对本次 http 请求的信息进行签名,生成管理凭证。签名的原始数据包括 http 请求的 Method
, Path
, RawQuery
, Content-Type
及 Body
等信息,这些信息的获取方法取决于具体所用的编程语言,建议参照七牛提供的 SDK 代码。
计算过程及伪代码如下:
// 1.构造待签名的 Data
// 添加 Method 和 Path
data = "<Method> <Path>"
// 添加 Query,如果Query不存在或者为空,则跳过此步
if "<RawQuery>" != "" {
data += "?<RawQuery>"
}
// 添加 Host
data += "\nHost: <Host>"
// 添加 Content-Type,如果Content-Type不存在或者为空,则跳过此步
if "<Content-Type>" != "" {
data += "\nContent-Type: <Content-Type>"
}
// 添加回车
data += "\n\n"
// 添加 Body, 如果Content-Length, Content-Type和Body任意一个不存在或者为空,则跳过此步;如果Content-Type为application/octet-stream,也跳过此步
bodyOK := "<Content-Length>" != "" && "<Body>" != ""
contentTypeOK := "<Content-Type>" != "" && "<Content-Type>" != "application/octet-stream"
if bodyOK && contentTypeOK {
data += "<Body>"
}
// 2. 计算 HMAC-SHA1 签名,并对签名结果做 URL 安全的 Base64 编码
sign = hmac_sha1(data, "Your_Secret_Key")
encodedSign = urlsafe_base64_encode(sign)
// 3. 将 Qiniu 标识与 AccessKey、encodedSign 拼接得到管理凭证
<QiniuToken> = "Qiniu " + "Your_Access_Key" + ":" + encodedSign
App 管理
在七牛云控制台页面打开实时音视频云可以看到 连麦应用列表,这里每个应用都应该和您的实际业务上的应用相对应,也就是我们这里说的 app。app 是您在七牛实时音视频云的业务配置集合。 一个 app 帐号下的连麦房间(频道)拥有独立的命名空间,并且这些房间的可配置功能选项遵从 app 的配置,例如人数限制、是否允许抢流、合流、旁路直播等。您可以创建多个不同的 app(最 多 10 个) ,以实现不同的配置需求。注意,不同 app 下面所属的同名房间并不互通(因为 app 相互独立)。
下面列举了操作和管理这些 app 的接口,如果您希望通过服务端 SDK 来调用,请具体参照各个 SDK 自己的文档。
CreateApp 创建一个应用
Host rtc.qiniuapi.com
POST /v3/apps
Authorization: qiniu mac
Content-Type: application/json
{
"hub": "<Hub>",
"title": "<Title>",
"maxUsers": <MaxUsers>,
"noAutoKickUser": <NoAutoKickUser>
}
Hub: 绑定的直播 hub,可选,使用此 hub 的资源进行推流等业务功能,hub 与 app 必须属于同一个七牛账户。
Title: app 的名称,可选,注意,Title 不是唯一标识,重复 create 动作将生成多个 app。
MaxUsers: int 类型,可选,连麦房间支持的最大在线人数。
NoAutoKickUser: bool 类型,可选,禁止自动踢人(抢流)。默认为 false ,即同一个身份的 client (app/room/user) ,新的连麦请求可以成功,旧连接被关闭。
200 OK
{
"appId": "<AppID>",
"hub": "<Hub>",
"title": "<Title>",
"maxUsers": <MaxUsers>,
"noAutoKickUser": <NoAutoKickUser>,
"createdAt": <CreatedAt>,
"updatedAt": <UpdatedAt>
}
616
{
"error": "hub not match"
}
AppID: app 的唯一标识。
Hub: 绑定的直播 hub,使用此 hub 的资源进行推流等业务功能,hub 与 app 必须属于同一个七牛账户。
Title: app 的名称,注意,Title 不是唯一标识。
MaxUsers: int 类型,连麦房间支持的最大在线人数。
NoAutoKickUser: bool 类型,禁止自动踢人。
CreatedAt: time 类型,app 创建的时间。
UpdatedAt: time 类型,app 更新的时间。
GetApp 获取一个应用当前的配置信息
Host rtc.qiniuapi.com
GET /v3/apps/<AppID>
Authorization: <qiniu mac>
AppID: app 的唯一标识,创建的时候由系统生成。
200 OK
{
"appId": "<AppID>",
"hub": "<Hub>",
"title": "<Title>",
"maxUsers": <MaxUsers>,
"noAutoKickUser": <NoAutoKickUser>,
"mergePublishRtmp": {
"enable": <Enable>,
"audioOnly": <AudioOnly>,
"height": <OutputHeight>,
"width": <OutputHeight>,
"fps": <OutputFps>,
"kbps": <OutputKbps>,
"url": "<URL>",
"streamTitle": "<StreamTitle>"
},
"createdAt": <CreatedAt>,
"updatedAt": <UpdatedAt>
}
612
{
"error": "app not found"
}
AppID: app 的唯一标识。
UID: 客户的七牛帐号。
Hub: 绑定的直播 hub,使用此 hub 的资源进行推流等业务功能,hub 与 app 必须属于同一个七牛账户。
Title: app 的名称,注意,Title 不是唯一标识。
MaxUsers: int 类型,连麦房间支持的最大在线人数。
NoAutoKickUser: bool 类型,禁止自动踢人。
MergePublishRtmp: 连麦合流转推 RTMP 的配置。
CreatedAt: time 类型,app 创建的时间。
UpdatedAt: time 类型,app 更新的时间。
DeleteApp 删除应用
Host rtc.qiniuapi.com
DELETE /v3/apps/<AppID>
Authorization: <qiniu mac>
AppID: app 的唯一标识,创建的时候由系统生成。
200 OK
612
{
"error": "app not found"
}
UpdateApp 更新一个应用的配置信息
注意!调用这个接口后仅对调用后新创建的房间有效,已经存在的房间需要等待被关闭重新创建后生效
Host rtc.qiniuapi.com
Post /v3/apps/<AppID>
Authorization: qiniu mac
{
"hub": "<Hub>",
"title": "<Title>",
"maxUsers": <MaxUsers>,
"noAutoKickUser": <NoAutoKickUser>,
"mergePublishRtmp": {
"enable": <Enable>,
"audioOnly": <AudioOnly>,
"height": <OutputHeight>,
"width": <OutputHeight>,
"fps": <OutputFps>,
"kbps": <OutputKbps>,
"url": "<URL>",
"streamTitle": "<StreamTitle>"
}
}
AppID: app 的唯一标识,创建的时候由系统生成。
Title: app 的名称, 可选。
Hub: 绑定的直播 hub,可选,用于合流后 rtmp 推流。
MaxUsers: int 类型,可选,连麦房间支持的最大在线人数。
NoAutoKickUser: bool 类型,可选,禁止自动踢人。
MergePublishRtmp: 连麦合流转推 RTMP 的配置,可选择。其详细配置包括如下
- Enable: 布尔类型,用于开启和关闭所有房间的合流功能。
- AudioOnly: 布尔类型,可选,指定是否只合成音频。
- Height, Width: int64,可选,指定合流输出的高和宽,默认为 640 x 480。
- OutputFps: int64,可选,指定合流输出的帧率,默认为 25 fps 。
- OutputKbps: int64,可选,指定合流输出的码率,默认为 1000 。
- URL: 合流后转推旁路直播的地址,可选,支持魔法变量配置按照连麦房间号生成不同的推流地址。如果是转推到七牛直播云,不建议配置。
- StreamTitle: 转推七牛直播云的流名,可选,支持魔法变量配置按照连麦房间号生成不同的流名。例如,配置 Hub 为
qn-zhibo
,配置 StreamTitle 为$(roomName)
,则房间 meeting-001 的合流将会被转推到 rtmp://pili-publish.qn-zhibo.***.com/qn-zhibo/meeting-001 地址。详细配置细则,请参考 portal.qiniu,com 配置页面,或咨询七牛技术支持。
备注:以上关于合流画面的配置项仅用于配置合流的输出效果,对某一个特定输入的画面的配置(例如位置、大小、层级等),请参考相关客户端 sdk 说明文档。
200 OK
{
"appId": "<AppID>",
"hub": "<Hub>",
"title": "<Title>",
"maxUsers": <MaxUsers>,
"noAutoKickUser": <NoAutoKickUser>,
"mergePublishRtmp": {
"enable": <Enable>,
"audioOnly": <AudioOnly>,
"height": <OutputHeight>,
"width": <OutputHeight>,
"fps": <OutputFps>,
"kbps": <OutputKbps>,
"url": "<URL>",
"streamTitle": "<StreamTitle>"
},
"createdAt": <CreatedAt>,
"updatedAt": <UpdatedAt>
}
612
{
"error": "app not found"
}
616
{
"error": "hub not match"
}
AppID: app 的唯一标识。
UID: 客户的七牛帐号。
Hub: 绑定的直播 hub,使用此 hub 的资源进行推流等业务功能,hub 与 app 必须属于同一个七牛账户。
Title: app 的名称,注意,Title 不是唯一标识。
MaxUsers: int 类型,连麦房间支持的最大在线人数。
NoAutoKickUser: bool 类型,禁止自动踢人。
MergePublishRtmp: 连麦合流转推 RTMP 的配置。
CreatedAt: time 类型,app 创建的时间。
UpdatedAt: time 类型,app 更新的时间。
房间管理
一次连麦过程,多个终端音视频通信行为的管理是通过 room 进行的。一个连麦房间必然属于某一个 app。房间无需主动创建或删除,用户直接使用客户端 sdk 指定某个 app 和 room 进行连麦即可加入房间。通过接口可以查询 app 下所有的活跃房间,也可以对某一个房间做相关的业务操作。
同样,您也可以使用服务端 SDK 提供的方法来完成下列操作,具体请参照相应的 SDK 文档。这里只说明手动发送控制请求的情况。
ListUser 列出指定房间下当前所有用户
Host rtc.qiniuapi.com
GET /v3/apps/<AppID>/rooms/<RoomName>/users
Authorization: qiniu mac
AppID: 连麦房间所属的 app 。
RoomName: 操作所查询的连麦房间。
200 OK
{
"users": [
{
"userId": "<UserID>"
},
]
}
612
{
"error": "app not found"
}
UserID: 连麦房间里在线的用户,如果无在线用户,则返回空数组。
KickUser 指定一个用户踢出房间
Host rtc.qiniuapi.com
DELETE /v3/apps/<AppID>/rooms/<RoomName>/users/<UserID>
Authorization: qiniu mac
AppID: 连麦房间所属的 app 。
RoomName: 连麦房间。
UserID: 操作所剔除的用户。
200 OK
612
{
"error": "app not found"
}
612
{
"error": "user not found"
}
615
{
"error": "room not active"
}
StopMerge 停止一个房间的合流转推
Host rtc.qiniuapi.com
DELETE /v3/apps/<AppID>/rooms/<RoomName>/merge
Authorization: qiniu mac
AppID: 连麦房间所属的 app 。
RoomName: 连麦房间。
用于停止某个房间的服务端合流。 不建议客户使用此接口,使用客户端信令可以更灵活准确地控制合流的启停。
200 OK
612
{
"error": "app not found"
}
615
{
"error": "room not active"
}
ListActiveRoom 获取当前所有活跃的房间
Host rtc.qiniuapi.com
GET /v3/apps/<AppID>/rooms?prefix=<RoomNamePrefix>&offset=<Offset>&limit=<Limit>
Authorization: qiniu mac
AppID: 连麦房间所属的 app 。
RoomNamePrefix: 所查询房间名的前缀索引,可以为空。
Offset: int 类型,分页查询的位移标记。
Limit: int 类型,此次查询的最大长度。
200 OK
{
"end": <IsEnd>,
"offset": <Offset>,
"rooms": [
"<RoomName>",
...
]
}
612
{
"error": "app not found"
}
IsEnd: bool 类型,分页查询是否已经查完所有房间。
Offset: int 类型,下次分页查询使用的位移标记。
RoomName: 当前活跃的房间名。