2016-06-22 2 views
1

안녕하세요.swift AVFoundation에서 오디오 메모리 문제가 발생했습니다.

필자는 지정된 피치로 오디오를 재생하는이 기능을 가지고 있습니다. NStimer에 의해 호출되어 1 초에 1 번 재생됩니다. (A SoundPlayer 클래스에 포함 된 기능과 다음 NStimer 설치와의 ViewController에서 사용)

func playPitchedAudio(audioFile: AVAudioFile, pitch: Float){ 
    audioEngine.stop() 
    audioEngine.reset() 

    let audioPlayerNode = AVAudioPlayerNode() 
    let changePitchEffect = AVAudioUnitTimePitch() 

    changePitchEffect.pitch = pitch 

    audioEngine.attachNode(audioPlayerNode) 
    audioEngine.attachNode(changePitchEffect) 

    audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil) 

    audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil) 

    audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: nil) 

    do { 
     try audioEngine.start() 
    } catch { 
     print("error") 
    } 

    audioPlayerNode.play() 

} 

이 잘 실행하지 않고 작동하지만 메모리에의 호출마다 몇 메가 바이트를 추가하고 결코 공간을 되 찾는다. 메모리 누수에 대한 조사를했지만 내 구체적인 시나리오에 도움이되는 것을 찾을 수 없으므로 누군가가 올바른 방향으로 나를 가리킬 수 있기를 바랍니다.

새 노드와 TimePitch를 호출 할 때마다 함수를 포함하는 클래스로 이동했지만 "libC++ abi.dylib : NSException 유형의 catch되지 않는 예외로 종료" 사운드가 두 번째로 재생하려고 시도 할 때 오류가 발생합니다.

도움을 주시면 감사하겠습니다.

여분의 것들. (이 참조되지 않기 때문에) 발표 될 수 없다 참조되지 않은 메모리의 조각 : -

// defined in class to be used by function 
var pitchedAudioPlayer = AVAudioPlayerNode() 
var audioEngine = AVAudioEngine() 

//Timer Start 
self.timer.invalidate() 
self.timer = NSTimer.scheduledTimerWithTimeInterval(tempo, target: self,  selector: #selector(ViewController.timeTriggerPointer), userInfo: nil, repeats: true) 

//Timer calls... (along with some other unrelated stuff) 
func timeTriggerPointer() { 
    soundPlayer.playPitchedAudio(pitchFilePath, pitch: -1000.0) 
} 

솔루션

import AVFoundation 

class SoundPlayer { 
    var pitchedAudioPlayer = AVAudioPlayerNode() 
    var audioEngine = AVAudioEngine() 

    let audioPlayerNode = AVAudioPlayerNode() 
    let changePitchEffect = AVAudioUnitTimePitch() 

    init() { 
     audioEngine.attachNode(audioPlayerNode) 
     audioEngine.attachNode(changePitchEffect) 

     audioEngine.connect(audioPlayerNode, to: changePitchEffect, format: nil) 
     audioEngine.connect(changePitchEffect, to: audioEngine.outputNode, format: nil) 
    } 

    func playPitchedAudio(audioFile: AVAudioFile, pitch: Float){ 
     audioPlayerNode.stop() 

     changePitchEffect.pitch = pitch 

     audioPlayerNode.scheduleFile(audioFile, atTime: nil,  completionHandler: nil) 



     do { 
      try audioEngine.start() 
     } catch { 
      print("error") 
     } 

     audioPlayerNode.play() 
    } 
} 
+0

무엇이 질문입니까? 누수인지 크래시인가? – matt

+0

죄송합니다. 누출 문제입니다. 충돌은 누수 문제를 해결하지 못한 것입니다. –

+0

어떻게 연결합니까? 질문이 될 것입니다. 나는 누출이 있는지 확실히 모르지만 타이머를 실행할 때 메모리 사용량은 약 120MB까지 계속 증가하고 충돌합니다. 응용 프로그램은 AVAudioPlayer를 사용할 때 제대로 작동했지만 (피치 변경을 허용하지 않음) 확실히이 기능을 일으키는 것입니다. 나는 누수를 추적하는 법을 모르지만 악기를 사용해 보았지만이 단계에서는 나보다 조금 앞서서 작성하지 않은 코드를 가리키는 것처럼 보였다.Xcode에서 직접하는 법을 모릅니다. 도와 주셔서 감사합니다! –

답변

2

A "누출"는 고도의 기술 일이다. 네가 누출 된 것 같지 않아. 당신은 점점 더 많은 물체를 가지고 있습니다.

당신은 반복 (한 번 할 때마다 타이머 화재)이 코드를 반복하고 있습니다 :

let audioPlayerNode = AVAudioPlayerNode() 
let changePitchEffect = AVAudioUnitTimePitch() 
audioEngine.attachNode(audioPlayerNode) 
audioEngine.attachNode(changePitchEffect) 

오디오 엔진 자체는, 그러나,의 속성으로, (가 함수 외부 선언의 장소에 남아 당신의 뷰 컨트롤러). 따라서 타이머가 작동 할 때마다 동일한 오디오 엔진에 노드가 두 개 더 추가됩니다. 노드가 메모리를 차지하므로 메모리가 계속 증가합니다. 놀랄 일이 아닙니다. 그런 일이 일어나기를 원하지 않는다면 그렇게하지 마십시오.

나는 거기

라고 당신이가는 그 새 노드를 만들 함께 할 수있는 뭔가 및 TimePitch 매번이었다 가정. 그래서 당신은 이미 당신 자신의 문제를 해결했습니다.

잠시 생각해보십시오. 노드가있는 오디오 엔진이 있습니다. 각 실행에서 변경할 수있는 유일한 것은 AVAudioUnitTimePitch 노드의 피치와 재생할 파일입니다. 따라서 전체 오디오 엔진과 노드를 미리 만들어서 그대로 두십시오. 속성으로 AVAudioUnitTimePitch에 대한 참조를 유지하십시오. 타이머 기능에서 해당 피치 값을 변경하십시오!

let theTimePitchNode = AVAudioUnitTimePitch() 
// and you have also added that node to the engine in your setup 
func playPitchedAudio(audioFile: AVAudioFile, pitch: Float){ 

    audioPlayerNode.stop() 

    theTimePitchNode.pitch = pitch 
    audioPlayerNode.scheduleFile(audioFile, atTime: nil, completionHandler: nil) 

    do { 
     try audioEngine.start() 
    } catch { 
     print("error") 
    } 

    audioPlayerNode.play() 

} 
+0

누출에 대한 잘못된 이해를 정리해 주셔서 감사합니다! 도움이됩니다. 그래서 나는 문제를 이해했다. 그러나 시도한 시도는 효과가 없었다! 다른 것들을 시도해보십시오. –

+0

하지만 당신은 시도한 시도를 보여주지 않았으므로 어떻게 잘못했는지 알 수 있습니까? 나는 당신이 여기서 따라야 할 전략을 보여주기 위해 나의 대답을 수정했다. – matt

+0

그래서 나는 이것을 시도했다. 그러나 소리는 이제 한 번만 재생되고 (첫 번째 타이머가 맞음) 메모리 문제는 여전히 존재한다. (질문에 코드 추가) –