这里对GME服务不做过多介绍,感兴趣的自己去官网查阅相关内容。
GME官网地址:游戏多媒体引擎GME_游戏语音_一站式游戏语音解决方案_腾讯云
开发环境
UE4.26.2源码版
GME SDK 2.9.1(从官方下载的SDK,这里有一个SDK的坑,后面会说到)。
备注:下载SDK不用进行付费,但是进行项目对接需要一个APPID和APPKEY,这个需要购买服务后才会有,具体怎么在GME服务上建立这些信息,见官网
GME建立新项目获取APPID和APPKEY:登录 - 腾讯云
GME对于4.26以上的版本需要下载一个适配文件,用于解决编译错误,这个在官方也有说明。
有需要可以评论邮箱,后面我放在网盘或者云上再更新地址。
其他应该就没什么要准备或者下载了。
开发思路
一般这种对接SDK都会有一套固定的流程和模板,思路其实很好确定,直接上图
其实接这类SDK难点不在于思路,在于写完代码到跑通的整个过程,我是半天左右写完代码,但是调试整个流程用了两天左右,后面会一一阐述我遇到的坑。
-----------------------下面就开始开发吧!!!
开发过程
切记切记切记!!!一定要常用官方的错误代码。
类型的问题
在我满怀斗志的写完配置代码,还自以为是的把demo中的std::string类型转换成FString,直接上代码:
这是demo中的代码例子,全部用的是std::string,这里主要是因为引擎提供FString,能用引擎的基础类型就不用c++的那套,这是之前的开发经验,没想到在这里翻车了。
std::string VoiceChatUserConfig::GetAppID() {
FString appID;
GConfig->GetString(*VoiceChatUserSection, TEXT("AppID"), appID, GGameIni);
if (appID.IsEmpty())
{
appID = DEFAULT_APPID;
}
return TCHAR_TO_UTF8(*appID);;
在这里把所有的std::string都替换完成之后,并做了类型统一,突然发现官方有一个明确建议,进入房间的参数尽量用string类型,好嘛,全部推倒重来,改回去,又花了一两个小时。
官方建议,直接上表
参数 | 类型 | 含义 |
---|---|---|
dwSdkAppID | int | 来自腾讯云控制台的 AppId 号码 |
strRoomID | char* | 房间号,最大支持127字符 |
strOpenID | char* | 用户标识。与 Init 时候的 openID相同。 |
strKey | char* | 来自腾讯云 控制台 的权限密钥 |
strAuthBuffer | char* | 返回的 authbuff |
bufferLength | int | 传入的 authbuff 长度,建议为 500 |
所以在直接调用SDK的那一层的地方全部用std::string的形式,然后在逻辑层进行转换即可。
SDK版本问题
在我测试整个流程的时候,一直出现一个报错
failed to use AAC Codec due to libgmefdkaac library load failuer。
这个接过第三方库的都知道,是缺少库文件,但是我用的是官方的SDK怎么会缺少库文件,在我和官方客服了解过情况之后,发现了问题。
因为现在官方提供的公开下载的SDK只可以提供流畅音质,
//enter room default quantity is FLUENCY
void EnterRoom(std::string roomID, ITMG_ROOM_TYPE roomType=ITMG_ROOM_TYPE::ITMG_ROOM_TYPE_FLUENCY);
这个是决定进入房间的音质,如果需要设置标准和高品质的语音音质,需要联系官方工作人员。
还有一个SDK版本不统一的问题,错误码是“7015”,也是由于SDK替换不完整导致的,这里建议将Plugin目录下的文件和依赖全部删除,然后重新复制进去。
POLL的定时调用问题
这个函数很重要很重要
void UVoiceChatModule::UpdateGME()
{
ITMGContextGetInstance()->Poll();
//GEngine->AddOnScreenDebugMessage(INDEX_NONE, 10.0f, FColor::Yellow, TEXT("UpdateGME"));
}
GetWorld()->GetTimerManager().SetTimer(GME_TIMER_HANDLE, this, &UVoiceChatModule::UpdateGME, 0.01f, true);
这边我是挂载到init函数上面,当玩家登录之后,启动这个定时器,进行定时调用poll函数,这里是为了保证GME的回调函数正常。
顺便说一句,所有GME的SDK接口调用都建议在主线程上。
如何确定是否在主线程?
主要在调用SDK的函数里打个断点,看最上层是不是从main入口进来即可。
开关麦克风的时机问题
这个问题也是困扰了我几个小时,在每个阶段我都打印log日志,发现所有返回结果都正常,但是两个玩家进入同一个房间就是听不见语音。
这里的主要问题就是:开关麦克风必须等进入房间回调完成。而我当时为了测试,就把开关麦克风直接写在了进入房间之后,这里正确的调用时机。
if (eventType == ITMG_MAIN_EVENT_TYPE_ENTER_ROOM)
{
int32 result = JsonObject->GetIntegerField(TEXT("result"));
FString error_info = JsonObject->GetStringField(TEXT("error_info"));
if (result == 0)
{
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 20.0f, FColor::Yellow, TEXT("Enter room success."));
//test here :enter room success open the mic and speaker
OnCheckMic(true);
OnCheckSpeaker(true);
}
else
{
FString msg = FString::Printf(TEXT("Enter room failed. result=%d, info = %ls"), result, *error_info);
GEngine->AddOnScreenDebugMessage(INDEX_NONE, 20.0f, FColor::Yellow, *msg);
}
//enter room success
OnEnterRoomCompleted(result, error_info);
}