/**
 * Copyright (c) 2025 Tencent. All rights reserved.
 * Module：   TMGAudioCtrl@GMESDK
 * Function： 腾讯云 GME 音频控制相关功能接口。
 */
#import <Foundation/Foundation.h>
#import "QAVError.h"
#import "QAVType.h"

@protocol ITMGAudioFrameCallback <NSObject>

/**
 * 本地采集并经过音频模块前处理后的音频数据回调。
 *
 * 当您设置完音频数据自定义回调之后，SDK 内部会把刚采集到并经过前处理（ANS、AEC、AGC）之后的数据，以 PCM 格式的形式通过本接口回调给您。
 * - 此接口回调出的音频时间帧长固定为0.02s，格式为 PCM 格式。
 * - 由时间帧长转化为字节帧长的公式为 `采样率 × 时间帧长 × 声道数 × 采样点位宽`。
 * - 以 GME 默认的音频录制格式48000采样率、单声道、16采样点位宽为例，字节帧长为 `48000 × 0.02s × 1 × 16bit = 15360bit = 1920字节`。
 * @param frame PCM 格式的音频数据帧。
 * @note
 * 1. 请不要在此回调函数中做任何耗时操作，由于 SDK 每隔 20ms 就要处理一帧音频数据，如果您的处理时间超过 20ms，就会导致声音异常。
 * 2. 此接口回调出的音频数据是可读写的，也就是说您可以在回调函数中同步修改音频数据，但请保证处理耗时。
 * 3. 此接口回调出的音频数据已经经过了前处理(ANS、AEC、AGC），但**不包含**背景音、音效、混响等前处理效果，延迟较低。
 */
- (void)OnCapturedAudioFrame:(TMGAudioFrame *)frame;

/**
 * 本地采集并经过音频模块前处理、音效处理和混 BGM 后的音频数据回调。
 *
 * 当您设置完音频数据自定义回调之后，SDK 内部会把刚采集到并经过前处理、音效处理和混 BGM 之后的数据，在最终进行网络编码之前，以 PCM 格式的形式通过本接口回调给您。
 * - 此接口回调出的音频时间帧长固定为0.02s，格式为 PCM 格式。
 * - 由时间帧长转化为字节帧长的公式为`采样率 × 时间帧长 × 声道数 × 采样点位宽`。
 * - 以 GME 默认的音频录制格式48000采样率、单声道、16采样点位宽为例，字节帧长为`48000 × 0.02s × 1 × 16bit = 15360bit = 1920字节`。
 * @param frame PCM 格式的音频数据帧。
 * @note
 * 1. 请不要在此回调函数中做任何耗时操作，由于 SDK 每隔 20ms 就要处理一帧音频数据，如果您的处理时间超过 20ms，就会导致声音异常。
 * 2. 此接口回调出的音频数据是可读写的，也就是说您可以在回调函数中同步修改音频数据，但请保证处理耗时。
 * 3. 此接口回调出的数据已经经过了前处理（ANS、AEC、AGC）、音效和混 BGM 处理，声音的延迟相比于 {@link OnCapturedAudioFrame} 要高一些。
 */
- (void)OnLocalProcessedAudioFrame:(TMGAudioFrame *)frame;

/**
 * 混音前的每一路远程用户的音频数据。
 *
 * 当您设置完音频数据自定义回调之后，SDK 内部会把远端的每一路原始数据，在最终混音之前，以 PCM 格式的形式通过本接口回调给您。
 * - 此接口回调出的音频时间帧长固定为0.02s，格式为 PCM 格式。
 * - 由时间帧长转化为字节帧长的公式为`采样率 × 时间帧长 × 声道数 × 采样点位宽`。
 * - 以 GME 默认的音频录制格式48000采样率、单声道、16采样点位宽为例，字节帧长为`48000 × 0.02s × 1 × 16bit = 15360bit = 1920字节`。
 * @param frame PCM 格式的音频数据帧。
 * @param userId 用户标识。
 * @note 此接口回调出的音频数据是只读的，不支持修改。
 */
- (void)OnPlayAudioFrame:(TMGAudioFrame *)frame userId:(NSString *)userId;

/**
 * 将各路待播放音频混合之后并在最终提交系统播放之前的数据回调。
 *
 * 当您设置完音频数据自定义回调之后，SDK 内部会把各路待播放的音频混合之后的音频数据，在提交系统播放之前，以 PCM 格式的形式通过本接口回调给您。
 * - 此接口回调出的音频时间帧长固定为0.02s，格式为 PCM 格式。
 * - 由时间帧长转化为字节帧长的公式为 `采样率 × 时间帧长 × 声道数 × 采样点位宽`。
 * - 以 GME 默认的音频录制格式48000采样率、单声道、16采样点位宽为例，字节帧长为 `48000 × 0.02s × 1 × 16bit = 15360bit = 1920字节`。
 * @param frame PCM 格式的音频数据帧。
 * @note
 * 1. 请不要在此回调函数中做任何耗时操作，由于 SDK 每隔 20ms 就要处理一帧音频数据，如果您的处理时间超过 20ms，就会导致声音异常。
 * 2. 此接口回调出的音频数据是可读写的，也就是说您可以在回调函数中同步修改音频数据，但请保证处理耗时。
 * 3. 此接口回调出的是对各路待播放音频数据的混合，但其中并不包含耳返的音频数据。
 */
- (void)OnMixedPlayAudioFrame:(TMGAudioFrame *)frame;

/**
 * SDK 所有音频混合后的音频数据（包括采集到的和待播放的）。
 *
 * 当您设置完音频数据自定义回调之后，SDK 内部会把所有采集到的和待播放的音频数据混合起来，以 PCM 格式的形式通过本接口回调给您，便于您进行自定义录制。
 * - 此接口回调出的音频时间帧长固定为0.02s，格式为 PCM 格式。
 * - 由时间帧长转化为字节帧长的公式为 `采样率 × 时间帧长 × 声道数 × 采样点位宽`。
 * - 以 GME 默认的音频录制格式48000采样率、单声道、16采样点位宽为例，字节帧长为 `48000 × 0.02s × 1 × 16bit = 15360bit = 1920字节`。
 * @param frame PCM 格式的音频数据帧。
 * @note
 * 1. 此接口回调出的是SDK所有音频数据的混合数据，包括：经过 3A 前处理、特效叠加以及背景音乐混音后的本地音频，所有远端音频，但不包括耳返音频。
 * 2. 此接口回调出的音频数据不支持修改。
 */
- (void)OnMixedAllAudioFrame:(TMGAudioFrame *)frame;

@end

GMESDK_OCEXPORT @interface ITMGAudioCtrl : NSObject

/////////////////////////////////////////////////////////////////////////////////
//
//                              音频控制
//
/////////////////////////////////////////////////////////////////////////////////

/**
 * 开启或关闭麦克风。
 *
 * 此接口用来开启/关闭麦克风，并推送音频流到房间，需要在**接收到进房成功事件后**调用，加入房间默认不会打开麦克风。
 * {@link EnableMic}(boolean) = {@link EnableAudioCaptureDevice}(boolean) + {@link EnableAudioSend}(boolean)。
 * @param enable true：开启  false：关闭。
 */
- (QAVResult)EnableMic:(BOOL)enable;

/**
 * 麦克风状态获取。
 *
 * 此接口用于获取麦克风状态，返回值 0 为关闭麦克风状态，返回值 1 为打开麦克风状态。
 */
- (int)GetMicState;

/**
 * 开启或关闭扬声器。
 *
 * 此接口用于开启/关闭扬声器，并接收远端的音频流，需要在**接收到进房成功事件后**调用，加入房间默认不会打开扬声器。
 * {@link EnableSpeaker}(boolean) = {@link EnableAudioPlayDevice}(boolean) + {@link EnableAudioRecv}(boolean)。
 * @param enable true：开启  false：关闭。
 */
- (QAVResult)EnableSpeaker:(BOOL)enable;

/**
 * 扬声器状态获取。
 *
 * 此接口用于扬声器状态获取。返回值 0 为关闭扬声器状态，返回值 1 为打开扬声器状态。
 */
- (int)GetSpeakerState;

/**
 * 开启音频采集设备。
 *
 * 此接口用来开启/关闭采集设备，需要在**接收到进房成功事件后**调用，加入房间默认不打开采集设备。
 * @param enable true：开启  false：关闭。
 */
- (QAVResult)EnableAudioCaptureDevice:(BOOL)enable;

/**
 * 获取采集设备状态。
 *
 * 此接口用于采集设备状态获取。
 */
- (BOOL)IsAudioCaptureDeviceEnabled;

/**
 * 开启或关闭播放设备。
 *
 * 此接口用于开启关闭播放设备，需要在**接收到进房成功事件后**调用，加入房间默认不打开播放设备。
 * @param enable true：开启  false：关闭。
 */
- (QAVResult)EnableAudioPlayDevice:(BOOL)enable;

/**
 * 获取播放设备状态。
 *
 * 此接口用于获取播放设备状态。
 */
- (BOOL)IsAudioPlayDeviceEnabled;

/**
 * 打开关闭音频上行。
 *
 * 此接口用于打开/关闭音频上行，需要在**接收到进房成功事件后**调用，用来控制否是将采集到的音频数据发送给远端用户。如果采集设备已经打开，那么会发送采集到的音频数据。如果采集设备没有打开，那么仍旧无声。采集设备的打开关闭请参见接口  {@link
 * EnableAudioCaptureDevice}。
 * @param enable true：打开  false：关闭。
 */
- (QAVResult)EnableAudioSend:(BOOL)enable;

/**
 * 获取音频上行状态。
 *
 * 此接口用于音频上行状态获取。
 */
- (BOOL)IsAudioSendEnabled;

/**
 * 打开或关闭音频下行。
 *
 * 此接口用于打开/关闭音频下行，需要在**接收到进房成功事件后**调用，用于控制是否接收远端用户的音频数据。如果播放设备已经打开，那么会播放房间里其他人的音频数据。如果播放设备没有打开，那么仍旧无声。播放设备的打开关闭参见接口请参见接口 {@link
 * EnableAudioPlayDevice}。
 * @param enable true：打开  false：关闭。
 */
- (QAVResult)EnableAudioRecv:(BOOL)enable;

/**
 * 获取音频下行状态。
 *
 * 此接口用于音频下行状态获取。
 */
- (BOOL)IsAudioRecvEnabled;

/**
 * 设置麦克风音量的增益。
 *
 * 此接口用于设置麦克风音量的增益。
 * @param volume 音量增益大小，取值 [0，200]，其中 100 为默认值，相当于音量大小不增不减。
 */
- (QAVResult)SetMicVolume:(int)volume;

/**
 * 获取麦克风音量的增益。
 *
 * 获取使用 {@link SetMicVolume} 设置的麦克风音量增益大小。
 */
- (int)GetMicVolume;

/**
 * 设置扬声器音量增益。
 *
 * 此接口用于设置扬声器音量的增益。
 * @param volume 音量增益大小，取值 [0，200]，其中 100 为默认值，相当于音量大小不增不减。
 */
- (QAVResult)SetSpeakerVolume:(int)volume;

/**
 * 获取扬声器音量增益。
 *
 * 获取使用 {@link SetSpeakerVolume} 设置的扬声器音量增益大小。
 */
- (int)GetSpeakerVolume;

/**
 * 动态设置房间内某成员音量增益。
 *
 * @param userID      用户 ID。
 * @param volume      音量增益大小，取值 [0，200]，其中 100 为默认值，相当于音量大小不增不减。
 */
- (int)SetSpeakerVolumeByUserID:(NSString *)userID volume:(int)volume;

/**
 * 获取设置的房间内成员音量增益。
 *
 * 获取通过{@link SetSpeakerVolumeByUserID}接口设置的音量增益。
 * @param userID      用户 ID。
 */
- (int)GetSpeakerVolumeByUserID:(NSString *)userID;

/**
 * 开启/关闭耳返。
 *
 * @param enable      是否开启耳返。
 */
- (QAVResult)EnableLoopBack:(BOOL)enable;

/**
 * 设置耳返音量。
 *
 * 此接口用于设置耳返的音量大小。
 * @param volume      音量大小，取值 [0，200]，其中 100 为默认值，相当于音量大小不增不减。
 */
- (QAVResult)SetLoopBackVolume:(int)volume;

/**
 * 禁言房间中某个用户。
 *
 * 将某个用户加入音频数据黑名单，即不接受该用户的语音， 只对本端生效，不会影响其他端。返回值为 0 表示调用成功。
 * @param userID      用户 ID。
 */
- (QAVResult)AddAudioBlackList:(NSString *)userID;

/**
 * 解除对房间中某个用户的禁言。
 *
 * 将某个用户移除音频数据黑名单。返回值为0表示调用成功。
 * @param userID      用户 ID。
 */
- (QAVResult)RemoveAudioBlackList:(NSString *)userID;

/**
 * 查询某个用户是否被禁言。
 *
 * @param userID      用户 ID。
 */
- (BOOL)IsUserIdInAudioBlackList:(NSString *)userID;

/**
 * 初始化 3D 音效处理器。
 *
 * 注意此接口已经废除，无需调用。
 */
- (QAVResult)InitSpatializer:(NSString *)modelPath;

/**
 * 开启或关闭 3D 音效。
 *
 * 此函数用于开启或关闭 3D 音效。开启之后可以听到 3D 音效。
 * @param enable           是否开启 3D 音效。
 */
- (QAVResult)EnableSpatializer:(BOOL)enable;

/**
 * 获取当前 3D 音效状态。
 *
 * 此函数用于获取当前 3D 音效状态。
 */
- (BOOL)IsEnableSpatializer;

/**
 * 启用音频自定义采集模式。
 *
 * 开启该模式后，SDK 不在运行原有的音频采集流程，即不再继续从麦克风采集音频数据，而是只保留音频编码和发送能力。
 * 您需要通过 {@link SendCustomAudioData} 不断地向 SDK 塞入自己采集的音频数据。
 * @param enable 是否启用，默认值：NO。
 * @note 由于回声抵消（AEC）需要严格的控制声音采集和播放的时间，所以开启自定义音频采集后，AEC 能力可能会失效。
 */
- (QAVResult)EnableCustomAudioCapture:(BOOL)enable;

/**
 * 设置音频路由
 *
 * 设置“音频路由”，即设置声音是从手机的哪个设备播放出来的，常见的播放设备包括扬声器，听筒，因此该接口仅适用于手机等移动端设备。
 * 手机默认有 2 个播放器：一个是位于手机顶部的听筒，一个是位于手机底部的立体声扬声器。
 * 设置音频路由为听筒时，声音比较小，只有将耳朵凑近才能听清楚，隐私性较好，适合用于接听电话。
 * 设置音频路由为扬声器时，声音比较大，不用将手机贴脸也能听清，因此可以实现“免提”的功能。
 * @param route 音频路由，即声音由哪里输出（扬声器、听筒），默认值：{@link $ITMG_AUDIO_ROUTE_SPEAKER$}。
 */
- (QAVResult)SetAudioRoute:(ITMG_AUDIO_ROUTE)route;

/**
 * 向 SDK 投送自己采集的音频数据。
 *
 * 请您精准地按每帧时长的间隔调用本接口，数据投送间隔不均匀时极易触发声音卡顿。
 * 参数 {@link TMGAudioFrame} 推荐下列填写方式（其他字段不需要填写）：
 * - data：音频帧 buffer。音频帧数据只支持 PCM 格式，支持[5ms ~ 100ms]帧长，推荐使用 20ms 帧长，长度计算方法：【48000采样率、单声道的帧长度：48000 × 0.02s × 1 × 16bit = 15360bit = 1920字节】。
 * - sample_rate：采样率，支持：16000、24000、32000、44100、48000。
 * - channel：声道数（如果是立体声，数据是交叉的），单声道：1； 双声道：2。
 * - timestamp：时间戳，单位为毫秒（ms），请使用音频帧在采集时被记录下来的时间戳（可以在采集到一帧音频帧之后，通过调用 {@link generateCustomPTS} 获取时间戳）。
 * - bits_type：位深，目前版本只支持16bit--PCM_BITS_TYPE_FIXED_16。
 * @param frame 音频数据。
 */
- (QAVResult)SendCustomAudioData:(TMGAudioFrame *)frame;

/**
 * 开启音频自定义播放。
 *
 * @note 需要您在进入房间前设置才能生效，暂不支持进入房间后再设置。
 * 如果您需要外接一些特定的音频设备，或者希望自己掌控音频的播放逻辑，您可以通过该接口启用音频自定义播放。
 * 启用音频自定义播放后，SDK 将不再调用系统的音频接口播放数据，您需要通过 {@link GetCustomAudioRenderingFrame} 获取 SDK 要播放的音频帧并自行播放。
 * @param enable 是否启用音频自定义播放，默认为关闭状态。
 */
- (QAVResult)EnableCustomAudioRendering:(BOOL)enable;

/**
 * 获取可播放的音频数据。
 *
 * 调用该接口之前，您需要先通过 {@link EnableCustomAudioRendering} 开启音频自定义播放。
 * 参数 {@link TMGAudioFrame} 推荐下列填写方式（其他字段不需要填写）：
 * - sample_rate：采样率，必填，支持 16000、24000、32000、44100、48000。
 * - channel：声道数，必填，单声道请填1，双声道请填2，双声道时数据是交叉的。
 * - data：用于获取音频数据的 buffer。需要您根据一帧音频帧的帧长度分配好 data 的内存大小。获取的 PCM 数据支持 10ms 或 20ms 两种帧长，推荐使用 20ms 的帧长。
 * - bits_type：位深，目前版本只支持16bit--PCM_BITS_TYPE_FIXED_16
 * 计算公式为：采样率 x 播放时长 x 声道数量 x 2（每个样点的字节数）， 例如： 48000采样率、单声道、且播放时长为 20ms 的一帧音频帧的 buffer 大小为 48000 × 0.02s × 1 × 16bit = 15360bit = 1920字节。
 * @param frame 音频数据帧。
 * @note
 *   1. 参数 frame 中的 sample_rate、channel 需提前设置好，同时分配好所需读取帧长的 data 空间。
 *   2. SDK 内部会根据 sample_rate 和 channel 自动填充 data 数据。
 *   3. 建议由系统的音频播放线程直接驱动该函数的调用，在播放完一帧音频之后，即调用该接口获取下一帧可播放的音频数据。
 */
- (QAVResult)GetCustomAudioRenderingFrame:(TMGAudioFrame *)frame;

/**
 * 开启音量回调。
 *
 * @param interval 音量回调周期，单位（秒）。
 * @note
 *   通过 ITMG_MAIN_EVENT_TYPE_USER_VOLUMES 事件返回用户音量数据。
 */
- (QAVResult)TrackingVolume:(float)interval;

/**
 * 停止音量回调。
 */
- (QAVResult)StopTrackingVolume;

/**
 * 获取实时麦克风音量。
 */
- (int)GetMicLevel;

/**
 * 获取实时扬声器音量。
 */
- (int)GetSpeakerLevel;

/**
 * 获取音频上行实时音量。
 */
- (int)GetSendStreamLevel;

/**
 * 获取房间内其他成员下行实时音量。
 *
 * @param userID 房间其他成员的 ID。
 */
- (int)GetRecvStreamLevel:(NSString *)userID;

/**
 * 开始麦克风测试 [仅桌面端有效]。
 *
 * @param interval 麦克风音量的回调间隔。
 * @note
 *   通过 ITMG_MAIN_EVENT_TYPE_TEST_MIC_VOLUME 事件返回测试结果。
 */
- (QAVResult)StartMicDeviceTest:(NSInteger)interval;

/**
 * 结束麦克风测试 [仅桌面端有效]。
 */
- (QAVResult)StopMicDeviceTest;

/**
 * 开始扬声器测试 [仅桌面端有效]。
 *
 * @param filePath 声音文件的路径。
 * @note
 *   通过ITMG_MAIN_EVENT_TYPE_TEST_SPEAKER_VOLUME事件返回测试结果。
 */
- (QAVResult)StartSpeakerDeviceTest:(NSString *)filePath;

/**
 * 结束扬声器测试 [仅桌面端有效]。
 */
- (QAVResult)StopSpeakerDeviceTest;

/**
 * 设置音频数据自定义回调。
 *
 * 设置该回调之后，SDK 内部会把音频数据（PCM 格式）回调出来，包括：
 * - {@link OnCapturedAudioFrame}：本地麦克风采集到的音频数据回调。
 * - {@link OnLocalProcessedAudioFrame}：本地采集并经过音频模块前处理后的音频数据回调。
 * - {@link OnPlayAudioFrame}：混音前的每一路远程用户的音频数据。
 * - {@link OnMixedPlayAudioFrame}：各路音频混合之后并最终要由系统播放出的音频数据回调。
 * - {@link OnMixedAllAudioFrame}：所有音频混合后的音频数据（包括采集到的和待播放的）回调。
 *
 * @note 设置回调为空即代表停止自定义音频回调，反之，设置回调不为空则代表启动自定义音频回调。
 */
- (void)SetAudioFrameCallback:(id<ITMGAudioFrameCallback>)callback;

@end
