[声网音频SDK实战教程] 小白教程1 : 声网SDK初始化配置, 以及如何加入一个声网频道

简介

通过本系列教程, 您将从零开始学习如何一步步使用声网音视频SDK完成 “语音房-RTC” 的能力提供.
本篇教程讲解2部分 : 
1) 声网SDK初始化配置;
2) 如何加入一个声网频道;

1] 声网SDK初始化配置

我们可以设计一个单例类, 用于持有一个 RtcEngine 单例对象, 不需要每次使用RtcEngine能力时, 再去创建对象.
并且在创建RtcEngine对象之前, 要配置好声网log config, 这个很重要, 也是后续声网同学协助定位问题个依据.

void init(String agoraRtcAppKey, Handler handler) throws Exception {
    this.agoraRtcAppKey = agoraRtcAppKey;
    this.handler = handler;

    try {
        // 开始时间戳(当前任务)
        long startTimestamp = SystemClock.elapsedRealtime();

        // 设置初始化方法,没有设置logconfig 默认log地址:
        // /storage/emulated/0/Android/data/<package name>/files/agorasdk.log
        // TODO : 目前 Agora RTC Native SDK 只支持每个 app 创建一个 RtcEngine 实例。
        /**
         * context : 安卓活动 (Android Activity) 的上下文。
         * appId   : Agora 为 app 开发者签发的 App ID,详见获取 App ID。
         *            使用同一个 App ID 的 app 才能进入同一个频道进行通话或直播。
         *            一个 App ID 只能用于创建一个 RtcEngine。如需更换 App ID,
         *            必须先调用 destroy 销毁当前 RtcEngine,并在 destroy 成功返回后,
         *            再调用 create 重新创建 RtcEngine。
         * handler : io.agora.rtc.IRtcEngineEventHandler 是一个提供了缺省实现的抽象类,
         *            SDK 通过该抽象类向 app 报告 SDK 运行时的各种事件
         */
        // Java

        RtcEngineConfig.LogConfig logConfig = new RtcEngineConfig.LogConfig();
        // TODO : 不要修改声网日志路径和名字, 否则声网无法在用户在频道期间在线拉取了...
        logConfig.level = Constants.LogLevel.getValue(Constants.LogLevel.LOG_LEVEL_INFO);
        logConfig.fileSize = 1024 * 4;// TODO : 单位 : K

        RtcEngineConfig config = new RtcEngineConfig();
        config.mAppId = agoraRtcAppKey;
        config.mEventHandler = new MyRtcEngineEventHandler(vcrSdk, handler);
        config.mContext = context.getApplicationContext();
        config.mLogConfig = logConfig;
        rtcEngine = RtcEngine.create(config);

        if (DebugLog.logIsOpen) {
            DebugLog.e(AppLaunchInitManage.TAG, "RtcEngine.create() 耗时 = " + (SystemClock.elapsedRealtime() - startTimestamp) + ")");
            DebugLog.e(vcrSdk.TAG_AGORA, "RtcEngine.create() --> " + (rtcEngine == null ? "创建引擎对象失败!!!" : ("创建引擎对象成功, 当前SDK版本号 = " + RtcEngine.getSdkVersion())));
        }
        if (rtcEngine == null) {
            throw new RuntimeException("RtcEngine.create()返回null.");
        }

    } catch (Exception e) {
        throw new RuntimeException("初始化声网SDK失败, 原因 = " + e.getLocalizedMessage());
    }
}


2] 如何加入一个声网频道

2.1] 注意 :  声网不能同时加入 2 个频道, 所以在加入新的频道之前, 建议先调用一下 leaveChannel() 方法.

rtcEngine.leaveChannel();

2.2] 设置声网引擎相关参数

1) 设置频道场景。

/**
 * 设置频道场景。
 *
 * SDK 初始化后默认的频道场景为通信场景,你可以调用该方法设置 Agora 频道的使用场景。
 * Agora SDK 会针对不同的使用场景采用不同的优化策略,如通信场景偏好流畅,直播场景偏好画质。
 *
 * 注解
 * 为保证实时音视频质量,我们建议相同频道内的用户必须使用同一种频道场景。
 * 该方法必须在加入频道前调用,进入频道后无法再设置频道模式。
 * 不同的频道场景下,SDK 的默认音频路由和默认视频编码码率是不同的,
 * 详见 setDefaultAudioRoutetoSpeakerphone 和 setVideoEncoderConfiguration 中的说明。
 * 参数
 * profile 频道使用场景:
 * CHANNEL_PROFILE_COMMUNICATION(0):通信场景。该场景下,频道内所有用户都可以发布和接收音、视频流。适用于语音通话、视频群聊等应用场景。
 * CHANNEL_PROFILE_LIVE_BROADCASTING(1):直播场景。该场景有主播和观众两种用户角色,可以通过 setClientRole 设置。主播可以发布和接收音视频流,观众直接接收流。适用于语聊房、视频直播、互动大班课等应用场景。
 * CHANNEL_PROFILE_GAME(2):Agora 不推荐使用。setParameters("{\"che.audio.opensl\":false }");
 * 返回
 * 0(ERR_OK): 方法调用成功。
 * < 0: 方法调用失败。
 * -2(ERR_INVALID_ARGUMENT): 参数无效。
 * -7(ERR_NOT_INITIALIZED): SDK 尚未初始化。
 */
resultCode = rtcEngine.setChannelProfile(Constants.CHANNEL_PROFILE_LIVE_BROADCASTING);
DebugLog.e(vcrSdk.TAG_AGORA, "rtcEngine.setChannelProfile(CHANNEL_PROFILE_LIVE_BROADCASTING) --> resultCode = " + resultCode);
if (resultCode < 0) {
    VCRTrackTools.trackForCallAgoraApiReturnErrorResultCode("setChannelProfile", resultCode);
}

2)设置音频编码配置。

/**
 * 设置音频编码配置。
 *
 * 注解
 * 该方法需要在 joinChannel 之前设置好,joinChannel 后设置不生效。
 * 通信和直播场景下,音质(码率)会有网络自适应的调整,通过该方法设置的是一个最高码率。
 * 在有高音质需求的场景(例如音乐教学场景)中,建议将 profile 设置为 MUSIC_HIGH_QUALITY (4),Scenario 设置为 GAME_STREAMING (3)。
 * 参数
 * profile 设置采样率,码率,编码模式和声道数,详见 AudioProfile。
 * scenario    设置音频应用场景,详见 AudioScenario。不同的音频场景下,设备的音量类型不同。详见如何区分媒体音量和通话音量。
 */
resultCode = rtcEngine.setAudioProfile(Constants.AUDIO_PROFILE_MUSIC_HIGH_QUALITY, Constants.AUDIO_SCENARIO_GAME_STREAMING);
DebugLog.e(vcrSdk.TAG_AGORA, "rtcEngine.setAudioProfile(AUDIO_PROFILE_MUSIC_HIGH_QUALITY, AUDIO_SCENARIO_GAME_STREAMING) --> resultCode = " + resultCode);
if (resultCode < 0) {
    VCRTrackTools.trackForCallAgoraApiReturnErrorResultCode("setAudioProfile", resultCode);
}

3)启用用户音量提示。

/**
 * 启用用户音量提示。
 *
 * 该方法允许 SDK 定期向 app 报告本地发流用户和瞬时音量最高的远端用户(最多 3 位)的音量相关信息。
 * 启用该方法后,只要频道内有发流用户,SDK 会在加入频道后按设置的时间间隔触发 onAudioVolumeIndication 回调。
 *
 * 参数
 * interval    指定音量提示的时间间隔:
 *      ≤ 0:禁用音量提示功能。
 *      > 0:返回音量提示的间隔,单位为毫秒。建议设置到大于 200 毫秒。最小不得少于 10 毫秒,否则会收不到 onAudioVolumeIndication 回调。
 * smooth  平滑系数,指定音量提示的灵敏度。取值范围为 [0, 10],建议值为 3,数字越大,波动越灵敏;数字越小,波动越平滑。
 * report_vad  是否开启人声检测
 *      true: 开启本地人声检测功能。开启后,onAudioVolumeIndication 回调的 vad 参数会报告是否在本地检测到人声。
 *      false: (默认)关闭本地人声检测功能。除引擎自动进行本地人声检测的场景外,onAudioVolumeIndication 回调的 vad 参数不会报告是否在本地检测到人声。
 * 返回
 *      0: 方法调用成功。
 *      < 0: 方法调用失败。
 *
 *
 * 实测发现enableAudioVolumeIndication   interval设置的间隔时间。
 * 我们在间隔时间开始内说话。是没有给我们回调的。
 * 比如说:设置回调是10s,如果我们在3s的时间节点说一句话,在10s前说话结束,那我们是没有收到onAudioVolumeIndication 回调的。
 */
resultCode = rtcEngine.enableAudioVolumeIndication(500, 3, false);
DebugLog.e(vcrSdk.TAG_AGORA, "rtcEngine.enableAudioVolumeIndication(2000, 3, false) --> resultCode = " + resultCode);
if (resultCode < 0) {
    VCRTrackTools.trackForCallAgoraApiReturnErrorResultCode("enableAudioVolumeIndication", resultCode);
}

重点说明 :

1) 我们APP的业务场景是 “语音房”, 没有视频场景;
2) 声网API被设计成调用之后, 有同步返回的错误代码, 当返回小于0的错误代码时, 意味着调用API失败, 
我们一定要检测这些API调用之后的错误代码, 如果出现问题就不要继续执行了.
否则后续流程也会出现问题, 还不好定位问题出现的时机.
2.3] 设置用户角色

/**
 * 设置用户角色。
 *
 * 详情
 * 在加入频道前和加入频道后均可调用该方法设置用户角色。
 *
 * 如果你在加入频道前调用该方法设置用户角色为主播、并且通过 setupLocalVideo 方法设置了本地视频属性,则用户加入频道时会自动开启本地视频预览。
 *
 * 如果你在加入频道后调用该方法切换用户角色,调用成功后:
 * 本地会触发 onClientRoleChanged 回调。
 * 远端会触发 onUserJoined 或 onUserOffline(USER_OFFLINE_BECOME_AUDIENCE) 回调。
 * 参数
 * role
 * 用户的角色:
 * CLIENT_ROLE_BROADCASTER (1):主播。
 * CLIENT_ROLE_AUDIENCE (2):观众。
 * 返回值
 * 0: 方法调用成功。
 * < 0: 方法调用失败。
 * -1: 一般性的错误(未明确归类)。
 * -2: 参数无效。
 * -7: SDK 尚未初始化。
 */
errorCode = rtcEngine.setClientRole(当前用户的用户角色, 由服务器负责返回);

2.4] 加入声网频道

/**
 * 加入频道。
 *
 * 详情
 * 该方法让用户加入通话频道,在同一个频道内的用户可以互相通话,多个用户加入同一个频道,可以群聊。 使用不同 App ID 的 app 不能互通。
 *
 * 成功调用该方法加入频道后会触发以下回调:
 * 本地会触发 onJoinChannelSuccess 和 onConnectionStateChanged 回调。
 * 通信场景下的用户和直播场景下的主播加入频道后,远端会触发 onUserJoined 回调。
 * 在网络状况不理想的情况下,客户端可能会与声网服务器失去连接;SDK 会自动尝试重连,重连成功后,本地会触发 onRejoinChannelSuccess 回调。
 *
 * 注意:用户成功加入频道后,默认订阅频道内所有其他用户的音频流和视频流,因此产生用量并影响计费。如果想取消订阅,可以通过调用相应的 mute 方法实现。
 * 参数
 * token
 * 在服务端生成的用于鉴权的动态密钥。详见使用 Token 鉴权。
 * channelId
 * 频道名。该参数标识用户进行实时音视频互动的频道。App ID 一致的前提下,填入相同频道名的用户会进入同一个频道进行音视频互动。该参数为长度在 64 字节以内的字符串。以下为支持的字符集范围(共 89 个字符):
 * 26 个小写英文字母 a~z
 * 26 个大写英文字母 A~Z
 * 10 个数字 0~9
 * 空格
 * "!"、"#"、"$"、"%"、"&"、"("、")"、"+"、"-"、":"、";"、"<"、"="、"."、">"、"?"、"@"、"["、"]"、"^"、"_"、"{"、"}"、"|"、"~"、","
 * optionalInfo
 * (非必选项) 预留参数。
 * optionalUid
 * 用户 ID。该参数用于标识在实时音视频互动频道中的用户。你需要自行设置和管理用户 ID,
 * 并确保同一频道内的每个用户 ID 是唯一的。该参数为 32 位无符号整数。
 * 建议设置范围:1 到 232-1。如果不指定(即设为 0),SDK 会自动分配一个,并在 onJoinChannelSuccess 回调中返回,
 * 应用层必须记住该返回值并维护,SDK 不对该返回值进行维护。
 */
errorCode = rtcEngine.joinChannel(声网token由服务器负责生成, 频道名由服务器负责生成, "", 声网UID由服务器负责生成);

注意 :

1] 在进入一个语音房之后, 我们会先请求一个 "房间详情接口”, 会在这里返回 当前用户加入声网频道的必要信息.

1) 声网角色(主播 or 观众) 

2) 该用户的声网token

3) 声网频道名称

4) 该用户的声网UserId


2] 一个设计细节, 我们APP因为是使用声网SDK提供RTC能力, 使用云信SDK提供IM能力, 而共同拼成我们自己的业务场景 “语音房”,
所以我们把 声网频道ID 和 云信聊天室ID 和 我们自己的业务语音房ID设计成一个ID.


2.5] 加入频道失败的异步回调
我们要自己做一个标志位, 用于标识当前正处于 "进房流程中”,
在 声网回调 IRtcEngineEventHandler 中 onError 回调中.
如果遇到如下错误代码时, 就判定进房失败.

if (errorCode == Constants.ERR_NOT_READY //SDK 初始化失败
        || errorCode == Constants.ERR_NOT_INITIALIZED //SDK 尚未初始化,就调用其 API。请确认在调用 API 之前已创建 RtcEngine 对象并完成初始化。
        || errorCode == Constants.ERR_ALREADY_IN_USE //资源已被占用,不能重复使用。
        || errorCode == Constants.ERR_INVALID_APP_ID //不是有效的 APP ID。请更换有效的 APP ID 重新加入频道。
        || errorCode == Constants.ERR_INVALID_CHANNEL_NAME //不是有效的频道名。请更换有效的频道名重新加入频道。
        || errorCode == Constants.ERR_INVALID_TOKEN //生成的 Token 无效。
        || errorCode == Constants.ERR_LOAD_MEDIA_ENGINE //加载媒体引擎失败。
        || errorCode == Constants.ERR_START_CALL) {// 启动媒体引擎开始通话失败。请尝试重新进入频道。


注意 : 如果不是 “进房流程” 状态下遇到上述错误代码, 意味着, 可以退出语音房了, 因为出现了不可逆的错误;

2.6] 加入频道成功的异步回调

在 声网回调 IRtcEngineEventHandler 中的 onJoinChannelSuccess 意味着加入频道成功.

推荐阅读
相关专栏
SDK 教程
167 文章
本专栏仅用于分享音视频相关的技术文章,与其他开发者和声网 研发团队交流、分享行业前沿技术、资讯。发帖前,请参考「社区发帖指南」,方便您更好的展示所发表的文章和内容。