2015-02-28 7 views
5

Ich habe um mit Apples glänzenden neuen AVFoundation Bibliothek zu spielen, aber bisher habe ich nicht in der Lage, die Eingabe- oder Ausgabegeräte zu setzen (zB eine USB-Soundkarte), die von einer AVAudioEngine, und mir Ich kann nichts in der Dokumentation finden, um zu sagen, dass es überhaupt möglich ist.Sets AVAudioEngine Ein- und Ausgabegeräte

Hat jemand Erfahrung damit?

+0

Als Totalen, habe ich versucht, die 'mainMixerNode' eines' AVAudioEngine' zu ​​einem 'AVAudioIONode' Gießen, die tatsächlich funktioniert (aus irgendeinem Grund?) - es ist ein Anfang. – benjineer

Antwort

2

Ok, nachdem die Dokumentation zum 10. Mal wieder zu lesen, bemerkte ich AVAudioEngine Mitglieder inputNode und outputNode hat (nicht sicher, wie ich das verpasst!).

Der folgende Code scheint die Arbeit zu tun:

AudioDeviceID inputDeviceID = 53; // get this using AudioObjectGetPropertyData 
AVAudioEngine *engine = [[AVAudioEngine alloc] init]; 
AudioUnit audioUnit = [[engine inputNode] audioUnit]; 

OSStatus error = AudioUnitSetProperty(audioUnit, 
             kAudioOutputUnitProperty_CurrentDevice, 
             kAudioUnitScope_Global, 
             0, 
             &inputDeviceID, 
             sizeof(inputDeviceID)); 

Ich lieh sich das nicht-AVFoundation C-Code aus dem CAPlayThrough Beispiel.

+0

Wenn ich versuche, das für den Ausgangsknoten zu tun ich den Fehler 'erforderliche Bedingung erhalten, ist falsch: numChannelsAggDevice> = numChannelsSubDevice'. – DanielGibbs

+0

Bekommen Sie die ID richtige Gerät 'AudioObjectGetPropertyData' verwenden oder verwenden Sie einfach' 53'? Wie viele Kanäle hat Ihr Eingabegerät? – benjineer

+0

Ich habe die richtige Geräte-ID und der Rückkehrstatus war 0, aber keine Ausgabe kam aus dem Gerät. Leider – DanielGibbs

2

Hier ist eine komplette, wenn auch etwas rau, Funktion, die einige Audio zu Testzwecken spielen wird (eine andere die Datei auswählen, wenn Sie Garage dort nicht installiert haben, natürlich). Um zu vermeiden, dass eine Geräte-ID hart codiert wird, wechselt sie zu Ihrem Alarmgerät ("Soundeffekte"), das Sie in den Systemeinstellungen einstellen können.

AVAudioEngine *engine = [[AVAudioEngine alloc] init]; 
AudioUnit outputUnit = engine.outputNode.audioUnit; 

OSStatus err = noErr; 
AudioDeviceID outputDeviceID; 
UInt32 propertySize; 

AudioObjectPropertyAddress propertyAddress = { 
    kAudioHardwarePropertyDefaultSystemOutputDevice, 
    kAudioObjectPropertyScopeGlobal, 
    kAudioObjectPropertyElementMaster }; 
propertySize = sizeof(outputDeviceID); 
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &propertySize, &outputDeviceID); 
if (err) { NSLog(@"AudioHardwareGetProperty: %d", (int)err); return; } 

err = AudioUnitSetProperty(outputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &outputDeviceID, sizeof(outputDeviceID)); 
if (err) { NSLog(@"AudioUnitSetProperty: %d", (int)err); return; } 

NSURL *url = [NSURL URLWithString:@"/Applications/GarageBand.app/Contents/Frameworks/MAAlchemy.framework/Versions/A/Resources/Libraries/WaveNoise/Liquid.wav"]; 
NSError *error = nil; 
AVAudioFile *file = [[AVAudioFile alloc] initForReading:url error:&error]; 
if (file == nil) { NSLog(@"AVAudioFile error: %@", error); return; } 

AVAudioPlayerNode *player = [[AVAudioPlayerNode alloc] init]; 
[engine attachNode:player]; 
[engine connect:player to:engine.outputNode format:nil]; 

NSLog(@"engine: %@", engine); 

if (![engine startAndReturnError:&error]) { 
    NSLog(@"engine failed to start: %@", error); 
    return; 
} 

[player scheduleFile:file atTime:[AVAudioTime timeWithHostTime:mach_absolute_time()] completionHandler:^{ 
    NSLog(@"complete"); 
}]; 
[player play]; 
+0

Das ist großartig, bekam Fehler beim Übergeben eines Formats an '[engine connect]' - passing 'nil' macht den Trick – benjineer