--- /dev/null
+/********************************************************************************************************
+ * @file adpcm.c
+ *
+ * @brief This is the source file for BLE SDK
+ *
+ * @author BLE GROUP
+ * @date 06,2020
+ *
+ * @par Copyright (c) 2020, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Unless for usage inside a TELINK integrated circuit, redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of TELINK, nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * TELINK integrated circuit. All other usages are subject to written permission
+ * from TELINK and different commercial license may apply.
+ *
+ * 5. Licensee shall be solely responsible for any claim to the extent arising out of or
+ * relating to such deletion(s), modification(s) or alteration(s).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************************************/
+
+#include "adpcm.h"
+
+static const signed char idxtbl[] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};
+static const unsigned short steptbl[] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };
+
+#define NUM_OF_ORIG_SAMPLE 2
+
+void adpcm_to_pcm (signed short *ps, signed short *pd, int len)
+{
+ int i;
+ //byte2,byte1: predict; byte3: predict_idx; byte4:adpcm data len
+ int predict = ps[0];
+ int predict_idx = ps[1] & 0xff;
+// int adpcm_len = (ps[1]>>8) & 0xff;
+ unsigned char *pcode = (unsigned char *) (ps + NUM_OF_ORIG_SAMPLE);
+ unsigned char code;
+ code = *pcode ++;
+
+ //byte5- byte128: 124 byte(62 sample) adpcm data
+ for (i=0; i<len; i++) {
+
+ if (1) {
+ int step = steptbl[predict_idx];
+
+ int diffq = step >> 3;
+
+ if (code & 4) {
+ diffq = diffq + step;
+ }
+ step = step >> 1;
+ if (code & 2) {
+ diffq = diffq + step;
+ }
+ step = step >> 1;
+ if (code & 1) {
+ diffq = diffq + step;
+ }
+
+ if (code & 8) {
+ predict = predict - diffq;
+ }
+ else {
+ predict = predict + diffq;
+ }
+
+ if (predict > 32767) {
+ predict = 32767;
+ }
+ else if (predict < -32768) {
+ predict = -32768;
+ }
+
+ predict_idx = predict_idx + idxtbl[code & 15];
+
+ if(predict_idx < 0) {
+ predict_idx = 0;
+ }
+ else if(predict_idx > 88) {
+ predict_idx = 88;
+ }
+
+ if (i&1) {
+ code = *pcode ++;
+ }
+ else {
+ code = code >> 4;
+ }
+ }
+
+ if (0 && i < NUM_OF_ORIG_SAMPLE) {
+ *pd++ = ps[i];
+ }
+ else {
+ *pd++ = predict;
+ }
+ }
+}
+
+//例子
+#if 0
+#define MIC_ADPCM_FRAME_SIZE 128 //一包 adpcm 的数据长度 128 byte
+#define MIC_SHORT_DEC_SIZE 248
+#define DEC_BUFFER_SIZE (MIC_SHORT_DEC_SIZE<<2)
+
+unsigned char abuf_dec_wptr; // 0~3 , 4个缓冲 ,循环使用
+unsigned char abuf_mic[MIC_ADPCM_FRAME_SIZE * 4]; //压缩的语音数据adpcm缓冲区 ,4个缓冲 ,每个缓冲区 128 byte , 循环使用
+signed short abuf_dec[DEC_BUFFER_SIZE]; //解压后存放的数据,注意数组类型是 16 bit,4个缓冲,循环使用
+
+//abuf_mic 源 , abuf_dec 目的 , 每次解压 128 byte adpcm
+adpcm_to_pcm ((signed short *)(abuf_mic + (abuf_dec_wptr & 3) * MIC_ADPCM_FRAME_SIZE), abuf_dec + (abuf_dec_wptr & 3) * MIC_SHORT_DEC_SIZE, MIC_SHORT_DEC_SIZE );
+
+#endif
+
--- /dev/null
+/********************************************************************************************************
+ * @file adpcm.h
+ *
+ * @brief This is the header file for BLE SDK
+ *
+ * @author BLE GROUP
+ * @date 06,2020
+ *
+ * @par Copyright (c) 2020, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Unless for usage inside a TELINK integrated circuit, redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of TELINK, nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * TELINK integrated circuit. All other usages are subject to written permission
+ * from TELINK and different commercial license may apply.
+ *
+ * 5. Licensee shall be solely responsible for any claim to the extent arising out of or
+ * relating to such deletion(s), modification(s) or alteration(s).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************************************/
+#ifndef ADPCM_H_
+#define ADPCM_H_
+
+void adpcm_to_pcm(signed short *ps, signed short *pd, int len);
+
+#endif /* ADPCM_H_ */
184A71202BDD11C70025A332 /* AiTrippleModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 184A711E2BDD11C70025A332 /* AiTrippleModel.m */; };
184A71242BDE2DA60025A332 /* AiSecretModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 184A71222BDE2DA60025A332 /* AiSecretModel.h */; };
184A71252BDE2DA60025A332 /* AiSecretModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 184A71232BDE2DA60025A332 /* AiSecretModel.m */; };
+ 187595B32C743F9300E88FFC /* ADPCMConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 187595B12C743F9300E88FFC /* ADPCMConverter.h */; };
+ 187595B42C743F9300E88FFC /* ADPCMConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 187595B22C743F9300E88FFC /* ADPCMConverter.m */; };
+ 187595B72C74423000E88FFC /* adpcm.c in Sources */ = {isa = PBXBuildFile; fileRef = 187595B52C74423000E88FFC /* adpcm.c */; };
+ 187595B82C74423000E88FFC /* adpcm.h in Headers */ = {isa = PBXBuildFile; fileRef = 187595B62C74423000E88FFC /* adpcm.h */; };
189C15862C05726600676A80 /* AiConnectManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 189C15842C05726600676A80 /* AiConnectManager.h */; };
189C15872C05726600676A80 /* AiConnectManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 189C15852C05726600676A80 /* AiConnectManager.m */; };
18AD83292BFB22DE009BDE3B /* AiSender.h in Headers */ = {isa = PBXBuildFile; fileRef = 18AD83272BFB22DE009BDE3B /* AiSender.h */; };
184A711E2BDD11C70025A332 /* AiTrippleModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AiTrippleModel.m; sourceTree = "<group>"; };
184A71222BDE2DA60025A332 /* AiSecretModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AiSecretModel.h; sourceTree = "<group>"; };
184A71232BDE2DA60025A332 /* AiSecretModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AiSecretModel.m; sourceTree = "<group>"; };
+ 187595B12C743F9300E88FFC /* ADPCMConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ADPCMConverter.h; sourceTree = "<group>"; };
+ 187595B22C743F9300E88FFC /* ADPCMConverter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ADPCMConverter.m; sourceTree = "<group>"; };
+ 187595B52C74423000E88FFC /* adpcm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = adpcm.c; sourceTree = "<group>"; };
+ 187595B62C74423000E88FFC /* adpcm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = adpcm.h; sourceTree = "<group>"; };
189C15842C05726600676A80 /* AiConnectManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AiConnectManager.h; sourceTree = "<group>"; };
189C15852C05726600676A80 /* AiConnectManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AiConnectManager.m; sourceTree = "<group>"; };
18AD83272BFB22DE009BDE3B /* AiSender.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AiSender.h; sourceTree = "<group>"; };
184A71232BDE2DA60025A332 /* AiSecretModel.m */,
180E7AB72BD7BD7D008558E8 /* AiAudioConverter.h */,
180E7B4B2BD7BD80008558E8 /* AiAudioConverter.m */,
+ 187595B12C743F9300E88FFC /* ADPCMConverter.h */,
+ 187595B22C743F9300E88FFC /* ADPCMConverter.m */,
180E7B502BD7BD82008558E8 /* AiAudioDecoder.h */,
180E7AB52BD7BD7D008558E8 /* AiAudioDecoder.m */,
180E7B4C2BD7BD81008558E8 /* AiAudioManager.h */,
180E7B4A2BD7BD80008558E8 /* AiMouseTools.m */,
180E7B532BD7BD82008558E8 /* AiMouseTools2.h */,
180E7B4F2BD7BD81008558E8 /* AiMouseTools2.m */,
+ 187595B52C74423000E88FFC /* adpcm.c */,
+ 187595B62C74423000E88FFC /* adpcm.h */,
180E7AB82BD7BD7D008558E8 /* AiRecordManager.h */,
180E7B4E2BD7BD81008558E8 /* AiRecordManager.m */,
);
180E7CE02BD8FC4E008558E8 /* version.h in Headers */,
180E7C972BD8FC4E008558E8 /* base64.h in Headers */,
180E7CC02BD8FC4E008558E8 /* mastering_display_metadata.h in Headers */,
+ 187595B82C74423000E88FFC /* adpcm.h in Headers */,
180E7CA02BD8FC4E008558E8 /* crc.h in Headers */,
180E7C8A2BD8FC4E008558E8 /* hwcontext_cuda.h in Headers */,
180E7CA62BD8FC4E008558E8 /* hwcontext_vaapi.h in Headers */,
180E7CD72BD8FC4E008558E8 /* aes_ctr.h in Headers */,
180E7CFC2BD8FC4F008558E8 /* vorbis_parser.h in Headers */,
180E7CE82BD8FC4E008558E8 /* avcodec.h in Headers */,
+ 187595B32C743F9300E88FFC /* ADPCMConverter.h in Headers */,
180E7C962BD8FC4E008558E8 /* pixdesc.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
buildActionMask = 2147483647;
files = (
180E7BE52BD7BD84008558E8 /* AiMouseTools2.m in Sources */,
+ 187595B42C743F9300E88FFC /* ADPCMConverter.m in Sources */,
184A71252BDE2DA60025A332 /* AiSecretModel.m in Sources */,
18AD832A2BFB22DE009BDE3B /* AiSender.m in Sources */,
184A71202BDD11C70025A332 /* AiTrippleModel.m in Sources */,
189C15872C05726600676A80 /* AiConnectManager.m in Sources */,
180E7BDF2BD7BD84008558E8 /* AiMouseConfig.m in Sources */,
184A710D2BDA4C050025A332 /* AFSecurityPolicy.m in Sources */,
+ 187595B72C74423000E88FFC /* adpcm.c in Sources */,
180E7B552BD7BD83008558E8 /* AiAudioDecoder.m in Sources */,
184A71092BDA4C050025A332 /* AFURLSessionManager.m in Sources */,
);
--- /dev/null
+//
+// AiAdpcm2pcm.h
+// AiMouseSdk
+//
+// Created by incar on 2024/8/20.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ADPCMConverter : NSObject
+
+- (NSData *)convertADPCMToPCM:(NSData *)adpcmData;
+
+@end
+
+NS_ASSUME_NONNULL_END
--- /dev/null
+
+#import "ADPCMConverter.h"
+#import <Foundation/Foundation.h>
+
+
+
+@implementation ADPCMConverter
+
+static const signed char idxtbl[] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};
+static const unsigned short steptbl[] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+#define NUM_OF_ORIG_SAMPLE 2
+
+- (NSData *)convertADPCMToPCM:(NSData *)adpcmData {
+ NSMutableData *pcmData = [NSMutableData data];
+ const signed short *source = (const signed short *)[adpcmData bytes];
+ signed short *destination = (signed short *)[pcmData mutableBytes];
+ int len = (int)[adpcmData length] / sizeof(signed short);
+
+ int i;
+ // 假设 source 中的前两个元素分别是 predict 和 predict_idx
+ int predict = source[0];
+ int predict_idx = source[1] & 0xff;
+ const unsigned char *pcode = (const unsigned char *)(source + NUM_OF_ORIG_SAMPLE);
+ unsigned char code;
+ code = *pcode++;
+
+ for (i = 0; i < len; i++) {
+ if (1) {
+ int step = steptbl[predict_idx];
+
+ int diffq = step >> 3;
+
+ if (code & 4) {
+ diffq = diffq + step;
+ }
+ step = step >> 1;
+ if (code & 2) {
+ diffq = diffq + step;
+ }
+ step = step >> 1;
+ if (code & 1) {
+ diffq = diffq + step;
+ }
+
+ if (code & 8) {
+ predict = predict - diffq;
+ } else {
+ predict = predict + diffq;
+ }
+
+ if (predict > 32767) {
+ predict = 32767;
+ } else if (predict < -32768) {
+ predict = -32768;
+ }
+
+ predict_idx = predict_idx + idxtbl[code & 15];
+
+ if (predict_idx < 0) {
+ predict_idx = 0;
+ } else if (predict_idx > 88) {
+ predict_idx = 88;
+ }
+
+ if (i & 1) {
+ code = *pcode++;
+ } else {
+ code = code >> 4;
+ }
+ }
+
+ if (0 && i < NUM_OF_ORIG_SAMPLE) {
+ destination[i] = source[i];
+ } else {
+ destination[i] = predict;
+ }
+ }
+ return pcmData;
+}
+
+@end
//
#import "AiAudioManager.h"
-#import "AiMouseTools.h"
-#import "AiAudioDecoder.h"
#import <AVFoundation/AVFoundation.h>
-#import <AudioToolbox/AudioToolbox.h>
+#import "ADPCMConverter.h"
+#import "adpcm.h"
@interface AiAudioManager ()
-@property (nonatomic,strong)AiAudioDecoder *audioDecoder;
@end
@implementation AiAudioManager
-(instancetype)init{
if (self = [super init]) {
- [self setupAudioDecoder];
+
}
return self;
}
- (void)receiveData:(NSData *)data{
// [self.audioDecoder decodeSBCData:data];
- if(self.decodeCallBack)self.decodeCallBack(data);
+
+
+ NSData *pcmData = [self convertADPCMDataToPCMData:data];
+ if(self.decodeCallBack)self.decodeCallBack(pcmData);
}
+- (NSData *)convertADPCMDataToPCMData:(NSData *)adpcmData {
+ const unsigned char *adpcmBytes = (const unsigned char *)[adpcmData bytes];
+ NSUInteger adpcmLength = [adpcmData length];
-- (void)setupAudioDecoder{
- self.audioDecoder = [AiAudioDecoder sharedInstance];
- __weak typeof(self) ws = self;
- self.audioDecoder.onRecvPCMData = ^(NSData * _Nonnull pcmData) {
-// [ws showLog:[NSString stringWithFormat:@"转换后数据%@",[AiMouseTools dataToHexString:pcmData]]];
- if(ws.decodeCallBack)ws.decodeCallBack(pcmData);
- };
- [self.audioDecoder initSBCDecodec];
-}
+ signed short *ps = (signed short *)malloc(adpcmLength);
+ memcpy(ps, adpcmBytes, adpcmLength);
-- (void)showLog:(NSString *)log{
- if (self.outputLog) {
- self.outputLog([NSString stringWithFormat:@"[audio] %@",log]);
- }
+ signed short *pd = (signed short *)malloc(adpcmLength * 4);
+
+ adpcm_to_pcm(ps, pd, adpcmLength / sizeof(signed short)*2);
+
+ NSData *pcmData = [NSData dataWithBytes:pd length:adpcmLength * 4];
+
+ free(ps);
+ free(pd);
+
+ return pcmData;
}
-//- (NSData *)convertADPCMData:(NSData *)adpcmData {
-// // 定义输入的 ADPCM 音频格式
-// AudioStreamBasicDescription adpcmInputFormat;
-// memset(&adpcmInputFormat, 0, sizeof(AudioStreamBasicDescription));
-// adpcmInputFormat.mFormatID = kAudioFormatADPCM;
-// adpcmInputFormat.mSampleRate = 44100.0;
-// adpcmInputFormat.mChannelsPerFrame = 1;
-// adpcmInputFormat.mBitsPerChannel = 4;
-// adpcmInputFormat.mBytesPerPacket = 4;
-// adpcmInputFormat.mFramesPerPacket = 1;
-// adpcmInputFormat.mBytesPerFrame = 4;
-// adpcmInputFormat.mReserved = 0;
-//
-// // 定义输出的 PCM 音频格式
-// AudioStreamBasicDescription pcmOutputFormat;
-// memset(&pcmOutputFormat, 0, sizeof(AudioStreamBasicDescription));
-// pcmOutputFormat.mFormatID = kAudioFormatLinearPCM;
-// pcmOutputFormat.mSampleRate = 44100.0;
-// pcmOutputFormat.mChannelsPerFrame = 1;
-// pcmOutputFormat.mBitsPerChannel = 16;
-// pcmOutputFormat.mBytesPerPacket = 2;
-// pcmOutputFormat.mFramesPerPacket = 1;
-// pcmOutputFormat.mBytesPerFrame = 2;
-// pcmOutputFormat.mReserved = 0;
-//
-// AudioConverterRef converter;
-// OSStatus status = AudioConverterNew(&adpcmInputFormat, &pcmOutputFormat, &converter);
-//
-// if (status!= noErr) {
-// NSLog(@"Failed to create audio converter. Error: %d", (int)status);
-// return nil;
-// }
-//
-// NSMutableData *outputData = [NSMutableData data];
-//
-// const UInt32 inputBufferSize = 1024;
-// UInt8 *inputBuffer = (UInt8 *)malloc(inputBufferSize);
-// UInt32 outputBufferSize = 2048;
-// UInt8 *outputBuffer = (UInt8 *)malloc(outputBufferSize);
-//
-// NSInteger offset = 0;
-// while (offset < [adpcmData length]) {
-// NSInteger dataToRead = MIN(inputBufferSize, [adpcmData length] - offset);
-// [adpcmData getBytes:inputBuffer range:NSMakeRange(offset, dataToRead)];
-//
-// UInt32 outputUsed = 0;
-// status = AudioConverterConvertBuffer(converter, dataToRead, inputBuffer, &outputUsed, outputBuffer);
-//
-// if (status!= noErr) {
-// NSLog(@"Conversion error. Error: %d", (int)status);
-// free(inputBuffer);
-// free(outputBuffer);
-// AudioConverterDispose(converter);
-// return nil;
-// }
-//
-// [outputData appendBytes:outputBuffer length:outputUsed];
-// offset += dataToRead;
-// }
-//
-// free(inputBuffer);
-// free(outputBuffer);
-// AudioConverterDispose(converter);
-//
-// return outputData;
-//}
@end
/// - Parameters:
/// - value: 数值(1-4)
/// - finished: 设置结果回调
-- (void)setDPI:(int)value completation:(void (^)(BOOL isSuccess,NSError *error))finished;
+- (void)setDPI:(uint8_t)value completation:(void (^)(BOOL isSuccess,NSError *error))finished;
/// 打开录音
/// - finished: 执行结果回调
[self sendToDevice:data];
}
-- (void)setDPI:(int)value completation:(void (^)(BOOL isSuccess,NSError *error))finished{
+- (void)setDPI:(uint8_t)value completation:(void (^)(BOOL isSuccess,NSError *error))finished{
self.setDpi = finished;
- NSData *data = [AiMouseTools dataWithHexString:[NSString stringWithFormat:@"0601010%d",value]];
- [self sendToDevice:data];
+
+ uint8_t type = 0x06;
+ uint8_t success = 0x01;
+ uint8_t len = 0x01;
+
+ NSMutableData *mData = NSMutableData.data;
+ [mData appendBytes:&type length:1];
+ [mData appendBytes:&success length:1];
+ [mData appendBytes:&len length:1];
+ [mData appendBytes:&value length:1];
+
+// NSData *data = [AiMouseTools dataWithHexString:[NSString stringWithFormat:@"0601010%d",value]];
+ [self sendToDevice:mData];
}
- (void)getDeviceInfo:(void (^)(AiMouseDeviceInfo *deviceInfo,NSError *error))finished{
self.getMouseInfo = finished;
--- /dev/null
+/********************************************************************************************************
+ * @file adpcm.c
+ *
+ * @brief This is the source file for BLE SDK
+ *
+ * @author BLE GROUP
+ * @date 06,2020
+ *
+ * @par Copyright (c) 2020, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Unless for usage inside a TELINK integrated circuit, redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of TELINK, nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * TELINK integrated circuit. All other usages are subject to written permission
+ * from TELINK and different commercial license may apply.
+ *
+ * 5. Licensee shall be solely responsible for any claim to the extent arising out of or
+ * relating to such deletion(s), modification(s) or alteration(s).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************************************/
+
+#include "adpcm.h"
+
+static const signed char idxtbl[] = { -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8};
+static const unsigned short steptbl[] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 };
+
+#define NUM_OF_ORIG_SAMPLE 2
+
+void adpcm_to_pcm (signed short *ps, signed short *pd, int len)
+{
+ int i;
+ //byte2,byte1: predict; byte3: predict_idx; byte4:adpcm data len
+ int predict = ps[0];
+ int predict_idx = ps[1] & 0xff;
+// int adpcm_len = (ps[1]>>8) & 0xff;
+ unsigned char *pcode = (unsigned char *) (ps + NUM_OF_ORIG_SAMPLE);
+ unsigned char code;
+ code = *pcode ++;
+
+ //byte5- byte128: 124 byte(62 sample) adpcm data
+ for (i=0; i<len; i++) {
+
+ if (1) {
+ int step = steptbl[predict_idx];
+
+ int diffq = step >> 3;
+
+ if (code & 4) {
+ diffq = diffq + step;
+ }
+ step = step >> 1;
+ if (code & 2) {
+ diffq = diffq + step;
+ }
+ step = step >> 1;
+ if (code & 1) {
+ diffq = diffq + step;
+ }
+
+ if (code & 8) {
+ predict = predict - diffq;
+ }
+ else {
+ predict = predict + diffq;
+ }
+
+ if (predict > 32767) {
+ predict = 32767;
+ }
+ else if (predict < -32768) {
+ predict = -32768;
+ }
+
+ predict_idx = predict_idx + idxtbl[code & 15];
+
+ if(predict_idx < 0) {
+ predict_idx = 0;
+ }
+ else if(predict_idx > 88) {
+ predict_idx = 88;
+ }
+
+ if (i&1) {
+ code = *pcode ++;
+ }
+ else {
+ code = code >> 4;
+ }
+ }
+
+ if (0 && i < NUM_OF_ORIG_SAMPLE) {
+ *pd++ = ps[i];
+ }
+ else {
+ *pd++ = predict;
+ }
+ }
+}
+
+//例子
+#if 0
+#define MIC_ADPCM_FRAME_SIZE 128 //一包 adpcm 的数据长度 128 byte
+#define MIC_SHORT_DEC_SIZE 248
+#define DEC_BUFFER_SIZE (MIC_SHORT_DEC_SIZE<<2)
+
+unsigned char abuf_dec_wptr; // 0~3 , 4个缓冲 ,循环使用
+unsigned char abuf_mic[MIC_ADPCM_FRAME_SIZE * 4]; //压缩的语音数据adpcm缓冲区 ,4个缓冲 ,每个缓冲区 128 byte , 循环使用
+signed short abuf_dec[DEC_BUFFER_SIZE]; //解压后存放的数据,注意数组类型是 16 bit,4个缓冲,循环使用
+
+//abuf_mic 源 , abuf_dec 目的 , 每次解压 128 byte adpcm
+adpcm_to_pcm ((signed short *)(abuf_mic + (abuf_dec_wptr & 3) * MIC_ADPCM_FRAME_SIZE), abuf_dec + (abuf_dec_wptr & 3) * MIC_SHORT_DEC_SIZE, MIC_SHORT_DEC_SIZE );
+
+#endif
+
--- /dev/null
+/********************************************************************************************************
+ * @file adpcm.h
+ *
+ * @brief This is the header file for BLE SDK
+ *
+ * @author BLE GROUP
+ * @date 06,2020
+ *
+ * @par Copyright (c) 2020, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Unless for usage inside a TELINK integrated circuit, redistributions
+ * in binary form must reproduce the above copyright notice, this list of
+ * conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of TELINK, nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ * TELINK integrated circuit. All other usages are subject to written permission
+ * from TELINK and different commercial license may apply.
+ *
+ * 5. Licensee shall be solely responsible for any claim to the extent arising out of or
+ * relating to such deletion(s), modification(s) or alteration(s).
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *******************************************************************************************************/
+#ifndef ADPCM_H_
+#define ADPCM_H_
+
+void adpcm_to_pcm(signed short *ps, signed short *pd, int len);
+
+#endif /* ADPCM_H_ */
/// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备
/// - Parameter data: 数据
-(void)aiMouseSendDeviceInfoData:(NSData *)data{
-// [self showLog:[NSString stringWithFormat:@"[send] %@",data]];
[self.connectPeripheral writeValue:data forCharacteristic:self.deviceInfoCha type:CBCharacteristicWriteWithResponse];
}
//产品id
const long productID = 0xB008;
+//供应商id
+//const long vendorID = 0x6675;
+//const long productID = 0x8601;
+
@interface HidManager ()<AiMouseDelegate>
@property(nonatomic, assign) IOHIDManagerRef hidManager;///hid管理
//注册消息回调
unsigned char InputBuffer[128];
IOHIDDeviceRegisterInputReportCallback(inIOHIDDeviceRef, InputBuffer, sizeof(InputBuffer), hidReceiveData, NULL);
- IOReturn ret = IOHIDDeviceOpen(inIOHIDDeviceRef, 0);
+ IOReturn ret = IOHIDDeviceOpen(inIOHIDDeviceRef, kIOHIDOptionsTypeNone);
if (ret != kIOReturnSuccess) {
NSLog(@"打开设备信息失败!");
}else{
NSData *data = [[NSData alloc] initWithBytes:report length:len];
[[HidManager shared] showLog:[NSString stringWithFormat:@"[receive] 处理后 %@",data]];
- uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsagePageKey));
- uint32_t PrimaryUsage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsageKey));
-
- if(PrimaryUsagePage == 1 && PrimaryUsage == 0){
- [[AiMouse shared] sendDeviceDataToSdk:data];
-
- }
- else if(PrimaryUsagePage == 65283 && PrimaryUsage == 0){
- [[AiMouse shared] sendAiDataToSdk:data];
- }
+// uint32_t PrimaryUsagePage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsagePageKey));
+// uint32_t PrimaryUsage = IOHIDDevGetUInt32Property(sender, CFSTR(kIOHIDPrimaryUsageKey));
+//
+// if(PrimaryUsagePage == 1 && PrimaryUsage == 0){
+// [[AiMouse shared] sendDeviceDataToSdk:data];
+//
+// }
+// else if(PrimaryUsagePage == 65283 && PrimaryUsage == 0){
+// [[AiMouse shared] sendAiDataToSdk:data];
+// }
}
+
#pragma mark - AiDelegate
/// 设备信息数据回调,需要将此数据通过设备信息特征转发给蓝牙设备
/// - Parameter data: 数据
/// 鼠标按键指令回调
/// - Parameter data: 数据。
-/// 前 第一次单击31(开始录音), 第二次单击32(结束录音) , 按下21(开始录音)抬起22(结束录音)
-/// 中 单击42, 按下25(开始录音)抬起26(结束录音)
-/// 后 单击43,按下27(开始录音)抬起28(结束录音)
+/// 前 单击0x06, 按下0x13(开始录音)抬起0x14(结束录音)
+/// 中 单击0x03, 按下0x11(开始录音)抬起0x12(结束录音)
+/// 后 第一次单击0x01, 第二次单击0x02(结束录音) , 按下0x09(开始录音)抬起0x10(结束录音)
/// 其他未定义
- (void)aiMouseSendCmdData:(NSData *)data{
uint8 cmd;
[data getBytes:&cmd length:1];
- [self showLog:[NSString stringWithFormat:@"收到指令 = %X",cmd]];
- if(cmd == 0x31 || cmd == 0x21 || cmd == 0x25 ||cmd == 0x27){
+ if(cmd == 0x13 || cmd == 0x11 || cmd == 0x01 ||cmd == 0x09){
[self showLog:@"开始录音"];
self.recordData = [[NSMutableData alloc] init];
}
- else if(cmd == 0x32 || cmd == 0x22 || cmd == 0x26 ||cmd == 0x28){
+ else if(cmd == 0x14 || cmd == 0x12 || cmd == 0x02 ||cmd == 0x10){
[self showLog:@"结束录音"];
[self finishRecored:self.recordData];
}
- (void)aiMouseConnectStateDidChange:(BOOL)connected{
[HidManager shared].connectStateCallBack(connected);
}
+
#pragma mark - public
+/// 获取设备信息
+- (void)getDeviceInfo:(void (^)(AiMouseDeviceInfo * _Nonnull, NSError * _Nonnull))completation{
+ [[AiMouse shared] getDeviceInfo:completation];
+}
+/// setDPI
+- (void)setDPI:(int)value completation:(void (^)(BOOL isSuccess,NSError *error))finished{
+ [[AiMouse shared] setDPI:value completation:finished];
+}
+/// 打开录音
+- (void)openRecord:(void (^)(BOOL isSuccess,NSError *error))finished{
+ [[AiMouse shared] openRecord:finished];
+}
+/// 停止录音
+- (void)closeRecord:(void (^)(BOOL isSuccess,NSError *error))finished{
+ [[AiMouse shared] closeRecord:finished];
+}
+
+#pragma mark - other
-(void)connectDevice{
//设置代理
[AiMouse shared].delegate = self;
//切换当前连接类型
[[AiMouse shared] switchConnect:AiMouseConnectType_hid];
}
-/// 获取设备信息
-- (void)getDeviceInfo:(void (^)(AiMouseDeviceInfo * _Nonnull, NSError * _Nonnull))completation{
- [[AiMouse shared] getDeviceInfo:completation];
-}
/// 发送数据给设备
-(void)sendData:(NSData *)data toDevice:(IOHIDDeviceRef)device{
[self showLog:@"数据发送成功!"];
}
}
+
//将录音数据保存
- (void)finishRecored:(NSData *)data{
NSString *doc = NSTemporaryDirectory();
NSLog(@"%@",log);
}
+
/// 实际到数据长度
static inline int get_data_len(uint8_t *buf, u_long len) {
if (len <= 0 ) return 0;
}];
}
- (void)setDPI:(NSMenuItem*)sender {
- [[DeviceManger shared] setDPI:1 completation:^(BOOL isSuccess, NSError * _Nonnull error) {
+ [[DeviceManger shared] setDPI:2 completation:^(BOOL isSuccess, NSError * _Nonnull error) {
}];
}