@@ -93,13 +93,35 @@ - (id)initWithDelegate:(NSObject<SuperpoweredIOSAudioIODelegate> *)d preferredBu
93
93
externalAudioDeviceName = nil ;
94
94
audioUnit = NULL ;
95
95
inputBuffer = NULL ;
96
-
96
+
97
97
#if (USES_AUDIO_INPUT == 1)
98
98
if (inputEnabled) [self createInputBuffer ];
99
99
#endif
100
- stopTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @selector (everySecond ) userInfo: nil repeats: YES ];
101
100
#if !__has_feature(objc_arc)
101
+ stopTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: @selector (everySecond ) userInfo: nil repeats: YES ];
102
102
[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
+ }];
103
125
#endif
104
126
[self resetAudio ];
105
127
@@ -109,7 +131,7 @@ - (id)initWithDelegate:(NSObject<SuperpoweredIOSAudioIODelegate> *)d preferredBu
109
131
[[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (onMediaServerReset: ) name: AVAudioSessionMediaServicesWereResetNotification object: [AVAudioSession sharedInstance ]];
110
132
[[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (onAudioSessionInterrupted: ) name: AVAudioSessionInterruptionNotification object: [AVAudioSession sharedInstance ]];
111
133
[[NSNotificationCenter defaultCenter ] addObserver: self selector: @selector (onRouteChange: ) name: AVAudioSessionRouteChangeNotification object: [AVAudioSession sharedInstance ]];
112
-
134
+
113
135
#if (USES_AUDIO_INPUT == 1)
114
136
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 170000
115
137
if ((recordOnly || [category isEqualToString: AVAudioSessionCategoryPlayAndRecord]) && ([AVAudioApplication sharedInstance ].recordPermission != AVAudioApplicationRecordPermissionGranted)) {
@@ -162,6 +184,7 @@ - (void)onMediaServerReset:(NSNotification *)notification { // The mediaserver d
162
184
};
163
185
}
164
186
187
+ #if !__has_feature(objc_arc)
165
188
- (void )everySecond { // If we waited for more than 1 second with silence, stop RemoteIO to save battery.
166
189
if (silenceFrames > samplerate) {
167
190
[self beginInterruption ];
@@ -180,6 +203,7 @@ - (void)everySecond { // If we waited for more than 1 second with silence, stop
180
203
}
181
204
}
182
205
}
206
+ #endif
183
207
184
208
- (void )beginInterruption { // Phone call, etc.
185
209
if (![NSThread isMainThread ]) [self performSelectorOnMainThread: @selector (beginInterruption ) withObject: nil waitUntilDone: NO ];
@@ -242,7 +266,7 @@ - (void)onRouteChange:(NSNotification *)notification {
242
266
[self performSelectorOnMainThread: @selector (onRouteChange: ) withObject: notification waitUntilDone: NO ];
243
267
return ;
244
268
};
245
-
269
+
246
270
bool receiverAvailable = false , usbOrHDMIAvailable = false ;
247
271
for (AVAudioSessionPortDescription *port in [[[AVAudioSession sharedInstance ] currentRoute ] outputs ]) {
248
272
if ([port.portType isEqualToString: AVAudioSessionPortUSBAudio] || [port.portType isEqualToString: AVAudioSessionPortHDMI]) {
@@ -274,7 +298,7 @@ - (void)onRouteChange:(NSNotification *)notification {
274
298
audioDeviceType type = NSStringToAudioDeviceType(port.portType );
275
299
[audioSystemInfo appendFormat: @" %s %@ (%i out)" , first ? " " : " , " , [port.portName stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet ]], channels];
276
300
first = false ;
277
-
301
+
278
302
if (type == audioDeviceType_headphone) outputChannelMap.headphoneAvailable = true ;
279
303
else if (type == audioDeviceType_HDMI) {
280
304
outputChannelMap.numberOfHDMIChannelsAvailable = channels;
@@ -293,7 +317,7 @@ - (void)onRouteChange:(NSNotification *)notification {
293
317
externalAudioDeviceName = port.portName ;
294
318
#endif
295
319
};
296
-
320
+
297
321
while (channels > 0 ) {
298
322
RemoteIOOutputChannelMap[n++] = type;
299
323
channels--;
@@ -303,15 +327,15 @@ - (void)onRouteChange:(NSNotification *)notification {
303
327
if ([[AVAudioSession sharedInstance ] isInputAvailable ]) {
304
328
[audioSystemInfo appendString: @" , Inputs: " ];
305
329
first = true ;
306
-
330
+
307
331
for (AVAudioSessionPortDescription *port in [[[AVAudioSession sharedInstance ] currentRoute ] inputs ]) {
308
332
int channels = (int )[port.channels count ];
309
333
audioDeviceType type = NSStringToAudioDeviceType(port.portType );
310
334
[audioSystemInfo appendFormat: @" %s %@ (%i in)" , first ? " " : " , " , [port.portName stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet ]], channels];
311
335
first = false ;
312
336
if (type == audioDeviceType_USB) inputChannelMap.numberOfUSBChannelsAvailable = channels;
313
337
};
314
-
338
+
315
339
if (first) [audioSystemInfo appendString: @" -" ];
316
340
};
317
341
@@ -401,7 +425,7 @@ static void streamFormatChangedCallback(void *inRefCon, AudioUnit inUnit, AudioU
401
425
static OSStatus coreAudioProcessingCallback (void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) {
402
426
__unsafe_unretained SuperpoweredIOSAudioIO *self = (__bridge SuperpoweredIOSAudioIO *)inRefCon;
403
427
self->lastCallbackTime = mach_absolute_time ();
404
-
428
+
405
429
if (!ioData) ioData = self->inputBuffer ;
406
430
div_t d = div (inNumberFrames, 8 );
407
431
if (d.rem != 0 ) {
@@ -448,7 +472,7 @@ static OSStatus coreAudioProcessingCallback(void *inRefCon, AudioUnitRenderActio
448
472
// If the app is in the background, check if we don't output anything.
449
473
if (self->background && self->saveBatteryInBackground ) self->silenceFrames += inNumberFrames; else self->silenceFrames = 0 ;
450
474
} else self->silenceFrames = 0 ;
451
-
475
+
452
476
return noErr ;
453
477
}
454
478
@@ -532,7 +556,7 @@ - (void)mapChannels {
532
556
outputChannelMap.deviceChannels [0 ] = outputChannelMap.deviceChannels [1 ] = -1 ;
533
557
for (int n = 0 ; n < 8 ; n++) outputChannelMap.HDMIChannels [n] = -1 ;
534
558
for (int n = 0 ; n < 32 ; n++) outputChannelMap.USBChannels [n] = inputChannelMap.USBChannels [n] = -1 ;
535
-
559
+
536
560
if ([(NSObject *)self ->delegate respondsToSelector: @selector (mapChannels:inputMap:externalAudioDeviceName:outputsAndInputs: )]) [delegate mapChannels: &outputChannelMap inputMap: &inputChannelMap externalAudioDeviceName: externalAudioDeviceName outputsAndInputs: audioSystemInfo];
537
561
if (!audioUnit || (numberOfChannels <= 2 )) return ;
538
562
@@ -547,7 +571,7 @@ - (void)mapChannels {
547
571
} else outputmap[n] = -1 ;
548
572
inputmap[n] = inputChannelMap.USBChannels [n];
549
573
};
550
-
574
+
551
575
#if !TARGET_IPHONE_SIMULATOR
552
576
AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Output , 0 , outputmap, 128 );
553
577
AudioUnitSetProperty (audioUnit, kAudioOutputUnitProperty_ChannelMap , kAudioUnitScope_Output , 1 , inputmap, 128 );
0 commit comments