为方便开发者调试和接入腾讯云游戏多媒体引擎产品 API,这里向您介绍 Native 工程快速接入文档。
GME 快速入门文档只提供最主要的接入接口,协助用户进行接入。
使用 GME 重要事项
GME 分为两个部分,提供实时语音服务、语音消息及转文本服务,使用这两个服务都依赖 Init 和 Poll 等核心接口。
关于 Init 接口
例如使用了实时语音服务,同时也需要使用语音消息服务,只需要调用一次 Init 初始化接口。
接口调用流程图
?
?
?接入步骤
核心接口
?初始化 GME?
实时语音
?加入实时语音房间?
?打开或关闭麦克风?
?打开或关闭扬声器?
?退出语音房间?
语音消息
?鉴权初始化?
?启动流式语音识别?
?停止录制?
?反初始化 GME?
核心接口接入
1. 下载 SDK
2. 引入头文件
import com.gme.TMG.ITMGContext;
#import "GMESDK/TMGEngine.h"#import "GMESDK/QAVAuthBuffer.h"
#include "auth_buffer.h"#include "tmg_sdk.h"
3. 获取单例
在使用语音功能时,需要首先获取 ITMGContext 对象。
函数原型
public static ITMGContext GetInstance(Context context)
+ (ITMGContext*) GetInstance;
static ITMGContext* ITMGContextGetInstance()
示例代码
//MainActivity.javaimport com.gme.TMG.ITMGContext;ITMGContext tmgContext = ITMGContext.GetInstance(this);
//TMGSampleViewController.mITMGContext* _context = [ITMGContext GetInstance];
ITMGContext* context = ITMGContextGetInstance();
4. 设置回调
接口类采用 Delegate 方法用于向应用程序发送回调通知。将回调函数注册给 SDK,用于接收回调的信息,需要在进房之前设置。
函数原型及示例代码
设置回调,用于接收回调的信息,需要在进房之前设置。
//ITMGContextpublic abstract int SetTMGDelegate(ITMGDelegate delegate);?//MainActivity.javatmgContext.SetTMGDelegate(TMGCallbackDispatcher.getInstance());
ITMGDelegate < NSObject >?//TMGSampleViewController.mITMGContext* _context = [ITMGContext GetInstance];_context.TMGDelegate = [DispatchCenter getInstance];
//在初始化 SDK 时候m_pTmgContext = ITMGContextGetInstance();m_pTmgContext->SetTMGDelegate(this);//在析构函数中CTMGSDK_For_AudioDlg::~CTMGSDK_For_AudioDlg(){ITMGContextGetInstance()->SetTMGDelegate(NULL);}
回调示例
在构造函数中重写此回调函数,对回调参数进行处理。
//MainActivity.javatmgContext.SetTMGDelegate(TMGCallbackDispatcher.getInstance());?//RealTimeVoiceActivity.javapublic 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.mTMGRealTimeViewController ()< 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 eventcase 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
5. 初始化 SDK
未初始化前,SDK 处于未初始化阶段,需要通过接口 Init 初始化 SDK,才可以使用实时语音服务、语音消息服务及转文本服务。调用 Init 接口的线程必须于其他接口在同一线程,建议都在主线程调用接口。
接口原型
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)
示例代码
//MainActivity.javaint nRet = tmgContext.Init(appId, openId);if (nRet == AV_OK ){// Step 4/11: Poll to trigger callback///document/product/607/15210#.E8.A7.A6.E5.8F.91.E4.BA.8B.E4.BB.B6.E5.9B.9E.E8.B0.83EnginePollHelper.createEnginePollHelper();showToast("Init success");}else if (nRet == AV_ERR_HAS_IN_THE_STATE) // 已经初始化过了,可以认为本次操作是成功的{showToast("Init success");}else{showToast("Init error errorCode:" + nRet);}
//TMGSampleViewController.mQAVResult 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. 触发事件回调
6. 触发事件回调
通过在 update 里面周期的调用 Poll 可以触发事件回调。Poll 是 GME 的消息泵,GME 需要周期性的调用 Poll 接口触发事件回调。如果没有调用 Poll ,将会导致整个 SDK 服务运行异常。详情请参见 Sample Project 中的 EnginePollHelper 文件。
示例代码
//MainActivity.javaEnginePollHelper.createEnginePollHelper();?//EnginePollHelper.javaprivate Handler mhandler = new Handler();private Runnable mRunnable = new Runnable() {@Overridepublic 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 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 |
示例代码
//GMEAuthBufferHelper.javaimport com.tencent.av.sig.AuthBuffer;//头文件public byte[] createAuthBuffer(String roomId){byte[] authBuffer;// 生成鉴权秘钥,在开发调试阶段可以使用GME SDK提供的接口生成;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提供的接口生成;?//实时语音鉴权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提供的接口生成;unsigned int bufferLen = 512;unsigned char retAuthBuff[512] = {0};QAVSDK_AuthBuffer_GenAuthBuffer(atoi(SDKAPPID3RD), roomId, "10001", AUTHKEY,retAuthBuff,bufferLen);
实时语音接入
1. 加入房间
1. 加入房间
用生成的鉴权信息进房,加入房间默认不打开麦克风及扬声器。返回值为 AV_OK 的时候代表调用成功,不代表进房成功。
接口原型
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[] | 鉴权码 |
示例代码
//RealTimeVoiceActivity.javabyte[] 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 函数中进行判断回调后处理。如果回调为成功,即此时进房成功,开始进行计费。
示例代码:回调处理相关参考代码,包括加入房间事件以及断网事件。
//RealTimeVoiceActivity.javapublic 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 eventint 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 eventcase 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. 开启或关闭麦克风
2. 开启或关闭麦克风
此接口用来开启关闭麦克风。加入房间默认不打开麦克风及扬声器。
示例代码
//RealTimeVoiceActivity.javaITMGContext.GetInstance(this).GetAudioCtrl().EnableMic(true);
//TMGRealTimeViewController.m[[[ITMGContext GetInstance] GetAudioCtrl] EnableMic:YES];
ITMGContextGetInstance()->GetAudioCtrl()->EnableMic(true);
3. 开启或关闭扬声器
3. 开启或关闭扬声器
此接口用于开启关闭扬声器。
示例代码
//RealTimeVoiceActivity.javaITMGContext.GetInstance(this).GetAudioCtrl().EnableSpeaker(true);
//TMGRealTimeViewController.m[[[ITMGContext GetInstance] GetAudioCtrl] EnableSpeaker:YES];
ITMGContextGetInstance()->GetAudioCtrl()->EnableSpeaker(true);
4. 退出房间
4. 退出房间
通过调用此接口可以退出所在房间。需等待退房回调并进行处理。
示例代码
//RealTimeVoiceActivity.javaITMGContext.GetInstance(this).ExitRoom();
//TMGRealTimeViewController.m[[ITMGContext GetInstance] ExitRoom];
ITMGContext* context = ITMGContextGetInstance();context->ExitRoom();
退出房间回调
退出房间完成后会有回调,消息为 ITMG_MAIN_EVENT_TYPE_EXIT_ROOM。示例代码如下:
//RealTimeVoiceActivity.javapublic 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. 鉴权初始化
1. 鉴权初始化
在初始化 SDK 之后调用鉴权初始化,authBuffer 的获取参见上文实时语音鉴权信息接口 genAuthBuffer。
接口原型
public abstract int ApplyPTTAuthbuffer(byte[] authBuffer);
-(QAVResult)ApplyPTTAuthbuffer:(NSData *)authBuffer;
ITMGPTT virtual int ApplyPTTAuthbuffer(const char* authBuffer, int authBufferLen)
参数 | 类型 | 含义 |
authBuffer | String | 鉴权 |
示例代码
//VoiceMessageRecognitionActivity.javabyte[] authBuffer = GMEAuthBufferHelper.getInstance().createAuthBuffer("");ITMGContext.GetInstance(this).GetPTT().ApplyPTTAuthbuffer(authBuffer);
//TMGPTTViewController.mNSData* 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. 启动流式语音识别
2. 启动流式语音识别
此接口用于启动流式语音识别,同时在回调中会有实时的语音转文字返回。停止录音调用 StopRecording,停止之后才有回调。
接口原型
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 | 存放的语音路径 |
示例代码
//VoiceMessageRecognitionActivity.javaITMGContext.GetInstance(this).GetPTT().StartRecordingWithStreamingRecognition(recordfilePath);
//TMGPTTViewController.mQAVResult 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天 |
示例代码
//VoiceMessageRecognitionActivity.javaimport 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 eventmIsRecording = 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. 停止录音
3. 停止录音
此接口用于停止录音。此接口为异步接口,停止录音后会有录音完成回调,成功之后录音文件才可用。
接口原型
public abstract int StopRecording();
-(QAVResult)StopRecording;
ITMGPTT virtual int StopRecording();
示例代码
//VoiceMessageRecognitionActivity.javaITMGContext.GetInstance(this).GetPTT().StopRecording();
//TMGPTTViewController.m?- (void)stopRecClick {// Step 3/12 stop recording, need handle ITMG_MAIN_EVNET_TYPE_PTT_RECORD_COMPLETE event// /document/product/607/15221#.E5.81.9C.E6.AD.A2.E5.BD.95.E9.9F.B3QAVResult ret = [[[ITMGContext GetInstance] GetPTT] StopRecording];if (ret == 0) {self.currentStatus = @"停止录音";} else {self.currentStatus = @"停止录音失败";}}
ITMGContextGetInstance()->GetPTT()->StopRecording();
?