@@ -93,13 +93,35 @@ - (id)initWithDelegate:(NSObject<SuperpoweredIOSAudioIODelegate> *)d preferredBu
9393 externalAudioDeviceName = nil ;
9494 audioUnit = NULL ;
9595 inputBuffer = NULL ;
96-
96+
9797#if (USES_AUDIO_INPUT == 1)
9898 if (inputEnabled) [self createInputBuffer ];
9999#endif
100- stopTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @selector (everySecond ) userInfo: nil repeats: YES ];
101100#if !__has_feature(objc_arc)
101+ stopTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @selector (everySecond ) userInfo: nil repeats: YES ];
102102 [self release ]; // to prevent NSTimer retaining this
103+ #else
104+ typeof (self) __weak weakSelf = self;
105+ stopTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0 repeats: YES block: ^(NSTimer * _Nonnull timer) {
106+ __strong typeof (weakSelf) strongSelf = weakSelf;
107+ if (!strongSelf) return ;
108+ if (strongSelf->silenceFrames > strongSelf->samplerate ) {
109+ [strongSelf beginInterruption ];
110+ strongSelf->silenceFrames = 0 ;
111+ } else if (!strongSelf->background && strongSelf->audioUnitRunning && strongSelf->started ) { // If it should run...
112+ mach_timebase_info_data_t timebase;
113+ mach_timebase_info (&timebase);
114+ uint64_t diff = mach_absolute_time () - strongSelf->lastCallbackTime ;
115+ diff *= timebase.numer ;
116+ diff /= timebase.denom ;
117+ if (diff > 1000000000 ) { // But it didn't call the audio processing callback in the past second.
118+ strongSelf->audioUnitRunning = false ;
119+ [[AVAudioSession sharedInstance ] setActive: NO error: nil ];
120+ [strongSelf resetAudio ];
121+ [strongSelf start ];
122+ }
123+ }
124+ }];
103125#endif
104126 [self resetAudio ];
105127
@@ -109,7 +131,7 @@ - (id)initWithDelegate:(NSObject<SuperpoweredIOSAudioIODelegate> *)d preferredBu
109131 [[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (onMediaServerReset: ) name: AVAudioSessionMediaServicesWereResetNotification object: [AVAudioSession sharedInstance ]];
110132 [[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (onAudioSessionInterrupted: ) name: AVAudioSessionInterruptionNotification object: [AVAudioSession sharedInstance ]];
111133 [[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (onRouteChange: ) name: AVAudioSessionRouteChangeNotification object: [AVAudioSession sharedInstance ]];
112-
134+
113135#if (USES_AUDIO_INPUT == 1)
114136#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000
115137 if ((recordOnly || [category isEqualToString: AVAudioSessionCategoryPlayAndRecord]) && ([AVAudioApplication sharedInstance ].recordPermission != AVAudioApplicationRecordPermissionGranted)) {
@@ -162,6 +184,7 @@ - (void)onMediaServerReset:(NSNotification *)notification { // The mediaserver d
162184 };
163185}
164186
187+ #if !__has_feature(objc_arc)
165188- (void )everySecond { // If we waited for more than 1 second with silence, stop RemoteIO to save battery.
166189 if (silenceFrames > samplerate) {
167190 [self beginInterruption ];
@@ -180,6 +203,7 @@ - (void)everySecond { // If we waited for more than 1 second with silence, stop
180203 }
181204 }
182205}
206+ #endif
183207
184208- (void )beginInterruption { // Phone call, etc.
185209 if (![NSThread isMainThread ]) [self performSelectorOnMainThread: @selector (beginInterruption ) withObject: nil waitUntilDone: NO ];
@@ -242,7 +266,7 @@ - (void)onRouteChange:(NSNotification *)notification {
242266 [self performSelectorOnMainThread: @selector (onRouteChange: ) withObject: notification waitUntilDone: NO ];
243267 return ;
244268 };
245-
269+
246270 bool receiverAvailable = false , usbOrHDMIAvailable = false ;
247271 for (AVAudioSessionPortDescription *port in [[[AVAudioSession sharedInstance ] currentRoute ] outputs ]) {
248272 if ([port.portType isEqualToString: AVAudioSessionPortUSBAudio] || [port.portType isEqualToString: AVAudioSessionPortHDMI]) {
@@ -274,7 +298,7 @@ - (void)onRouteChange:(NSNotification *)notification {
274298 audioDeviceType type = NSStringToAudioDeviceType(port.portType );
275299 [audioSystemInfo appendFormat: @" %s %@ (%i out)" , first ? " " : " , " , [port.portName stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet ]], channels];
276300 first = false ;
277-
301+
278302 if (type == audioDeviceType_headphone) outputChannelMap.headphoneAvailable = true ;
279303 else if (type == audioDeviceType_HDMI) {
280304 outputChannelMap.numberOfHDMIChannelsAvailable = channels;
@@ -293,7 +317,7 @@ - (void)onRouteChange:(NSNotification *)notification {
293317 externalAudioDeviceName = port.portName ;
294318#endif
295319 };
296-
320+
297321 while (channels > 0 ) {
298322 RemoteIOOutputChannelMap[n++] = type;
299323 channels--;
@@ -303,15 +327,15 @@ - (void)onRouteChange:(NSNotification *)notification {
303327 if ([[AVAudioSession sharedInstance ] isInputAvailable ]) {
304328 [audioSystemInfo appendString: @" , Inputs: " ];
305329 first = true ;
306-
330+
307331 for (AVAudioSessionPortDescription *port in [[[AVAudioSession sharedInstance ] currentRoute ] inputs ]) {
308332 int channels = (int )[port.channels count ];
309333 audioDeviceType type = NSStringToAudioDeviceType(port.portType );
310334 [audioSystemInfo appendFormat: @" %s %@ (%i in)" , first ? " " : " , " , [port.portName stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet ]], channels];
311335 first = false ;
312336 if (type == audioDeviceType_USB) inputChannelMap.numberOfUSBChannelsAvailable = channels;
313337 };
314-
338+
315339 if (first) [audioSystemInfo appendString: @" -" ];
316340 };
317341
@@ -401,7 +425,7 @@ static void streamFormatChangedCallback(void *inRefCon, AudioUnit inUnit, AudioU
401425static OSStatus coreAudioProcessingCallback (void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) {
402426 __unsafe_unretained SuperpoweredIOSAudioIO *self = (__bridge SuperpoweredIOSAudioIO *)inRefCon;
403427 self->lastCallbackTime = mach_absolute_time ();
404-
428+
405429 if (!ioData) ioData = self->inputBuffer ;
406430 div_t d = div (inNumberFrames, 8 );
407431 if (d.rem != 0 ) {
@@ -448,7 +472,7 @@ static OSStatus coreAudioProcessingCallback(void *inRefCon, AudioUnitRenderActio
448472 // If the app is in the background, check if we don't output anything.
449473 if (self->background && self->saveBatteryInBackground ) self->silenceFrames += inNumberFrames; else self->silenceFrames = 0 ;
450474 } else self->silenceFrames = 0 ;
451-
475+
452476 return noErr;
453477}
454478
@@ -532,7 +556,7 @@ - (void)mapChannels {
532556 outputChannelMap.deviceChannels [0 ] = outputChannelMap.deviceChannels [1 ] = -1 ;
533557 for (int n = 0 ; n < 8 ; n++) outputChannelMap.HDMIChannels [n] = -1 ;
534558 for (int n = 0 ; n < 32 ; n++) outputChannelMap.USBChannels [n] = inputChannelMap.USBChannels [n] = -1 ;
535-
559+
536560 if ([(NSObject *)self ->delegate respondsToSelector: @selector (mapChannels:inputMap:externalAudioDeviceName:outputsAndInputs: )]) [delegate mapChannels: &outputChannelMap inputMap: &inputChannelMap externalAudioDeviceName: externalAudioDeviceName outputsAndInputs: audioSystemInfo];
537561 if (!audioUnit || (numberOfChannels <= 2 )) return ;
538562
@@ -547,7 +571,7 @@ - (void)mapChannels {
547571 } else outputmap[n] = -1 ;
548572 inputmap[n] = inputChannelMap.USBChannels [n];
549573 };
550-
574+
551575#if !TARGET_IPHONE_SIMULATOR
552576 AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Output , 0 , outputmap, 128 );
553577 AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Output , 1 , inputmap, 128 );
0 commit comments