Talk SDK for Android 使用指南

适用范围

本文档适用于游密实时语音引擎(Talk SDK)Android Studio开发环境下接入。

开发环境

在开始集成游密Video SDK 前,请确保开发环境满足以下要求:

  • Android Studio 2.1 或以上版本。
  • Android SDK 25、Android SDK Build-Tools 25.0.2、Android SDK Platform-Tools 25.x.x 或以上版本。
  • Android 4.0 或以上版本,且支持音频的 Android 设备或模拟器(推荐使用真机) Android 设备已经连接到 Internet。

SDK目录概述

语音SDK中有lib文件夹,该文件夹下又包含几种cpu系统架构的动态库文件以及youme_voice_engine.jar包。

集成SDK

  1. 将SDK内的lib文件夹的所有文件移至Android工程libs文件夹下(示例代码中 “libs” 目录仅为举例,开发者可根据实际路径填写),如下图所示:

  2. 添加 SDK 引用,进入到 “app” 目录,打开 “build.gradle” 文件。在 “defaultConfig” 节点添加 “ndk” 节点,指定支持的平台类型:
    defaultConfig{
        //添加如下设置支持到so库架构
        ndk{
            abiFilters 'armeabi','armeabi-v7a','x86'      //架构可选对应项目需要的
        }
    }
  3. 在 “android” 节点添加 “sourceSets” 节点,指定 “libs” 所在目录:
    sourceSets{
        main{
            jniLibs.srcDirs = ['libs']
        }
    }
  4. 在 “dependencies” 节点引入 “libs” 下所有的 jar:

    dependencies {
    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
    }
  5. AndroidManifest.xml配置添加录音和网络相关权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <!-- Androi target api 31+ 必须配置 -->
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
  6. 防止混淆代码:YOUMESDK不需要混淆,如果你的工程有混淆,请在proguard-rules.pro文件中添加如下代码:
    -keep class com.youme.**{*;}
    -keepattributes Signature
  7. 设置加载so库以及启动相关服务 在入口Activity类先导入package:

    import android.content.Intent;
    import android.os.Bundle;
    import com.youme.voiceengine.mgr.YouMeManager;

    然后在onCreate方法里添加“YouMeManager.Init”,且需要在“super.onCreate”之前调用,以解决某些设备兼容性问题:

    YouMeManager.Init(this);
    
    super.onCreate(savedInstanceState);

语音通话流程图

流程图

语音通话时序图

时序图

语音通话相关代码

初始化

设置回调监听。

api.SetCallback(this);

然后implements YouMeCallBackInterface。

public class MainActivity extends AppCompatActivity implements YouMeCallBackInterface

重写里面的方法,其中里面的onEvent会得到关于所有Talk相关的回调。

// 消息回调接口实现
    @Override
    public void onEvent(int eventType, int errorCode, String channelID, Object param) {  
    }
    @Override
    public void onRequestRestAPI(int i, int i1, String s, String s1) {
    }
    @Override
    public void onMemberChange(String s, MemberChange[] memberChanges, boolean b) {
    }
    @Override
    public void onBroadcast(int i, String s, String s1, String s2, String s3) {
    }

初始化Talk SDK:其中appKey和appSecret为在游密后台申请的App Key和App Secret。serverZone:IM服务器区域,一般使用0表示中国,其余设置值可查看官网文档-服务器部署地区定义

// 初始化
api.init(appKey, appSecret, serverZone, "");

加入频道

onEvent收到初始化成功消息YouMeEvent.YOUME_EVENT_INIT_OK后: 加入频道: 其中userID:用户标识,channelID:频道标识,userRole:用户在语音频道里面的角色,主要分为YOUME_USER_HOST(可以随时讲话和播放战歌等)、YOUME_USER_LISTENER(只听不讲)、YOUME_USER_TALKER_FREE(自由讲话者)等,详情见YouMeUserRole定义。

api.joinChannelSingleMode(userID, channelID, userRole, autoRecv);

开关音频设备

onEvent收到加入频道成功消息YouMeEvent.YOUME_EVENT_JOIN_OK后: 打开/关闭麦克风:其中mute为true表示关闭麦克风,false表示开启麦克风。

api.setMicrophoneMute(mute);

打开/关闭扬声器:其中mute为true表示关闭麦克风,false表示开启麦克风。

api.setSpeakerMute(mute);

设置音量(音量范围0-100,建议设置70比较适中)。

api.setVolume(70); 

离开频道,反初始化

离开频道。

api.leaveChannelAll();

反初始化。

api.unInit();

附:部分事件状态码

    @Override
    public void onEvent(int eventType, int errorCode, String channelID, Object param) {

        log("OnEvent:event "+eventType + ",error " + errorCode + ",channel " + channelID + ",param_" + param.toString());
        Message msg = new Message();
        switch( eventType ){
            case YouMeEvent.YOUME_EVENT_INIT_OK: //YOUME_EVENT_INIT_OK:
                log("Talk 初始化成功");
                break;
            case YouMeEvent.YOUME_EVENT_INIT_FAILED://YOUME_EVENT_INIT_FAILED:
                log("Talk 初始化失败");

                break;
            case YouMeEvent.YOUME_EVENT_JOIN_OK://YOUME_EVENT_JOIN_OK:
                log("Talk 进入频道成功,频道:"+channelID+" 用户id:"+param);

                break;
            case YouMeEvent.YOUME_EVENT_JOIN_FAILED://YOUME_EVENT_JOIN_FAILED:
                log("Talk 进入频道:"+channelID+"失败,code:"+errorCode);

                break;
            case YouMeEvent.YOUME_EVENT_LEAVED_ONE://YOUME_EVENT_LEAVED_ONE:
                log("Talk 离开单个频道:"+channelID);

                break;
            case YouMeEvent.YOUME_EVENT_LEAVED_ALL://YOUME_EVENT_LEAVED_ALL:
                log("Talk 离开所有频道,这个回调channel参数为空字符串");

                break;
            case YouMeEvent.YOUME_EVENT_PAUSED://YOUME_EVENT_PAUSED:
                log("Talk 暂停");
                break;
            case YouMeEvent.YOUME_EVENT_RESUMED://YOUME_EVENT_RESUMED:
                log("Talk 恢复");
                break;
            case YouMeEvent.YOUME_EVENT_SPEAK_SUCCESS://YOUME_EVENT_SPEAK_SUCCESS:///< 切换对指定频道讲话成功(适用于多频道模式)
                break;
            case YouMeEvent.YOUME_EVENT_SPEAK_FAILED://YOUME_EVENT_SPEAK_FAILED:///< 切换对指定频道讲话失败(适用于多频道模式)
                break;
            case YouMeEvent.YOUME_EVENT_RECONNECTIN://YOUME_EVENT_RECONNECTING:///< 断网了,正在重连
                log("Talk 正在重连");
                break;
            case YouMeEvent.YOUME_EVENT_RECONNECTED://YOUME_EVENT_RECONNECTED:///< 断网重连成功
                log("Talk 重连成功");
                break;
            case YouMeEvent.YOUME_EVENT_REC_PERMISSION_STATUS://YOUME_EVENT_REC_FAILED:///< 通知录音启动失败(此时不管麦克风mute状态如何,都没有声音输出)
                log("录音启动失败,code:"+errorCode);
                break;
            case YouMeEvent.YOUME_EVENT_BGM_STOPPED://YOUME_EVENT_BGM_STOPPED:///< 通知战歌播放结束
                log("战歌播放结束,path:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_BGM_FAILED://YOUME_EVENT_BGM_FAILED:///< 通知战歌播放失败
                log("战歌播放失败,code:"+errorCode);
                break;
            case YouMeEvent.YOUME_EVENT_OTHERS_MIC_ON://YOUME_EVENT_OTHERS_MIC_ON:///< 其他用户麦克风打开
                log("其他用户麦克风打开,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_OTHERS_MIC_OFF://YOUME_EVENT_OTHERS_MIC_OFF:///< 其他用户麦克风关闭
                log("其他用户麦克风关闭,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_OTHERS_SPEAKER_ON://YOUME_EVENT_OTHERS_SPEAKER_ON:///< 其他用户扬声器打开
                log("其他用户扬声器打开,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_OTHERS_SPEAKER_OFF://YOUME_EVENT_OTHERS_SPEAKER_OFF: ///< 其他用户扬声器关闭
                log("其他用户扬声器关闭,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_OTHERS_VOICE_ON://YOUME_EVENT_OTHERS_VOICE_ON: ///< 其他用户进入讲话状态
                log("开始讲话,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_OTHERS_VOICE_OFF://YOUME_EVENT_OTHERS_SPEAKER_OFF: ///< 其他用户停止讲话
                log("停止讲话userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_MY_MIC_LEVEL://YOUME_EVENT_MY_MIC_LEVEL: ///< 自己的麦克风的语音音量级别
                log("我当前讲话的音量级别是,数值:"+errorCode);
                break;
            case YouMeEvent.YOUME_EVENT_MIC_CTR_ON://YOUME_EVENT_MIC_CTR_ON: ///< 自己的麦克风被其他用户打开
                log("自己的麦克风被其他用户打开,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_MIC_CTR_OFF://YOUME_EVENT_MIC_CTR_OFF: ///< 自己的麦克风被其他用户关闭
                log("自己的麦克风被其他用户关闭,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_SPEAKER_CTR_ON://YOUME_EVENT_SPEAKER_CTR_ON: ///< 自己的扬声器被其他用户打开
                log("自己的扬声器被其他用户打开,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_SPEAKER_CTR_OFF://YOUME_EVENT_SPEAKER_CTR_OFF: ///< 自己的扬声器被其他用户关闭
                log("自己的扬声器被其他用户关闭,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_LISTEN_OTHER_ON://YOUME_EVENT_LISTEN_OTHER_ON: ///< 取消屏蔽某人语音
                log("取消屏蔽某人语音,userid:"+param);
                break;
            case YouMeEvent.YOUME_EVENT_LISTEN_OTHER_OFF://YOUME_EVENT_LISTEN_OTHER_OFF: ///< 屏蔽某人语音
                log("屏蔽某人语音,userid:"+param);
                break;
            default:
                break;
        }

    @Override
    public void onRequestRestAPI(int a,int b,String c,String d){
    }

    @Override
    public void onMemberChange(String a, MemberChange[] b,boolean d){
    }

    @Override
    public void onBroadcast(int a,String b,String c,String d,String e){
    }

更多的事件状态码可以参考官网的状态码定义-YouMeEvent类。

  1. 打开创建的新New project,在MainActivity.java文件里的示例代码如下:

    package com.example.stepbytalkdemo;  
    import androidx.appcompat.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import com.youme.voiceengine.mgr.YouMeManager;
    import com.youme.voiceengine.*;
    public class MainActivity extends AppCompatActivity implements YouMeCallBackInterface {  
    public static final String appKey = "YOUME";
    public static final String appSecret = "123456789";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        YouMeManager.Init(this);
        api.SetCallback(this);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        api.init(appKey,appSecret,0,"");
    }
    
    @Override
    public void onEvent(int eventType,int errorCode,String channelID,Object param){
    
        if(eventType== YouMeConst.YouMeEvent.YOUME_EVENT_INIT_OK){
            api.joinChannelSingleMode("12345","12345",1,false);
        }if(eventType== YouMeConst.YouMeEvent.YOUME_EVENT_INIT_FAILED){
            Log.i("初始化失败:",""+errorCode);
        }else{
            switch (eventType){
                case YouMeConst.YouMeEvent.YOUME_EVENT_JOIN_OK:
                    api.setMicrophoneMute(false);
                    api.setSpeakerMute(false);
                    break;
            }
        }
    
    }
    @Override
    public void onRequestRestAPI(int a,int b,String c,String d){
    }
    
    @Override
    public void onMemberChange(String a, MemberChange[] b,boolean d){
    }
    @Override
    public void onBroadcast(int a,String b,String c,String d,String e){
    }

场景调用流程

调用流程时序图

title:Talk SDK 接口调用流程,具体接口说明参见API接口手册

participant Game Client as A
participant YM Talk SDK as B

A->B:设置回调(SetCallback)

A->B:初始化(init)
B-->A:返回初始化回调结果(在OnEvent里返回)
Note right of A:用户可以用自由说话身份加入频道
A->B:加入频道(joinchannelSingleMode)

A->B:根据业务端逻辑打开麦克风扬声器 \n(SetMicrophoneMute、setSpeakerMute)

Note right of A:上述的回调若都是返回success,则在同一频道内\n的用户就都可以相互通话或收听了

A->B:离开频道(LeaveChannelAll)

核心调用API

初始化流程

接口 含义
api.SetCallback(YouMeCallBackInterface callBack) 注册回调(event、memberchange等)
api.init 引擎初始化,区域参数使用app发版地区对应的区域参数,若需要全球互通,可联系游密相关人员配置开通
  • 调用示例:
    api.SetCallback(this);     //设置回调监听对象,需要implement YouMeCallBackInterface
    api.init("Appkey", "strAPPSecret", YOUME_RTC_SERVER_REGION.RTC_CN_SERVER, "");      //只有appkey,appsecret,serverRegionId 都一样时,才可以进行语音互通,改任意一个视为另外一个区服;

加入/退出房间流程

接口 含义
api.joinChannelSingleMode 加入房间,建议 role建议设置为1,autoRecv设为fasle
api.leaveChannelAll 退出所有房间

本地设备控制接口

收到加入房间成功JOIN_OK事件后可设置:

接口 含义
api.setMicrophoneMute 设置麦克风状态
api.setSpeakerMute 设置扬声器状态
api.setAutoSendStatus 设置是否通知别人麦克风和扬声器的开关,设置后用户开关麦克风或者扬声器都会通知到同频道到其他用户
api.setUseMobileNetworkEnabled 设置是否允许使用移动网络
api.setReleaseMicWhenMute 设置当麦克风静音时,是否释放麦克风设备,(需要在初始化成功后,加入房间之前调用)

通话管理

  • 在用户切到后台或者要收听电话时,可调用暂停通话;以便释放麦克风等设备资源的占用,当切换会前台时,可以调用恢复通话接口用于继续通话。
接口 含义
api.pauseChannel 暂停通话
api.resumeChannel 恢复通话

设置回调监听

引擎底层对于耗时操作都采用异步回调的方式,函数调用会立即返回,操作结果java层会同步回调。因此,用户必须实现相关接口并在初始化前通过 api.SetCallback(this) 注册接收回调通知的对象。

使用类需要implements接口YouMeCallBackInterface,并实现该接口下的所有回调函数。回调都在子线程中执行,不能用于更新UI等耗时操作。

  • 首先要导入相关的包:
  import com.youme.voiceengine.MemberChange;
  import com.youme.voiceengine.YouMeCallBackInterface;
  • 然后implements接口YouMeCallBackInterface,具体实现回调方法:
  @Override
  public void onEvent(int eventType, int iErrorCode, String roomid, Object param){}
  @Override
  public void onMemberChange(String channelID, MemberChange[] arrChanges, boolean isUpdate){}

网络质量检测

实现接口YouMeCallBackInterface里的public void onDetectNetWorkComplete(boolean b, String s);回调函数。回调都在子线程中执行,不能用于更新UI等耗时操作。

  • 在需要检测网络质量时,可调用开始检测网络质量接口;当需要终止检测网络质量时,可调用终止检测网络质量接口。
接口 含义
api.detectNetworkQuality(nDetectTime, nOverTime, nInterval, nPackSize); 开始检测网络质量
api.stopDetectNetworkQuality(); 终止检测网络质量

最终的网络质量检测结果会通过public void onDetectNetWorkComplete(boolean b, String s);回调函数返回。如果调用了终止检测网络质量接口将不会通过回调函数返回结果。

建议:客户端最好在开始检测网络质量之前,对网络的连通性进行检查,如果不连通的话就不用进行网络质量检测了。