2013-04-27 53 views
7

这个问题可能是过于空泛通过StackOverflow's标准,但我必须尝试张贴,因为我跑出来的选项...:/AVAudioPlayer和随机慢度

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

我已经通过每种可能的诊断工具运行该应用程序,但没有发现任何错误;没有内存泄漏或CPU使用率异常高。但是,这并不令人惊讶,因为该应用程序非常简单,适用于纸牌游戏的跟踪器应用程序。

所有这些让我相信,当用户点击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]; 

回答

1

我从代码中观察到以上情况,我建议两个改变。

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

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

+0

好的见解。我会在这个周末给他们一个尝试并分享结果! – 2013-05-09 19:10:52

4

从我从您的问题中收集的信息看来,您想要播放的唯一声音似乎相对简单且音质较短。如果事实如此,我不会使用AVAudioPlayer,因为它是一个资源较重的库,可以用于以固定音量播放音效的简单事情。我会直接使用音频服务。以下是我从其他地方拉出的Sound Effect Class的示例(不记得在哪里了)。

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]; 

为了优化,我会将所有声音效果加载到某处并静态存储它们,以便获得实际的声音文件被预加载,然后只要你需要它们就打电话给他们“播放”。这样做比使用AVAudioPlayer播放声音效果要少得多。谁知道,也许它会解决你的问题。

预加载声音文件:

我的意思是由这是什么简单的比它的声音。我的意思是你将在程序第一次加载时初始化它们之后为每个Sound Effect对象创建一个静态引用。有几种方法可以做到这一点。我通常使用+加载方法。这将是这个样子:

添加静态变量在SoundEffect类

static SoundEffect *mySoundEffect; 

接下来的实施,在初始化的音效类+ load方法变量。

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

现在刚刚创建的声音效果一流这样一个静态方法:通过调用

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

之后,你可以播放声音在任何时间:

[SoundEffect playMySound]; 

关于音量控制的说明:

我在几个IOS应用程序中使用此代码,并且我可以确认followi ng:

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

我一定会试试这个。但是,我注意到了代码中的SystemSoundID变量。这是否意味着你的方法使用系统声音对象来播放声音?如果是这样,我的问题是在使用系统声音时缺乏价值控制。我试过了。 此外,你可以提供一个如何“预载”声音文件的例子吗?我不熟悉这种做法。 – 2013-05-09 19:10:00

+0

这是正确的,在这种情况下,您将无法以编程方式控制音效的音量。如果您需要声音效果处于较低或较高音量,则需要在较低和较高音量时使用不同版本的声音文件。 如果您需要对音效的音量进行动态控制,那么不幸的是,这种解决方案可能并不适合您。 :( – csundman 2013-05-09 19:12:57

+0

编辑与预载声音效果的解释 – csundman 2013-05-09 19:22:25