// Copyright 2018 Cameron Kaiser, all rights reserved // Replaces main.m in TestMTCoreAudio // BSD license #import #import #import #import #import #import #import "TestDelegate.h" #import "MTConversionBuffer.h" @interface CKAudioTarget : NSObject { MTCoreAudioDevice *inputDevice; MTCoreAudioDevice *outputDevice; id converter; } - (void)playThruFrom:(MTCoreAudioDevice *)newInputDevice to:(MTCoreAudioDevice *)newOutputDevice; - (void)stop; @end @implementation CKAudioTarget - (void) audioDeviceDidOverload:(MTCoreAudioDevice *)theDevice { NSLog ( @"overload: %@", [theDevice deviceUID] ); } - (void) audioDeviceStartDidFail:(MTCoreAudioDevice *)theDevice forReason:(OSStatus)theReason { NSLog ( @"device:%@ start failed, reason:%4.4s\n", [theDevice deviceUID], (char *)&theReason ); } - (void) MTConversionBuffer:sender didUnderrunFrames:(unsigned)count { // NSLog ( @"underrun frames: %u\n", count ); } - (void) MTConversionBuffer:sender didOverrunFrames:(unsigned)count { // NSLog ( @"overrun frames: %u\n", count ); } - (OSStatus) recordIOForDevice:(MTCoreAudioDevice *)theDevice timeStamp:(const AudioTimeStamp *)inNow inputData:(const AudioBufferList *)inInputData inputTime:(const AudioTimeStamp *)inInputTime outputData:(AudioBufferList *)outOutputData outputTime:(const AudioTimeStamp *)inOutputTime clientData:(void *)inClientData { [converter writeFromAudioBufferList:inInputData timestamp:inInputTime]; return noErr; } - (OSStatus) playbackIOForDevice:(MTCoreAudioDevice *)theDevice timeStamp:(const AudioTimeStamp *)inNow inputData:(const AudioBufferList *)inInputData inputTime:(const AudioTimeStamp *)inInputTime outputData:(AudioBufferList *)outOutputData outputTime:(const AudioTimeStamp *)inOutputTime clientData:(void *)inClientData { [converter readToAudioBufferList:outOutputData timestamp:inOutputTime]; return noErr; } - (void) playThruFrom:(MTCoreAudioDevice *)newInputDevice to:(MTCoreAudioDevice *)newOutputDevice { if (inputDevice || outputDevice) [self stop]; inputDevice = newInputDevice; [inputDevice retain]; [inputDevice setDelegate:self]; SEL inputSelector = @selector(recordIOForDevice:timeStamp:inputData:inputTime:outputData:outputTime:clientData:); [inputDevice setIOTarget:self withSelector:inputSelector withClientData:nil]; [inputDevice setDeviceBufferSizeInFrames:ceil(([inputDevice nominalSampleRate] / 100))]; outputDevice = newOutputDevice; [outputDevice retain]; [outputDevice setDelegate:self]; SEL outputSelector = @selector(playbackIOForDevice:timeStamp:inputData:inputTime:outputData:outputTime:clientData:); [outputDevice setIOTarget:self withSelector:outputSelector withClientData:nil]; [outputDevice setDeviceBufferSizeInFrames:ceil(([outputDevice nominalSampleRate] / 100))]; if (converter) [converter release]; converter = [[MTConversionBuffer alloc] initWithSourceDevice:inputDevice destinationDevice:outputDevice]; [converter setDelegate:self]; // The radioSHARK tends to overdrive its output. This uses the // built-in converter to keep it from clipping as much. [converter setGain:0.8 forOutputChannel:0]; [converter setGain:0.8 forOutputChannel:1]; [outputDevice deviceStart]; [inputDevice deviceStart]; } - (void)stop { if (inputDevice) { [inputDevice deviceStop]; [inputDevice release]; inputDevice = nil; } if (outputDevice) { [outputDevice deviceStop]; [outputDevice release]; outputDevice = nil; } } @end int main (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // "radioSHARK" : v2 // "RadioSHARK" : v1 // These strings are system dependent. You can get them from the // demo application with MTCoreAudio, or enumerating the device UIDs // yourself. The hex value varies on the connected port and controller. MTCoreAudioDevice *inputDevice = [MTCoreAudioDevice deviceWithUID:@"AppleUSBAudioEngine:Griffin Technology, Inc.:radioSHARK:2b100000:1"]; // MTCoreAudioDevice *inputDevice = [MTCoreAudioDevice deviceWithUID:@"AppleUSBAudioEngine:Griffin Technology, Inc.:radioSHARK:9130000:1"]; MTCoreAudioDevice *outputDevice = [MTCoreAudioDevice defaultOutputDevice]; CKAudioTarget *playThru = [[[CKAudioTarget alloc] init] autorelease]; [playThru playThruFrom:inputDevice to:outputDevice]; [[NSRunLoop currentRunLoop] run]; [pool release]; return 0; }