使用 Go SDK 开始云端转码
本文向新手介绍如何使用声网 Go SDK 开始第一次云端转码。
Go SDK 旨在帮助开发者更轻松集成声网 RESTful API。该 SDK 具有如下特性:
- 简化通信流畅:通过封装 RESTful API 的请求和响应处理,让你与 RESTful API 的通信更加简单。
- 保障可用性:遇到 DNS 解析失败、网络错误、请求超时等网络问题时,会自动切换到最佳域名,确保 REST 服务的可用性。
- API 易用性:提供简洁易懂的 API,让你能轻松实现创建云端转码、销毁云端转码等常用功能。
- 其他优势:基于 Go 语言编写,具有高效性、并发性、可扩展性。
前提条件
开通服务并获取关键参数
参考开通服务在控制台创建项目,并联系技术支持开通云端转码服务。复制保存如下参数,以供后续使用:
- App ID
- 临时 Token
- App 证书
- 客户 ID
- 客户密钥
模拟音视频互动场景
模拟一个音视频互动场景,频道内有两名主播发布音视频流,云端转码服务后续会将两名主播的流进行转码处理。
此处使用声网实时互动 Web Demo 在浏览器中模拟一个基础视频直播场景:
- 打开 Web Demo,完成初始化设置,填入 App ID 和 App 证书。
- 进入基础视频直播页面,在 Channel 填入频道名为 show,设置用户 ID 为 1234,点击 Join as host。
- 邀请一位朋友通过另一台设备,使用相同的 App ID、App 证书、频道名、临时 Token,重复上述 2 个步骤,设置用户 ID 为 2345,来加入频道。
如果模拟成功,你们会在 local stream 和 remote stream 区域分别看到自己和对方的视频画面。
准备开发环境
安装 Go
-
访问官网下载 Go,版本要求不低于 1.18。
-
在 Terminal 中执行如下命令,检查 Go 是否成功安装。
Shellgo version
如果安装成功,你会得到版本号信息,例如
go version go1.22.2 darwin/arm64
。
创建 Go 项目
创建一个 Go 项目。在项目文件夹下,执行如下命令初始化 Go 模块,并新建一个空的 main.go
文件。
go mod init <module_name>
安装 SDK
-
在 Terminal 中,进入项目文件夹,执行如下命令,安装 Go SDK。
Shell#(可选)设置代理,防止网络超时
go env -w GOPROXY=https://goproxy.cn,direct
# 安装 Go SDK
go get -u github.com/AgoraIO-Community/agora-rest-client-go
# 更新依赖
go mod tidy -
安装完成后,在你的
main.go
文件中添加如下代码,以导入 Go SDK。Goimport (
"context"
"log"
"time"
"github.com/AgoraIO-Community/agora-rest-client-go/core"
"github.com/AgoraIO-Community/agora-rest-client-go/services/cloudtranscoder"
v1 "github.com/AgoraIO-Community/agora-rest-client-go/services/cloudtranscoder/v1"
)
进行云端转码
本节介绍进行云端转码的极简流程。为方便说明,本节以上面模拟的视频直播为例,并假设将主播的音频和视频进行转码处理。
定义变量
在 main.go
文件中,添加如下代码,定义或配置关键参数,取值可参考前提条件。
// 定义关键参数
const (
appId = "<your_app_id>"
token = "<your_token>"
username = "<your_key>" // 客户 ID
password = "<your_secret>" // 客户密钥
inputChannelName = "show" // 输入流的频道名
inputUID1 = 1234 // 输入流的用户 ID 1
inputUID2 = 2345 // 输入流的用户 ID 2
inputToken1 = "<your_token>" // 用户 ID 1 对应的 Token
inputToken2 = "<your_token>" // 用户 ID 2 对应的 Token
outputChannelName = "show" // 输出流的频道名
outputUID = 56789 // transcoder 在输出频道内的用户 ID
outputToken = "<your_token>" // transcoder 在进入输出频道时所需设置的 Token
instanceId = "quickstart" // transcoder 的实例 ID
)
本示例中将 show 频道的两位主播作为 transcoder 的输入流。为简化参数设置,transcoder 输出流也指定到 show 频道中,因此输入流和输出流的临时 Token 相同。多条输入流需来自同一频道,输出流可以为一条或者多条,并且指定到任意频道。
参数 | 输入 1 | 输入 2 | 输出 1 |
---|---|---|---|
频道名 | "show" | "show" | "show" |
用户 ID | 1234 | 2345 | 56789 |
Token | "<your_token>" | "<your_token>" | "<your_token>" |
创建并初始化 Client
在 main.go
文件中,添加如下代码,创建一个 main
函数,在其中创建并初始化 Client。
func main() {
// 创建并初始化 Client
client := core.NewClient(&core.Config{
AppID: appId,
// 通过传入的客户 ID 和客户密钥进行 HTTP Basic Auth
Credential: core.NewBasicAuthCredential(username, password),
RegionCode: core.CNRegionArea,
Logger: core.NewDefaultLogger(core.LogDebug),
})
v1Impl := cloudtranscoder.NewAPI(client).V1()
}
获取云端转码资源
在开始创建云端转码之前,你需要调用 Acquire
方法获取一个 tokenName
,一个 tokenName
仅可用于一次云端转码任务。
func main() {
// 创建并初始化 Client
...
ctx := context.Background()
// 获取云端转码资源
acquireResp, err := v1Impl.Acquire().Do(ctx, &v1.AcquireReqBody{
InstanceId: instanceId,
})
if err != nil {
log.Fatalln(err)
}
if acquireResp.IsSuccess() {
log.Printf("acquire success: %+v\n", acquireResp)
} else {
log.Fatalf("acquire failed: %+v\n", acquireResp)
}
// 保存 tokenName
tokenName := acquireResp.SuccessResp.TokenName
if tokenName == "" {
log.Fatalln("tokenName is empty")
}
log.Printf("tokenName: %s\n", tokenName)
开始云端转码
获取资源后,调用 Create
创建云端转码任务,开始云端转码。本示例中,将同一频道的两位主播的音视频流进行混音和合图处理。
func main() {
// 创建并初始化 Client
...
// 获取云端转码资源
...
// 创建云端转码任务以开始云端转码,并传入之前保存的 tokenName 等参数
createResp, err := v1Impl.Create().Do(ctx, tokenName, &v1.CreateReqBody{
Services: &v1.CreateReqServices{
CloudTranscoder: &v1.CloudTranscoderPayload{
ServiceType: "cloudTranscoderV2",
Config: &v1.CloudTranscoderConfig{
// 将转码时输入流的两位主播进行混音和合图
// 参与转码的主播在 AudioInputs 和 VideoInputs 中设置
// 转码后的音视频配置在 Outputs 中设置
Transcoder: &v1.CloudTranscoderConfigPayload{
AudioInputs: []v1.CloudTranscoderAudioInput{
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID1,
RtcToken: inputToken1,
},
},
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID2,
RtcToken: inputToken2,
},
},
},
VideoInputs: []v1.CloudTranscoderVideoInput{
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID1,
RtcToken: inputToken1,
},
Region: &v1.CloudTranscoderRegion{
X: 0,
Y: 0,
Width: 480,
Height: 360,
ZOrder: 2,
},
},
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID2,
RtcToken: inputToken2,
},
Region: &v1.CloudTranscoderRegion{
X: 0,
Y: 240,
Width: 480,
Height: 360,
ZOrder: 2,
},
},
},
Canvas: &v1.CloudTranscoderCanvas{
Width: 1280,
Height: 720,
Color: 255,
},
Outputs: []v1.CloudTranscoderOutput{
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: outputChannelName,
RtcUID: outputUID,
RtcToken: outputToken,
},
AudioOption: &v1.CloudTranscoderOutputAudioOption{
ProfileType: "AUDIO_PROFILE_MUSIC_STANDARD",
},
VideoOption: &v1.CloudTranscoderOutputVideoOption{
FPS: 15,
Codec: "H264",
Width: 1280,
Height: 720,
},
},
},
},
},
},
},
})
if err != nil {
log.Fatalln(err)
}
if createResp.IsSuccess() {
log.Printf("create success: %+v\n", createResp)
} else {
log.Printf("create failed: %+v\n", createResp)
return
}
// 保存 taskId
taskId := createResp.SuccessResp.TaskID
if taskId == "" {
log.Fatalln("taskId is empty")
}
log.Printf("taskId: %s\n", taskId)
}
补全 main.go
的代码后,在项目文件夹下,执行如下命令本地运行 Go 项目:
go run main.go
查看云端转码效果
在 Web Demo 中,查看 show 频道内出现的用户 ID 为 56789 的音视频。该音频为两位主播的混音,视频为两位主播的合图画面。
如需停止云端转码,可参照如下代码:
func main() {
// 创建并初始化 Client
...
// 获取云端转码资源
...
// 创建云端转码任务以开始云端转码,并传入之前保存的 tokenName 等参数
...
// 停止云端转码,并传入之前保存的 taskId、tokenName 等参数
deleteResp, err := v1Impl.Delete().Do(ctx, taskId, tokenName)
if err != nil {
log.Println(err)
return
}
if deleteResp.IsSuccess() {
log.Printf("delete success: %+v\n", deleteResp)
} else {
log.Printf("delete failed: %+v\n", deleteResp)
}
}
完整示例代码
完成上述步骤后,main.go
文件中完整代码如下,你可自行比对:
package main
import (
"context"
"log"
"time"
"github.com/AgoraIO-Community/agora-rest-client-go/core"
"github.com/AgoraIO-Community/agora-rest-client-go/services/cloudtranscoder"
v1 "github.com/AgoraIO-Community/agora-rest-client-go/services/cloudtranscoder/v1"
)
// 定义关键参数
const (
appId = "<your_app_id>"
token = "<your_token>"
username = "<your_key>" // 客户 ID
password = "<your_secret>" // 客户密钥
inputChannelName = "show" // 输入流的频道名
inputUID1 = 1234 // 输入流的用户 ID 1
inputUID2 = 2345 // 输入流的用户 ID 2
inputToken1 = "<your_token>" // 用户 ID 1 对应的 Token
inputToken2 = "<your_token>" // 用户 ID 2 对应的 Token
outputChannelName = "show" // 输出流的频道名
outputUID = 56789 // transcoder 在输出频道内的用户 ID
outputToken = "<your_token>" // transcoder 在进入输出频道时所需设置的 Token
instanceId = "quickstart" // transcoder 的实例 ID
)
func main() {
// 创建并初始化 Client
client := core.NewClient(&core.Config{
AppID: appId,
// 通过传入的客户 ID 和客户密钥进行 HTTP Basic Auth
Credential: core.NewBasicAuthCredential(username, password),
RegionCode: core.CNRegionArea,
Logger: core.NewDefaultLogger(core.LogDebug),
})
v1Impl := cloudtranscoder.NewAPI(client).V1()
ctx := context.Background()
// 获取云端转码资源
acquireResp, err := v1Impl.Acquire().Do(ctx, &v1.AcquireReqBody{
InstanceId: instanceId,
})
if err != nil {
log.Fatalln(err)
}
if acquireResp.IsSuccess() {
log.Printf("acquire success: %+v\n", acquireResp)
} else {
log.Fatalf("acquire failed: %+v\n", acquireResp)
}
// 保存 tokenName
tokenName := acquireResp.SuccessResp.TokenName
if tokenName == "" {
log.Fatalln("tokenName is empty")
}
log.Printf("tokenName: %s\n", tokenName)
// 创建云端转码任务以开始云端转码,并传入之前保存的 tokenName 等参数
createResp, err := v1Impl.Create().Do(ctx, tokenName, &v1.CreateReqBody{
Services: &v1.CreateReqServices{
CloudTranscoder: &v1.CloudTranscoderPayload{
ServiceType: "cloudTranscoderV2",
Config: &v1.CloudTranscoderConfig{
// 将转码时输入流的两位主播进行混音和合图
// 参与转码的主播在 AudioInputs 和 VideoInputs 中设置
// 转码后的音视频配置在 Outputs 中设置
Transcoder: &v1.CloudTranscoderConfigPayload{
AudioInputs: []v1.CloudTranscoderAudioInput{
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID1,
RtcToken: inputToken1,
},
},
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID2,
RtcToken: inputToken2,
},
},
},
VideoInputs: []v1.CloudTranscoderVideoInput{
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID1,
RtcToken: inputToken1,
},
Region: &v1.CloudTranscoderRegion{
X: 0,
Y: 0,
Width: 480,
Height: 360,
ZOrder: 2,
},
},
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: inputChannelName,
RtcUID: inputUID2,
RtcToken: inputToken2,
},
Region: &v1.CloudTranscoderRegion{
X: 0,
Y: 240,
Width: 480,
Height: 360,
ZOrder: 2,
},
},
},
Canvas: &v1.CloudTranscoderCanvas{
Width: 1280,
Height: 720,
Color: 255,
},
Outputs: []v1.CloudTranscoderOutput{
{
Rtc: &v1.CloudTranscoderRtc{
RtcChannel: outputChannelName,
RtcUID: outputUID,
RtcToken: outputToken,
},
AudioOption: &v1.CloudTranscoderOutputAudioOption{
ProfileType: "AUDIO_PROFILE_MUSIC_STANDARD",
},
VideoOption: &v1.CloudTranscoderOutputVideoOption{
FPS: 15,
Codec: "H264",
Width: 1280,
Height: 720,
},
},
},
},
},
},
},
})
if err != nil {
log.Fatalln(err)
}
if createResp.IsSuccess() {
log.Printf("create success: %+v\n", createResp)
} else {
log.Printf("create failed: %+v\n", createResp)
return
}
// 保存 taskId
taskId := createResp.SuccessResp.TaskID
if taskId == "" {
log.Fatalln("taskId is empty")
}
log.Printf("taskId: %s\n", taskId)
// 等待 10 秒后停止云端转码
time.Sleep(time.Second * 10)
// 停止云端转码,并传入之前保存的 taskId、tokenName 等参数
deleteResp, err := v1Impl.Delete().Do(ctx, taskId, tokenName)
if err != nil {
log.Println(err)
return
}
if deleteResp.IsSuccess() {
log.Printf("delete success: %+v\n", deleteResp)
} else {
log.Printf("delete failed: %+v\n", deleteResp)
}
}
云端转码支持设置的所有参数请参考 API 文档。
示例项目
完成快速开始后,你可以体验更多云端转码示例:
排查错误
如果遇到问题,可参考响应状态码和错误码排查。