iPhone AVAudioPlayer 应用程序在第一次播放时冻结

Posted

技术标签:

【中文标题】iPhone AVAudioPlayer 应用程序在第一次播放时冻结【英文标题】:iPhone AVAudioPlayer app freeze on first play 【发布时间】:2010-09-22 09:40:49 【问题描述】:

我正在使用 ios SDK 中的 AVAudioPlayer 在 tableView 行中的每次单击时播放短声音。 我已经在每一行的按钮上手动创建了@selector,它启动了方法playSound:(id)receiver 。从接收器我得到声音网址,所以我可以播放它。

这个方法看起来像这样:

- (void)playSound:(id)sender 
    [audioPlayer prepareToPlay];
    UIButton *audioButton = (UIButton *)sender;
    [audioButton setImage:[UIImage imageNamed:@"sound_preview.png"] forState:UIControlStateNormal];
    NSString *soundUrl = [[listOfItems objectForKey:[NSString stringWithFormat:@"%i",currentPlayingIndex]] objectForKey:@"sound_url"];

    //here I get mp3 file from http url via NSRequest in NSData
    NSData *soundData = [sharedAppSettingsController getSoundUrl:defaultDictionaryID uri:soundUrl];
    NSError *error;
    audioPlayer = [[AVAudioPlayer alloc] initWithData:soundData error:&error];
    audioPlayer.numberOfLoops = 0;
    if (error) 
        NSLog(@"Error: %@",[error description]);
    
    else 
        audioPlayer.delegate = self;
        [audioPlayer play];
    

除了第一次播放一些声音外,一切正常。应用程序冻结约 2 秒钟,然后播放声音。点击声音按钮后,第二个和所有其他声音播放都可以正常工作。

我想知道为什么应用程序启动时第一次播放时会有大约 2 秒的卡顿?

【问题讨论】:

【参考方案1】:

根据您的代码 sn-p,audioPlayer 必须是 ivar,对吧?

在方法的顶部,您在现有的 audioPlayer 实例上调用 -prepareToPlay(至少在第一次传递时可能为零)。

稍后在该方法中,您将这个现有的音频播放器替换为一个全新的 AVAudioPlayer 实例。之前的-prepareToPlay 被浪费了。每个新的 AVAudioPlayer 都会泄漏内存。

我会尝试创建一个 AVAudioPlayer 对象的缓存,而不是缓存声音数据或 URL,每个声音一个缓存。在您的-playSound: 方法中,获取对表格行的适当音频播放器的引用,以及-play

您可以使用-tableView:cellForRowAtIndexPath: 作为适当的点来获取该行的 AVAudioPlayer 实例,也可以懒惰地创建该实例并将其缓存在那里。

您可以尝试将 -tableView:willDisplayCell:forRowAtIndexPath: 作为在行的 AVAudioPlayer 实例上调用 -prepareToPlay 的点。

或者您可以在-tableView:cellForRowAtIndexPath: 中进行准备。试验一下,看看哪种效果最好。

【讨论】:

【参考方案2】:

检查你是否在函数中异步获取数据..

NSData *soundData = [sharedAppSettingsController getSoundUrl:defaultDictionaryID uri:soundUrl];

如果您是异步获取,则执行将被阻止,直到它获取数据为止。

【讨论】:

【参考方案3】:

如果您的音频长度小于 30 秒,并且是线性 PCM 或 IMA4 格式,并且被打包为 .caf、.wav 或 .aiff,您可以使用系统声音:

导入 AudioToolbox 框架

在你的 .h 文件中创建这个变量:

SystemSoundID mySound;

在您的 .m 文件中,在您的 init 方法中实现它:

-(id)init
if (self) 
//Get path of VICTORY.WAV <-- the sound file in your bundle
 NSString* soundPath = [[NSBundle mainBundle] pathForResource:@"VICTORY" ofType:@"WAV"];
//If the file is in the bundle
if (soundPath) 
    //Create a file URL with this path
    NSURL* soundURL = [NSURL fileURLWithPath:soundPath];

    //Register sound file located at that URL as a system sound
    OSStatus err = AudioServicesCreateSystemSoundID((CFURLRef)soundURL, &mySound);

        if (err != kAudioServicesNoError) 
            NSLog(@"Could not load %@, error code: %ld", soundURL, err);
        
    

return self;

在您的 IBAction 方法中,您可以这样调用声音:

AudioServicesPlaySystemSound(mySound);

这对我有用,在按下按钮时播放的声音非常接近。希望对您有所帮助。

【讨论】:

【参考方案4】:

这有时也会发生在我的模拟器中。一切似乎都在设备上正常工作。您是否在实际硬件上进行过测试?

【讨论】:

你是对的。可能我应该在真实设备上进行测试。感谢您的建议...

以上是关于iPhone AVAudioPlayer 应用程序在第一次播放时冻结的主要内容,如果未能解决你的问题,请参考以下文章

iPhone SDK:如何使用 AVAudioPlayer 标准化音频播放?

通过 Apple iPhone Earpods 控制 AVAudioPlayer

即使 iPhone 处于静音状态,AVAudioPlayer 仍在播放环境声音

iPhone AVAudioPlayer 应用程序在第一次播放时冻结

iPhone:AVAudioPlayer 并不总是在设备上播放音频

带有 iOS 6 AVAudioPlayer 的 iPhone 4S 工作正常,但没有声音