Ich versuche, einen MTAudioProcessingTap basierend auf dem Tutorial aus diesem Blog-Eintrag zu erstellen - http://chritto.wordpress.com/2013/01/07/processing-avplayers-audio-with-mtaudioprocessingtap/
Das Problem liegt im Umgang mit verschiedenen Audioformaten. Ich konnte erfolgreich einen Tap mit M4A's erstellen, aber es funktioniert nicht mit MP3's. Noch seltsamer für mich ist - der Code funktioniert auf einem Simulator mit beiden Formaten, aber nicht auf dem Gerät (nur m4a funktioniert). Ich erhalte den OSStatusError-Code 50 in meinem Prozessblock, und wenn ich versuche, die AudioBufferList-Daten zu verwenden, erhalte ich einen schlechten Zugriff. Der Tap-Setup und die Callbacks, die ich verwende, sind unten aufgeführt. Der Prozessblock scheint der Übeltäter zu sein (denke ich), aber ich weiß nicht, warum.
Update - Es scheint, als ob es sehr sporadisch auf dem ersten Mal nach einer kurzen Pause funktioniert, aber nur beim ersten Mal. Ich habe das Gefühl, dass es eine Art Sperrung auf meiner Audiodatei gibt. Weiß jemand, was im Unprepare-Block für die Bereinigung getan werden sollte?
Unprepare-Block -
void unprepare(MTAudioProcessingTapRef tap)
{
NSLog(@"Audio Tap Processor wird entladen");
}
Prozessblock (wird OSStatus-Fehler 50 erhalten) -
void process(MTAudioProcessingTapRef tap, CMItemCount numberFrames,
MTAudioProcessingTapFlags flags, AudioBufferList *bufferListInOut,
CMItemCount *numberFramesOut, MTAudioProcessingTapFlags *flagsOut)
{
OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut,
flagsOut, NULL, numberFramesOut);
if (err) NSLog(@"Fehler bei GetSourceAudio: %ld", err);
}
Tap-Setup -
NSURL *assetURL = [[NSBundle mainBundle] URLForResource:@"DLP" withExtension:@"mp3"];
assert(assetURL);
// Erstellen des AVAsset
AVAsset *asset = [AVAsset assetWithURL:assetURL];
assert(asset);
// Erstellen des AVPlayerItem
AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:asset];
assert(playerItem);
assert([asset tracks]);
assert([[asset tracks] count]);
self.player = [AVPlayer playerWithPlayerItem:playerItem];
assert(self.player);
// Fortsetzung von dem Punkt, an dem wir das AVAsset erstellt haben...
AVAssetTrack *audioTrack = [[asset tracks] objectAtIndex:0];
AVMutableAudioMixInputParameters *inputParams = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:audioTrack];
// Erstellen eines Processing Tap für die Eingabeparameter
MTAudioProcessingTapCallbacks callbacks;
callbacks.version = kMTAudioProcessingTapCallbacksVersion_0;
callbacks.clientInfo = (__bridge void *)(self);
callbacks.init = init;
callbacks.prepare = prepare;
callbacks.process = process;
callbacks.unprepare = unprepare;
callbacks.finalize = finalize;
MTAudioProcessingTapRef tap;
// Die Create-Funktion erstellt eine Kopie unserer Callbacks-Struktur
OSStatus err = MTAudioProcessingTapCreate(kCFAllocatorDefault, &callbacks,
kMTAudioProcessingTapCreationFlag_PostEffects, &tap);
if (err || !tap) {
NSLog(@"Der Audio Processing Tap konnte nicht erstellt werden");
return;
}
assert(tap);
// Weisen Sie den Tap den Eingabeparametern zu
inputParams.audioTapProcessor = tap;
// Erstellen eines neuen AVAudioMix und weisen Sie es unserem AVPlayerItem zu
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
audioMix.inputParameters = @[inputParams];
playerItem.audioMix = audioMix;
// Und dann erstellen wir den AVPlayer mit dem playerItem und senden ihm die Wiedergabe-Nachricht...
[self.player play];