范围语音

最近更新时间:2020-10-22 09:44:45

为方便开发者调试和接入腾讯云游戏多媒体引擎产品 API,这里向您介绍 GME 范围语音的接入技术文档。

GME 范围语音是专门为吃鸡类游戏开发的定制化产品。其有别于普通小队语音房间的核心能力为:

  1. 提供吃鸡类游戏、大逃杀类型游戏中特有的“仅小队”或“所有人”的语音模式。
  2. 依托于范围判断能力,在同一个语音房间内,支持大量用户同时打开麦克风进行语音通话。

基本概念

范围语音房间

使用范围语音,需要调用 SetRangeAudioTeamID 接口设置小队号 TeamID,再调用 EnterRoom 接口进入语音房间,即当进入语音房间时指定的 TeamID != 0 时,进入范围语音房间模式。

语音模式

当进入范围语音房间时,有两种语音模式可供选择:

语音模式 参数名称 功能
所有人 RANGE_AUDIO_MODE_WORLD 设置后玩家附近一定范围的人都能听到该玩家讲话,但不影响小队成员互相通话
仅小队 RANGE_AUDIO_MODE_TEAM 仅队友可以听到

不同的语音模式下,其具体的声音可达情况如下:
a. 同一小队内,无论距离多远、玩家为何种语音状态都能听见。
b. 不同小队情况下,双方开启“所有人”的语音状态情况下,在距离内可以互相听见。

说明:

具体玩家声音可达情况请参见 附录

语音距离范围

如果设置的语音模式为【所有人】(RANGE_AUDIO_MODE_WORLD),此时的语音可达范围受 UpdateAudioRecvRange 接口影响。

  • 是否在语音距离范围内,不影响同一小队成员互相通话。
  • 设置接收语音距离范围参考 API:UpdateAudioRecvRange。
  • 支持在范围语音房间中实时切换语音模式。但不支持在房间内更换 TeamID,TeamID 必须在进房前指定。
  • 使用范围语音,必须使用流畅音质进房(即 RoomType=1)。

使用流程

有别于普通小队语音房间,在使用范围语音能力时,必须使用流畅音质进房,且在调用 EnterRoom 之前,需调用以下两个 API:SetRangeAudioTeamID、 SetRangeAudioMode。在进房成功后,调用 UpdateAudioRecvRange,及每帧调用 UpdateSelfPosition。

如果需要同时使用 3D 音效,请在以下步骤1、2 完成后请参见 同时使用 3D 音效

1. 设置 TeamID

通过此方法设置队伍号,必须在 EnterRoom 之前调用,否则将直接返回错误码:AV_ERR_ROOM_NOT_EXITED(1202)。如果是退房后再进房,请在退房成功回调回来之后再调用设置队伍号接口。

注意:

在退房时,此参数不会自动重置为0,所以一旦决定调用此语音模式,请在每次 EnterRoom 之前都调用此方法设置 TeamID。

函数原型

ITMGContext SetRangeAudioTeamID(int teamID)
参数 类型 意义
teamID int 队伍号,专供范围语音中进行上下行音频流控制。当 TeamID 为0时,通话模式为普通小队语音,默认0。

2. 设置语音模式

  • 通过此方法修改语音模式,可在进房前调用,也可在进房后调用。
  • 在进房前调用此方法,方法将影响下一次进房。
  • 在进房后调用此方法,将直接改变当前用户的语音模式。
  • 在退房时,此参数不会自动重置为 MODE_WORLD,所以一旦决定调用此方法,请在每次 EnterRoom 之前都调用此方法设置语音模式。

函数原型

ITMGRoom int SetRangeAudioMode(RANGE_AUDIO_MODE rangeAudioMode)
参数 类型 意义
rangeAudioMode int 0(MODE_WORLD) 代表“所有人”,1(MODE_TEAM) 代表"仅小队"

3. 进入语音房间

在调用 EnterRoom 之前,需调用以下两个 API:SetRangeAudioTeamID、 SetRangeAudioMode。

ITMGContext.GetInstance(this).EnterRoom(roomId,ITMG_ROOM_TYPE_FLUENCY, authBuffer); 

一定要使用流畅音质进入语音房间,随后监听进房的回调并进行处理。

public void OnEvent(ITMGContext.ITMG_MAIN_EVENT_TYPE type, Intent data) {
    if (ITMGContext.ITMG_MAIN_EVENT_TYPE.ITMG_MAIN_EVENT_TYPE_ENTER_ROOM == type)
        {
               //对事件返回的Data进行解析
            int nErrCode = data.getIntExtra("result" , -1);
            String strErrMsg = data.getStringExtra("error_info");

            if (nErrCode == AVError.AV_OK)
            {
                //收到进房信令,进房成功,可以操作设备
                ScrollView_ShowLog("EnterRoom success");
                Log.i(TAG,"EnterRoom success!");
            }
            else
            {
                //进房失败,需分析返回的错误信息
                ScrollView_ShowLog("EnterRoom fail :" + strErrMsg);
                Log.i(TAG,"EnterRoom fail!");
            }  
        }
    }

在进房成功后,调用 UpdateAudioRecvRange(至少调用一次),及每帧调用 UpdateSelfPosition。

4. 设置接收语音距离范围

  • 通过此方法用于设置接收的语音范围(距离以游戏引擎为准),只支持在进房成功后调用
  • 此方法必须配合 UpdateSelfPosition 更新声源方位联合使用。
  • 此方法只需调用一次即可生效。

函数原型

ITMGRoom int UpdateAudioRecvRange(int range)
参数 类型 意义
range int 最大可以接收音频的范围,单位为引擎距离单位

示例代码

ITMGContext.GetInstance().GetRoom().UpdateAudioRecvRange(300);

5. 更新声源方位

更新声源方位,目的是告诉服务器本端位置,通过本端世界坐标+本端接收音频的范围,与其他端世界坐标+其他端接收音频的范围进行判断,达到范围语音效果。

  • 此函数用于更新声源位置信息,只支持在进房成功后调用,且需要每帧调用,以 Unity 引擎为例,此接口需要在 Update 中调用。
  • 使用范围语音一定要更新声源方位,如果不需要范围判断能力,也需要进房后调用此接口一次
  • 如果需要同时使用 3D 音效效果,此接口中的参数 axisForward、axisRight 及 axisUp 需要按照下文 3D 语音部分 进行设置。

函数原型

public abstract int UpdateSelfPosition(int position[3], float axisForward[3], float axisRight[3], float axisUp[3])
参数 类型 意义
position int[] 自身在世界坐标系中的坐标,顺序是前、右、上
axisForward float[] 在本产品中无需关注
axisRight float[] 在本产品中无需关注
axisUp float[] 在本产品中无需关注

同时使用 3D 音效

使用范围语音的同时,如果需要同时使用3D音效功能,需要以下几个步骤。

在进房后使用范围语音步骤1、2、3完成后。

1. 初始化 3D 音效引擎

此函数用于初始化 3D 音效引擎,在进房后调用。在使用 3D 音效之前必须先调用此接口,只接收 3D 音效而不发出 3D 音效的用户也需要调用此接口。

函数原型

public abstract int InitSpatializer(string modelPath)
参数 类型 意义
modelPath string 3D 音效资源文件路径,3D 音效模型文件请在此路径 下载,md5: d0b76aa64c46598788c2f35f5a8a8694,存放于本地中,并通过该参数将存放路径传递给 SDK。必须使用官方提供的文件。

2. 开启或关闭 3D 音效

此函数用于开启或关闭 3D 音效。开启之后可以听到 3D 音效。

函数原型

public abstract int EnableSpatializer(bool enable, bool applyToTeam)
参数 类型 意义
enable bool 开启之后可以听到 3D 音效
applyToTeam bool 3D 语音是否作用于小队内部,仅 enble 为 true 时有效

通过 IsEnableSpatializer 接口获取 3D 音效状态。

3. 设置接收语音距离范围(3D)

  • 通过此方法用于设置接收的语音范围(距离以游戏引擎为准),只支持在进房成功后调用
  • 此方法必须配合 UpdateSelfPosition 更新声源方位联合使用。
  • 此方法只需调用一次即可生效。
  • 3D 音效中,音源音量的大小与音源距离有一定的衰减关系。单位距离超过 range 之后,音量衰减到几乎为零。
  • 距离与声音衰减的关系参考文档附录。

函数原型

ITMGRoom int UpdateAudioRecvRange(int range)
参数 类型 意义
range int 最大可以接收音频的范围,单位为引擎距离单位

示例代码

ITMGContext.GetInstance().GetRoom().UpdateAudioRecvRange(300);

4. 更新声源方位(3D)

更新声源方位,目的是告诉服务器本端位置,通过本端世界坐标+本端接收音频的范围,与其他端世界坐标+其他端接收音频的范围进行判断,达到范围语音效果。

详细技术细节及讲解可参考文章 《3D 位置语音,引领吃鸡游戏体验升级》

  • 此函数用于更新声源位置信息,只支持在进房成功后调用,且需要每帧调用,以 Unity 引擎为例,此接口需要在 Update 中调用。
  • 请直接复制并调用示例代码使用此功能

函数原型

public abstract int UpdateSelfPosition(int position[3], float axisForward[3], float axisRight[3], float axisUp[3])
参数 类型 意义
position int[] 自身在世界坐标系中的坐标,顺序是前、右、上
axisForward float[] 自身坐标系前轴的单位向量
axisRight float[] 自身坐标系右轴的单位向量
axisUp float[] 自身坐标系上轴的单位向量

示例代码

Unreal

FVector cameraLocation = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraLocation();
FRotator cameraRotation = UGameplayStatics::GetPlayerCameraManager(GetWorld(), 0)->GetCameraRotation();
int position[] = { 
    (int)cameraLocation.X,
    (int)cameraLocation.Y,
    (int)cameraLocation.Z };
FMatrix matrix = ((FRotationMatrix)cameraRotation);
float forward[] = { 
    matrix.GetColumn(0).X,
    matrix.GetColumn(1).X,
    matrix.GetColumn(2).X };
float right[] = { 
    matrix.GetColumn(0).Y,
    matrix.GetColumn(1).Y,
    matrix.GetColumn(2).Y };
float up[] = { 
    matrix.GetColumn(0).Z,
    matrix.GetColumn(1).Z,
    matrix.GetColumn(2).Z};
ITMGContextGetInstance()->GetRoom()->UpdateSelfPosition(position, forward, right, up); 

Unity

Transform selftrans = currentPlayer.gameObject.transform;
Matrix4x4 matrix = Matrix4x4.TRS(Vector3.zero, selftrans.rotation, Vector3.one);
int[] position = new int[3] { 
    selftrans.position.z,
    selftrans.position.x,
    selftrans.position.y};
float[] axisForward = new float[3] { 
    matrix.m22,
    matrix.m02,
    matrix.m12 };
float[] axisRight = new float[3] { 
    matrix.m20,
    matrix.m00,
    matrix.m10 };
float[] axisUp = new float[3] { 
    matrix.m21,
    matrix.m01,
    matrix.m11 };
ITMGContext.GetInstance().GetRoom().UpdateSelfPosition(position, axisForward, axisRight, axisUp);

附录

不同语音模式

不同语音模式下,玩家声音可达情况:

  • 假设 A 玩家状态为“所有人”,对应 B 玩家在不同语音模式下声音可达情况:
是否同一小队 是否范围内 语音模式 A 能不能听到 B 的声音 B 能不能听到 A 的声音
同一小队 MODE_WORLD A 可以听到 B 的声音 B 可以听到 A 的声音
同一小队 MODE_TEAM A 可以听到 B 的声音 B 可以听到 A 的声音
同一小队 MODE_WORLD A 可以听到 B 的声音 B 可以听到 A 的声音
同一小队 MODE_TEAM A 可以听到 B 的声音 B 可以听到 A 的声音
不同小队 MODE_WORLD A 可以听到 B 的声音 B 可以听到 A 的声音
不同小队 MODE_TEAM A 不可以听到 B 的声音 B 不可以听到 A 的声音
不同小队 MODE_WORLD A 不可以听到 B 的声音 B 不可以听到 A 的声音
不同小队 MODE_TEAM A 不可以听到 B 的声音 B 不可以听到 A 的声音
  • 假设 A 玩家状态为“仅小队“,对应 B 玩家在不同语音模式下声音可达情况:
是否同一小队 是否范围内 语音状态 A 能不能听到 B 的声音 B 能不能听到 A 的声音
同一小队 MODE_WORLD A 可以听到 B 的声音 B 可以听到 A 的声音
同一小队 MODE_TEAM A 可以听到 B 的声音 B 可以听到 A 的声音
同一小队 MODE_WORLD A 可以听到 B 的声音 B 可以听到 A 的声音
同一小队 MODE_TEAM A 可以听到 B 的声音 B 可以听到 A 的声音
不同小队 MODE_WORLD A 不可以听到 B 的声音 B 不可以听到 A 的声音
不同小队 MODE_TEAM A 不可以听到 B 的声音 B 不可以听到 A 的声音
不同小队 MODE_WORLD A 不可以听到 B 的声音 B 不可以听到 A 的声音
不同小队 MODE_TEAM A 不可以听到 B 的声音 B 不可以听到 A 的声音

距离与声音衰减的关系

3D 音效中,音源音量的大小与音源距离有一定的衰减关系。单位距离超过 range 之后,音量衰减到几乎为零。

距离范围(引擎单位) 衰减公式
0 < N < range/10 衰减系数:1.0 (音量无衰减)
N ≥ range/10 衰减系数:range/10/N

目录