| 1.0.17 | 增加命令控制录音功能 | 梁振营 | 2024-05-28 |\r
| 1.0.19 | 新增连接状态回调 | 梁振营 | 2024-05-29 |\r
| 1.0.21 | 鉴权逻辑优化,隐藏鉴权接口 | 梁振营 | 2024-05-31 |\r
+| 1.0.21 | 新增设置品牌接口、USB数据异常接口回调 | 梁振营 | 2024-06-06 |\r
\r
\r
\r
## SDK相关接口\r
\r
```objective-c\r
+\r
/// 单利\r
+(AiMouse *)shared;\r
\r
/// - Parameter level: 等级\r
- (void)setLogLevel:(AiMouseLogLevel)level;\r
\r
+\r
+/// 断开连接\r
+- (void)didDisconnect;\r
+\r
/// 切换连接类型\r
/// - Parameter type: 连接类型\r
- (void)switchConnect:(AiMouseConnectType)type;\r
\r
+///// 开始鉴权\r
+///// - Parameter finished: 鉴权结果回调\r
+//- (void)startAuthentication:(void (^)(AiMouseAuthState state))complete;\r
+\r
/// 传输业务数据给sdk\r
/// - Parameter data:ai特征传过来的数据\r
- (void)sendAiDataToSdk:(NSData *)data;\r
/// - Parameter completation: 信号强度回调,如果获取成功,则value有值,否则为nil\r
- (void)getRSSI:(void (^)(NSString *value,NSError *error))complete;\r
\r
+/// 设置品牌名称\r
+/// - Parameters:\r
+/// - value: 品牌名称\r
+/// - finished: 设置结果回调\r
+- (void)setBrand:(NSString *)brand completation:(void (^)(BOOL isSuccess,NSError *error))finished;\r
+\r
/// 设置CPI\r
/// - Parameters:\r
/// - value: AiMouseDeviceInfo 中可以设置的值CPI_list\r
/// - finished: 设置结果回调\r
- (void)setMouseMode:(int)mode completation:(void (^)(BOOL isSuccess,NSError *error))finished;\r
\r
-\r
/// 获取录音模式\r
/// - Parameter complete: mode 0:常规模式,按按键打开关闭录音 1:命令模式,发命令打开关闭录音 。error为nil才代表获取成功\r
- (void)getRecordMode:(void (^)(int mode,NSError *error))complete;\r
/// - Parameter complete: mode 0:2.4G模式,1:蓝牙1模式,2:蓝牙2模式 。error为nil才代表获取成功\r
- (void)getMouseModel:(void (^)(int mode,NSError *error))complete;\r
\r
-\r
/// 打开录音\r
/// - finished: 执行结果回调\r
- (void)openRecord:(void (^)(BOOL isSuccess,NSError *error))finished;\r
```objective-c\r
@protocol AiMouseDelegate <NSObject>\r
\r
-\r
/// 设备连接状态\r
/// - Parameter connected: 是否连接\r
- (void)aiMouseConnectStateDidChange:(BOOL)connected;\r
\r
-/// 设备鉴权结果返回\r
+/// 鉴权结果返回\r
/// - Parameter authState: 鉴权状态\r
- (void)aiMouseAuthenticationResult:(AiMouseAuthState)authState;\r
\r
/// 输出sdk日志\r
/// - Parameter log: 日志\r
- (void)aiMouseAddLog:(NSString *)log;\r
+\r
+/// hid数据异常,需要重新开启监听usb设备\r
+- (void)hidDataError;\r
@end\r
+\r
```\r
\r
\r
## 注意事项\r
\r
- 设备信息数据使用的是设备信息通道,走设备信息接口;AI数据使用的是AI通道,走AI接口。\r
-- 只有鉴权成功了以后,AI相关功能才可用。authState鉴权状态,默认是Unknow。所以必须在连上蓝牙设备找到鉴权特征后,需要主动调用startAuthentication方法去鉴权。(只有鉴权成功,AI功能才可用)\r
-- SDK只封装了蓝牙相关数据处理,APP自己维护蓝牙设备的扫描连接。蓝牙设备一段时间没有任何操作的话,会自动断开连接。APP可以在检测到断开后重连。\r
-- 当切换蓝牙或者USB,需要调用switchConnect切换连接类型。\r
+- 只有鉴权成功了以后,AI相关功能才可用。\r
\r
@protocol AiMouseDelegate <NSObject>
-
/// 设备连接状态
/// - Parameter connected: 是否连接
- (void)aiMouseConnectStateDidChange:(BOOL)connected;
/// 输出sdk日志
/// - Parameter log: 日志
- (void)aiMouseAddLog:(NSString *)log;
+
+/// hid数据异常,需要重新开启监听usb设备
+- (void)hidDataError;
@end
@interface AiMouse : NSObject
}
-(NSString *)version{
- return @"1.0.27";
+ return @"1.0.29";
}
-(AiDeviceInfoManager *)deviceInfoManager{
}
- (void)didDisconnect{
[self showLog:@"系统断开连接"];
+ [self stopRecord:true];
[self.connectManager disConnected];
+
}
- (void)switchConnect:(AiMouseConnectType)type{
if(type != _connectType && self.connected){
[subData getBytes:&cmd length:1];
// [self showLog:[NSString stringWithFormat:@"cmd = %X",cmdInt]];
if(cmd == 0x31 || cmd == 0x21 || cmd == 0x25 ||cmd == 0x27){
+ self.recordManager.startCmd = subData;
[self startRecord];
}
else if(cmd == 0x32 || cmd == 0x22 || cmd == 0x26 ||cmd == 0x28){
- [self stopRecord];
+ [self stopRecord:false];
}
}
else{
#pragma mark - deviceInfoManager
-(void)sendDeviceDataToSdk:(NSData *)data{
- [self.connectManager resetTimeOut];
[self showLog:[NSString stringWithFormat:@"[receive][device] %@",data]];
+ if (self.connected == false) {
+ if([AiMouseTools dataToHexString:data].length < 10){
+ if (self.delegate) [self.delegate hidDataError];
+ return;
+ }
+ }
+
+ [self.connectManager resetTimeOut];
[self.deviceInfoManager receiveData:data];
[self checkAuthState];
}
[ws sendCmdData:cmd];
if(self.connectType == AiMouseConnectType_hid){
- [ws stopRecord];
+ [ws stopRecord:false];
}
}
}];
[self.recordManager start];
}
-- (void)stopRecord{
- [self.recordManager stop];
+- (void)stopRecord:(BOOL)sendCmd{
+ if (self.recordManager.recording ) {
+ [self.recordManager stop];
+ }
+ if (sendCmd) {
+ [self sendCmdData:self.recordManager.stopCmd];
+ }
// [self showLog:@"结束录音"];
}
NS_ASSUME_NONNULL_BEGIN
@interface AiRecordManager : NSObject
+@property (nonatomic,assign)BOOL recording;
+@property (nonatomic,strong)NSData *startCmd;
+@property (nonatomic,readonly)NSData *stopCmd;
@property (nonatomic,strong)void (^didRecordData)(NSData *data);
- (void)checkPermissions;
// return manager;
//}
+/// 前 第一次单击31(开始录音), 第二次单击32(结束录音) , 按下21(开始录音)抬起22(结束录音)
+/// 中 单击42, 按下25(开始录音)抬起26(结束录音)
+/// 后 单击43,按下27(开始录音)抬起28(结束录音)
+-(NSData *)stopCmd{
+
+ uint8 startCmd;
+ [self.startCmd getBytes:&startCmd length:1];
+
+ uint8 cmd = 0x00;
+ if (startCmd== 0x31) {
+ cmd = 0x32;
+ }
+ else if (startCmd == 0x21) {
+ cmd = 0x22;
+ }
+ else if (startCmd == 0x25) {
+ cmd = 0x26;
+ }
+ else if (startCmd == 0x27) {
+ cmd = 0x28;
+ }
+
+ NSData *data = [NSData dataWithBytes:&cmd length:1];
+ return data;
+}
+
-(instancetype)init{
if (self = [super init ]) {
self.isAllowRecord = false;
// catch let error as NSError {
// print("ERROR:", error)
// }
-
+ self.recording = true;
self.audioEngine = [[AVAudioEngine alloc] init];
AVAudioInputNode *input = self.audioEngine.inputNode;
- (void)stop{
[self.audioEngine stop];
+ self.recording = false;
// [self finishRecored:self.recordData];
}
- (void)open{
self.hidManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
- IOHIDManagerScheduleWithRunLoop(self.hidManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
+ IOHIDManagerScheduleWithRunLoop(self.hidManager, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOReturn ret = IOHIDManagerOpen(self.hidManager, 0L);
if (ret != kIOReturnSuccess) {
NSLog(@"打开设备失败!");
#pragma mark - Hid CallBack
/// 匹配到设备回调
static void hidAppearDevice(void *inContext,IOReturn inResult,void *inSender,IOHIDDeviceRef inIOHIDDeviceRef) {
- uint32_t vid = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDVendorIDKey));
- uint32_t pid = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDProductIDKey));
+ [[HidManager shared] showLog:[NSString stringWithFormat:@"发现设备 %@\n ",inIOHIDDeviceRef]];
uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsagePageKey));
uint32_t PrimaryUsage = IOHIDDevGetUInt32Property(inIOHIDDeviceRef, CFSTR(kIOHIDPrimaryUsageKey));
- [[HidManager shared] showLog:[NSString stringWithFormat:@"vid = %u, pid = %u, PrimaryUsagePage = %u, PrimaryUsage = %u,",vid,pid,PrimaryUsagePage,PrimaryUsage]];
- [[HidManager shared] showLog:[NSString stringWithFormat:@"发现设备 %@\n ",inIOHIDDeviceRef]];
-
- // PrimaryUsagePage=1 PrimaryUsage=0,设备信息
- // PrimaryUsagePage=65283 PrimaryUsage=0,ai
if(PrimaryUsagePage == 1 && PrimaryUsage == 0){
//设备信息
[HidManager shared].deviceInfoCha = inIOHIDDeviceRef;
}else{
NSLog(@"打开设备信息成功!");
}
+ CFRetain(inIOHIDDeviceRef);
+ IOHIDDeviceScheduleWithRunLoop(inIOHIDDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
else if(PrimaryUsagePage == 65283 && PrimaryUsage == 0){
//ai
}else{
NSLog(@"打开AI成功!");
}
+ CFRetain(inIOHIDDeviceRef);
+ IOHIDDeviceScheduleWithRunLoop(inIOHIDDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
}
if(PrimaryUsagePage == 1 && PrimaryUsage == 0){
[HidManager shared].deviceInfoCha = nil;
+ [HidManager shared].aiCha = nil;
[[AiMouse shared] didDisconnect];
}
}
if(PrimaryUsagePage == 1 && PrimaryUsage == 0){
[[AiMouse shared] sendDeviceDataToSdk:data];
+
}
else if(PrimaryUsagePage == 65283 && PrimaryUsage == 0){
[[AiMouse shared] sendAiDataToSdk:data];
// [self showLog:log];
}
+-(void)hidDataError{
+ [self close];
+ [self open];
+}
+
// 连接状态改变
- (void)aiMouseConnectStateDidChange:(BOOL)connected{
[HidManager shared].connectStateCallBack(connected);
}
#pragma mark - public
-(void)connectDevice{
- //连上设备
-// [HidManager shared].connectStateCallBack(true);
//设置代理
[AiMouse shared].delegate = self;
//切换当前连接类型
[self showLog:@"请先连上设备"];
return;
}
-// [self showLog:[NSString stringWithFormat:@"开始发送[send] %@",data]];
IOReturn ret = IOHIDDeviceSetReport(device, kIOHIDReportTypeOutput, 0, data.bytes, data.length);
if (ret != kIOReturnSuccess) {