2013-04-27 28 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