文档中心>游戏多媒体引擎

接入实时语音功能

最近更新时间:2024-11-26 17:54:42

我的收藏
本文介绍如何在项目中接入GME 实时语音功能,为了方便演示,只提供了基础功能的接入,其他功能的使用请参考API 文档。

前置条件:

已完成 GME 应用的创建,并获取SDK AppID 和 Key。请参见 服务开通指引
已开通 GME 实时语音服务,请参见 服务开通指引
已将 GME SDK导入到项目中,请参见 导入 SDK 到 Android 项目。

接口调用流程图



调用指引

步骤1:引入头文件

C++
Java
Object-C
#include "tmg_sdk.h"
import com.gme.TMG.ITMGContext;
#import "GMESDK/TMGEngine.h"

步骤2:获取SDK实例并设置事件监听器

C++
Java
Object-C
gmeContext = ITMGContextGetInstance();
gmeContext->SetTMGDelegate(this);
gmeContext = ITMGContext.GetInstance(this);
gmeContext.SetTMGDelegate(this);
gmeContext = [ITMGContext GetInstance];
[[ITMGContext GetInstance] setTMGDelegate:self];

步骤3:监听 SDK 的事件

通过设置事件回调接口,您可以监听 SDK 在运行期间所发生的各种音视事件。
C++
Java
Object-C
// 我们可以让自己的类继承 ITMGDelegate,并重载OnEvent函数,然后在该函数中处理需要响应的事件

// 重载OnEvent函数
void OnEvent(ITMG_MAIN_EVENT_TYPE eventType, const char* data) {
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_ENTER_ROOM:
// 进房完成事件
break;
case ITMG_MAIN_EVENT_TYPE_EXIT_ROOM:
// 退房完成事件
break;
}
}
// 我们可以让自己的类继承 ITMGContext.ITMGDelegate,并重载OnEvent函数,然后在该函数中处理需要响应的事件

// 重载OnEvent函数
public void OnEvent(ITMGType.ITMG_MAIN_EVENT_TYPE eventType, Intent data) {
switch (eventType) {
case ITMGType.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVENT_TYPE_ENTER_ROOM:
// 进房完成事件
break;
case ITMGType.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVENT_TYPE_EXIT_ROOM:
// 退房完成事件
break;
}
}
// 我们可以让自己的类继承 ITMGDelegate,并重载OnEvent函数,然后在该函数中处理需要响应的事件

// 重载OnEvent函数
- (void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary *)data {
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_ENTER_ROOM:
// 进房完成事件
break;
case ITMG_MAIN_EVENT_TYPE_EXIT_ROOM:
// 退房完成事件
break;
}
}

步骤4:初始化SDK

在使用 GME SDK 相关功能之前必须先对 SDK 进行初始化。
C++
Java
Object-C
gmeContext = ITMGContextGetInstance();
int ret = gmeContext->Init(sdkAppId, userID);
if (ret== AV_OK) {
// 初始化成功
} else {
// 初始化失败
}

gmeContext = ITMGContext.GetInstance(this);
int ret = gmeContext.Init(sdkAppId, userID);
if (ret == AV_OK) {
// 初始化成功
} else {
// 初始化失败
}
gmeContext = [ITMGContext GetInstance];
int result = [gmeContext InitEngine:sdkAppId openID:userID];
if (ret == QAV_OK) {
// 初始化成功
} else {
// 初始化失败
}
参数名称
类型
含义
sdkAppId
字符串
来自 腾讯云控制台 的 GME 服务提供的 AppID,获取方法请参见 服务开通指引
userID
字符串
用户名,只允许包含大小写英文字母(a-z、A-Z)、数字(0-9)及下划线和连词符,最大127个字符。注意 GME 不支持同一个 userId 在两台不同的设备上同时进入房间,否则会相互干扰

步骤5:触发事件回调

周期性(例如每30ms)调用 Poll 接口可以触发 GME 的事件回调。Poll 是 GME 的消息泵,GME 需要周期性的调用 Poll 接口触发事件回调,如果没有调用 Poll ,将会导致整个 SDK 服务运行异常,可参考 GME Sample Code 中 EnginePollHelper 的实现。
C++
Java
Object-C
gmeContext = ITMGContextGetInstance();
gmeContext ->Poll();
gmeContext = ITMGContext.GetInstance(this);
gmeContext.Poll();
gmeContext = [ITMGContext GetInstance];
[gmeContext Poll];

步骤6:计算鉴权信息

在调用进房接口时需要传入进房鉴权票据(UserSig),该鉴权票据是通过 SDKAppID 和 userId 等信息计算得到的;开发调试时您可使用 SDK 提供的接口生成userSig(为了方便 2.X 版本的升级,SDK 中计算 UserSig 的接口依然命名为 AuthBuffer),应用上线发布时建议使用服务器生成鉴权信息,计算方法请参见 UserSig 相关
C++
Java
Object-C
// 接口原型
// int GMESDK_CALL QAVSDK_AuthBuffer_GenAuthBuffer(unsigned int appId, const char* roomId, const char* userId, const char* key, unsigned char* authBuffer, unsigned int authBufferLen);

int userSigLen = 0;
unsigned char userSig[1024] = {0};
userSigLen = QAVSDK_AuthBuffer_GenAuthBuffer(1400******, "", "1000", "key*****", userSig, userSigLen);
import com.gme.av.sig.AuthBuffer;

// 接口原型
// public byte[] genAuthBuffer(int appId, String roomId, String userId, String appKey)

byte[] userSig;
userSig = AuthBuffer.getInstance().genAuthBuffer(1400******, "", "1000", "key*****");
#import "GMESDK/QAVAuthBuffer.h"

// 接口原型
// + (NSData*)GenAuthBuffer:(unsigned int)appId roomID:(NSString*)roomID openID:(NSString*)openID key:(NSString*)key;

NSData* userSig = [QAVAuthBuffer GenAuthBuffer:1400****** roomID:@"" openID:@"1000" key:@"key*****"];
参数名称
数据类型
含义
appId
数字
来自 腾讯云控制台 的 GME 服务提供的 AppID,获取请参见 服务开通指引
roomId
字符串
暂时未用到,填空字符串即可
userId
字符串
用户名,只允许包含大小写英文字母(a-z、A-Z)、数字(0-9)及下划线和连词符,最大127个字符。注意 GME 不支持同一个 userId 在两台不同的设备上同时进入房间,否则会相互干扰
key
字符串
来自 腾讯云控制台 的权限密钥

步骤7:加入实时语音房间

调用EnterRoom接口加入到实时语音房间,返回值为AV_OK只表示该次函数调用成功,并不代表进房成功。
C++
Java
Object-C
// 接口原型
// int EnterRoom(const char* room_id, ITMG_ROOM_TYPE room_type, const char* userSig, int userSigLen)

gmeContext = ITMGContextGetInstance();
gmeContext->EnterRoom("roomid_001", ITMG_ROOM_TYPE_FLUENCY, userSig, userSigLen);
// 接口原型
// public abstract int EnterRoom(String roomId, ITMG_ROOM_TYPE roomType, byte[] userSig);

gmeContext = ITMGContext.GetInstance(this);
gmeContext.EnterRoom("roomid_001", ITMGType.ITMG_ROOM_TYPE.ITMG_ROOM_TYPE_FLUENCY, userSig);
// 接口原型
// - (int)EnterRoom:(NSString *)roomID roomType:(ITMG_ROOM_TYPE)roomType authBuffer:(NSData *)userSig;

gmeContext = [ITMGContext GetInstance];
[gmeContext EnterRoom:@"roomid_001" roomType:ITMG_ROOM_TYPE_FLUENCY authBuffer:userSig];

参数名称
类型
含义
room_id
字符串
房间号,最大支持127字符
room_type
枚举值
房间类型,代表了房间的音频质量,每个用户都可设置自己房间类型,不会影响其他用户,房间类型有下面3种可选 ITMG_ROOM_TYPE_FLUENCY:流畅音质,端到端延迟小,适合游戏开黑场景 ITMG_ROOM_TYPE_STANDARD:标准音质,端到端延迟中等,适合狼人杀场景 ITMG_ROOM_TYPE_HIGHQUALITY:高清音质,端到端延时相对大一些,适合娱乐连麦场景
userSig
字符串
进房鉴权票据,参见 步骤6
userSigLen
数字
进房鉴权票据长度(仅C++版本需要该参数)

步骤8:处理进房完成事件

加入实时语音房间是一个异步过程,GME SDK 会将进房结果通过事件回调的方式通知给上层应用,上层应用需要处理ITMG_MAIN_EVENT_TYPE_ENTER_ROOM 事件。
C++
Java
Object-C
// 重载OnEvent函数
void OnEvent(ITMG_MAIN_EVENT_TYPE eventType, const char* data) {
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_ENTER_ROOM: // 进房完成事件
// data字段是一个Json串,形式如:{"result":0, "error_info":""}
// 解析中data中的字段
int result = GetItemFromJson(data, "result");
if (result == AV_OK) {
// 进房成功
} else {
// 进房失败
}
break;
}
}
// 重载OnEvent函数
public void OnEvent(ITMGType.ITMG_MAIN_EVENT_TYPE eventType, Intent data) {
switch (eventType) {
case ITMGType.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVENT_TYPE_ENTER_ROOM: // 进房完成事件
int result = data.getIntExtra("result" , -1);
String error_info = data.getStringExtra("error_info");
if (result == AVError.AV_OK) {
// 进房成功
} else {
// 进房失败
}
break;
}
}
// 重载OnEvent函数
- (void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary *)data {
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_ENTER_ROOM: // 进房完成事件
int result = ((NSNumber *)[data objectForKey:@"result"]).intValue;
NSString *error_info = [data objectForKey:@"error_info"];
if (result == QAV_OK) {
// 进房成功
} else {
// 进房失败
}
break;
}
}

步骤9:开启或关闭麦克风

GME SDK 中麦克风默认是关闭的,在加入实时语音房间成功后,可以调用 EnableMic 接口打开或关闭麦克风。
C++
Java
Object-C
gmeContext = ITMGContextGetInstance();
gmeContext->GetAudioCtrl()->EnableMic(true);
gmeContext = ITMGContext.GetInstance(this);
gmeContext.GetAudioCtrl().EnableMic(true);
gmeContext = [ITMGContext GetInstance];
[[gmeContext GetAudioCtrl] EnableMic:YES];

步骤10:开启或关闭扬声器

GME SDK 中扬声器默认是关闭的,在加入实时语音房间成功后,可以调用 EnableSpeaker 接口打开或关闭麦克风。
C++
Java
Object-C
gmeContext = ITMGContextGetInstance();
gmeContext->GetAudioCtrl()->EnableSpeaker(true);
gmeContext = ITMGContext.GetInstance(this);
gmeContext.GetAudioCtrl().EnableSpeaker(true);
gmeContext = [ITMGContext GetInstance];
[[gmeContext GetAudioCtrl] EnableSpeaker:YES];

步骤11:处理房间内成员状态变化事件【可选】

当语音房间内其他用户的状态(有成员进入/退出房间开始/停止发送音频数据)发生变化时,上层应用会收到 ITMG_MAIN_EVNET_TYPE_USER_UPDATE 事件,其中 data 字段包含两个信息:event_id 及 user_list,event_id用来表示具体是哪一种事件,user_list 里面包含了发生该事件的用户 ID。SDK 不提供房间内所有成员列表的获取接口,需要上层应用通过进入/退出房间事件来自己维护房间内成员列表。
event_id
含义
应用侧维护内容
ITMG_EVENT_ID_USER_ENTER
有成员进入房间,返回此时进房的 openid
应用侧维护成员列表
ITMG_EVENT_ID_USER_EXIT
有成员退出房间,返回此时退房的 openid
应用侧维护成员列表
ITMG_EVENT_ID_USER_HAS_AUDIO
有成员发送音频包,返回此时房间内说话的 openid,通过此事件可以判断用户是否说话,并展示声纹效果
应用侧维护成员列表
ITMG_EVENT_ID_USER_NO_AUDIO
有成员停止发送音频包,返回此时房间内停止说话的 openid
应用侧维护成员列表
C++
Java
Object-C
// 重载OnEvent函数
void OnEvent(ITMG_MAIN_EVENT_TYPE eventType, const char* data) {
switch (eventType) {
case ITMG_MAIN_EVNET_TYPE_USER_UPDATE: // 房间内成员状态发生变化
// data字段是一个Json串,形式如:{"event_id":0, "user_list":[]}
// 解析中data中的字段
int event_id = GetItemFromJson(data, "event_id");
switch (event_id ) {
case ITMG_EVENT_ID_USER_ENTER:
// 有成员进入房间
break;
case ITMG_EVENT_ID_USER_EXIT:
// 有成员退出房间
break;
case ITMG_EVENT_ID_USER_HAS_AUDIO:
// 有成员发送音频数据
break;
case ITMG_EVENT_ID_USER_NO_AUDIO:
// 有成员停止发送音频数据
break;
default:
break;
}
}
break;
}
}
// 重载OnEvent函数
public void OnEvent(ITMGType.ITMG_MAIN_EVENT_TYPE eventType, Intent data) {
switch (eventType) {
case ITMGType.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVNET_TYPE_USER_UPDATE: // 房间内成员状态发生变化
int event_id= data.getIntExtra("event_id" , -1);
String[] strUsers = data.getStringArrayExtra("user_list");
if (event_id == ITMGType.ITMG_EVENT_ID_USER_UPDATE.ITMG_EVENT_ID_USER_ENTER.getNativeValue()) {
// 有成员进入房间
} else if (event_id == ITMGType.ITMG_EVENT_ID_USER_UPDATE.ITMG_EVENT_ID_USER_EXIT.getNativeValue()){
// 有成员退出房间
} else if (event_id == ITMGType.ITMG_EVENT_ID_USER_UPDATE.ITMG_EVENT_ID_USER_HAS_AUDIO.getNativeValue()){
// 有成员发送音频数据
} else if (event_id == ITMGType.ITMG_EVENT_ID_USER_UPDATE.ITMG_EVENT_ID_USER_NO_AUDIO.getNativeValue()){
// 有成员停止发送音频数据
}
break;
}
}
// 重载OnEvent函数
- (void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary *)data {
switch (eventType) {
case ITMG_MAIN_EVNET_TYPE_USER_UPDATE: // 进房完成事件
int event_id = ((NSNumber *)[data objectForKey:@"event_id"]).intValue;
NSMutableArray *user_list = [NSMutableArray arrayWithArray:[data objectForKey:@"user_list"]];
switch (event_id) {
case ITMG_EVENT_ID_USER_ENTER:
// 有成员进入房间
break;
case ITMG_EVENT_ID_USER_EXIT:
// 有成员退出房间
break;
case ITMG_EVENT_ID_USER_HAS_AUDIO:
// 有成员发送音频数据
break;
case ITMG_EVENT_ID_USER_NO_AUDIO:
// 有成员停止发送音频数据
break;
default:
break;
}
break;
}
}

步骤12:退出实时语音房间

在使用完实时语音供后需要从房间里面退出时,调用 ExitRoom 接口即可。
C++
Java
Object-C
gmeContext = ITMGContextGetInstance();
gmeContext->ExitRoom();
gmeContext = ITMGContext.GetInstance(this);
gmeContext.ExitRoom();
gmeContext = [ITMGContext GetInstance];
[gmeContext ExitRoom];

步骤13:处理退房完成事件

退出实时语音房间是一个异步过程,GME SDK 会将进房结果通过事件回调的方式通知给上层应用,上层应用需要处理ITMG_MAIN_EVENT_TYPE_EXIT_ROOM事件。
C++
Java
Object-C
// 重载OnEvent函数
void OnEvent(ITMG_MAIN_EVENT_TYPE eventType, const char* data) {
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_EXIT_ROOM: // 退房完成事件
// 退房完成
break;
}
}
// 重载OnEvent函数
public void OnEvent(ITMGType.ITMG_MAIN_EVENT_TYPE eventType, Intent data) {
switch (eventType) {
case ITMGType.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVENT_TYPE_EXIT_ROOM: // 退房完成事件
// 退房完成
break;
}
}
// 重载OnEvent函数
- (void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary *)data {
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_EXIT_ROOM: // 退房完成事件
// 退房完成
break;
}
}

步骤14:反初始化SDK

在使用完 GME 的相关功能之后可以调用 Uninit 接口反初始化 SDK。
注意:
如果您在调用 Uninit 接口后会立即停止调用 Poll,需要在停止之前主动调用一次 Poll,将 SDK 内部的事件都清空,不然会有事件积累在 SDK 内部。
C++
Java
Object-C
gmeContext = ITMGContextGetInstance();
gmeContext->Uninit();
gmeContext = ITMGContext.GetInstance(this);
gmeContext.Uninit();
gmeContext = [ITMGContext GetInstance];
[gmeContext Uninit];
至此,GME 的实时语音供就集成进您的应用中了,如需使用其他功能,可参见相关 API 文档。