AVAudioPlayer和随机慢

时间:2013-04-27 21:07:09

标签: iphone ios objective-c audio avaudioplayer

这个问题可能过于模糊,不能通过StackOverflow's标准,但我必须尝试发布它,因为我的选项用完了......:/

长话短说:我的应用程序经历了随机的缓慢时期。它不会经常发生(可能每个月一次),但是当它运行的iDevice 仅完全重启时会有帮助。症状是:2-3秒的响应时间和缓慢,波动的动画;整个应用程序基本上变得无法使用。

我通过各种可能的诊断工具运行应用程序,其中没有发现任何错误;没有内存泄漏或异常高的CPU使用率。但是,这并不奇怪,考虑到应用程序非常简单,一个卡片游戏的跟踪器应用程序。

所有这些让我相信,当用户点击AVAudioPlayer时,我用来播放声音的button可能是导致问题的原因(它是唯一的,相对较高的复杂因素)整个应用程序)。但是,我不确定,这是我需要帮助的地方。我在这里提供了一个示例代码,也许有iOS音频播放经验的人可以查看它,看看是否有一些我忽略的错误。

我们走了: 首先,我初始化一个“静音播放器”,每秒钟保持播放一个静音音轨以保持AVAudioPlayer活着。这是必要的,因为在长时间不活动后被调用时,响应时间相对较长AVAudioPlayer

NSString *silenceFilePath = [[NSBundle mainBundle] pathForResource: @"silence" ofType: @"wav"];
NSURL *silenceFileURL = [[NSURL alloc] initFileURLWithPath: silenceFilePath];
silencePlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: silenceFileURL error: nil];
[silencePlayer setDelegate: self];
[silencePlayer prepareToPlay];

silenceTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f
                                                target:self
                                              selector:@selector(repeatSilence)
                                              userInfo:nil
                                               repeats:YES];

NSTimer调用以下方法:

- (void) repeatSilence
{
    if (isAudioON == YES)
    {
        if (silencePlayer.playing)
        {
            [silencePlayer stop];
            silencePlayer.currentTime = 0;
            [silencePlayer play];
        }
        else
        {
            [silencePlayer play];
        }
    }
}

其余的相当简单。我启动另一个AVAudioPlayer来播放特定的按钮声音(其中有两个):

NSString *buttonSoundFilePath = [[NSBundle mainBundle] pathForResource: @"button_pushed" ofType: @"wav"];
NSURL *buttonFileURL = [[NSURL alloc] initFileURLWithPath: buttonSoundFilePath];
buttonPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: buttonFileURL error: nil];
[buttonPlayer setDelegate: self];
[buttonPlayer prepareToPlay];

当按下按钮时,我播放声音(就像我对静音播放器一样):

if (isAudioON == YES)
{
    if (buttonPlayer.playing)
    {
        [buttonPlayer stop];
         buttonPlayer.currentTime = 0;
        [buttonPlayer play];
    }
    else
    {
        [buttonPlayer play];
    }
}

真的就是它。然而,我担心,尽管这种方法具有简单的特性,但不知何故,这种连续的音频播放创造了一个罕见的例子,其中iOS只是疯了。但这只是一个理论,这就是为什么我需要有经验的人来看看我的代码并分享他的意见。

谢谢!

更新 我发现了另外几行代码也可能与问题有关。有了它们,我将AVAudioPlayer设置为与在后台播放音乐同时工作(例如,从另一个应用程序):

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[[AVAudioSession sharedInstance] setDelegate:self];

2 个答案:

答案 0 :(得分:4)

从我的问题中收集到的,似乎你想要播放的唯一声音是相对简单和短的声音效果。如果实际上是这种情况,我就不会使用AVAudioPlayer,因为它是一个资源丰富的库,可以像在固定音量下播放音效一样简单。我会直接使用音频服务。这是我从其他地方拉出的音效类的一个例子(不记得在哪里)。

SoundEffect.h

#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>

@interface SoundEffect : NSObject
{
    SystemSoundID soundID;
}

- (id)initWithSoundNamed:(NSString *)filename;
- (void)play;

@end

SoundEffect.m

#import "SoundEffect.h"

@implementation SoundEffect

- (id)initWithSoundNamed:(NSString *)filename
{
    if ((self = [super init]))
    {
        NSURL *fileURL = [[NSBundle mainBundle] URLForResource:filename withExtension:nil];
        if (fileURL != nil)
        {
            SystemSoundID theSoundID;
            OSStatus error = AudioServicesCreateSystemSoundID((__bridge CFURLRef)fileURL, &theSoundID);
            if (error == kAudioServicesNoError)
                soundID = theSoundID;
        }
    }
    return self;
}

- (void)dealloc
{
    AudioServicesDisposeSystemSoundID(soundID);
}

- (void)play
{
    AudioServicesPlaySystemSound(soundID);
}

@end

完成本课程后,您可以使用以下代码轻松播放任何音效:

SoundEffect *mySoundEffect = [[SoundEffect alloc] initWithSoundNamed:@"mySound.wav"];
[shareSoundEffect play];

为了优化,我会在某处加载所有声音效果并静态存储它们,以便预先加载实际的声音文件,然后只要你需要它们就可以在它们上面调用“play”。与使用AVAudioPlayer相比,这样做比播放声音效果的资源更少。谁知道,也许它会解决你的问题。

预加载声音文件:

我的意思是这比听起来简单。我只是意味着在程序首次加载时初始化后,您将为每个Sound Effect对象创建一个静态引用。有几种方法可以做到这一点。我通常使用+ load方法。它看起来像这样:

在SoundEffect类的实现中添加一个静态变量

static SoundEffect *mySoundEffect;

接下来,在Sound Effect类的+ load方法中初始化该变量。

+(void)load
{
    mySoundEffect = [[SoundEffect alloc] initWithSoundNamed:@"mySound.wav"];
}

现在只需为声音效果类创建一个静态方法,如下所示:

+(void)playMySound
{
    [mySoundEffect play];
}

之后,您可以随时拨打:

播放该声音
[SoundEffect playMySound];

关于音量控制的说明:

我在我的几个IOS应用程序中使用此代码,我可以确认以下内容:

  1. 设备侧面的标准音量控制器将正常工作,但前提是用户的设置指定可以使用按钮更改铃声和警报。
  2. 无法控制代码中的声音音量。

答案 1 :(得分:1)

我从上面的代码中看到,我建议做两处修改。

1)您使用了两个AVAudioPlayer实例,一个用于每秒连续播放静音。 AVAudioPlayer的第二个实例用于在单击按钮时播放声音。同时运行两个AVAudioPlayer实例,因为在设备内存不足的某个时间点,需要同时播放静音和按键声音时设备会缓慢运行。最好使用一个AVAudioPlayer实例来播放这两种声音。

2)继续播放静音,直到用户点击按钮。当用户单击该按钮时,暂停计时器并停止当前声音并使用相同的AVAudioPlayer实例播放按钮声音。这样,当需要播放按钮声时,当按钮声音播放完毕时,不推荐的计时器将停止一段时间,当按钮声音结束播放时,恢复计时器以播放与AVAudioPlayer实例相同的静音。这将从内存和处理中消除大量负载。