有奖捉虫:办公协同&微信生态&物联网文档专题 HOT
为方便开发者调试和接入腾讯云游戏多媒体引擎产品 API,这里向您介绍 Native 工程快速接入文档。
GME 快速入门文档只提供最主要的接入接口,协助用户进行接入。

使用 GME 重要事项

GME 分为两个部分,提供实时语音服务、语音消息及转文本服务,使用这两个服务都依赖 Init 和 Poll 等核心接口。
关于 Init 接口
例如使用了实时语音服务,同时也需要使用语音消息服务,只需要调用一次 Init 初始化接口

接口调用流程图


image



接入步骤

核心接口

实时语音

语音消息

核心接口接入

1. 下载 SDK

进入下载指引页面,下载对应的 客户端 SDK

2. 引入头文件

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

3. 获取单例

在使用语音功能时,需要首先获取 ITMGContext 对象。

函数原型

Java
Object-C
C++
public static ITMGContext GetInstance(Context context)
+ (ITMGContext*) GetInstance;
static ITMGContext* ITMGContextGetInstance()

示例代码

Java
Object-C
C++
//MainActivity.java
import com.gme.TMG.ITMGContext;
ITMGContext tmgContext = ITMGContext.GetInstance(this);
//TMGSampleViewController.m
ITMGContext* _context = [ITMGContext GetInstance];
ITMGContext* context = ITMGContextGetInstance();

4. 设置回调

接口类采用 Delegate 方法用于向应用程序发送回调通知。将回调函数注册给 SDK,用于接收回调的信息,需要在进房之前设置。

函数原型及示例代码

设置回调,用于接收回调的信息,需要在进房之前设置。
Java
Object-C
C++
//ITMGContext
public abstract int SetTMGDelegate(ITMGDelegate delegate);

//MainActivity.java
tmgContext.SetTMGDelegate(TMGCallbackDispatcher.getInstance());
ITMGDelegate < NSObject >

//TMGSampleViewController.m
ITMGContext* _context = [ITMGContext GetInstance];
_context.TMGDelegate = [DispatchCenter getInstance];
//在初始化 SDK 时候
m_pTmgContext = ITMGContextGetInstance();
m_pTmgContext->SetTMGDelegate(this);
//在析构函数中
CTMGSDK_For_AudioDlg::~CTMGSDK_For_AudioDlg()
{
ITMGContextGetInstance()->SetTMGDelegate(NULL);
}

回调示例

在构造函数中重写此回调函数,对回调参数进行处理。
Java
Object-C
C++
//MainActivity.java
tmgContext.SetTMGDelegate(TMGCallbackDispatcher.getInstance());

//RealTimeVoiceActivity.java
public void OnEvent(ITMGContext.ITMG_MAIN_EVENT_TYPE type, Intent data) {
if (type == ITMG_MAIN_EVENT_TYPE_ENTER_ROOM)
{
//回调处理
}
}

//需要参考 TMGCallbackDispatcher.java、TMGCallbackHelper.java以及 TMGDispatcherBase.java
//TMGRealTimeViewController.m
TMGRealTimeViewController ()< ITMGDelegate >


- (void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary *)data {
NSString *log = [NSString stringWithFormat:@"OnEvent:%d,data:%@", (int)eventType, data];
[self showLog:log];
NSLog(@"====%@====", log);
switch (eventType) {
// Step 6/11 : Perform the enter room event
case ITMG_MAIN_EVENT_TYPE_ENTER_ROOM: {
int result = ((NSNumber *)[data objectForKey:@"result"]).intValue;
NSString *error_info = [data objectForKey:@"error_info"];

[self showLog:[NSString stringWithFormat:@"OnEnterRoomComplete:%d msg:(%@)", result, error_info]];

if (result == 0) {
[self updateStatusEnterRoom:YES];
}
}
break;

}
}

//需要参考 DispatchCenter.h、DispatchCenter.m
//头文件中声明
virtual void OnEvent(ITMG_MAIN_EVENT_TYPE eventType,const char* data);
//示例代码
void CTMGSDK_For_AudioDlg::OnEvent(ITMG_MAIN_EVENT_TYPE eventType, const char* data)
{
switch(eventType)
{
case ITMG_MAIN_EVENT_TYPE_XXXX_XXXX:
{
//对回调进行处理
}
break;
}
}
参数
类型
含义
type
ITMGContext.ITMG_MAIN_EVENT_TYPE
回调的事件类型
data
Intent 消息类型
回调的相关信息,事件数据

5. 初始化 SDK

未初始化前,SDK 处于未初始化阶段,需要通过接口 Init 初始化 SDK,才可以使用实时语音服务、语音消息服务及转文本服务。调用 Init 接口的线程必须于其他接口在同一线程,建议都在主线程调用接口。

接口原型

Java
Object-C
C++
public abstract int Init(String sdkAppId, String openId);
-(int)InitEngine:(NSString*)sdkAppID openID:(NSString*)openID;
ITMGContext virtual int Init(const char* sdkAppId, const char* openId)
参数
类型
含义
sdkAppId
string
来自 腾讯云控制台 的 GME 服务提供的 AppID,获取请参见 服务开通指引
openID
string
openID 只支持 Int64 类型(转为 string 传入),规则由 App 开发者自行制定,App 内不重复即可。如需使用字符串作为 Openid 传入,可 提交工单 联系开发者。

示例代码

Java
Object-C
C++
//MainActivity.java
int nRet = tmgContext.Init(appId, openId);
if (nRet == AV_OK )
{
// Step 4/11: Poll to trigger callback
//https://cloud.tencent.com/document/product/607/15210#.E8.A7.A6.E5.8F.91.E4.BA.8B.E4.BB.B6.E5.9B.9E.E8.B0.83
EnginePollHelper.createEnginePollHelper();
showToast("Init success");
}else if (nRet == AV_ERR_HAS_IN_THE_STATE) // 已经初始化过了,可以认为本次操作是成功的
{
showToast("Init success");
}else
{
showToast("Init error errorCode:" + nRet);
}
//TMGSampleViewController.m
QAVResult result = [_context InitEngine:self.appIDTF.text openID:self.openIDTF.text];
if (result == QAV_OK) {
self.isSDKInit = YES;
}
#define SDKAPPID3RD "14000xxxxx"
cosnt char* openId="10001";
ITMGContext* context = ITMGContextGetInstance();
context->Init(SDKAPPID3RD, openId);

6. 触发事件回调

通过在 update 里面周期的调用 Poll 可以触发事件回调。Poll 是 GME 的消息泵,GME 需要周期性的调用 Poll 接口触发事件回调。如果没有调用 Poll ,将会导致整个 SDK 服务运行异常。详情请参见 Sample Project 中的 EnginePollHelper 文件。

示例代码

Java
Object-C
C++
//MainActivity.java
EnginePollHelper.createEnginePollHelper();

//EnginePollHelper.java
private Handler mhandler = new Handler();
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
if (s_pollEnabled) {
if (ITMGContext.GetInstance(null) != null)
ITMGContext.GetInstance(null).Poll();
}
mhandler.postDelayed(mRunnable, 33);
}
};
//周期性调用 Poll 请参考 EnginePollHelper.java 写法
//TMGSampleViewController.m
[EnginePollHelper createEnginePollHelper];
//需要参考 EnginePollHelper.m 以及 EnginePollHelper.h
void TMGTestScene::update(float delta)
{
ITMGContextGetInstance()->Poll();
}

7. 本地鉴权计算

生成 AuthBuffer,用于相关功能的加密和鉴权,如正式发布请使用后台部署密钥,后台部署请参见 鉴权密钥

接口原型

Java
Object-C
C++
AuthBuffer public native byte[] genAuthBuffer(int sdkAppId, String roomId, String openId, String key)
//TMGSampleViewController.m
[EnginePollHelper createEnginePollHelper];
//需要参考 EnginePollHelper.m 以及 EnginePollHelper.h
void TMGTestScene::update(float delta)
{
ITMGContextGetInstance()->Poll();
}
参数
类型
含义
appId
int
来自腾讯云控制台的 AppId 号码。
roomId
string
房间号,最大支持127字符(离线语音房间号参数必须填 null)。
openId
string
用户标识。与 Init 时候的 openId 相同。
key
string
来自腾讯云 控制台 的权限密钥。

示例代码

Java
Object-C
C++
//GMEAuthBufferHelper.java
import com.tencent.av.sig.AuthBuffer;//头文件
public byte[] createAuthBuffer(String roomId)
{
byte[] authBuffer;
// 生成鉴权秘钥,在开发调试阶段可以使用GME SDK提供的接口生成;
// 应用正式发布时建议使用服务器生成,可参考https://cloud.tencent.com/document/product/607/12218
if (TextUtils.isEmpty(roomId))
{
authBuffer = AuthBuffer.getInstance().genAuthBuffer(Integer.parseInt(mAppId), "0", mOpenId, mKey);
}else
{
authBuffer = AuthBuffer.getInstance().genAuthBuffer(Integer.parseInt(mAppId), roomId, mOpenId, mKey);
}
return authBuffer;
}
// 生成鉴权秘钥,在开发调试阶段可以使用GME SDK提供的接口生成;
// 应用正式发布时建议使用服务器生成,可参考https://cloud.tencent.com/document/product/607/12218

//实时语音鉴权
NSData* authBuffer = [QAVAuthBuffer GenAuthBuffer:SDKAPPID3RD.intValue roomID:self.roomIdTF.text openID:_openId key:_key];
//语音消息鉴权
NSData* authBuffer = [QAVAuthBuffer GenAuthBuffer:(unsigned int)SDKAPPID3RD.integerValue roomID:nil openID:self.openId key:AUTHKEY];
// 生成鉴权秘钥,在开发调试阶段可以使用GME SDK提供的接口生成;
// 应用正式发布时建议使用服务器生成,可参考https://cloud.tencent.com/document/product/607/12218
unsigned int bufferLen = 512;
unsigned char retAuthBuff[512] = {0};
QAVSDK_AuthBuffer_GenAuthBuffer(atoi(SDKAPPID3RD), roomId, "10001", AUTHKEY,retAuthBuff,bufferLen);

实时语音接入

1. 加入房间

用生成的鉴权信息进房,加入房间默认不打开麦克风及扬声器。返回值为 AV_OK 的时候代表调用成功,不代表进房成功。

接口原型

Java
Object-C
C++
public abstract int EnterRoom(String roomID, int roomType, byte[] authBuffer);
-(int)EnterRoom:(NSString*) roomId roomType:(int)roomType authBuffer:(NSData*)authBuffer;
ITMGContext virtual int EnterRoom(const char* roomID, ITMG_ROOM_TYPE roomType, const char* authBuff, int buffLen);
参数
类型
含义
roomId
String
房间号,最大支持127字符
roomType
int
请使用 FLUENCY 类型音质进入房间
authBuffer
byte[]
鉴权码

示例代码

Java
Object-C
C++
//RealTimeVoiceActivity.java
byte[] authBuffer = GMEAuthBufferHelper.getInstance().createAuthBuffer(roomId);
ITMGContext.GetInstance(this).EnterRoom(roomId, roomType, authBuffer);
//TMGRealTimeViewController.m
[[ITMGContext GetInstance] EnterRoom:self.roomIdTF.text roomType:(int)self.roomTypeControl.selectedSegmentIndex + 1 authBuffer:authBuffer];
ITMGContext* context = ITMGContextGetInstance();
context->EnterRoom(roomID, ITMG_ROOM_TYPE_FLUENCY, (char*)retAuthBuff,bufferLen);

加入房间事件回调

加入房间完成后会发送信息 ITMG_MAIN_EVENT_TYPE_ENTER_ROOM,在 OnEvent 函数中进行判断回调后处理。如果回调为成功,即此时进房成功,开始进行计费
示例代码:回调处理相关参考代码,包括加入房间事件以及断网事件。
Java
Object-C
C++
//RealTimeVoiceActivity.java
public void OnEvent(ITMGContext.ITMG_MAIN_EVENT_TYPE type, Intent data) {
if (type == ITMG_MAIN_EVENT_TYPE_ENTER_ROOM)
{
// Step 6/11 : Perform the enter room event
int nErrCode = TMGCallbackHelper.ParseIntentParams2(data).nErrCode;
String strMsg = TMGCallbackHelper.ParseIntentParams2(data).strErrMsg;
if (nErrCode == AV_OK)
{
appendLog2MonitorView("EnterRomm success");
}else
{
appendLog2MonitorView(String.format(Locale.getDefault(), "EnterRomm errCode:%d errMsg:%s", nErrCode, strMsg));
}
}
}
//TMGRealTimeViewController.m

- (void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary *)data {
NSString *log = [NSString stringWithFormat:@"OnEvent:%d,data:%@", (int)eventType, data];
[self showLog:log];
NSLog(@"====%@====", log);
switch (eventType) {
// Step 6/11 : Perform the enter room event
case ITMG_MAIN_EVENT_TYPE_ENTER_ROOM: {
int result = ((NSNumber *)[data objectForKey:@"result"]).intValue;
NSString *error_info = [data objectForKey:@"error_info"];

[self showLog:[NSString stringWithFormat:@"OnEnterRoomComplete:%d msg:(%@)", result, error_info]];

if (result == 0) {
[self updateStatusEnterRoom:YES];
}
}
break;

}
void TMGTestScene::OnEvent(ITMG_MAIN_EVENT_TYPE eventType,const char* data){
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_ENTER_ROOM:
{
ListMicDevices();
ListSpeakerDevices();
std::string strText = "EnterRoom complete: ret=";
strText += data;
m_EditMonitor.SetWindowText(MByteToWChar(strText).c_str());
}
}
}
错误码
错误码值
原因及建议方案
7006
鉴权失败,原因如下:
AppID 不存在或者错误
authbuff 鉴权错误
鉴权过期
openId 不符合规范
7007
已经在其它房间
1001
已经在进房过程中,然后又重复了此操作。建议在进房回调返回之前不要再调用进房接口
1003
已经进房了在房间中,又调用一次进房接口
1101
确保已经初始化 SDK,确保 openId 是否符合规则,或者确保在同一线程调用接口,以及确保 Poll 接口正常调用

2. 开启或关闭麦克风

此接口用来开启关闭麦克风。加入房间默认不打开麦克风及扬声器。

示例代码

Java
Object-C
C++
//RealTimeVoiceActivity.java
ITMGContext.GetInstance(this).GetAudioCtrl().EnableMic(true);
//TMGRealTimeViewController.m
[[[ITMGContext GetInstance] GetAudioCtrl] EnableMic:YES];
ITMGContextGetInstance()->GetAudioCtrl()->EnableMic(true);

3. 开启或关闭扬声器

此接口用于开启关闭扬声器。

示例代码

Java
Object-C
C++
//RealTimeVoiceActivity.java
ITMGContext.GetInstance(this).GetAudioCtrl().EnableSpeaker(true);
//TMGRealTimeViewController.m
[[[ITMGContext GetInstance] GetAudioCtrl] EnableSpeaker:YES];
ITMGContextGetInstance()->GetAudioCtrl()->EnableSpeaker(true);

4. 退出房间

通过调用此接口可以退出所在房间。需等待退房回调并进行处理。

示例代码

Java
Object-C
C++
//RealTimeVoiceActivity.java
ITMGContext.GetInstance(this).ExitRoom();
//TMGRealTimeViewController.m
[[ITMGContext GetInstance] ExitRoom];
ITMGContext* context = ITMGContextGetInstance();
context->ExitRoom();

退出房间回调

退出房间完成后会有回调,消息为 ITMG_MAIN_EVENT_TYPE_EXIT_ROOM。示例代码如下:
Java
Object-C
C++
//RealTimeVoiceActivity.java
public void OnEvent(ITMGContext.ITMG_MAIN_EVENT_TYPE type, Intent data) {
if (ITMGContext.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVENT_TYPE_EXIT_ROOM == type)
{
//收到退房成功事件
}
}
//TMGRealTimeViewController.m
-(void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary *)data{
NSLog(@"OnEvent:%lu,data:%@",(unsigned long)eventType,data);
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_EXIT_ROOM:
{
//收到退房成功事件
}
break;
}
}
void TMGTestScene::OnEvent(ITMG_MAIN_EVENT_TYPE eventType,const char* data){
switch (eventType) {
case ITMG_MAIN_EVENT_TYPE_EXIT_ROOM:
{
//进行处理
break;
}
}
}

语音消息接入

1. 鉴权初始化

在初始化 SDK 之后调用鉴权初始化,authBuffer 的获取参见上文实时语音鉴权信息接口 genAuthBuffer。

接口原型

Java
Object-C
C++
public abstract int ApplyPTTAuthbuffer(byte[] authBuffer);
-(QAVResult)ApplyPTTAuthbuffer:(NSData *)authBuffer;
ITMGPTT virtual int ApplyPTTAuthbuffer(const char* authBuffer, int authBufferLen)
参数
类型
含义
authBuffer
String
鉴权

示例代码

Java
Object-C
C++
//VoiceMessageRecognitionActivity.java
byte[] authBuffer = GMEAuthBufferHelper.getInstance().createAuthBuffer("");
ITMGContext.GetInstance(this).GetPTT().ApplyPTTAuthbuffer(authBuffer);
//TMGPTTViewController.m
NSData* authBuffer = [QAVAuthBuffer GenAuthBuffer:(unsigned int)SDKAPPID3RD.integerValue roomID:nil openID:self.openId key:AUTHKEY];
[[[ITMGContext GetInstance] GetPTT] ApplyPTTAuthbuffer:authBuffer];
ITMGContextGetInstance()->GetPTT()->ApplyPTTAuthbuffer(authBuffer,authBufferLen);

2. 启动流式语音识别

此接口用于启动流式语音识别,同时在回调中会有实时的语音转文字返回。停止录音调用 StopRecording,停止之后才有回调。

接口原型

Java
Object-C
C++
public abstract int StartRecordingWithStreamingRecognition (String filePath);

public abstract int StopRecording();
-(int)StartRecordingWithStreamingRecognition:(NSString *)filePath;

-(QAVResult)StopRecording;
ITMGPTT virtual int StartRecordingWithStreamingRecognition(const char* filePath)

ITMGPTT virtual int StopRecording()
参数
类型
含义
filePath
String
存放的语音路径

示例代码

Java
Object-C
C++
//VoiceMessageRecognitionActivity.java
ITMGContext.GetInstance(this).GetPTT().StartRecordingWithStreamingRecognition(recordfilePath);
//TMGPTTViewController.m
QAVResult ret = [[[ITMGContext GetInstance] GetPTT] StartRecordingWithStreamingRecognition:[self pttTestPath]];
if (ret == 0) {
self.currentStatus = @"开始流式录音";
} else {
self.currentStatus = @"开始流式录音失败";
}
ITMGContextGetInstance()->GetPTT()->StartRecordingWithStreamingRecognition(filePath);

流式语音识别回调

启动流式语音识别后,需要在回调函数 OnEvent 中监听回调消息,事件消息分为 ITMG_MAIN_EVNET_TYPE_PTT_STREAMINGRECOGNITION_COMPLETE ,在停止录制并完成识别后才返回文字,相当于一段话说完才会返回识别的文字。
根据需求在 OnEvent 函数中对相应事件消息进行判断。传递的参数包含以下4个信息。
消息名称
含义
result
用于判断流式语音识别是否成功的返回码
text
语音转文字识别的文本
file_path
录音存放的本地地址
file_id
录音在后台的 url 地址,录音在服务器存放90天
示例代码
Java
Object-C
C++
//VoiceMessageRecognitionActivity.java
import static com.tencent.TMG.ITMGContext.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVNET_TYPE_PTT_STREAMINGRECOGNITION_COMPLETE;
public void OnEvent(ITMGContext.ITMG_MAIN_EVENT_TYPE type, Intent data) {
if (type == ITMG_MAIN_EVNET_TYPE_PTT_STREAMINGRECOGNITION_COMPLETE)
{
// Step 1.3/3 handle ITMG_MAIN_EVNET_TYPE_PTT_STREAMINGRECOGNITION_COMPLETE event
mIsRecording = false;
if (nErrCode ==0)
{
String recordfilePath = data.getStringExtra("file_path");
mRecFilePathView.setText(recordfilePath);

String recordFileUrl = data.getStringExtra("file_id");
mRecFileUrlView.setText(recordFileUrl);
}
else
{
appendLog2MonitorView("Record and recognition fail errCode:" + nErrCode);
}
}

}
//TMGPTTViewController.m

- (void)OnEvent:(ITMG_MAIN_EVENT_TYPE)eventType data:(NSDictionary*)data
{
NSNumber *number = [data objectForKey:@"result"];
switch (eventType)
{
case ITMG_MAIN_EVNET_TYPE_PTT_STREAMINGRECOGNITION_COMPLETE:
{
if (data != NULL &&[[data objectForKey:@"result"] intValue]== 0)
{
self.translateTF.text = [data objectForKey:@"text"] ;
self.currentStatus = @"流式转换完成";
}
}
break;
}
void TMGTestScene::OnEvent(ITMG_MAIN_EVENT_TYPE eventType,const char* data){
switch (eventType) {
case ITMG_MAIN_EVNET_TYPE_PTT_STREAMINGRECOGNITION_COMPLETE:
{
HandleSTREAM2TEXTComplete(data,true);
break;
}
...
case ITMG_MAIN_EVNET_TYPE_PTT_STREAMINGRECOGNITION_IS_RUNNING:
{
HandleSTREAM2TEXTComplete(data, false);
break;
}
}
}
void CTMGSDK_For_AudioDlg::HandleSTREAM2TEXTComplete(const char* data, bool isComplete)
{
std::string strText = "STREAM2TEXT: ret=";
strText += data;
m_EditMonitor.SetWindowText(MByteToWChar(strText).c_str());
Json::Reader reader;
Json::Value root;
bool parseRet = reader.parse(data, root);
if (!parseRet) {
::SetWindowText(m_EditInfo.GetSafeHwnd(),MByteToWChar(std::string("parse result Json error")).c_str());
}
else
{
if (isComplete) {
::SetWindowText(m_EditUpload.GetSafeHwnd(), MByteToWChar(root["file_id"].asString()).c_str());
}
else {
std::string isruning = "STREAMINGRECOGNITION_IS_RUNNING";
::SetWindowText(m_EditUpload.GetSafeHwnd(), MByteToWChar(isruning).c_str());
}
}
}
错误码
错误码
含义
处理方式
32775
流式语音转文本失败,但是录音成功
调用 UploadRecordedFile 接口上传录音,再调用 SpeechToText 接口进行语音转文字操作
32777
流式语音转文本失败,但是录音成功,上传成功
返回的信息中有上传成功的后台 url 地址,调用 SpeechToText 接口进行语音转文字操作
32786
流式语音转文本失败
在流式录制状态当中,请等待流式录制接口执行结果返回

3. 停止录音

此接口用于停止录音。此接口为异步接口,停止录音后会有录音完成回调,成功之后录音文件才可用。

接口原型

Java
Object-C
C++
public abstract int StopRecording();
-(QAVResult)StopRecording;
ITMGPTT virtual int StopRecording();

示例代码

Java
Object-C
C++
//VoiceMessageRecognitionActivity.java
ITMGContext.GetInstance(this).GetPTT().StopRecording();
//TMGPTTViewController.m

- (void)stopRecClick {
// Step 3/12 stop recording, need handle ITMG_MAIN_EVNET_TYPE_PTT_RECORD_COMPLETE event
// https://cloud.tencent.com/document/product/607/15221#.E5.81.9C.E6.AD.A2.E5.BD.95.E9.9F.B3
QAVResult ret = [[[ITMGContext GetInstance] GetPTT] StopRecording];
if (ret == 0) {
self.currentStatus = @"停止录音";
} else {
self.currentStatus = @"停止录音失败";
}
}
ITMGContextGetInstance()->GetPTT()->StopRecording();