本文介绍如何使用 ZIM SDK 和 ZIM Audio SDK 快速实现基本的语音消息发送与接收功能。
在实现“发送与接收语音消息”功能之前,请确保:
已在 ZEGO 控制台 创建项目,获取到了接入 ZIM SDK 服务所需的 AppID、AppSign。ZIM 服务权限不是默认开启的,使用前,请先在 ZEGO 控制台 自助开通 ZIM 服务(详情请参考控制台的 服务配置 - 即时通讯 - 开通服务),若无法开通 ZIM 服务,请联系 ZEGO 技术支持开通。
已集成 ZIM SDK,详情请参考 快速开始 - 实现基本收发消息 的 “2 集成 SDK”。
已集成 ZIM Audio SDK,详情请参考 语音组件 - 集成 SDK。
用户发送与接收语音消息的过程主要包含录制音频、发送音频、接收音频和播放音频等环节。以客户端 A 和 B 的语音消息交互为例:
在项目文件中导入包。
import im.zego.zim_audio.ZIMAudio;
在使用 ZIM Audio SDK 其他接口前,请先调用 init 进行初始化。
在调用此接口时,如果您只希望实现最基础的语音消息收发,接口参数可以传空字符串。
如果您希望实现更多音频处理,请传入鉴权文件 License,如何获取 License,请参考 在线鉴权。
// 初始化 ZIM Audio SDK
// 本文描述的场景无需 License
String license = "";
ZIMAudio.getInstance().init(application, license);
创建一个继承 ZIMAudioEventHandler 抽象类的子类,并重写其中的方法。
import im.zego.zim_audio.callback.ZIMAudioEventHandler;
import im.zego.zim_audio.entity.ZIMAudioError;
public class ZIMAudioEventHandler extends ZIMAudioEventHandler {
@Override
public void onError(ZIMAudioError errorInfo) {
super.onError(errorInfo);
}
}
@end
调用 setEventHandler 设置该类的一个实例作为监听对象。
ZIMAudio.getInstance().setEventHandler(ZIMAudioEventHandlerImpl.getInstance());
消息发送客户端调用 startRecord 接口定义音频文件存放的本地绝对路径(需包含音频文件名称与后缀,如 xxx/xxx/xxx.m4a,仅支持 .m4a 和 .mp3)和录制时长上限,开始录制音频文件。
ZIMAudioRecordConfig config = new ZIMAudioRecordConfig();
config.maxDuration = 10 * 1000; // 音频的最大录制时长,单位为 ms。
// 默认为 60000 ms(即 60 秒)。最大值不超过 120000 ms(即 120 秒)。
// 此处示例表示 10 个 1000 ms(即 10 秒)。
config.filePath = ""; // 音频文件预期存放的本地绝对路径并携带文件后缀名(仅支持 .m4a 和 .mp3),如 xxx/xxx/xxx.m4a
ZIMAudio.getInstance().startRecord(config);
触发相关回调。
开始录制后,消息发送客户端可以监听 onRecorderStarted 回调,用于更新 UI。
public void onRecorderStarted() {}
ZIM Audio SDK 会每 500 毫秒通过 onRecorderProgress 回调一次进度通知,说明已录制的音频文件时长,此信息可用于 UI 更新 。
public void onRecorderProgress(int currentDuration) {}
在录音开始时或在录音过程中,如果因异常导致录音失败,ZIM Audio SDK 将会通过 onRecorderFailed 进行通知,消息发送客户端可以监听该回调并参考 ZIM Audio 错误码文档 处理失败事件。
public void onRecorderFailed(ZIMAudioErrorCode errorCode) {}
如需结束录制音频,请调用 completeRecord 接口。
请在调用 completeRecord 接口之前,您已监听到 onRecorderStarted 回调,否则会导致本次录制取消,且收到录制时间过短的报错。
如果录制没有被 完成 或 取消,当录制时长达到时间上限时,ZIM Audio SDK 将会自动完成录制,并触发 onRecorderCompleted 回调。
ZIMAudio.getInstance().completeRecord();
收到 onRecorderCompleted 回调后,即可根据开始录制时传入的路径找到该音频文件。
public void onRecorderCompleted(int totalDuration) {} // totalDuration 为音频文件总时长,单位为毫秒
如需提前停止录音且不需要发送语音消息时,调用 cancelRecord 即可中断录制并删除该录制文件。
ZIMAudio.getInstance().cancelRecord();
调用 cancelRecord 接口后,将会触发 onRecorderCancelled 回调,消息发送客户端可监听该回调用于 UI 更新。
public void onRecorderCancelled() {}
如需在某一时刻检查当前是否正在录制中,可调用 isRecording 接口获取当前录制状态。
boolean isRecording = ZIMAudio.getInstance().isRecording();
实现此步骤前,请确认用户已 登录 ZIM。
当 onRecorderCompleted 触发后,消息发送客户端可以使用音频文件绝对路径构造 ZIMAudioMessage(ZIM 音频消息),并调用 sendMediaMessage 接口发送该消息,下列代码以在单聊会话中发送音频消息为例。
ZIMAudio.getInstance().setEventHandler(new ZIMAudioEventHandler() {
// 录制完成回调
@Override
public void onRecorderCompleted(int totalDuration) {
super.onRecorderCompleted(totalDuration);
// 将单位为毫秒的音频时长转换为 ZIM 需要的秒
int second = totalDuration / 1000;
// 构造 ZIM 音频消息
ZIMAudioMessage message = new ZIMAudioMessage("录制音频文件路径", second);
ZIMMessageSendConfig config = new ZIMMessageSendConfig();
// 在单聊会话中发送音频消息
ZIM.getInstance().sendMediaMessage(message, "单聊会话 ID", ZIMConversationType.PEER, config, new ZIMMediaMessageSentCallback() {
@Override
public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
if(errorInfo.code == ZIMErrorCode.SUCCESS){
//成功
}else{
//根据官网错误码表处理
}
}
@Override
public void onMessageAttached(ZIMMediaMessage message){
}
@Override
public void onMediaUploadingProgress(String fileUID, long currentFileSize, long totalFileSize, ZIMMediaMessage message) {
}
});
}
});
如需了解发送进度,请参考收发消息文档的 富媒体文件消息的发送进度回调。
实现此步骤前,请确认用户已 登录 ZIM。
根据会话类型(单聊、房间、群组),消息接收客户端监听 onReceivePeerMessage、onReceiveGroupMessage、onReceiveRoomMessage,接收语音消息的相关通知,然后可以调用 downloadMediaFile 接口,下载音频文件到本地。
下列代码描述在单聊会话接收并下载音频消息。
// 收到单聊消息时,将会触发 onReceivePeerMessage 回调
// 接收富媒体消息示例 - 单聊 接收富媒体消息
@Override
public void onReceivePeerMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromUserID) {
super.onReceivePeerMessage(zim, messageList, fromUserID);
// 遍历收到的消息列表
for (ZIMMessage message : messageList) {
// 收到消息时,可通过消息的 Type 进行判断接收到何种类型的消息
// 如果消息类型为音频消息
if (message.getType() == ZIMMessageType.AUDIO) {
// 获取音频消息
ZIMAudioMessage audioMessage = (ZIMAudioMessage) message;
zim.downloadMediaFile(imageMessage, ZIMMediaFileType.ORIGINAL_FILE, new ZIMMediaDownloadedCallback() {
@Override
public void onMediaDownloaded(ZIMMediaMessage message, ZIMError errorInfo) {
if(errorInfo.code == ZIMErrorCodeSuccess){
message.fileLocalPath; // 下载成功,获取音频文件本地绝对路径
}else{
// 下载失败,根据 ZIM 官网错误码表处理失败事件
}
}
@Override
// 此处获取音频文件下载进度
public void onMediaDownloadingProgress(ZIMMediaMessage message, long currentFileSize, long totalFileSize) {
// 下载进度回调
}
});
}
}
}
如需了解下载进度,请参考收发消息文档的 富媒体文件消息的下载进度回调。
消息接收客户端调用 startPlay 接口,传入音频文件的本地绝对路径,设置音频输出的路由类型,开始播放音频文件。
// 开始播放音频
// 构造播放设置
ZIMAudioPlayConfig config = new ZIMAudioPlayConfig();
/ **
* ZIMAudioRouteTypeSpeaker:扬声器播放
* ZIMAudioRouteTypeReceiver:听筒播放
*/
config.routeType = ZIMAudioRouteTypeSpeaker;
config.filePath = "";//填入音频文件的本地路径。
ZIMAudio.getInstance().startPlay(config);
触发相关回调。
监听回调 onPlayerStarted ,用于 UI 更新。
public void onPlayerStarted(int totalDuration) {} // totalDuration 为音频文件总时长,单位为毫秒
ZIM Audio SDK 会每 500 毫秒通过 onPlayerProgress 回调一次进度通知,说明已播放时长,此信息可用于 UI 更新 。
public void onPlayerProgress(int currentDuration) {}
在播放开始时或在播放过程中,如果因异常导致播放失败,ZIM Audio SDK 将会通过 onPlayerFailed 进行通知,消息接收客户端可以监听该回调并参考 ZIM Audio 错误码文档 处理失败事件。
public void onPlayerFailed(ZIMAudioErrorCode errorCode) {}
若因其他操作(如在播放期间开始录音、在播放期间接收到系统的来电事件、在播放期间音频设备被其他应用抢占等情况。)导致播放终端,ZIM Audio SDK 将回调 onPlayerInterrupted。
public void onPlayerInterrupted() {}
播放完成时,ZIM Audio SDK 将会回调 onPlayerEnded。
public void onPlayerEnded() {}
(可选)如需在播放过程中切换音频输出设备(扬声器或听筒),请调用 setAudioRouteType 。
若用户已连接耳机,该接口调用将不会生效,音频输出仍将通过耳机进行。
// 设置输出设备为扬声器
ZIMAudio.getInstance().setAudioRouteType(ZIMAudioRouteType.SPEAKER);
如需中断播放,请调用 stopPlay 接口。
ZIMAudio.getInstance().stopPlay();
监听 onPlayerStopped 回调,更新 UI。停止播放或播放完成后,ZIM Audio SDK 将释放对音频设备的占用。
public void onPlayerStopped() {}
如果用户彻底不使用语音功能,可调用 uninit 释放资源。
ZIMAudio.getInstance().uninit();
联系我们
文档反馈