IPhoneのAVAudioPlayerを介して(非常に短い-2秒未満の)オーディオファイルを再生するときの起動の遅れをなくそうとしています。
まず、コード:
NSString *audioFile = [NSString stringWithFormat:@"%@/%@.caf", [[NSBundle mainBundle] resourcePath], @"audiofile"];
NSData *audioData = [NSData dataWithContentsOfMappedFile:audioFile];
NSError *err;
AVAudioPlayer *audioPlayer = [(AVAudioPlayer*)[AVAudioPlayer alloc] initWithData:audioData error:&err];
audioPlayer.delegate = self;
[audioPlayer play];
また、audioPlayerDidFinishPlayingメソッドを実装して、完了したらAVAudioPlayerを解放します。
初めてオーディオを再生するとき、ラグは明白です-少なくとも2秒。ただし、その後すぐに音が鳴ります。そのため、原因は[NSData dataWithContentsOfMappedFile]が最初にフラッシュからの読み取りに長い時間を要したが、その後の読み取りでは高速であることが原因であると思われます。ただし、それをテストする方法はわかりません。
そうですか?もしそうなら、NSDataオブジェクトを事前にキャッシュし、メモリ不足の状態でそれらをクリアすることに積極的に取り組む必要がありますか?
この遅延は、AVAudioPlayerを初めてインスタンス化することに関連しているようです。オーディオをロードし、[audioPlayer prepareToPlay]を実行してすぐにリリースすると、他のすべてのオーディオのロード時間はほとんど認識できなくなります。だから今私はapplicationDidFinishLaunchingでそれをやっていて、他のすべてはうまく動作します。
ドキュメントでこれについて何も見つけることができませんが、確かにそうであるようです。
これが私が(別のスレッドで)行ったことです:
[audioplayer start]
[audioplayer stop]
self.audioplayer = audioplayer
[audioplayer prepareToPlay]は非同期メソッドのようであるため、オーディオを実際に再生する準備ができているかどうかをいつ返すかはわかりません。
私の場合、実際に再生を開始するためにstartを呼び出します-これは同期しているように見えます。それから私はすぐにそれを止めます。とにかくシミュレーターでは、このアクティビティから音が出ません。サウンドを「本当に」再生する準備ができたので、ローカル変数をメンバー変数に割り当てて、スレッド外のコードがそれにアクセスできるようにします。
IOS 4でも、長さがわずか4秒のオーディオファイルをロードするのに2秒ほどかかるのは少し意外だと言わざるを得ません。
オーディオの長さが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);
これは私にとってはうまくいき、ボタンが押されたときにかなり近い音を再生します。これがお役に立てば幸いです。
私は自分に合った別のアプローチを取りました。私は他の場所で言及されているこのテクニックを見たことがあります(それがあった瞬間には思い出せません)。
つまり、他の作業を行う前に、短い「空白」のサウンドをロードして再生することにより、サウンドシステムをプリフライトします。ビューコントローラのviewDidLoad
メソッドにプリロードした短いmp3ファイルのコードは次のようになります。このファイルの長さは0.1秒です。
NSError* error = nil;
NSString* soundfilePath = [[NSBundle mainBundle] pathForResource:@"point1sec" ofType:@"mp3"];
NSURL* soundfileURL = [NSURL fileURLWithPath:soundfilePath];
AVAudioPlayer* player = [[[AVAudioPlayer alloc] initWithContentsOfURL:soundfileURL error:&error] autorelease];
[player play];
必要に応じて、独自の空白のmp3を作成するか、「空白のmp3」をグーグル検索して、他の誰かがすでに作成したものを見つけてダウンロードすることができます。
実際に機能するprepareToPlayメソッドを提供するAVAudioPlayerの簡単なラッパーを作成しました。
https://github.com/nicklockwood/SoundManager
基本的には、アプリでサウンドファイルをスキャンし、1つを選択して、ゼロ音量で再生します。これにより、オーディオハードウェアが初期化され、次のサウンドを即座に再生できるようになります。
これは、前の回答で示した0ボリュームでの再生と停止のアイデアを使用するAVAudioPlayerの単純なSwift拡張機能です。残念ながら、PrepareToPlay()は少なくとも私にとってはうまくいきませんでした。
extension AVAudioPlayer {
private func initDelaylessPlayback() {
volume = 0
play()
stop()
volume = 1
}
convenience init(contentsOfWithoutDelay : URL) throws {
try self.init(contentsOf: contentsOfWithoutDelay, fileTypeHint: nil)
initDelaylessPlayback()
}
}
他の回避策は、短くて静かなオーディオを作成し、プレーヤーが最初に起動されたときにそれを再生することです。
自分で新しいサウンドファイルを作成したくない場合は、ここから短くてサイレントなオーディオファイルをダウンロードできます: https://www.dropbox.com/s/3u45x9v72ic70tk/silent.m4a?dl= ==