背景

iLiveSDK 1.9.5版本引入了进房角色不存在时直接报错的机制。但是在确认角色已配置的情况下,仍有小部分概率因为网络不理想等原因,(首次)拉配置失败后,将面临进房找不到角色的问题,这里强烈推荐使用默认角色或者加载本地spear配置来进行配置角色。

一、iLiveSDK 设置角色的工作原理

这里简单介绍一下 iLiveSDK 设置角色的工作原理:

1.登录SDK时从服务器拉取角色配置表并缓存本地

2.进房时从配置表中查找角色

从上面的流程可以看到,如果在登录时拉取角色配置失败,将会导致无法进房;或者正常拉取到角色配置,但是从没有在腾讯云控制台设置过对应角色也会获取不到,本文章主要讨论前一种情况。

二、如何解决 Role not exists 角色不存在问题

这里推荐的有三种方式可以避免这个问题:

  1. 重试:
    即在进房失败时,判断若失败原因是角色不存在,可以尝试直接重新登录(重新拉取角色配置)
  2. 登录配置默认角色:
    登录接口中已支持设置默认角色配置(拉取失败时会使用默认角色配置)
  3. 从本地Spear配置启动:
    提前获取Spear配置以文件的方式保存到本地,就能有效避免云端拉取失败的问题,不过如果腾讯云控制台修改了Spear配置就需要及时更新本地Spear配置(建议使用这种方式)

三、如何获取Spear角色配置

1.配置地址组成:

http://conf.voice.qcloud.com/index.php?sdk_appid=[sdkappid]&interface=Voice_Conf_Download&platform=[platform]
  • SDKAPPID:对应用户的应用标识
  • 平台:对应终端平台, 0(pc/web), 1(ios), 2(android), 4(mac)

2.例如sdkappid为1400049564的iOS平台配置可通过下面地址获取(可以直接浏览器打开):

http://conf.voice.qcloud.com/index.php?sdk_appid=1400049564&interface=Voice_Conf_Download&platform=1

3.拉到的配置如下,请勿自行修改其中的参数,对于拉取配置失败时,用户可以尝试使用浏览器访问上面地址,排查下网络故障,确认下对应的角色是不是不存在:

{
    "data":{
        "biz_id":1400049564,
        "conf":[
            {
                "audio":{
                    "aec":1,
                    "agc":0,
                    "ans":1,
                    "anti_dropout":0,
                    "au_scheme":1,
                    "channel":2,
                    "codec_prof":4106,
                    "frame":40,
                    "kbps":24,
                    "max_antishake_max":1000,
                    "max_antishake_min":400,
                    "min_antishake":120,
                    "sample_rate":48000,
                    "silence_detect":0
                },
                "is_default":1,
                "net":{
                    "rc_anti_dropout":1,
                    "rc_init_delay":100,
                    "rc_max_delay":500
                },
                "role":"LiveMaster",
                "type":1,
                "video":{
                    "anti_dropout":0,
                    "codec_prof":5,
                    "format":-2,
                    "format_fix_height":480,
                    "format_fix_width":640,
                    "format_max_height":-1,
                    "format_max_width":-1,
                    "fps":15,
                    "fqueue_time":-1,
                    "live_adapt":0,
                    "maxkbps":400,
                    "maxqp":-1,
                    "minkbps":400,
                    "minqp":-1,
                    "qclear":1,
                    "small_video_upload":0
                }
            },
            {
                "audio":{
                    "aec":1,
                    "agc":0,
                    "ans":1,
                    "anti_dropout":0,
                    "au_scheme":1,
                    "channel":2,
                    "codec_prof":4106,
                    "frame":40,
                    "kbps":24,
                    "max_antishake_max":1000,
                    "max_antishake_min":400,
                    "min_antishake":120,
                    "sample_rate":48000,
                    "silence_detect":0
                },
                "is_default":0,
                "net":{
                    "rc_anti_dropout":1,
                    "rc_init_delay":500,
                    "rc_max_delay":1000
                },
                "role":"Guest",
                "type":2,
                "video":{
                    "anti_dropout":0,
                    "codec_prof":5,
                    "format":-2,
                    "format_fix_height":480,
                    "format_fix_width":640,
                    "format_max_height":-1,
                    "format_max_width":-1,
                    "fps":15,
                    "fqueue_time":-1,
                    "live_adapt":0,
                    "maxkbps":400,
                    "maxqp":-1,
                    "minkbps":400,
                    "minqp":-1,
                    "qclear":1,
                    "small_video_upload":0
                }
            },
            {
                "audio":{
                    "aec":1,
                    "agc":0,
                    "ans":1,
                    "anti_dropout":0,
                    "au_scheme":1,
                    "channel":2,
                    "codec_prof":4106,
                    "frame":40,
                    "kbps":24,
                    "max_antishake_max":1000,
                    "max_antishake_min":400,
                    "min_antishake":120,
                    "sample_rate":48000,
                    "silence_detect":0
                },
                "is_default":0,
                "net":{
                    "rc_anti_dropout":1,
                    "rc_init_delay":100,
                    "rc_max_delay":500
                },
                "role":"LiveGuest",
                "type":3,
                "video":{
                    "anti_dropout":0,
                    "codec_prof":5,
                    "format":-2,
                    "format_fix_height":480,
                    "format_fix_width":640,
                    "format_max_height":-1,
                    "format_max_width":-1,
                    "fps":15,
                    "fqueue_time":-1,
                    "live_adapt":0,
                    "maxkbps":400,
                    "maxqp":-1,
                    "minkbps":400,
                    "minqp":-1,
                    "qclear":1,
                    "small_video_upload":0
                }
            }
        ],
        "platform":1,
        "scheme":1,
        "sequence":20
    },
    "errmsg":"success.",
    "retcode":0
}

四、iLiveSDK配置默认角色

// Android接口如下:
/**
 * iLiveSDK 登录(配置默认角色配置)
 *
 * @param id 用户id
 * @param sig 用户密钥
 * @param roleCfg 默认角色配置(拉不到网络配置时使用此角色)
 */
public void iLiveLogin(final String id, String sig, String roleCfg, ILiveCallBack tilvbLoginListener);


// iOS/macOS接口如下:
/**
 网络不稳定,拉取spear配置经常失败时,才会用到本接口(一般适用于海外)
 */
- (void)iLiveLogin:(NSString *)uid sig:(NSString *)sig spearCfg:(NSString *)roleCfg succ:(TCIVoidBlock)succ failed:(TCIErrorBlock)failed;

登录接口参数:

参数名 类型 描述
id String 用户标识
sig String 用户签名
roleCfg String 默认角色配置
  • roleCfg 获取:根据前面步骤如何获取Spear角色配置中的操作,拉到业务自身的spear json串后,在json中找到需要默认角色如LiveMaster,字符串内容如下,将其作为参数传入到roleCfg即可;
{
    "audio":{
        "aec":1,
        "agc":0,
        "ans":1,
        "anti_dropout":0,
        "au_scheme":1,
        "channel":2,
        "codec_prof":4106,
        "frame":40,
        "kbps":24,
        "max_antishake_max":1000,
        "max_antishake_min":400,
        "min_antishake":120,
        "sample_rate":48000,
        "silence_detect":0
    },
    "is_default":1,
    "net":{
        "rc_anti_dropout":1,
        "rc_init_delay":100,
        "rc_max_delay":500
    },
    "role":"LiveMaster",
    "type":1,
    "video":{
        "anti_dropout":0,
        "codec_prof":5,
        "format":-2,
        "format_fix_height":480,
        "format_fix_width":640,
        "format_max_height":-1,
        "format_max_width":-1,
        "fps":15,
        "fqueue_time":-1,
        "live_adapt":0,
        "maxkbps":400,
        "maxqp":-1,
        "minkbps":400,
        "minqp":-1,
        "qclear":1,
        "small_video_upload":0
    }
}

五、iLiveSDK本地Spear配置启动

  • 功能说明:默认情况下,登录是到服务器拉取Spear配置,其有可能会失败; 此时即需要从本地进行加载spear配置;
  • 接口如下:
// Android
/**
 * iLiveSDK 登录(配置自定义Spear配置,忽略Spear后台配置)
 * http://conf.voice.qcloud.com/index.php?sdk_appid=[sdkappid]&interface=Voice_Conf_Download&platform=1
 *
 * @param id 用户id
 * @param sig 用户密钥
 * @param spearCfg 自定义spear配置
 */
public void iLiveLoginWithSpear(final String id, String sig, String spearCfg, ILiveCallBack tilvbLoginListener);


// iOS/macOS接口如下:
/**
 * 登录(配置自定spear配置,忽略spear后台配置)
 * @param uid      用户id
 * @param sig      用户签名
 * @param config   自定义spear配置(从 http://conf.voice.qcloud.com/index.php?sdk_appid=sdkappid&interface=Voice_Conf_Download&platform=1(platform:1 ios,2 android) 获取)
 * @param succ     成功回调
 * @param failed   失败回调
 */
- (void)iLiveLoginWithCustomSpearCfg:(NSString *)spearCfg uid:(NSString *)uid sig:(NSString *)sig  succ:(TCIVoidBlock)succ failed:(TCIErrorBlock)failed;
参数名 类型 描述
id String 用户标识
sig String 用户签名
spearCfg String 自定义配置信息
  • spearCfg获取:根据前面步骤如何获取Spear角色配置中的操作,拉到业务自身的spear json串后,将json字符串作为参数传入到spearCfg 即可;
  • 同时在统一事件回调中添加onSetSpearConfigEvent上抛配置是否成功.

六、QAVSDK配置本地spear配置以及代码示例

展开前面 Spear 配置下载存储的文件内容: data["conf"] 即为角色列表:

{
    "data":{
        "biz_id":1400049564,
        "conf":[
            {
                "audio":{
                    "aec":1,
                    "agc":0,
                    "ans":1,
                    "anti_dropout":0,
                    "au_scheme":1,
                    "channel":2,
                    "codec_prof":4106,
                    "frame":40,
                    "kbps":24,
                    "max_antishake_max":1000,
                    "max_antishake_min":400,
                    "min_antishake":120,
                    "sample_rate":48000,
                    "silence_detect":0
                },
                "is_default":1,
                "net":{
                    "rc_anti_dropout":1,
                    "rc_init_delay":100,
                    "rc_max_delay":500
                },
                "role":"LiveMaster",
                "type":1,
                "video":{
                    "anti_dropout":0,
                    "codec_prof":5,
                    "format":-2,
                    "format_fix_height":480,
                    "format_fix_width":640,
                    "format_max_height":-1,
                    "format_max_width":-1,
                    "fps":15,
                    "fqueue_time":-1,
                    "live_adapt":0,
                    "maxkbps":400,
                    "maxqp":-1,
                    "minkbps":400,
                    "minqp":-1,
                    "qclear":1,
                    "small_video_upload":0
                }
            },
            {
                "audio":{
                    "aec":1,
                    "agc":0,
                    "ans":1,
                    "anti_dropout":0,
                    "au_scheme":1,
                    "channel":2,
                    "codec_prof":4106,
                    "frame":40,
                    "kbps":24,
                    "max_antishake_max":1000,
                    "max_antishake_min":400,
                    "min_antishake":120,
                    "sample_rate":48000,
                    "silence_detect":0
                },
                "is_default":0,
                "net":{
                    "rc_anti_dropout":1,
                    "rc_init_delay":500,
                    "rc_max_delay":1000
                },
                "role":"Guest",
                "type":2,
                "video":{
                    "anti_dropout":0,
                    "codec_prof":5,
                    "format":-2,
                    "format_fix_height":480,
                    "format_fix_width":640,
                    "format_max_height":-1,
                    "format_max_width":-1,
                    "fps":15,
                    "fqueue_time":-1,
                    "live_adapt":0,
                    "maxkbps":400,
                    "maxqp":-1,
                    "minkbps":400,
                    "minqp":-1,
                    "qclear":1,
                    "small_video_upload":0
                }
            },
            {
                "audio":{
                    "aec":1,
                    "agc":0,
                    "ans":1,
                    "anti_dropout":0,
                    "au_scheme":1,
                    "channel":2,
                    "codec_prof":4106,
                    "frame":40,
                    "kbps":24,
                    "max_antishake_max":1000,
                    "max_antishake_min":400,
                    "min_antishake":120,
                    "sample_rate":48000,
                    "silence_detect":0
                },
                "is_default":0,
                "net":{
                    "rc_anti_dropout":1,
                    "rc_init_delay":100,
                    "rc_max_delay":500
                },
                "role":"LiveGuest",
                "type":3,
                "video":{
                    "anti_dropout":0,
                    "codec_prof":5,
                    "format":-2,
                    "format_fix_height":480,
                    "format_fix_width":640,
                    "format_max_height":-1,
                    "format_max_width":-1,
                    "fps":15,
                    "fqueue_time":-1,
                    "live_adapt":0,
                    "maxkbps":400,
                    "maxqp":-1,
                    "minkbps":400,
                    "minqp":-1,
                    "qclear":1,
                    "small_video_upload":0
                }
            }
        ],
        "platform":1,
        "scheme":1,
        "sequence":20
    },
    "errmsg":"success.",
    "retcode":0
}

iOS

1.要使用自定义配置作为sdk配置,需要在QAVContext start时时指定QAVContextStartParam使用 QAVCustomSpearEngineCtrl

QAVContextStartParam *startParam = [[QAVContextStartParam alloc] init];
            startParam.sdkAppId = appIdInt;
            startParam.appidAt3rd = appIdStr;
            startParam.accountType = accountType;
            startParam.identifier = uid;
            
            // 主要是这一步
            startParam.engineCtrlType = QAVSpearEngineCtrlTypeCustom;
            
            QAVContext *avContext = [QAVSDK CreateContext];
            [avContext startWithParam: startParam completion:^(int result, NSString *errorInfo) {
	            if(result == 0)
	            {
	            	// TODO: 开始设置avContext.customSpearCtrl
	            }
            }]
            

2.开始设置customSpearCtrl

// 1: 互动直播 
[avContext.customSpearCtrl setScene:1];

// 以下添加为伪代码

NSDictionary *spearjson = loadFromResourceFile(); // 从加载第一步spear文件内容
NSDictionary *data =  spearjson[@"data"];
NSArray *conf =  data[@"conf"];
for (NSDictionary *confitem in conf)
{
	NSString *role = confitem[@"role"];
	avContext.customSpearCtrl addParamByRole:role jsonParam: confitem.tojsonstring];
}

Android

1.要使用自定义配置作为sdk配置,需要在QAVContext start时时指定QAVContextStartParam使用 QAVCustomSpearEngineCtrl

AVContext.StartParam param = new AVContext.StartParam();
param.sdkAppId = mUserInfo.sdkAppId;
param.accountType = "" + mUserInfo.accountType;
param.appIdAt3rd = "" + mUserInfo.sdkAppId;
param.identifier = mUserInfo.identifier;
param.useSurfaceTexture = ILiveSDK.getInstance().isUseSurfaceTexture();

// 主要是这一步
param.engineCtrlType = AVSpearEngineCtrl.SPEAR_ENGINE_CTRL_TYPE_CUSTOM;
mAVContext.start(param, new AVCallback(){
    @Override
    public void onComplete(int errCode, String errInfo) {
        if(errCode == 0)
        {
            // TODO: 开始设置mAVContext.getCustomSpearEngineCtrl()
        }
    }
});            

2.开始设置customSpearCtrl

// 1: 互动直播
mAVContext.getCustomSpearEngineCtrl().setScene(1);

// 以下添加为伪代码
try {
    JSONObject jsonConfig = loadFromResourceFile();  // 从加载第一步spear文件内容
    JSONObject jsonData = jsonConfig.getJSONObject("data");
    JSONArray jsonConf = jsonData.getJSONArray("conf");
    for (int i=0; i<jsonConf.length(); i++){
        JSONObject jsonRole = jsonConf.getJSONObject(i);
        mAVContext.getCustomSpearEngineCtrl().addParamByRole(jsonRole.getString("role"), jsonRole.toString());
    }
}catch (Exception e){
    // 处理异常
}

七、参考文档

1.手机端进房失败(Role no exists)

2.Windows进房失败(Role no exists)

3.角色配置


文章来源于腾讯云开发者社区,点击查看原文