Unity3D集成腾讯语音GVoiceSDK

友情提示:最近发现腾讯GVoice有另一个官网,叫做腾讯游戏服务,经过对比发现这个网站才是最新的,下面我介绍的那个估计是已经废弃的,但不知道为啥老的网站没有直接链接到新网址而是仍然保留了。不过新官网的文档更加详细,SDK也有所更新,所以建议去新官网下载SDK和Demo,接入流程基本没有啥大变化。

简述

我们项目中用到了实时语音功能,在最初语音 SDK 技术选型的时候测试过融云、声网和腾讯的 GVoice 。融云和声网我都在我们项目中使用过,但是效果都不如王者荣耀游戏中的实时语音效果,这两天好好研究了一下腾讯的 GVoice,终于成功集成。由于腾讯 GVoice 官网的接入流程并不是很详细,如果只懂 Unity3D 不懂 Android 基础知识的朋友,可能接入过程不会一帆风顺。我虽了解一点点 Android 基础,但仍趟过了好几个坑,下面我就分享一下我在 Android 平台接入 GVoice 的过程。

资源准备

进入腾讯GVoice官网下载 GVoice SDK 和 Unity3D Demo。如下图:

GVoice SDK.png

接入流程

1. 导入SDK

先创建一个空的 Unity 项目 GVoiceDemo,按照官网的接入流程,我们直接将下载的SDK压缩包解压后将其中的 Plugins 和 Scripts 两个文件夹都拷贝到 Unity 项目中。

2. 创建 Jar 包

将Unity项目导出成安卓项目,导出路径选择某个指定的文件夹,我这里在桌面新建了一个叫 unity_gvoicedemo 的文件夹,将项目导出到该文件夹中,操作如下图:

Export Project.png
导出成功后会生成 GCloudVoice 和 GVoiceDemo 两个文件夹,用 eclipse 将这两个项目一起导入,如下图

Import Projects.png

导入成功后,在 UnityPlayerActivity 项目下新建一个 MainActivity 类,继承自 UnityPlayerActivity,详细代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.shehweiwei.gvoicedemo;

import android.os.Bundle;

import com.tencent.gcloud.voice.GCloudVoiceEngine;
// 注意:下面这句代码必须有,如果没有可能会导致闪退
import com.unity3d.player.UnityPlayerActivity;

public class MainActivity extends UnityPlayerActivity
{
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
GCloudVoiceEngine.getInstance().init(getApplicationContext(), this);
}
}

注意:代码中一定要引入com.unity3d.player.UnityPlayerActivity这个包,如果没有引入则进入应用就闪退,这里是个大坑,我好不容易才爬出来。
然后,选中 MainActivity.java 文件,右键选择 Export -> Java -> JAR file, 然后点击 Next 按钮, 接下来操作如下图:

JAR Export.png

最后,生成一个 GVoiceDemo.jar 文件。

3. 导入其他文件

将下载的 unity_demo.zip 压缩包解压后将其中的 unity_demo\Assets\Plugins\Android 目录下的 AndroidManifest.xml 和 android-support-v4.jar 两个文件拷贝到项目的 Plugins\Android 目录下。注意还有个GCloudVoiceDemo.jar 文件我们没有拷贝,这里我们使用上一步创建的 GVoiceDemo.jar 文件来替代。注意 jar 包中的包名必须与 AndroidManifest.xml 文件和 Unity 编辑器中PlayerSettings的 Bundle Identifier 包名保持一致。所以,要把 AndroidManifest.xml 文件中的 package="com.example.gcloudu3ddemo" 这一句代码修改成 package="com.shehweiwei.gvoicedemo"

注意:AndroidManifest.xml 文件中的入口 Activity 的名字必须和创建的 Jar 包中的新建的 Activity 名字保持一致。这里的入口 Activity 叫 MainActivity,所以 AndroidManifest.xml 文件中的代码为android:name=".MainActivity",当然也可以写成 android:name="com.example.gcloudu3ddemo.MainActivity"

4. 构建Unity场景

这里我用uGUI搭建了一个简单的界面,有六个按钮分别调用 GVoice SDK 的六个 API ,然后一个 Text 用来显示回调结果。界面效果如下图:
Create UI.png
然后新建一个 GVoiceDemo 的 C# 脚本,脚本代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using UnityEngine;
using gcloud_voice;
using UnityEngine.UI;
using System;

public class GVoiceDemo : MonoBehaviour
{
// 用来显示调用API返回的结果
public Text result;

private IGCloudVoice m_voiceengine = null;

// TODO: 这里的appId和appKey使用的是官方提供的测试值,正式项目中可使用申请的值
private const string appId = "932849489";
private const string appKey = "d94749efe9fce61333121de84123ef9b";
// TODO: 这里使用的是测试账号,所以房间名使用默认的100,正式项目中可根据实际情况赋值
private string roomName = "100";

void Start()
{
if (m_voiceengine == null)
{
m_voiceengine = GCloudVoice.GetEngine();
TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
string strTime = System.Convert.ToInt64(ts.TotalSeconds).ToString();
// TODO: 这里用时间模拟了一个openId,在正式项目中应该把这里的strTime换成用户唯一ID
m_voiceengine.SetAppInfo(appId, appKey, strTime);
m_voiceengine.Init();

// 注册SDK常用回调监听
m_voiceengine.OnJoinRoomComplete += OnJoinRoom;
m_voiceengine.OnQuitRoomComplete += OnExitRoom;
m_voiceengine.OnMemberVoice += OnMemberVoice;
}
}

void Update()
{
if (m_voiceengine != null)
{
// 不断检测GVoice引擎回调
m_voiceengine.Poll();
}
}

void OnApplicationPause(bool pauseStatus)
{
if (m_voiceengine == null)
{
return;
}

// 应用暂停时GVoice引擎也暂停,应用重新开始时引擎继续
if (pauseStatus)
{
m_voiceengine.Pause();
}
else
{
m_voiceengine.Resume();
}
}

/// <summary>
/// 加入房间,BtnJoin按钮点击调用
/// </summary>
public void JoinRoom()
{
m_voiceengine.SetMode(GCloudVoiceMode.RealTime);
int ret = m_voiceengine.JoinTeamRoom(roomName, 15000);

result.text += "\nJoinRoom:" + ret;
}

/// <summary>
/// 退出房间,BtnExit按钮点击调用
/// </summary>
public void ExitRoom()
{
int ret = m_voiceengine.QuitRoom(roomName, 6000);
result.text += "\nExitRoom:" + ret;
}

/// <summary>
/// 打开麦克风,BtnOpenMic按钮点击调用
/// </summary>
public void OpenMic()
{
int ret = m_voiceengine.OpenMic();
result.text += "\nOpenMic:" + ret;
}

/// <summary>
/// 关闭麦克风,BtnCloseMic按钮点击调用
/// </summary>
public void CloseMic()
{
int ret = m_voiceengine.CloseMic();
result.text += "\nCloseMic:" + ret;
}

/// <summary>
/// 打开扬声器,BtnOpenSpeaker按钮点击调用
/// </summary>
public void OpenSpeaker()
{
int ret = m_voiceengine.OpenSpeaker();
result.text += "\nOpenSpeaker:" + ret;
}

/// <summary>
/// 关闭扬声器,BtnCloseSpeaker按钮点击调用
/// </summary>
public void CloseSpeaker()
{
int ret = m_voiceengine.CloseSpeaker();
result.text += "\nCloseSpeaker:" + ret;
}

/// <summary>
/// 加入房间回调
/// </summary>
/// <param name="code"></param>
/// <param name="roomName"></param>
/// <param name="memberID"></param>
private void OnJoinRoom(IGCloudVoice.GCloudVoiceCompleteCode code, string roomName, int memberID)
{
result.text += string.Format("\nOnJoinRoom ---> code: {0}, roomName: {1}, memberID: {2}", code, roomName, memberID);
}

/// <summary>
/// 退出房间回调
/// </summary>
/// <param name="code"></param>
/// <param name="roomName"></param>
/// <param name="memberID"></param>
private void OnExitRoom(IGCloudVoice.GCloudVoiceCompleteCode code, string roomName, int memberID)
{
result.text += string.Format("\nOnExitRoom ---> code: {0}, roomName: {1}, memberID: {2}", code, roomName, memberID);

m_voiceengine.OnJoinRoomComplete -= OnJoinRoom;
m_voiceengine.OnQuitRoomComplete -= OnExitRoom;
m_voiceengine.OnMemberVoice -= OnMemberVoice;
}

/// <summary>
/// 有成员说话时回调
/// </summary>
/// <param name="members"></param>
/// <param name="count"></param>
private void OnMemberVoice(int[] members, int count)
{
result.text += string.Format("\nOnMemberVoice ---> count: {0}, roomName: {1}, memberID: {2}", count);
}
}

将 GVoiceDemo 脚本添加到Canvas对象上,然后将脚本中对应的方法注册到对应的按钮的OnClick事件上,保存场景,然后运行到手机上,使用两个手机就可以语音聊天了,效果如下图:

App.png

其他事项

按照上面的流程集成完的项目并不能在PC上运行,如果要在PC上运行不报错,可以将下载的 unity_demo.zip 文件解压后的 unity_demo\Assets\Plugins 目录下的 X86 和 x86_64 两个文件夹拷贝到项目的 Plugins 文件夹下,这样PC上运行就不会报错。因为我这里没有麦克风设备,不知道在PC上能不能使用语音聊天,有条件的朋友可以试试,有结果了可以反馈给我,先谢过了!

项目源码

我把项目的源码托管在了Github上了, 有需要的朋友自取。项目链接点这里