2013-04-27 30 views
7

Câu hỏi này có thể quá mơ hồ để vượt qua StackOverflow's tiêu chuẩn, nhưng tôi phải cố gắng đăng nó bởi vì tôi đang chạy ra khỏi tùy chọn ...:/AVAudioPlayer và Random Chậm

câu chuyện dài ngắn: Tôi có một ứng dụng mà trải qua những giai đoạn chậm chạp ngẫu nhiên. Nó không xảy ra quá thường xuyên (có thể một lần mỗi tháng), nhưng khi nó chỉ khởi động lại hoàn toàn của iDevice nó chạy trên giúp. Các triệu chứng là: thời gian đáp ứng 2-3 giây và hình ảnh động chậm chạp, chậm chạp; toàn bộ ứng dụng về cơ bản trở nên không sử dụng được.

Tôi đã chạy ứng dụng thông qua mọi công cụ chẩn đoán có thể, không tìm thấy công cụ nào sai; không có rò rỉ bộ nhớ hoặc sử dụng CPU cao bất thường. Nhưng, điều này là không đáng ngạc nhiên, xem xét các ứng dụng là cực kỳ đơn giản, một ứng dụng theo dõi cho một trò chơi thẻ.

Tất cả điều này khiến tôi tin rằng AVAudioPlayer Tôi sử dụng để phát âm thanh khi người dùng chạm vào button có thể là nguyên nhân của sự cố (đó là yếu tố phức tạp duy nhất tương đối cao trong toàn bộ ứng dụng). Tôi, tuy nhiên, không chắc chắn, đó là nơi tôi cần sự giúp đỡ. Tôi bao gồm một mã mẫu ở đây, và có lẽ ai đó có kinh nghiệm trong phát lại âm thanh iOS có thể xem nó và xem nếu có một số sai lầm tôi bỏ qua.

Ở đây chúng tôi đi: Đầu tiên, tôi khởi tạo "trình phát im lặng" tiếp tục phát một bản nhạc im lặng mỗi giây để giữ cho AVAudioPlayer còn sống. Điều này là cần thiết vì thời gian phản hồi tương đối dài AVAudioPlayer trải nghiệm khi được gọi sau một thời gian không hoạt động lâu hơn.

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

Các NSTimer gọi phương thức sau đây:

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

Phần còn lại là khá đơn giản. Tôi khởi AVAudioPlayer khác để chơi một âm thanh nút cụ thể (có hai trong số này):

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

Và khi nút được đẩy tôi chơi âm thanh (giống như tôi đã làm với các cầu thủ im lặng):

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

Và thực sự tất cả là có. Tuy nhiên, tôi sợ rằng, mặc dù bản chất đơn giản của phương pháp này, bằng cách nào đó việc phát lại âm thanh liên tục này tạo ra một trường hợp hiếm hoi mà iOS chỉ phát điên. Nhưng tất cả điều này chỉ là một lý thuyết, và đó là lý do tại sao tôi cần một người có nhiều kinh nghiệm hơn để xem mã của tôi và chia sẻ ý kiến ​​của mình.

Cảm ơn!

Cập nhật: Tôi tìm thấy một vài dòng mã khác cũng có thể liên quan đến sự cố. Với họ, tôi đặt AVAudioPlayer hoạt động đồng thời với nhạc phát trong nền (ví dụ: từ một ứng dụng khác):

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

Trả lời

1

Điều tôi quan sát từ mã ở trên, tôi sẽ đề xuất hai thay đổi.

1) Bạn đã sử dụng hai phiên bản AVAudioPlayer, một để phát âm thanh im lặng liên tục mỗi giây. Một phiên bản thứ hai của AVAudioPlayer là để phát âm thanh khi nút được nhấp.Chạy đồng thời hai phiên bản của AVAudioPlayer, tại một thời điểm nào đó khi bộ nhớ còn thấp trên thiết bị và âm thanh và âm thanh nút im lặng cần được phát cùng lúc với thiết bị sẽ hoạt động chậm chạp. Tốt hơn nên sử dụng một cá thể AVAudioPlayer để phát cả hai âm thanh.

2) Tiếp tục phát âm thanh im lặng cho đến khi người dùng nhấp vào nút. Khi người dùng nhấp vào nút, tạm dừng bộ hẹn giờ và dừng âm thanh hiện tại và phát âm thanh nút bằng cùng một phiên bản AVAudioPlayer. Bằng cách này, bộ đếm thời gian không được khuyên dùng chủ yếu sẽ bị dừng trong một thời gian khi âm thanh nút cần được phát, khi âm thanh nút phát xong, tiếp tục hẹn giờ để phát âm thanh im lặng với cùng một bản AVAudioPlayer. Điều này sẽ lấy đi rất nhiều tải từ bộ nhớ và xử lý.

+0

Thông tin chi tiết hữu ích. Tôi sẽ cung cấp cho họ một thử vào cuối tuần này và chia sẻ kết quả! –

4

Từ nội dung tôi thu thập được từ câu hỏi của bạn, có vẻ như âm thanh duy nhất bạn muốn phát là hiệu ứng âm thanh tương đối đơn giản và ngắn. Nếu điều này là trong thực tế, trường hợp, tôi sẽ không sử dụng AVAudioPlayer, vì nó là một thư viện tài nguyên nặng cho một cái gì đó đơn giản như chơi hiệu ứng âm thanh ở một khối lượng cố định. Tôi sẽ sử dụng Dịch vụ âm thanh trực tiếp. Dưới đây là một ví dụ về một lớp hiệu ứng âm thanh mà tôi đã kéo từ một nơi khác (không thể nhớ ở đâu nữa).

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 

Một khi bạn có lớp học này, bạn có thể dễ dàng chơi bất kỳ hiệu ứng âm thanh bằng cách sử dụng đoạn mã sau:

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

Để tối ưu hóa, tôi sẽ tải tất cả các hiệu ứng âm thanh của bạn ở đâu đó và lưu trữ chúng tĩnh, để âm thanh thực tế các tệp được tải trước, sau đó chỉ cần gọi "phát" trên chúng bất cứ khi nào bạn cần chúng. Làm điều này là một cách ít tốn kém về tài nguyên để chơi hiệu ứng âm thanh hơn là sử dụng AVAudioPlayer. Ai biết được, có lẽ nó sẽ giải quyết vấn đề của bạn.

Tải trước tệp âm thanh:

Điều tôi muốn nói là đơn giản hơn âm thanh. Tôi chỉ có nghĩa là bạn sẽ tạo một tham chiếu tĩnh cho mỗi đối tượng Hiệu ứng âm thanh sau khi khởi tạo chúng khi chương trình tải lần đầu tiên. Có nhiều hướng khác nhau để làm điều đó. Tôi thường sử dụng phương pháp tải +. Nó sẽ giống như thế này:

Thêm một biến tĩnh trong việc thực hiện của lớp SoundEffect

static SoundEffect *mySoundEffect; 

Tiếp theo, khởi tạo rằng biến trong phương thức tải + cho lớp Sound Effect.

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

Bây giờ chỉ cần tạo ra một phương pháp tĩnh cho lớp hiệu ứng âm thanh như thế này:

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

Sau đó, bạn chỉ có thể chơi âm thanh mà bất cứ lúc nào bằng cách gọi:

[SoundEffect playMySound]; 

Lưu ý về các điều khiển âm lượng:

Tôi sử dụng mã này trong một số ứng dụng IOS của mình và tôi có thể xác nhận theo dõi ng:

  1. Điều khiển âm lượng tiêu chuẩn ở mặt bên của thiết bị sẽ hoạt động bình thường, nhưng chỉ khi cài đặt của người dùng chỉ định chuông và cảnh báo có thể thay đổi bằng nút.
  2. Không có cách nào để kiểm soát âm lượng của âm thanh trong mã của bạn.
+0

Tôi chắc chắn sẽ thử điều này. Tuy nhiên, tôi nhận thấy biến SystemSoundID trong mã của bạn. Điều đó có nghĩa là phương pháp của bạn sử dụng đối tượng âm thanh hệ thống để phát âm thanh? Nếu đó là trường hợp, vấn đề của tôi là thiếu kiểm soát giá trị khi sử dụng âm thanh hệ thống. Tôi đã thử chúng. Ngoài ra, bạn có thể cung cấp ví dụ về cách "tải trước" tệp âm thanh không? Tôi không quen với thực hành này. –

+0

Đó là chính xác, bạn sẽ không thể kiểm soát được khối lượng hiệu ứng âm thanh trong trường hợp này. Nếu bạn cần hiệu ứng âm thanh ở mức âm lượng thấp hơn hoặc cao hơn, bạn sẽ cần phải có các phiên bản khác nhau của tệp âm thanh ở mức âm lượng thấp hơn và cao hơn. Nếu bạn cần kiểm soát động lượng âm thanh, thì rất tiếc, giải pháp này có thể không phù hợp với bạn. :( – csundman

+0

Đã chỉnh sửa bằng cách tải trước các hiệu ứng âm thanh – csundman