本文介绍Golang 集成实时音视频Linux ARTC SDK。
准备工作
解压Linux SDK压缩包,打开解压后的文件夹里面的Go文件夹,交付产物包括如下:
artc_linux_go/
├── alirtc
│ ├── AliRTCEngine.go
│ ├── AliRTCEngineImpl.go
│ ├── AliRTCLinuxSdkDefine.go
│ ├── go.mod
│ └── lib
│ ├── AliRtcCoreService
│ ├── libAliRtcLinuxEngine.so
│ ├── libonnxruntime.so.1.16.3
│ └── libPluginOpus.so
├── Demo
├── demo.go
├── go.mod
└── README.md
请确保您的Linux内核版本在2.6以上,且Go运行时为1.22.5及以上版本。若您希望基于C++接口进行额外开发,还需确保GCC版本在4.8以上。
alirtc目录包含需要链接的SDK动态库(lib),以及对应的Go接口封装,从而通过Go代码实现与C++接口一致的RTC推拉流功能。
demo.go提供简易例程,需要将ALIRTC_APPID、ALIRTC_APPKEY、LIBPATH替换以执行。
二、核心API
1.初始化SDK
步骤:
实现
EngineEventHandlerInterface
类,该类型包含RTC所需回调,收到数据或状态变更,其中的回调函数将被触发。创建
EngineEventListener
实例 。调用
alirtc.CreateAliRTCEngine
函数创建AliRTCEngine实例,过程中会将EngineEventListener
实例注册为engine的回调对象。后面只需要调用AliRTCEngine实例的各方法完成推拉流设置 。若需要向多个房间推流,请创建多个AliRTCEngine实例,每个实例对应一个房间内的虚拟用户。
Demo中基于协程管理调用和回调API,因此为避免eventLoop自锁,若有并发管理多AliRTCEngine实例的需求,建议优先使用多线程或多进程。
示例如下:
# 实现EngineEventHandlerInterface类
...
# 初始化SDK
eventHandler = &EngineEventListener{}
h5mode := false
coreServicePath := "/path/AliRtcCoreService" // AliRtcCoreService路径
extraJobj := map[string]interface{}{
"user_specified_disable_audio_ranking": "true",
}
extraBytes, _ := json.Marshal(extraJobj)
extra := string(extraBytes)
linuxEngine := alirtc.CreateAliRTCEngine(eventHandler, 42000, 45000, "/tmp", coreServicePath, h5mode, extra)
CreateAliRTCEngine函数被调用后,将启动一个AliRtcCoreService进程,函数参数如下:
eventHandler:EngineEventHandlerInterface
:回调对象,负责处理回调逻辑。lowPort:int
:端口号下限,lowPort~highPort之间的端口将被随机选择用于进程间通信。highPort:int
:端口号上限。logPath:str
:Linux SDK运行过程中,日志文件的保存路径。coreServicePath:str
:AliRtcCoreService的实际路径。h5mode:bool
:h5兼容模式,若要与Web端互通请务必设置为True,其他场景一般为False即可。extra:str
:对SDK进行额外配置时传入的JSON格式字符串。
2.入会
请先参考官网文档了解阿里云RTC鉴权过程:Token鉴权。
入会token存在两个版本,建议使用单参数入会token,Go接口仅提供该token对应的入会API。
步骤:
设置用户名、房间号等基本信息,从appserver请求获取单参数token 。
配置JoinChannelConfig,设置推拉流模式等参数。
调用JoinChannel成员方法以入会 。
EngineEventListener实例的OnJoinChannelResult函数将被触发,以告知入会结果。
// -------- 获取入会所需基本信息 --------
authInfo := alirtc.AuthInfo{
AppID: "", // appid,业务方传入
UserID: "", // 用户名,房间内各用户的唯一标识,若有重复将被踢出房间
UserName: "", // 用户昵称,可与userid一致,也可自行设置
Channel: "", // 入会房间号
}
// ...向appserver请求,获取单参数入会token
authInfo.Token = "" // appserver响应的入会token
// -------- 配置JoinChannelConfig --------
joinConfig := alirtc.NewJoinChannelConfig()
joinConfig.ChannelProfile = alirtc.ChannelProfileInteractiveLive // 互动模式
joinConfig.SubscribeAudioFormat = alirtc.AudioFormatPcmBeforMixing // 音频订阅格式
joinConfig.SubscribeVideoFormat = alirtc.VideoFormatH264 // 视频订阅格式
joinConfig.IsAudioOnly = false // 仅音频模式,一般为False
joinConfig.PublishAvsyncMode = alirtc.PublishAvsyncWithPts // 推流音画同步模式
joinConfig.SubscribeMode = alirtc.SubscribeAutomatically // 订阅模式
joinConfig.PublishMode = alirtc.PublishAutomatically // 推流模式
// -------- 调用JoinChannel入会 --------
linuxEngine.JoinChannel(authInfo.Token, authInfo.Channel, authInfo.UserID, authInfo.UserName, joinConfig)
JoinChannelConfig参数说明:
推流模式:支持自动和手动推流模式。前者入会后自动开启音视频推流,后者则需要手动调用API后才能进行推流。
订阅模式:支持自动订阅和手动订阅模式。前者当房间内有主播入会后,便会自动订阅该主播的音视频流,后者需要手动调用API,指定要订阅的主播uid。
在仅订阅音频或视频的场景下,建议使用
SubscribeAudioAutoAndOnly
或SubscribeCameraAutoAndOnly
,以降低解码器带来的CPU占用。音频订阅格式:
AudioFormatMixedPcm
表示合流,房间内所有远端用户的音频被订阅后,会混合为一路音频数据回调;而AudioFormatPcmBeforMixing
表示分流,每位远端用户的音频数据,将会被单独回调。视频订阅格式:设置为
VideoFormatH264
,当收到数据后,会触发OnRemoteVideoSample
回调,否则即使收到数据也不会触发回调。音画同步模式:选择
PublishAvysncWithPts
后,在推送音视频数据时将根据API传入的timestamp进行音画同步,否则将不参考时间戳,按照实际调用的频率进行推送
视频订阅不支持合流回调,每个uid对应单独一路视频。
在未离会时,请勿重复调用JoinChannel。
Demo中演示了用GenerateToken模拟appserver生成入会参数的过程,该接口是专为简化开发、测试过程而提供的,生产环境中,请通过与app server的交互获取token,避免appkey泄漏。
3.手动开启与关闭推流
以下API设置是否推送音视频流,请在发送数据前调用接口打开推流。
/**
* @brief 是否推送本地视频(摄像头)流
* @param enabled 是否开启/关闭本地视频流推送
- true: 开启视频流推送
- false: 关闭视频流推送
* @return
- 0: 设置成功
- <0: 设置失败,返回错误码
* @note SDK默认设置推送视频流,在加入频道前也可以调用此接口修改默认值,并在加入频道成功时生效
**/
PublishLocalVideoStream(enabled bool) int
/**
* @brief 是否推送本地音频流
* @param enabled 是否开启/关闭本地音频流推送
- true: 开启音频流推送
- false: 关闭音频流推送
* @return
- 0: 设置成功
- <0: 设置失败,返回错误码
* @note SDK默认设置推送音频流,在加入频道前也可以调用此接口修改默认值,并在加入频道成功时生效
**/
PublishLocalAudioStream(enabled bool) int
若数据发送已结束,但不立即离会,建议调用上述两接口关闭推流。
4.推送外部视频数据
/**
* @brief 启用外部视频输入源
* @param enable true 开启, false 关闭
* @param type 流类型
* @note 启用后使用PushExternalVideoFrame接口输入视频数据
**/
SetExternalVideoSource(enable bool, sourceType VideoSource, renderMode RenderMode) int
/**
* @brief 输入外部输视频, 暂不支持2k及以上的视频输入
* @param frame 帧数据
* @param type 流类型
* @param 输入视频帧支持多种类型,如YUV和RGB
**/
PushExternalVideoFrame(frame *VideoDataSample, sourceType VideoSource) int
5.推送外部音频数据
不调用SetExternalAudioPublishVolume
默认按100音量推音频。
/**
* @brief 设置是否启用外部音频输入推流
* @param enable true 开启,false 关闭
* @param sampleRate 采样率 16k 48k...
* @param channelsPerFrame 通道数 1 2...
* @return >=0表示成功, <0表示失败
* @note 可通过SetExternalAudioPublishVolume设置输入音频推流音量
**/
SetExternalAudioSource(enable bool, sampleRate, channelsPerFrame int) int
/**
* @brief 输入外部音频数据推流
* @param audioSamples 音频数据
* @param sampleLength 音频数据长度
* @param timestamp 时间戳
* @return <0表示失败,返回值为ERR_AUDIO_BUFFER_FULL时,需要在间隔投递数据时间长度后再次重试投递
**/
PushExternalAudioFrameRawData(audioSamples []byte, sampleLength int, timestamp int64) int
/**
* @brief 设置外部输入音频推流混音音量
* @param vol 音量 0-100
**/
SetExternalAudioPublishVolume(volume int) int
/**
* @brief 获取外部输入音频推流混音音量
* @return vol 音量
**/
GetExternalAudioPublishVolume() int
推流过程中请关注OnPushAudioFrameBufferFull
和OnPushAudioFrameBufferFull
的回调内容,从而判断当前数据速度推送过快或过慢。此外若RTC进程异常退出(如被恶意kill),将触发OnError
回调。
6.手动订阅
在自动订阅的模式下,无需调用这部分接口拉流 。
/**
* @brief 停止/恢复订阅特定远端用户的音频流, 用于会中调用, 会前调用无效
* @param uid 用户ID,从App server分配的唯一标示符
* @param sub 是否订阅远端用户的音频流
* - true:订阅指定用户的音频流
* - false:停止订阅指定用户的音频流
* @return
* - 0: 成功
* - 非0: 失败
**/
SubscribeRemoteAudioStream(uid string, sub bool) int
/**
* @brief 停止/恢复订阅远端用户的视频流, 用于会中调用, 会前调用无效
* @param uid 用户ID,从App server分配的唯一标示符
* @param track 视频流类型
* - AliEngineVideoTrackNo: 无效参数,设置不会有任何效果
* - AliEngineVideoTrackCamera: 相机流
* - AliEngineVideoTrackScreen: 屏幕共享流
* - AliEngineVideoTrackBoth: 相机流和屏幕共享流
* @param sub 是否订阅远端用户的视频流
* - true:订阅指定用户的视频流
* - false:停止订阅指定用户的视频流
* @return
* - 0:设置成功
* - <0:设置失败
* @note
**/
SubscribeRemoteVideoStream(uid string, videoTrack VideoTrack, sub bool) int
7.数据回调
7.1 音频
选择AudioFormatPcmBeforMixing
模式后,收到音频帧将触发EventHandler实例的回调函数OnSubscribeAudioFrame
。
uid: 表示此时收到的音频帧来自哪个远端用户,借此区分订阅的各路音频流。
frame: 收到的音频帧,pcm格式。
/**
* @brief 混音前每一路远端用户的音频数据回调
* @details 来自远端单个用户的音频数据 对应AliRTCSdk::Linux::AudioFormatPcmBeforMixing
* @param frame 音频数据,详见{@link AliRTCSdk::Linux::AudioFrame}
**/
OnSubscribeAudioFrame(uid string, frame AudioFrame)
选择AudioFormatMixedPcm模式,收到音频帧将触发EventHandler实例的回调函数OnSubscribeMixAudioFrame
。
/**
* @brief 本地订阅音频数据回调
* @details 远端所有用户混音后待播放的音频数据 对应AliRTCSdk::Linux::AudioFormatMixedPcm
* @param frame 音频数据,详见{@link AliRTCSdk::Linux::AudioFrame}
**/
OnSubscribeMixAudioFrame(frame AudioFrame)
7.2 视频
收到视频帧时将触发EventHandler实例的回调函数OnRemoteVideoSample
。
uid: 表示此时收到的视频帧来自哪个远端用户,借此区分订阅的各路视频流。
frame: 收到的视频帧,yuv I420格式。
/**
* @brief 订阅的远端视频数据回调
* @param uid 用户ID
* @param frame 视频裸数据
* @return
**/
OnRemoteVideoSample(uid string, frame VideoFrame)
8.离会
// 结束推流
linuxEngine.PublishLocalVideoStream(false)
linuxEngine.PublishLocalAudioStream(false)
若要在停止推流后,仍在会中,请手动调用此接口;直接离会也具有停止推流的效果。
linuxEngine.LeaveChannel()
9.销毁SDK
linuxEngine.Release()
linuxEngine = nil
三、Demo使用方式
demo.go中替换您的ALIRTC_APPID、ALIRTC_APPKEY,并正确指定AliRtcCoreService的路径后,在demo.go所在目录执行go run demo.go
。
若终端有以下输出,表示入会、推流成功。
# 入会成功
[Go] on join channel result. Channel: 123123, user: linux, result: 0
# 推流成功
[Go] on audio publish state changed, oldState: 0, newState: 2
[Go] on video publish state changed, oldState: 0, newState: 2
[Go] on audio publish state changed, oldState: 2, newState: 3
[Go] on video publish state changed, oldState: 2, newState: 3
# 远端用户web已上线
[Go] on remote user online: web
# 收到来自远端用户abcd的音视频流
[Go] on audio subscribe state of web, oldState: 0, newState: 2
[Go] on video subscribe state of web, oldState: 0, newState: 2
[Go] on audio subscribe state of web, oldState: 2, newState: 3
[Go] on video subscribe state of web, oldState: 2, newState: 3
音频订阅选择AudioFormatMixedPcm模式时,无论是否有远端用户在会上,入会时就会有音频回调。选择AudioFormatPcmBeforMixing时,只有会上有其他用户,且其他用户在推音频流时,才会触发音频回调。
四、消息通讯
除音视频互动外,RTC SDK还支持实时消息收发,以用于有消息互动需求的场景。您可以通过Data Channel和SEI(Supplemental Enhancement Information)两种通道进行消息收发,前者独立于音视频传输通道,后者依赖视频数据收发,一般场景下建议使用Data Channel。
1. Data Channel
请调用SetParameter以开启Data Channel:linuxEngine.SetParameter("{\"data\":{\"enablePubDataChannel\":true,\"enableSubDataChannel\":true}}")
。
通过SendDataChannelMessage
发送消息:
dataChannelMsg := alirtc.AliEngineDataChannelMsg{}
message := "This is data channel message"
dataChannelMsg.Data = []byte(message)
dataChannelMsg.DataLen = len(dataChannelMsg.Data)
dataChannelMsg.NetworkTime = 0 // 网络时间字段,也可以自定义取值,不影响消息收发
dataChannelMsg.Progress = 0 // 保留字段
dataChannelMsg.Type = alirtc.AliEngineDataChannelCustom
linuxEngine.SendDataChannelMessage(dataChannelMsg)
当接收到Data Channel消息后,会触发回调:
/**
* @brief 获得dataChannel远端数据
* @param msg 远端传来的消息
**/
OnDataChannelMsg(uid string, msg AliEngineDataChannelMsg)
2. SEI
/**
* @brief 发送 媒体扩展信息(SEI), 最大长度为4*1024字节,用于业务的少量数据传输
* @param message 扩展信息内容,可以传递4K Bytes数据
* @param length 扩展信息长度,单位:字节
* @param repeatCount 重复次数,用于防止网络丢包导致的消息丢失
* @param delay 延迟多久发出去,单位:毫秒
* @param isKeyFrame 是否只在关键帧上增加SEI
* @return <0: 成功,-1: SDK内部错误>
**/
SendMediaExtensionMsg(message []byte, length, repeatCount, delay int, isKeyFrame bool) int
通过SendMediaExtensionMsg
发送消息:
seiMsg := []byte("This is SEI message")
linuxEngine.SendMediaExtensionMsg(seiMsg, len(seiMsg), 3, 0, false)
由于关键帧间隔较长,若需要高频收发SEI消息,建议isKeyFrame设置为false。同时为保证消息有效送达,建议重复次数大于1。
当接收到SEI消息后,会触发回调:
/**
* @brief 收到媒体扩展信息回调
* @param uid 发送用户userId
* @param message 扩展信息内容
* @param size 扩展信息长度
* @note 当一端通过 {@link SendMediaExtensionMsg} 发送信息后,其他端通过该回调接收数据
**/
OnMediaExtensionMsgReceived(userid string, message []byte, size int)
五、其他功能
1. 关闭Audio Ranking
Audio Ranking是多人语聊房中,仅订阅音量较大几路音频流的功能,使听众听到的声音更为清晰,默认为开启状态。若场景需要订阅全部音频流,需要通过如下字段关闭Audio Ranking功能:
{"user_specified_disable_audio_ranking" : "true"}
2. 开启订阅音频时的转码AAC功能
对于有拉流存档需求的场景,SDK提供将订阅到的远端音频转码至AAC编码的能力。您可通过AudioTranscodingCodec中的各项选择以何种格式获取远端音频(PCM、AAC或二者皆要),若开启AAC转码功能,还可选择是否进行重采样以降低CPU和存储占用。当user_specified_audio_observer_resample_rate设置为0表示不进行重采样。
{"user_specified_audio_observer_codec" :
AudioTranscodingCodec.AudioTranscodingCodecBothPcmAndAac.value}
{"user_specified_audio_observer_codec_format" : 0} // 目前只支持adts格式
{"user_specified_audio_observer_resample_rate" : 16000} // 重采样率
{"user_specified_audio_observer_codec_bitrate" : 64000} // 转码的目标码率
3. 开启订阅视频时直接获取H264码流功能
对于有拉流存档需求的场景,SDK提供直接获取远端视频H264码流的能力。您可通过VideoTranscodingCodec的各项,选择以何种格式获取远端视频(YUV、H264码流或二者皆要)。
{"user_specified_video_observer_codec" :
VideoTranscodingCodec.VideoTranscodingCodecBothYuvAndH264.value}
{"user_specified_video_observer_codec_format" : 0} // 目前只支持annexb格式