
#import <Foundation/Foundation.h>
#include <objc/NSObject.h>
#include <Foundation/NSArray.h>
#import <UIKit/UIKit.h>
#import <CoreVideo/CoreVideo.h>
#import "engine_define.h"

/* 错误码枚举 */
typedef NS_ENUM(NSInteger, AoqErrorCode) {
    AoqECOK                       = 0,
    AoqECParamInvalid             = 1,
    AoqECStateInvalid             = 2,
    AoqECUnSupport                = 3,

    AoqECAudio                    = 100,
    AoqECAudioExternalBufferFull  = 110,
    /* 音频设备 */
    AoqECAudioDevice                       = 120,
    AoqECAudioDeviceRecordingAuthFailed     = 121,
    AoqECAudioDeviceRecordingOccupied       = 122,
    AoqECAudioDeviceRecordingBackgroundStart = 123,
    AoqECAudioDeviceRecordingStartFail      = 124,
    AoqECAudioDevicePlayoutOccupied         = 125,
    AoqECAudioDevicePlayoutBackgroundStart  = 126,
    AoqECAudioDevicePlayoutStartFail        = 127,
    AoqECAudioDeviceEarpieceRequiresVoipMode = 128,

    AoqECVideo                    = 200,
    AoqECVideoExternalBufferFull  = 210,
    AoqECVideoExternalCaptureNotEnabled = 211,
    AoqECVideoExternalEncoderNotEnabled = 212,
    /* 视频设备/采集 */
    AoqECVideoDevice              = 220,
    AoqECVideoDeviceCameraOpenFail     = 221,
    AoqECVideoDeviceCameraAuthFailed   = 222,
    AoqECVideoDeviceCameraOccupied     = 223,
    AoqECVideoDeviceCameraRunningError = 224,
    /* 视频编解码 */
    AoqECVideoCodec               = 230,
    AoqECVideoCodecEncoderInitFail = 231,
    /* 视频渲染 */
    AoqECVideoRender              = 240,
    AoqECVideoRenderCreateFail    = 241,
    AoqECVideoRenderDrawError     = 242,
};

/* 警告码枚举 */
typedef NS_ENUM(NSInteger, AoqWarningCode) {
    AoqWCOK            = 0,
    AoqWCAudio         = 100,
    AoqWCAudioHowling  = 101,
    /* 音频设备 */
    AoqWCAudioDevice                      = 120,
    AoqWCAudioDeviceMicEnumerateError     = 121,
    AoqWCAudioDeviceMicStartTimeout       = 122,
    AoqWCAudioDeviceRecordingError        = 123,
    AoqWCAudioDeviceSpeakerEnumerateError = 124,
    AoqWCAudioDeviceSpeakerStartTimeout   = 125,
    AoqWCAudioDevicePlayoutError          = 126,

    AoqWCVideo         = 200,
    AoqWCVideoCameraEnumerateError = 201,
    AoqWCVideoEncoderSwitched      = 202,
    AoqWCVideoRenderDowngrade      = 203,
};

/**
 * @brief 链接鉴权
 */
AOQ_API @interface AoqCreateConfig : NSObject
/* SDK工作目录 */
@property (nonatomic, copy) NSString * _Nonnull workDir;
/* 是否开启音频原始数据 dump (调试用)，默认 NO */
@property (nonatomic, assign) BOOL enableDumpAudio;
/* 扩展参数 */
@property (nonatomic, copy) NSString * _Nonnull extras;

@end

/* track枚举值 */
typedef NS_ENUM(NSInteger, AoqTrackType) {
    AoqTrackTypeAudio  = 0,
    AoqTrackTypeVideo  = 1,
    AoqTrackTypeData   = 2,
};

/* track媒体格式枚举值 */
typedef NS_ENUM(NSInteger, AoqEncoderType) {
    AoqEncoderTypeUnknown = 0,
    AoqEncoderTypeAudioPCM = 1,
    AoqEncoderTypeAudioOpus = 2,
    AoqEncoderTypeVideoH264 = 3,
    AoqEncoderTypeVideoJpeg = 4,
    AoqEncoderTypeDataText = 5,
};

/* track属性 */
AOQ_API @interface AoqTrackParam : NSObject

/* track的枚举值 */
@property (nonatomic, assign) AoqTrackType trackType;

@end

/* relay 接入点 */
AOQ_API @interface AoqRelayEndpoint : NSObject

/* 服务端地址(域名或 IP) */
@property (nonatomic, copy) NSString * _Nonnull endpoint;
/* 服务端端口 */
@property (nonatomic, assign) NSInteger port;

@end

/* 引擎连接状态 */
typedef NS_ENUM(NSInteger, AoqConnectionStatus) {
    AoqConnectionStatusDisconnected = 0,
    AoqConnectionStatusConnecting   = 1,
    AoqConnectionStatusConnected    = 2,
    AoqConnectionStatusFailed       = 3,
};

/**
 * @brief 链接鉴权
 */
AOQ_API @interface AoqConnectConfig : NSObject

@property (nonatomic, copy) NSString * _Nonnull token;
@property (nonatomic, copy) NSString * _Nonnull sid;
@property (nonatomic, copy) NSString * _Nonnull certFingerprint;
/* relay 接入点数组 */
@property (nonatomic, copy) NSArray<AoqRelayEndpoint *> * _Nonnull relayEndpoints;
/* 工作空间哈希 ID */
@property (nonatomic, copy) NSString * _Nonnull workspaceIdHash;
/* 推流track属性的数组 */
@property (nonatomic, copy) NSArray<AoqTrackParam *> * _Nonnull publishTracks;
/* 拉流track属性数组 */
@property (nonatomic, copy) NSArray<AoqTrackParam *> * _Nonnull subscribeTracks;

@end

#pragma mark - Stats

AOQ_API @interface AoqAudioPublishStats : NSObject
@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) NSUInteger bitrate;
@property (nonatomic, assign) NSUInteger bytes;
@property (nonatomic, assign) NSUInteger encodeVolume;
@end

AOQ_API @interface AoqVideoPublishStats : NSObject
@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) NSUInteger bitrate;
@property (nonatomic, assign) NSUInteger bytes;
@property (nonatomic, assign) NSUInteger encodeFps;
@end

AOQ_API @interface AoqDataMsgPublishStats : NSObject
@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) NSUInteger bitrate;
@property (nonatomic, assign) NSUInteger bytes;
@end

AOQ_API @interface AoqAudioSubscribeStats : NSObject
@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) NSUInteger bitrate;
@property (nonatomic, assign) NSUInteger bytes;
@property (nonatomic, assign) NSUInteger playVolume;
@end

AOQ_API @interface AoqVideoSubscribeStats : NSObject
@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) NSUInteger bitrate;
@property (nonatomic, assign) NSUInteger bytes;
@property (nonatomic, assign) NSUInteger decodeFps;
@property (nonatomic, assign) NSUInteger renderFps;
@end

AOQ_API @interface AoqDataMsgSubscribeStats : NSObject
@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) NSUInteger bitrate;
@property (nonatomic, assign) NSUInteger bytes;
@end

AOQ_API @interface AoqNetworkStats : NSObject
@property (nonatomic, assign) NSUInteger sendBitrate;
@property (nonatomic, assign) NSUInteger sendBytes;
@property (nonatomic, assign) NSUInteger recvBitrate;
@property (nonatomic, assign) NSUInteger recvBytes;
@property (nonatomic, assign) NSUInteger loss;
@property (nonatomic, assign) NSUInteger rtt;
@end

AOQ_API @interface AoqStats : NSObject
@property (nonatomic, copy) NSArray<AoqAudioPublishStats *> * _Nullable audioPublishStats;
@property (nonatomic, copy) NSArray<AoqVideoPublishStats *> * _Nullable videoPublishStats;
@property (nonatomic, copy) NSArray<AoqDataMsgPublishStats *> * _Nullable dataMsgPublishStats;
@property (nonatomic, copy) NSArray<AoqAudioSubscribeStats *> * _Nullable audioSubscribeStats;
@property (nonatomic, copy) NSArray<AoqVideoSubscribeStats *> * _Nullable videoSubscribeStats;
@property (nonatomic, copy) NSArray<AoqDataMsgSubscribeStats *> * _Nullable dataMsgSubscribeStats;
@property (nonatomic, strong) AoqNetworkStats * _Nullable networkStats;
@end

#pragma mark - Audio

/** 音频采集配置 */
AOQ_API @interface AoqAudioCaptureConfig : NSObject
/** 是否外部采集 默认为 NO */
@property (nonatomic, assign) BOOL isExternal;
/** 是否启用 VoIP 模式（硬件AEC） 移动端有效 默认为 NO */
@property (nonatomic, assign) BOOL isVoipMode;

/** 音频采集通道数 默认为1 支持1/2 */
@property (nonatomic, assign) NSInteger channel;
@end

/** 音频播放配置 */
AOQ_API @interface AoqAudioPlaybackConfig : NSObject
/** 是否启用 VoIP 模式（硬件AEC） 移动端有效，采集播放参数先到为准 默认为 NO */
@property (nonatomic, assign) BOOL isVoipMode;
/** 是否默认扬声器 移动端有效 默认为 YES */
@property (nonatomic, assign) BOOL isDefaultSpeaker;
/** 是否外部播放 默认为 NO */
@property (nonatomic, assign) BOOL isExternal;

/** 音频播放通道数 默认为1 支持1/2 */
@property (nonatomic, assign) NSInteger channel;
@end

/* 音频设备状态码 */
typedef NS_ENUM(NSInteger, AoqAudioDeviceStateCode) {
    AoqAudioDeviceNone          = 0,
    AoqAudioDeviceRecordStarting = 1,
    AoqAudioDeviceRecordStarted  = 2,
    AoqAudioDeviceRecordStopping = 3,
    AoqAudioDeviceRecordStopped  = 4,
    AoqAudioDeviceRecordFail     = 5,
    AoqAudioDevicePlayStarting   = 6,
    AoqAudioDevicePlayStarted    = 7,
    AoqAudioDevicePlayStopping   = 8,
    AoqAudioDevicePlayStopped    = 9,
    AoqAudioDevicePlayFail       = 10,
};

/* 音频设备状态数据结构 */
AOQ_API @interface AoqAudioDeviceState : NSObject
/** 状态码 */
@property (nonatomic, assign) AoqAudioDeviceStateCode state;
/** 错误码 (AoqErrorCode) */
@property (nonatomic, assign) NSInteger reason;
@end

/* Audio Encoder属性结构体 */
AOQ_API @interface AoqAudioCodecConfig : NSObject

@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) AoqEncoderType codecType;
@property (nonatomic, assign) NSInteger sampleRate;
@property (nonatomic, assign) NSInteger channel;
@property (nonatomic, assign) NSInteger bitrate;

@end

/* AudioSession控制权限 */
typedef NS_OPTIONS(NSInteger, AoqAudioSessionRestriction) {
    AoqAudioSessionNone               = 0,
    AoqAudioSessionSetCategory        = 1 << 0,
    AoqAudioSessionConfigureSession   = 1 << 1,
    AoqAudioSessionDeactivateSession  = 1 << 2,
    AoqAudioSessionActivateSession    = 1 << 3,
};

/* 音频设备路由类型 */
typedef NS_ENUM(NSInteger, AoqAudioDeviceRouteType) {
    AoqAudioDeviceRouteDefault       = 0,
    AoqAudioDeviceRouteHeadset       = 1,
    AoqAudioDeviceRouteEarpiece      = 2,
    AoqAudioDeviceRouteHeadsetNoMic  = 3,
    AoqAudioDeviceRouteSpeakerPhone  = 4,
    AoqAudioDeviceRouteUsb           = 5,
    AoqAudioDeviceRouteBluetooth     = 6,
    AoqAudioDeviceRouteBluetoothA2dp = 7,
};

#pragma mark - AudioFileMix

/* 音频文件播放配置 */
AOQ_API @interface AoqAudioFileMixConfig : NSObject
/** 文件名（含路径） */
@property (nonatomic, copy) NSString * _Nonnull fileName;
/** 循环次数，-1 表示无限循环，默认 -1 */
@property (nonatomic, assign) NSInteger cycles;
/** 起始播放位置(ms)，默认 0 */
@property (nonatomic, assign) NSInteger startPosMs;
/** 推流音量，取值范围[0-100]，默认 100 */
@property (nonatomic, assign) NSInteger publishVolume;
/** 播放音量，取值范围[0-100]，默认 100 */
@property (nonatomic, assign) NSInteger playoutVolume;
@end

/* 音频文件状态码 */
typedef NS_ENUM(NSInteger, AoqAudioFileStateCode) {
    AoqAudioFileNone      = 0,
    AoqAudioFileStarted        = 1,
    AoqAudioFileStopped        = 2,
    AoqAudioFilePaused         = 3,
    AoqAudioFileResumed        = 4,
    AoqAudioFileEnded          = 5,
    AoqAudioFileBuffering      = 6,
    AoqAudioFileBufferingEnd   = 7,
    AoqAudioFileFailed         = 8,
};

/* 音频文件错误码 */
typedef NS_ENUM(NSInteger, AoqAudioFileErrorCode) {
    AoqAudioFileNoError       = 0,
    AoqAudioFileOpenFailed    = 1,
    AoqAudioFileDecodeFailed  = 2,
};

/* 音频文件状态数据结构 */
AOQ_API @interface AoqAudioFileState : NSObject
/** 文件ID */
@property (nonatomic, copy) NSString * _Nonnull fileId;
/** 状态码 */
@property (nonatomic, assign) AoqAudioFileStateCode stateCode;
/** 错误码 */
@property (nonatomic, assign) AoqAudioFileErrorCode errorCode;
@end

#pragma mark - AudioExternalStream

/** 外部音频流类型 */
typedef NS_ENUM(NSInteger, AoqAudioStreamDirection) {
    AoqAudioStreamPublish = 0,
    AoqAudioStreamPlayout = 1,
};

/** 外部音频流切换状态 */
typedef NS_ENUM(NSInteger, AoqAudioExternalStreamToggle) {
    AoqAudioExternalStreamToggleNormal = 0,
    AoqAudioExternalStreamTogglePause  = 1,
};

/** 外部音频流配置 */
AOQ_API @interface AoqAudioExternalStreamConfig : NSObject
/** 音频轨道类型，默认 Audio */
@property (nonatomic, assign) AoqTrackType   trackType;
/** 音频流格式，默认 PCM */
@property (nonatomic, assign) AoqEncoderType codecType;
/** 声道数，默认值：1 */
@property (nonatomic, assign) NSInteger channels;
/** 采样率，默认值：48000 */
@property (nonatomic, assign) NSInteger sampleRate;
/** 播放音量，[0-100]，默认值：100 */
@property (nonatomic, assign) NSInteger playoutVolume;
/** 推流音量，[0-100]，默认值：100 */
@property (nonatomic, assign) NSInteger publishVolume;
/** 最大缓冲时长 ms，默认值：1000 */
@property (nonatomic, assign) NSInteger maxBufferDuration;
/** 输入PCM做3A处理 */
@property (nonatomic, assign) BOOL enable3A;
@end

/** 外部音频数据 */
AOQ_API @interface AoqAudioFrameData : NSObject
/** 音频PCM裸数据指针 */
@property (nonatomic, assign) void* _Nullable dataPtr;
/** PCM数据字节数 */
@property (nonatomic, assign) NSInteger dataSize;
/** 采样点数（单声道） */
@property (nonatomic, assign) NSInteger numOfSamples;
/** 每个采样点字节数 */
@property (nonatomic, assign) NSInteger bytesPerSample;
/** 声道数 */
@property (nonatomic, assign) NSInteger numOfChannels;
/** 每秒采样点数 */
@property (nonatomic, assign) NSInteger samplesPerSec;
/** PCM输入轮次 */
@property (nonatomic, assign) int32_t pushSequence;
/** 时间戳 */
@property (nonatomic, assign) int64_t timeStamp;
/** 数据回调有效，true-SDK生成的静音数据 */
@property (nonatomic, assign) BOOL autoGenMute;
@end

#pragma mark - AudioFrameObserver

/** 音频帧回调数据来源 */
typedef NS_ENUM(NSInteger, AoqAudioSource) {
    /** 采集的音频数据 */
    AoqAudioSourceCaptured         = 0,
    /** 3A后的音频数据 */
    AoqAudioSourceProcessCaptured  = 1,
    /** 推流的音频数据 */
    AoqAudioSourcePublish          = 2,
    /** 播放的音频数据 */
    AoqAudioSourcePlayback         = 3,
};

/** 音频帧回调模式 */
typedef NS_ENUM(NSInteger, AoqAudioObserverMode) {
    AoqAudioObserverModeReadOnly  = 0,
    AoqAudioObserverModeReadWrite = 1,
};

/** 音频帧回调配置 */
AOQ_API @interface AoqAudioObserverConfig : NSObject
/** 回调音频采样率，默认 48000 */
@property (nonatomic, assign) NSInteger sampleRate;
/** 回调音频声道数，默认 1 */
@property (nonatomic, assign) NSInteger channels;
/** 读写模式，默认只读 */
@property (nonatomic, assign) AoqAudioObserverMode mode;
@end

#pragma mark - DataMessage

/* 实时消息数据结构 */
AOQ_API @interface AoqDataMsg : NSObject
/** 指向调用方持有的内存 */
@property (nonatomic, copy) NSData * _Nonnull data;
@end

#pragma mark - Video

/* 渲染显示的模式枚举值 */
typedef NS_ENUM(NSUInteger, AoqRenderMode) {
    /** 自动模式 */
    AoqRenderModeAuto    = 0,
    /** 拉伸平铺模式 ，如果外部输入的视频宽高比和推流设置的宽高比不一致时，将输入视频拉伸到推流设置的比例，画面会变形*/
    AoqRenderModeStretch = 1,
    /** 填充黑边模式，如果外部输入的视频宽高比和推流设置的宽高比不一致时，将输入视频上下或者左右填充黑边 */
    AoqRenderModeFill    = 2,
    /** 裁剪模式，如果外部输入的视频宽高比和推流设置的宽高比不一致时，将输入视频宽或者高进行裁剪，画面内容会丢失 */
    AoqRenderModeCrop    = 3,
};

/* 视频渲染数据结构 */
AOQ_API @interface AoqVideoCanvas : NSObject
/** 显示视图，传 nil 表示移除渲染绑定 */
@property (nonatomic, strong, nullable) UIView *view;
/** 渲染模式，默认值为 AoqRenderMode */
@property (nonatomic, assign) AoqRenderMode renderMode;
@end

/* 摄像头方向枚举 */
typedef NS_ENUM(NSInteger, AoqCameraDirection) {
    /** 前置摄像头 */
    AoqCameraDirectionFront = 0,
    /** 后置摄像头（移动端有效） */
    AoqCameraDirectionBack  = 1,
};

/* 视频采集配置 */
AOQ_API @interface AoqVideoCaptureConfig : NSObject
/** 采集宽度（像素），默认 1280；isExternal=YES 时无效 */
@property (nonatomic, assign) NSInteger width;
/** 采集高度（像素），默认 720；isExternal=YES 时无效 */
@property (nonatomic, assign) NSInteger height;
/** 采集帧率，默认 15；isExternal=YES 时无效（节奏由送帧决定） */
@property (nonatomic, assign) NSInteger fps;
/** 是否外部采集；YES 时不打开摄像头，由 pushExternalVideoCapturedFrame: 喂帧 */
@property (nonatomic, assign) BOOL isExternal;
/** 摄像头方向；isExternal=YES 时无效 */
@property (nonatomic, assign) AoqCameraDirection cameraDirection;
@end

/* 视频像素格式 */
typedef NS_ENUM(NSInteger, AoqVideoPixelFormat) {
    AoqVideoPixelFormatUnknown       = 0,
    AoqVideoPixelFormatI420          = 1,
    AoqVideoPixelFormatNV12          = 2,
    AoqVideoPixelFormatNV21          = 3,
    AoqVideoPixelFormatBGRA          = 4,
    AoqVideoPixelFormatRGBA          = 5,
    /** Apple 平台零拷贝路径，pixelBuffer 字段填 CVPixelBufferRef */
    AoqVideoPixelFormatCVPixelBuffer = 6,
};

/* 外部视频数据 */
AOQ_API @interface AoqVideoFrame : NSObject
/** 像素格式 */
@property (nonatomic, assign) AoqVideoPixelFormat format;

/** 宽度（像素） */
@property (nonatomic, assign) NSInteger width;
/** 高度（像素） */
@property (nonatomic, assign) NSInteger height;

/** 打包格式数据 (NV12/NV21/BGRA/RGBA) */
@property (nonatomic, copy, nullable) NSData *data;

/** I420 三平面 */
@property (nonatomic, copy, nullable) NSData *dataY;
@property (nonatomic, copy, nullable) NSData *dataU;
@property (nonatomic, copy, nullable) NSData *dataV;
@property (nonatomic, assign) NSInteger strideY;
@property (nonatomic, assign) NSInteger strideU;
@property (nonatomic, assign) NSInteger strideV;

/** Apple 零拷贝；format=AoqVideoPixelFormatCVPixelBuffer 时使用 */
@property (nonatomic, assign, nullable) CVPixelBufferRef pixelBuffer;

/** 时间戳，单位 ms；0 时 SDK 用本地时钟补 */
@property (nonatomic, assign) int64_t timeStamp;
@end


/* 外部编码帧 codec 类型 */
typedef NS_ENUM(NSInteger, AoqVideoCodecType) {
    AoqVideoCodecTypeJPEG = 0,
};

/* 外部已编码视频帧；调用方自行完成编码，SDK 不做二次编码，直接打包发送 */
AOQ_API @interface AoqVideoEncodedFrame : NSObject
/** 编码格式 */
@property (nonatomic, assign) AoqVideoCodecType codec;
/** 编码后数据 */
@property (nonatomic, copy, nonnull) NSData *data;
/** 宽度（像素） */
@property (nonatomic, assign) NSInteger width;
/** 高度（像素） */
@property (nonatomic, assign) NSInteger height;
/** 时间戳，单位 ms；0 时 SDK 用本地时钟补 */
@property (nonatomic, assign) int64_t timeStamp;
@end

/* 视频设备状态码 */
typedef NS_ENUM(NSInteger, AoqVideoDeviceStateCode) {
    AoqVideoDeviceNone               = 0,
    /* 摄像头正在启动 */
    AoqVideoDeviceCaptureStarting    = 1,
    /* 摄像头已启动 */
    AoqVideoDeviceCaptureStarted     = 2,
    /* 摄像头正在停止 */
    AoqVideoDeviceCaptureStopping    = 3,
    /* 摄像头已停止 */
    AoqVideoDeviceCaptureStopped     = 4,
    /* 摄像头启动失败 */
    AoqVideoDeviceCaptureFail        = 5,
};

/* 视频设备状态数据结构 */
AOQ_API @interface AoqVideoDeviceState : NSObject
/** 状态码 */
@property (nonatomic, assign) AoqVideoDeviceStateCode state;
/** 错误码 (AoqErrorCode) */
@property (nonatomic, assign) NSInteger reason;
@end

/* aoq mirror枚举值 */
typedef NS_ENUM(NSInteger, AoqMirrorMode) {
    AoqMirrorModeDisabled = 0,
    AoqMirrorModeEnabled = 1,
};

/* aoq orientation枚举值 */
typedef NS_ENUM(NSInteger, AoqOrientationMode) {
    AoqOrientationModeAuto = 0,
    AoqOrientationModePortrait = 1,
    AoqOrientationModeLandscape = 2,
};

/* Video Encoder属性结构体 */
AOQ_API @interface AoqVideoCodecConfig : NSObject

/** 外部编码模式：YES 时由客户推送已编码帧，SDK 不做采集和编码 */
@property (nonatomic, assign) BOOL isExternal;
@property (nonatomic, assign) AoqTrackType trackType;
@property (nonatomic, assign) AoqEncoderType codecType;
@property (nonatomic, assign) NSInteger width;
@property (nonatomic, assign) NSInteger height;
@property (nonatomic, assign) NSInteger fps;
@property (nonatomic, assign) NSInteger bitrate;
@property (nonatomic, assign) NSInteger minBitrate;
@property (nonatomic, assign) NSInteger keyframeInterval;
@property (nonatomic, assign) AoqMirrorMode mirrorMode;
@property (nonatomic, assign) AoqOrientationMode orientationMode;

@end


#pragma mark - Callback

/* 引擎回调协议 */
AOQ_API @protocol AoqEngineDelegate <NSObject>
/* 引擎错误 AoqErrorCode */
- (void)onError:(NSInteger)code message:(NSString * _Nonnull)message;
/* 引擎警告 AoqWarningCode */
- (void)onWarning:(NSInteger)code message:(NSString * _Nonnull)message;

/* 引擎链接状态变化回调 */
- (void)onConnectionStatusChange:(AoqConnectionStatus)status;

/* 统计数据回调 */
- (void)onStats:(AoqStats * _Nonnull)stats;

#pragma mark - Audio
/* 音频设备采集播放操作状态变化回调 */
- (void)onAudioDeviceStateChanged:(AoqAudioDeviceState * _Nonnull)state;
/* 音频设备路由变化回调 AoqAudioDeviceRouteType */
- (void)onAudioDeviceRouteChanged:(NSInteger)routeType;
/* 音频设备中断回调 */
- (void)onAudioDeviceInterrupted:(BOOL)interrupt;

#pragma mark - AudioFile
/* 音频文件状态回调 */
- (void)onAudioFileState:(AoqAudioFileState * _Nonnull)state;

#pragma mark - Video
/* 视频设备采集操作状态变化回调 */
- (void)onVideoDeviceStateChanged:(AoqVideoDeviceState * _Nonnull)state;

#pragma mark - DataMessage
/* 接收实时消息回调 */
- (void)onDataMsg:(AoqDataMsg * _Nonnull)msg;
@end

#pragma mark - "音频数据回调Delegate"

@protocol AoqAudioFrameDelegate <NSObject>
@optional
/** 采集裸数据回调 */
- (void)onCapturedAudioFrame:(AoqAudioFrameData * _Nonnull)frame;
/** 3A后数据回调 */
- (void)onProcessCapturedAudioFrame:(AoqAudioFrameData * _Nonnull)frame;
/** 推流数据回调 */
- (void)onPublishAudioFrame:(AoqTrackType)trackType frame:(AoqAudioFrameData * _Nonnull)frame;
/** 播放数据回调 */
- (void)onPlaybackAudioFrame:(AoqAudioFrameData * _Nonnull)frame;

@end

#pragma mark - VideoFrameObserver

/** 视频帧回调数据源（管线位置） */
typedef NS_ENUM(NSInteger, AoqVideoSource) {
    /** 采集后的视频数据（前处理前） */
    AoqVideoSourceCaptured  = 0,
    /** 编码前的视频数据（前处理后） */
    AoqVideoSourcePreEncode = 1,
    /** 远端解码后、渲染前的视频数据 */
    AoqVideoSourceRemote    = 2,
};

/** 视频帧回调模式 */
typedef NS_ENUM(NSInteger, AoqVideoObserverMode) {
    AoqVideoObserverModeReadOnly  = 0,
    AoqVideoObserverModeReadWrite = 1,
};

/** 视频输出宽度对齐方式 */
typedef NS_ENUM(NSInteger, AoqVideoObserverAlignment) {
    AoqVideoObserverAlignmentDefault = 0,
    AoqVideoObserverAlignmentEven    = 1,
    AoqVideoObserverAlignment4       = 2,
    AoqVideoObserverAlignment8       = 3,
    AoqVideoObserverAlignment16      = 4,
};

/** 视频帧回调配置 */
AOQ_API @interface AoqVideoObserverConfig : NSObject
/** 期望回调像素格式，默认 I420 */
@property (nonatomic, assign) AoqVideoPixelFormat       format;
/** 宽度对齐策略，默认 Default */
@property (nonatomic, assign) AoqVideoObserverAlignment alignment;
/** 读写模式，默认 ReadOnly。仅 I420 / CVPixelBuffer 支持 ReadWrite */
@property (nonatomic, assign) AoqVideoObserverMode      mode;
/** 是否对回调数据应用镜像，默认 NO */
@property (nonatomic, assign) BOOL                      mirrorApplied;
@end

#pragma mark - "视频数据回调Delegate"

@protocol AoqVideoFrameDelegate <NSObject>
@optional
/** 本地采集后裸数据回调（前处理前）
 *  @return YES 数据已修改、需写回 SDK；NO 只读
 *  @note  写回仅对 I420 / CVPixelBuffer 生效
 */
- (BOOL)onCapturedVideoFrame:(AoqVideoFrame * _Nonnull)frame;

/** 本地编码前裸数据回调（前处理后） */
- (BOOL)onPreEncodeVideoFrame:(AoqTrackType)trackType
                        frame:(AoqVideoFrame * _Nonnull)frame;

/** 远端解码后、渲染前裸数据回调 */
- (BOOL)onRemoteVideoFrame:(AoqTrackType)trackType
                     frame:(AoqVideoFrame * _Nonnull)frame;
@end

#pragma mark - Interface

/* 引擎接口 */
AOQ_API @interface AoqClientEngine : NSObject
/* 创建引擎实例 */
+ (instancetype _Nonnull)createEngine:(AoqCreateConfig * _Nonnull)config delegate:(id<AoqEngineDelegate> _Nonnull)delegate;
/* 销毁引擎实例 */
+ (int)destroy;
/* 获取SDK的版本号 */
+ (NSString * _Nonnull)getVersion;

/* 连接服务器 */
- (int)connect:(AoqConnectConfig * _Nonnull)config;
/* 断开服务器 */
- (int)disconnect;

#pragma mark - Audio

/* 打开音频采集设备 */
- (int)startAudioCapture:(AoqAudioCaptureConfig * _Nonnull)config;
/* 关闭音频采集设备 */
- (int)stopAudioCapture;
/* 静音音频采集 */
- (int)muteAudioCapture:(BOOL)mute;
/* 开始音频渲染 */
- (int)startAudioPlayer:(AoqAudioPlaybackConfig * _Nonnull)config;
/* 停止音频渲染 */
- (int)stopAudioPlayer;
/* 暂停音频渲染 */
- (int)pauseAudioPlayer:(NSInteger)fadeMs;
/* 恢复音频渲染 */
- (int)resumeAudioPlayer:(NSInteger)fadeMs;
/* 打断本轮音频通话 */
- (int)interruptAudioPlayer:(AoqTrackType)trackType fadeMs:(NSInteger)fadeMs;
/** 设置扬声器 */
- (int)enableSpeakerphone:(BOOL)enable;
/** 查询是否是扬声器 */
- (BOOL)isSpeakerphoneEnabled;
/** 设置AVAudioSession的控制权限 AoqAudioSessionRestriction */
- (int)setAudioSessionRestriction:(int)restriction;
/* 设置音频编码参数 */
- (int)setAudioEncoderConfig:(AoqAudioCodecConfig * _Nonnull)config;
- (int)setAudioDecoderConfig:(AoqAudioCodecConfig * _Nonnull)config;

#pragma mark - AudioFileMix

- (int)startAudioFile:(NSString * _Nonnull)fileId
               config:(AoqAudioFileMixConfig * _Nonnull)config;
- (int)stopAudioFile:(NSString * _Nonnull)fileId;
- (int)pauseAudioFile:(NSString * _Nonnull)fileId;
- (int)resumeAudioFile:(NSString * _Nonnull)fileId;
- (long long)getAudioFileDuration:(NSString * _Nonnull)fileId;
- (long long)getAudioFileCurrentPosition:(NSString * _Nonnull)fileId;
- (int)setAudioFilePositionMillis:(NSString * _Nonnull)fileId
                  positionMillis:(long long)positionMillis;
- (int)setAudioFileVolume:(NSString * _Nonnull)fileId
                     type:(AoqAudioStreamDirection)type
                   volume:(NSInteger)volume;
- (int)getAudioFileVolume:(NSString * _Nonnull)fileId
                     type:(AoqAudioStreamDirection)type;

#pragma mark - AudioExternalStream

/* 新增外部音频流 */
- (int)addAudioExternalStream:(NSString * _Nonnull)streamId
                       config:(AoqAudioExternalStreamConfig * _Nonnull)config;
/* 输入外部音频数据 */
- (int)pushAudioExternalStreamData:(NSString * _Nonnull)streamId
                              data:(AoqAudioFrameData * _Nonnull)data;
/* 设置外部音频流音量 (0-100) */
- (int)setAudioExternalStreamVolume:(NSString * _Nonnull)streamId
                               type:(AoqAudioStreamDirection)type
                             volume:(NSInteger)volume;
/* 获取外部音频流音量 */
- (int)getAudioExternalStreamVolume:(NSString * _Nonnull)streamId
                               type:(AoqAudioStreamDirection)type;
/* 清空外部音频流缓存 fadeoutMs: -1 默认/0 立即/>0 保留 ms 淡出 */
- (void)clearAudioExternalStreamBuffer:(NSString * _Nonnull)streamId
                              fadeoutMs:(NSInteger)fadeoutMs;
/* 移除外部音频流 */
- (int)removeAudioExternalStream:(NSString * _Nonnull)streamId;

#pragma mark - AudioFrameObserver

/* 设置音频帧数据回调 delegate */
- (int)setAudioFrameObserver:(id<AoqAudioFrameDelegate> _Nullable)delegate;
/* 开启/关闭音频帧数据回调 */
- (int)enableAudioFrameObserver:(BOOL)enabled audioSource:(AoqAudioSource)audioSource
                            config:(AoqAudioObserverConfig * _Nonnull)config;

#pragma mark - Video

/* 打开视频采集设备 */
- (int)startVideoCapture:(AoqVideoCaptureConfig * _Nonnull)config;
/* 关闭视频采集设备 */
- (int)stopVideoCapture;
/* 切换前后置摄像头 */
- (int)switchCamera:(AoqCameraDirection)direction;
/* 设置或移除本地渲染窗口；canvas 为 nil 或 canvas.view 为 nil 表示解绑 */
- (int)setLocalView:(AoqTrackType)trackType canvas:(AoqVideoCanvas * _Nullable)canvas;
/* 设置或移除远端渲染窗口；canvas 为 nil 或 canvas.view 为 nil 表示解绑 */
- (int)setRemoteView:(AoqTrackType)trackType canvas:(AoqVideoCanvas * _Nullable)canvas;
/* 设置视频编码参数，按 config.trackType 路由 */
- (int)setVideoEncoderConfig:(AoqVideoCodecConfig * _Nonnull)config;
/**
 * @brief 推送外部视频帧
 * @param trackType 路由目标 AoqTrackTypeVideo
 * @return 0 成功；AoqECVideoExternalBufferFull 缓冲满；<0 其他错误
 */
- (int)pushExternalVideoCapturedFrame:(AoqTrackType)trackType frame:(AoqVideoFrame * _Nonnull)frame;

/**
 * @brief 推送外部已编码视频帧（SDK 不做二次编码，直接打包发送）
 * @param trackType 路由目标，仅 AoqTrackTypeVideo（需先 setVideoEncoderConfig.isExternal=YES）
 * @return 0 成功；<0 失败
 */
- (int)pushExternalVideoEncodedFrame:(AoqTrackType)trackType frame:(AoqVideoEncodedFrame * _Nonnull)frame;

/**
 * @brief 控制本地媒体流的发送
 * @param trackType 路由目标 AoqTrackTypeAudio / AoqTrackTypeVideo
 * @param enable YES 启用发送，NO 停用发送
 * @return 0 调用已下发（异步执行）；<0 失败
 */
- (int)enableSendMediaStream:(AoqTrackType)trackType enable:(BOOL)enable;

#pragma mark - VideoFrameObserver

/* 设置视频帧数据回调 delegate */
- (int)setVideoFrameObserver:(id<AoqVideoFrameDelegate> _Nullable)delegate;
/* 开启/关闭某个位置的视频帧回调 */
- (int)enableVideoFrameObserver:(BOOL)enabled videoSource:(AoqVideoSource)videoSource
                         config:(AoqVideoObserverConfig * _Nonnull)config;

#pragma mark - DataMessage

/* 发送实时消息 */
- (int)sendDataMsg:(AoqDataMsg * _Nonnull)msg;

@end
