From: liangzhenying <867174124@qq.com> Date: Mon, 15 Dec 2025 09:14:58 +0000 (+0800) Subject: 骨传导调试 X-Git-Tag: 1.0.2~34 X-Git-Url: http://git.snicker.com.cn/Users/apple/Desktop/static/gitweb.css?a=commitdiff_plain;h=4792f1d50bcfa2be96d2a601723bd0b1dab73d35;p=mirrors%2FShenYin.git 骨传导调试 --- diff --git a/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PcmSound.m b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PcmSound.m new file mode 100644 index 0000000..c3e509a --- /dev/null +++ b/DeepChordsSdk_iOS/DeepChordsSdk/Example/Example/VC/PcmSound.m @@ -0,0 +1,267 @@ +#import "PcmSound.h" +#import + +#if TARGET_OS_IOS +#import +#endif + +#define kOutputBus 0 +#define NAMESPACE @"pcm_sound" // Assuming this is the namespace you want + +typedef NS_ENUM(NSUInteger, LogLevel) { + none = 0, + error = 1, + standard = 2, + verbose = 3, +}; + +@interface PcmSound () +@property(nonatomic) LogLevel mLogLevel; +@property(nonatomic) AudioComponentInstance mAudioUnit; +@property(nonatomic) NSMutableData *mSamples; +@property(nonatomic) int mNumChannels; +@property(nonatomic) int mFeedThreshold; +@property(nonatomic) bool mDidInvokeFeedCallback; +@end + +@implementation PcmSound + ++ (instancetype)sharedInstance { + static PcmSound *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + sharedInstance.mLogLevel = verbose; + sharedInstance.mSamples = [NSMutableData new]; + sharedInstance.mFeedThreshold = 0; + sharedInstance.mDidInvokeFeedCallback = false; + }); + return sharedInstance; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + + } + return self; +} + +-(void)dealloc { + +} + +-(void)setLogLevel:(NSNumber*)logLevelNumber { + self.mLogLevel = (LogLevel)[logLevelNumber integerValue]; +} + +-(void)setup:(int)sampleRate withchannels:(int)numChannels { + + self.mNumChannels = numChannels; + + // cleanup + if (_mAudioUnit != nil) { + [self cleanup]; + } + + // create + AudioComponentDescription desc; + desc.componentType = kAudioUnitType_Output; +#if TARGET_OS_IOS + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#else // MacOS + desc.componentSubType = kAudioUnitSubType_DefaultOutput; +#endif + desc.componentFlags = 0; + desc.componentFlagsMask = 0; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + + AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc); + OSStatus status = AudioComponentInstanceNew(inputComponent, &_mAudioUnit); + if (status != noErr) { + //NSString* message = [NSString stringWithFormat:@"AudioComponentInstanceNew failed. OSStatus: %@", @(status)]; + return; + } + + // set stream format + AudioStreamBasicDescription audioFormat; + audioFormat.mSampleRate = sampleRate; + audioFormat.mFormatID = kAudioFormatLinearPCM; + audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + audioFormat.mFramesPerPacket = 1; + audioFormat.mChannelsPerFrame = self.mNumChannels; + audioFormat.mBitsPerChannel = 16; + audioFormat.mBytesPerFrame = self.mNumChannels * (audioFormat.mBitsPerChannel / 8); + audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket; + + status = AudioUnitSetProperty(_mAudioUnit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + kOutputBus, + &audioFormat, + sizeof(audioFormat)); + if (status != noErr) { + //NSString* message = [NSString stringWithFormat:@"AudioUnitSetProperty StreamFormat failed. OSStatus: %@", @(status)]; + return; + } + + // set callback + AURenderCallbackStruct callback; + callback.inputProc = RenderCallback; + callback.inputProcRefCon = (__bridge void *)(self); + + status = AudioUnitSetProperty(_mAudioUnit, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Global, + kOutputBus, + &callback, + sizeof(callback)); + if (status != noErr) { + //NSString* message = [NSString stringWithFormat:@"AudioUnitSetProperty SetRenderCallback failed. OSStatus: %@", @(status)]; + return; + } + + // initialize + status = AudioUnitInitialize(_mAudioUnit); + if (status != noErr) { + //NSString* message = [NSString stringWithFormat:@"AudioUnitInitialize failed. OSStatus: %@", @(status)]; + return; + } +} + +-(void)feed:(NSData*)buffer { + + @synchronized (self.mSamples) { + [self.mSamples appendData:buffer]; + } + + // reset + self.mDidInvokeFeedCallback = false; + + // start playback if we can + if (_mAudioUnit != nil) { + UInt32 isPlaying = 0; + UInt32 size = sizeof(isPlaying); + OSStatus status = AudioUnitGetProperty(_mAudioUnit, + kAudioOutputUnitProperty_IsRunning, + kAudioUnitScope_Global, + 0, + &isPlaying, + &size); + if (status != noErr) { + //NSString* message = [NSString stringWithFormat:@"AudioUnitGetProperty IsRunning failed. OSStatus: %@", @(status)]; + return; + } + if (!isPlaying) { + status = AudioOutputUnitStart(_mAudioUnit); + if (status != noErr) { + //NSString* message = [NSString stringWithFormat:@"AudioOutputUnitStart failed. OSStatus: %@", @(status)]; + return; + } + } + } +} + +-(void)setFeedThreshold:(NSNumber*)feedThreshold { + self.mFeedThreshold = [feedThreshold intValue]; +} + +-(BOOL)isPlaying { + return self.mSamples.length > 0; +} + + +- (void)cleanup +{ + if (_mAudioUnit != nil) { + AudioUnitUninitialize(_mAudioUnit); + AudioComponentInstanceDispose(_mAudioUnit); + _mAudioUnit = nil; + } + @synchronized (self.mSamples) { + self.mSamples = [NSMutableData new]; + } +} + +- (void)stopAudioUnit +{ + if (_mAudioUnit != nil) { + UInt32 isRunning = 0; + UInt32 size = sizeof(isRunning); + OSStatus status = AudioUnitGetProperty(_mAudioUnit, + kAudioOutputUnitProperty_IsRunning, + kAudioUnitScope_Global, + 0, + &isRunning, + &size); + if (status != noErr) { + NSLog(@"AudioUnitGetProperty IsRunning failed. OSStatus: %@", @(status)); + return; + } + if (isRunning) { + status = AudioOutputUnitStop(_mAudioUnit); + if (status != noErr) { + NSLog(@"AudioOutputUnitStop failed. OSStatus: %@", @(status)); + } else { + NSLog(@"AudioUnit stopped because no more samples"); + } + } + } +} + + +static OSStatus RenderCallback(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, + UInt32 inNumberFrames, + AudioBufferList *ioData) +{ + PcmSound *instance = (__bridge PcmSound *)(inRefCon); + + NSUInteger remainingFrames; + BOOL shouldRequestMore = false; + + @synchronized (instance.mSamples) { + + // clear + memset(ioData->mBuffers[0].mData, 0, ioData->mBuffers[0].mDataByteSize); + + NSUInteger bytesToCopy = MIN(ioData->mBuffers[0].mDataByteSize, [instance.mSamples length]); + + // provide samples + memcpy(ioData->mBuffers[0].mData, [instance.mSamples bytes], bytesToCopy); + + // pop front bytes + NSRange range = NSMakeRange(0, bytesToCopy); + [instance.mSamples replaceBytesInRange:range withBytes:NULL length:0]; + + remainingFrames = [instance.mSamples length] / (instance.mNumChannels * sizeof(short)); + + // should request more frames? + shouldRequestMore = remainingFrames <= instance.mFeedThreshold && !instance.mDidInvokeFeedCallback; + } + + // stop running, if needed + if (remainingFrames == 0) { + dispatch_async(dispatch_get_main_queue(), ^{ + [instance stopAudioUnit]; + }); + } + + if (shouldRequestMore) { + instance.mDidInvokeFeedCallback = true; + //NSDictionary *response = @{@"remaining_frames": @(remainingFrames)}; + dispatch_async(dispatch_get_main_queue(), ^{ + if ([instance.delegate respondsToSelector:@selector(remaining:)]) { + [instance.delegate remaining:remainingFrames]; + } + }); + } + + return noErr; +} + + +@end