# EZOpenSDK iOS 对讲

## 对讲模块 import 参考

```objc
#import <EZOpenSDKFramework/EZOpenSDK.h>
#import <EZOpenSDKFramework/EZPlayer.h>
#import <EZOpenSDKFramework/EZDeviceInfo.h>
#import <EZOpenSDKFramework/EZCameraInfo.h>
```

## 一、对讲能力判断

通过 EZDeviceInfo 判断设备对讲能力：
```objc
NSInteger talkCapability = deviceInfo.isSupportTalk;
// 或使用工具类（兼容子设备）
NSInteger talkCapability = [EZBusinessTool isSupportTalk:deviceInfo cameraInfo:cameraInfo];
```

| 值 | 说明 |
|----|------|
| 0 | 不支持对讲 |
| 1 | 支持全双工对讲 |
| 3 | 支持半双工对讲 |
| 4 | 同时支持全双工和半双工 |

## 二、权限申请（对讲前必须）

对讲功能需要麦克风权限，**必须在发起对讲前向系统申请**，否则第一次对讲无声音或异常。

### Info.plist 声明

```xml
<key>NSMicrophoneUsageDescription</key>
<string>需要麦克风权限以使用对讲功能</string>
```

### 动态申请示例

```objc
#import <AVFoundation/AVFoundation.h>

/// 检查麦克风权限并发起对讲
- (void)checkMicPermissionAndStartTalk {
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
    switch (authStatus) {
        case AVAuthorizationStatusNotDetermined: {
            // 首次请求权限
            AVAudioSession *avSession = [AVAudioSession sharedInstance];
            [avSession requestRecordPermission:^(BOOL granted) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (granted) {
                        [self startTalk];
                    } else {
                        [EZToast show:@"需要麦克风权限才能使用对讲功能"];
                    }
                });
            }];
            break;
        }
        case AVAuthorizationStatusAuthorized:
            // 已授权，直接开始对讲
            [self startTalk];
            break;
        case AVAuthorizationStatusDenied:
        case AVAuthorizationStatusRestricted:
            // 已拒绝或受限，提示用户去设置中开启
            [EZToast show:@"未开启麦克风权限，请在设置中开启"];
            break;
    }
}
```

### 注意事项

- **必须**在点击对讲按钮时检查权限，不要在页面启动时提前申请（避免用户困惑）
- 用户拒绝权限后应给出提示，引导去系统设置中手动开启
- iOS 首次请求麦克风权限时系统会弹出授权弹框，授权后才能正常采集音频

---

## 三、全双工对讲

全双工对讲允许双方同时发送和接收语音。

### 完整流程
```objc
@interface EZRealPlayViewController ()<EZPlayerDelegate>
@property (nonatomic, strong) EZPlayer *player;     // 预览播放器
@property (nonatomic, strong) EZPlayer *talkPlayer; // 对讲播放器（必须独立）
@end

// 1. 创建对讲播放器（需独立于预览播放器）
_talkPlayer = [EZOpenSDK createPlayerWithDeviceSerial:deviceSerial cameraNo:cameraNo];
_talkPlayer.delegate = self;

// 2. IPC 设备发起对讲
[_talkPlayer startVoiceTalk];

// 3. NVR 设备通道对讲
// [_talkPlayer startVoiceTalkNeedVoiceChannel:YES];

// 4. 停止对讲
[_talkPlayer stopVoiceTalk];

// 5. 释放对讲播放器
[EZOpenSDK releasePlayer:_talkPlayer];
```

### 对讲消息回调
```objc
- (void)player:(EZPlayer *)player didReceivedMessage:(NSInteger)messageCode {
    if (messageCode == PLAYER_VOICE_TALK_START) {
        // 对讲成功
        // 非国标设备需要关闭预览播放器声音（避免回音）
        if (self.deviceInfo.devProtoEnum == 0) {
            [_player closeSound];
        }
    } else if (messageCode == PLAYER_VOICE_TALK_END) {
        // 对讲结束，恢复预览声音
        [_player openSound];
    }
}

- (void)player:(EZPlayer *)player didPlayFailed:(NSError *)error {
    if (player == _talkPlayer) {
        // 对讲失败
        [_talkPlayer stopVoiceTalk];
    }
}
```

### 非国标 vs 国标设备对讲声音处理

| 设备类型 | 对讲成功后 | 说明 |
|---------|-----------|------|
| 非国标设备（萤石设备） | 关闭 player 声音 | talkPlayer 传输音频，player 同时播放会回音 |
| 国标设备 | 不关闭 player 声音 | talkPlayer 只采集手机端声音，设备端声音通过 player 播放 |

判断方式：`deviceInfo.devProtoEnum == 0` 为非国标设备。

## 四、半双工对讲

半双工对讲为交替模式，代码实现与全双工一致。区别在于发起成功后默认为"手机端听-设备端说"模式。

### 听说模式切换
```objc
// 切换到 手机端说-设备端听
[_talkPlayer audioTalkPressed:YES];

// 切换到 手机端听-设备端说
[_talkPlayer audioTalkPressed:NO];
```

## 五、对讲变声

在门铃、门禁等场景中保护隐私。需设备开通变声服务（仅国内支持）。

```objc
// 对讲过程中调用
[_talkPlayer startVoiceChange:EZVoiceChangeTypeMan complete:^(BOOL ret, NSError *error) {
}];
```

| 枚举值 | 效果 |
|--------|------|
| EZVoiceChangeTypeNormal | 原音 |
| EZVoiceChangeTypeMan | 大叔音 |
| EZVoiceChangeTypeClown | 小丑音 |

## 六、本地音频音量回调

对讲时获取手机本地采集的音频音量，用于音柱效果展示：
```objc
// 在 startVoiceTalk 之前设置
[_talkPlayer setVoiceTalkLoudnessInterval:0.15f];

// 代理回调
- (void)player:(EZPlayer *)player didReceivedVoiceTalkLoudness:(float)loudness {
    // loudness 为分贝值（负数）
    // [-90, -40) 显示1格
    // [-40, -35) 显示2格
    // [-35, -30) 显示3格
    // [-30, -20) 显示4格
    // [-20, 0]   显示5格
}
```

## 七、注意事项

1. 对讲播放器必须独立于预览/回放播放器，播放器功能是单一的
2. **对讲前必须申请麦克风权限**：务必在发起对讲前通过 `AVAudioSession.requestRecordPermission` 申请权限，否则第一次对讲异常
3. 非国标设备对讲开启后关闭预览播放器声音，对讲结束后恢复
4. 国标设备不能关闭预览播放器声音
5. v5.18 起对讲播放器无须配置验证码
6. IPC 设备对讲通道号：AccessToken 模式下使用实际通道号（通常为 1）；小权限 TKToken 模式下，对讲 streamToken 需使用 0 通道生成
7. iOS 对讲声音比 Android 大是正常现象（iOS 开了 AGC 音效增强）
