快速接入

本文介绍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
说明
  1. 请确保您的Linux内核版本在2.6以上,且Go运行时为1.22.5及以上版本。若您希望基于C++接口进行额外开发,还需确保GCC版本在4.8以上。

  2. alirtc目录包含需要链接的SDK动态库(lib),以及对应的Go接口封装,从而通过Go代码实现与C++接口一致的RTC推拉流功能。

  3. demo.go提供简易例程,需要将ALIRTC_APPID、ALIRTC_APPKEY、LIBPATH替换以执行。

二、核心API

1.初始化SDK

步骤:

  1. 实现EngineEventHandlerInterface类,该类型包含RTC所需回调,收到数据或状态变更,其中的回调函数将被触发。

  2. 创建EngineEventListener实例 。

  3. 调用alirtc.CreateAliRTCEngine函数创建AliRTCEngine实例,过程中会将EngineEventListener实例注册为engine的回调对象。后面只需要调用AliRTCEngine实例的各方法完成推拉流设置 。

  4. 若需要向多个房间推流,请创建多个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。

步骤:

  1. 设置用户名、房间号等基本信息,从appserver请求获取单参数token 。

  2. 配置JoinChannelConfig,设置推拉流模式等参数。

  3. 调用JoinChannel成员方法以入会 。

  4. 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参数说明:

  1. 推流模式:支持自动和手动推流模式。前者入会后自动开启音视频推流,后者则需要手动调用API后才能进行推流。

  2. 订阅模式:支持自动订阅和手动订阅模式。前者当房间内有主播入会后,便会自动订阅该主播的音视频流,后者需要手动调用API,指定要订阅的主播uid。

    在仅订阅音频或视频的场景下,建议使用SubscribeAudioAutoAndOnlySubscribeCameraAutoAndOnly,以降低解码器带来的CPU占用。

  3. 音频订阅格式:AudioFormatMixedPcm表示合流,房间内所有远端用户的音频被订阅后,会混合为一路音频数据回调;而AudioFormatPcmBeforMixing表示分流,每位远端用户的音频数据,将会被单独回调。

  4. 视频订阅格式:设置为VideoFormatH264,当收到数据后,会触发OnRemoteVideoSample回调,否则即使收到数据也不会触发回调。

  5. 音画同步模式:选择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
说明

推流过程中请关注OnPushAudioFrameBufferFullOnPushAudioFrameBufferFull的回调内容,从而判断当前数据速度推送过快或过慢。此外若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格式