12

Próbuję odtworzyć MP3 przez AVAudioPlayer, które uważałem za dość proste. Niestety nie działa. Oto wszystko, co zrobił:AVAudioPlayer przestaje grać natychmiast z ARC

  • Dla testów, stworzyłem nową aplikację dla systemu iOS (Single View) w Xcode.
  • Dodałem ramy AVFoundation do projektu, jak również #import <AVFoundation/AVFoundation.h> do ViewController.m

  • I dodaje plik MP3 do folderu apps "dokumenty.

  • Zmieniłem ViewControllersviewDidLoad: na następujące kwestie:

Kod:

- (void)viewDidLoad 
{ 
    [super viewDidLoad];   

    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];  

    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil]; 
    audioPlayer.numberOfLoops = 1; 

    [audioPlayer play]; 

    //[NSThread sleepForTimeInterval:20]; 
} 

Niestety, dźwięk oczywiście zatrzymuje się tuż po tym jak zaczyna grać. Jeśli odkomentuję numer sleepForTimeInterval, będzie on odtwarzany przez 20 sekund, a następnie zatrzyma się. Ten problem występuje tylko podczas kompilacji z ARC, w przeciwnym razie działa bezbłędnie.

+0

Nie trzeba zaczynać kolejnego wątku, aby odtwarzać dźwięk. Czy próbowałeś podać wskaźnik błędu, aby sprawdzić, czy coś jest rejestrowane? – isaac

+0

jaki błąd dostałeś? – Daniel

+0

Tak, przekazałem NSError do initWithContensOfURL. Pozostaje jednak zero, więc ... Nie mam żadnych błędów, po prostu przestaje grać od razu. – Phlibbo

Odpowiedz

7

Problemem jest to, że podczas kompilacji z ARC trzeba się upewnić, aby zachować odniesienie do przypadków, które chcą utrzymać przy życiu jak kompilator automatycznie naprawić „niezrównoważony” alloc wkładając release połączeń (przynajmniej koncepcyjnie, przeczytaj Mikes Ash blog post for more details). Możesz rozwiązać ten problem, przypisując instancję do właściwości lub zmiennej instancji.

W przypadku Phlibbo kod zostanie przekształcony:

- (void)viewDidLoad 
{ 
    [super viewDidLoad];   
    NSString* recorderFilePath = [NSString stringWithFormat:@"%@/MySound.mp3", [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]];  
    AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:recorderFilePath] error:nil]; 
    audioPlayer.numberOfLoops = 1; 
    [audioPlayer play]; 
    [audioPlayer release]; // inserted by ARC 
} 

A AVAudioPlayer zatrzyma odtwarzanie natychmiast jak robi zwalniane, gdy nie ma odniesienia w lewo.

Ja sam nie używałem ARC i przeczytałem krótko o tym. Proszę skomentować moją odpowiedź, jeśli wiesz więcej na ten temat, a zaktualizuję ją, podając więcej informacji.

Więcej ARC informacje:
Transitioning to ARC Release Notes
LLVM Automatic Reference Counting

+0

Masz absolutną rację. Jak wspomniano w komentarzach powyżej. ;) – yinkou

+0

Nie używam ARC i próbowałem odtwarzać krótkie dźwięki w ten sam sposób, w jaki piszesz. Słyszę tylko pierwszy dźwięk (i dziękuję za błąd z AVAudioPlayer przy pierwszym odtwarzaniu dźwięku). W najlepszym razie twój kod obcina pierwsze sekundy dźwięku, w najgorszym przypadku przestaje grać, zanim dźwięk zostanie zatrzymany. – Gargo

+0

@Gargo: Jak pisze Mattias w swoim poście, kod wyjaśnia, dlaczego odtwarzacz nie działał w moim przypadku, jest celowo wadliwy. Powinieneś popatrzeć na samouczek AVAudioPlayer, jeśli nie masz z nim doświadczenia. – Phlibbo

3

Użyj AVAudioPlayer jako ivar w pliku nagłówka z strong:

@property (strong,nonatomic) AVAudioPlayer *audioPlayer 
3

Jeśli potrzebujesz wielu AVAudioPlayers grających w tym samym czasie, należy utworzyć NSMutableDictionary. Ustaw klucz jako nazwę pliku. Usuń ze słownika za pośrednictwem delegowania oddzwaniania, tak:

-(void)playSound:(NSString*)soundNum { 


    NSString* path = [[NSBundle mainBundle] 
         pathForResource:soundNum ofType:@"m4a"]; 
    NSURL* url = [NSURL fileURLWithPath:path]; 

    NSError *error = nil; 
    AVAudioPlayer *audioPlayer =[[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; 

    audioPlayer.delegate = self; 

    if (_dictPlayers == nil) 
     _dictPlayers = [NSMutableDictionary dictionary]; 
    [_dictPlayers setObject:audioPlayer forKey:[[audioPlayer.url path] lastPathComponent]]; 
    [audioPlayer play]; 

} 

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {   
    [_dictPlayers removeObjectForKey:[[player.url path] lastPathComponent]]; 
} 
+0

Jest to najlepsze rozwiązanie do jednoczesnego odtwarzania dźwięków. Jeśli korzystasz z AVAudioPlayer jako właściwości, to obiekt zostanie zwolniony, kiedy zagrasz następnym dźwiękiem, a niektórzy używają AudioServicesPlaySystemSound, ale jabłko odrzuca aplikacje, ponieważ nadal będzie odtwarzane, gdy urządzenie zostanie wyciszone i nie ma api do sprawdzenia, czy urządzenie jest wyciszony. – Zeeshan