Unity3D 实现简单的语音聊天 iOS版本

2016年12月06日 14:52 0 点赞 0 评论 更新于 2025-11-21 20:58
Unity3D 实现简单的语音聊天 iOS版本

如今,许多手机游戏的聊天系统都加入了语音聊天功能。相较于传统的文字聊天,语音聊天在 MMORPG 游戏中显得尤为重要,毕竟直接口头交流比打字更快、更直观。

实现语音聊天的方法众多,在 Unity3D(U3D)中有不少第三方插件,它们提供了强大的语音功能。由于本文旨在从原生开发的角度实现一个简单的语音聊天功能,因此不具体列举这些插件。

语音聊天流程概述

语音聊天的大致流程如下:客户端录制语音数据,对其进行编码转换和数据压缩,然后将语音数据发送到语音服务器,语音服务器负责进行派发(语音服务器也可对语音进行翻译)。当客户端请求或接收到语音服务器推送的语音数据后,对数据进行解压,转换为可播放的编码,最后进行播放。

本文仅探讨客户端的处理,关于语音服务器的搭建、语音数据的压缩和发送等内容,暂不详细展开。

可能遇到的问题及解决方案

1. U3D C# 与 iOS 的 OC 之间的通讯

U3D C# 与 iOS 的 OC 之间的通讯和与 Android 的通讯有所不同。C# 与 OC 通讯类似于将非托管的动态库导入 C# 中。

在 OC 中添加一个 C++ 接口:

extern "C" void __SendOCMessage(const char* methodName, const char* arg0, const char* arg1);

在 C# 中引入该接口:

private const string IOSSDKDLL = "__Internal";
#if UNITY_IPHONE
[DllImport(IOSSDKDLL, CallingConvention = CallingConvention.Cdecl)]
public static extern void __SendSDKMessage(string methodName, string arg0, string arg1);
#endif

通过上述设置,就可以在 C# 中向 OC 发送消息,所有消息都可通过该接口发送,只需根据参数 methodName 执行相应模块。

若 OC 想向 C# 发送消息,可以调用 U3D 提供的 OC 接口:

extern void UnitySendMessage(const char *, const char *, const char *);

其中,第一个参数是场景中的 GameObject 名字,第二个参数是组件中的方法名字,第三个参数是任意的消息参数。

2. iOS 调用原生的录音功能和播放功能

在 iOS 中调用原生的录音和播放功能,需要引入 AVFoundation 库:

#import <AVFoundation/AVFoundation.h>

我们会使用 AVAudioRecorderAVAudioPlayer 这两个类,分别用于录音和播放。

录音功能(AVAudioRecorder)

以下是创建录音实例并进行录音的代码:

// 创建录音文件保存路径
NSURL *url = [NSURL URLWithString:voiceDataPath];

// 创建录音格式设置
NSDictionary *setting = [NSMutableDictionary dictionary];

// 设置录音格式
[setting setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];

// 设置录音采样率,一般采用 8000,太低失真比较严重
[setting setObject:@(8000) forKey:AVSampleRateKey];

// 设置通道,单通道
[setting setObject:@(1) forKey:AVNumberOfChannelsKey];

// 每个采样点位数,分为 8、16、24、32,这里采用 16 位
[setting setObject:@(16) forKey:AVLinearPCMBitDepthKey];

// 是否使用浮点数采样
[setting setObject:@(YES) forKey:AVLinearPCMIsFloatKey];

// 创建录音机
NSError *error = nil;
AVAudioRecorder *audioRecorder = [[AVAudioRecorder alloc] initWithURL:url settings:setting error:&error];

[audioRecorder record];

// 停止录音的时候,调用 Stop 接口
[audioRecorder stop];

播放功能(AVAudioPlayer)

以下是创建音频播放器实例并进行播放的代码:

NSURL *url = [NSURL URLWithString:voiceDataPath];
NSError *error = nil;
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];

audioPlayer.numberOfLoops = 0;

// 设置播放声音
audioPlayer.volume = 1;

// 播放
[audioPlayer prepareToPlay];

// 停止播放
[audioPlayer stop];

结合上述代码,整个录音和播放的流程如下:

  • 录音时,U3D 向 iOS 发送消息,创建 AVAudioRecorder 实例进行录音,并附带参数 voiceDataPath 作为录音文件的绝对路径。录音结束后,录音文件将保存在传入的 voiceDataPath 路径,并通知 U3D 录音完成。U3D 回调后,将数据发送给语音服务器。
  • 播放时,U3D 向语音服务器请求下载数据,下载完成后将数据存储在本地,然后向 iOS 发送消息,创建 AVAudioPlayer 实例进行播放,并附带参数 voiceDataPath 作为声音文件的路径。

通过封装 AVAudioPlayerAVAudioRecorder 的接口,就可以实现一个简单的语音聊天模块。

3. 编码转换问题

iOS 录制的音频格式为 wav,这种格式占用内存空间较大,不利于向语音服务器发送数据或下载。因此,需要将其转换为压缩的音频数据格式,以减少录音文件的大小,保证语音聊天的流畅体验。

ARM 格式是语音聊天中较好的压缩格式,但在 iOS 中不支持该格式的播放和转换。为此,需要引入一个转换类库 VoiceConverter,该类库可在 GitHub 上找到(具体链接将在随笔后面给出)。该类库提供了两个接口,可实现 arm 和 wav 的相互转换:

[VoiceConverter wavToAmr:wavPath amrSavePath:amrPath];
[VoiceConverter amrToWav:armPath wavSavePath:wavPath];

结合上述录音和播放流程,编码转换的具体操作如下:

  • 录音结束后,将 AVAudioRecorder 录制的 wav 格式的 voiceData 转换为 arm 格式,然后发送给语音服务器。
  • 从语音服务器下载 arm 格式的语音文件后,先将其转换为 wav 格式,再创建 AVAudioPlayer 对象进行播放。

总结

通过使用 iOS 原生 API 的 AVAudioPlayerAVAudioRecorder,可以实现客户端的语音录制和播放功能。结合语音服务器,即可在游戏中实现语音聊天功能。

关于语音翻译,由于本人接触较少,不清楚原生的 iOS API 是否提供翻译功能,也不确定是否有第三方库可用于语音翻译。据其他开发者介绍,语音翻译通常在语音服务器中完成,语音服务器调用第三方接口对语音进行异步翻译,完成后将结果推送给客户端。有兴趣的朋友可以自行探索,也欢迎留言分享相关信息。

需要注意的是,VoiceConverter 类库的 GitHub 链接将在后续补充。

作者信息

孟子菇凉

孟子菇凉

共发布了 3994 篇文章