Ich habe in meinem Projekt mit einem MTAudioProcessingTapRef gearbeitet, um die Pufferdaten in Echtzeit während der Wiedergabe von Audio-Streaming zu analysieren. Die Sache ist, ich kann den Wasserhahnprozessor nicht dazu bringen, sich korrekt zu entziehen, wenn ich ihn brauche.MTAudioProcessingTapRef in swift3.2/4 korrekt entfernen
Ich habe eine AudioViewController Swift-Klasse mit einem Verweis auf meine AudioTapProcessor Objective-C-Klasse, die Swift-Klasse ist verantwortlich für den Prozessor die Verarbeitung für das AVPlayerItem zu starten und zu stoppen. Der Prozessor hat auch einen Delegaten (in diesem Fall den View-Controller), um während der Verarbeitung über Pufferänderungen zu informieren.
Mein Problem ist, wenn ich den Prozessor delegieren als schwach (wie es sein sollte), der Prozessor wird zufällig abstürzen versuchen, einen bereits freigegebenen Delegierten informieren, weil die Prozessmethode des Tap-Prozessor wurde ein paar Mal nach dem Stopp ausgeführt Verarbeitungsaufruf Der einzige Weg, den ich gefunden habe, um dies zu beheben, ist, den Tap-Prozessor-Delegaten als eine starke Eigenschaft zu deklarieren, was offensichtlich einen Retain-Zyklus verursacht, und meine AudioViewControllers werden niemals freigegeben.
Unten einige Code, den Sie relevant aus de Situation helfen könnte:
AudioTapProcessor.h
@interface AudioTapProcessor : NSObject
@property (nonatomic, strong) AVPlayerItem *item;
@property (nonatomic, strong) id<AudioProcessorDelegate> delegate;
- (instancetype)initWithDelegate:(id<AudioProcessorDelegate>)delegate
item:(AVPlayerItem *)item;
- (void)startProcessing;
- (void)stopProcessing;
@end
AudioTapProcessor.m
void init(MTAudioProcessingTapRef tap, void *clientInfo, void
**tapStorageOut) {
*tapStorageOut = clientInfo;
}
void finalize(MTAudioProcessingTapRef tap) {}
void prepare(
MTAudioProcessingTapRef tap,
CMItemCount maxFrames,
const AudioStreamBasicDescription *processingFormat
) {}
void unprepare(MTAudioProcessingTapRef tap) {}
void process(
MTAudioProcessingTapRef tap,
CMItemCount numberFrames,
MTAudioProcessingTapFlags flags,
AudioBufferList *bufferListInOut,
CMItemCount *numberFramesOut,
MTAudioProcessingTapFlags *flagsOut
) {
//Random crashes here if I declare the delegate weak
//Something like AUDeferredRenderer-0x7ff8f448ef (364): EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
AudioTapProcessor *processor = (__bridge AudioTapProcessor *)MTAudioProcessingTapGetStorage(tap);
OSStatus err = MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, flagsOut, NULL, numberFramesOut);
AudioBuffer *pBuffer = &bufferListInOut->mBuffers[0];
UInt32 frameLength = pBuffer->mDataByteSize/sizeof(float);
float *pData = (float *)pBuffer->mData;
if (err == noErr && processor) {
if ([processor.delegate
respondsToSelector:@selector(updateWith:withSize:)]) {
[processor.delegate updateWith:pData withSize:frameLength];
}
}
}
- (void)stopProcessing
{
[self.item removeObserver:self forKeyPath:@"status"];
AVMutableAudioMixInputParameters *params =
(AVMutableAudioMixInputParameters *) _item.audioMix.inputParameters[0];
MTAudioProcessingTapRef tap = params.audioTapProcessor;
self.item.audioMix = nil;
CFRelease(tap);
//By doing this the tap processor does call its unprepare and finalize methods, so it is being deallocated fine.
}
Da ist in meinem AudioViewController.swift ich habe:
var processor: AudioTapProcessor!
override func prepareForPlayback() {
super.prepareForPlayback()
if processor == nil {
processor = AudioTapProcessor(delegate: self, item: item)
processor.startProcessing()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
player.pause()
}
deinit {
//I tried to do this early in the lifecycle(viewWillDissapear) and it is the same thing.
processor.stopProcessing()
}
Jeder Tipp wäre zu schätzen, ich verrückt damit. Danke