アプリで音を鳴らす方法(簡単な方法編)

iPhoneアプリで音を鳴らす方法をいろいろと試してみたのでまとめ。

■簡単な方法
 AudioServicesPlaySystemSoundを使う

使い方

1.AudioToolbox フレームワークをプロジェクトに登録

プロジェクトに「AudioToolbox.framework」を追加。

2.コードに以下のコマンドを書き込む

AudioServicesPlaySystemSound (SoundID);


以上。終わり。

SoundIDに何を入れるかは、以下のページで確認すべし。

AudioServices - iPhone Development Wiki

バイブレーションだけなら以下のコマンド。

AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);

問題点が二つ
・マナーモードの時は音が鳴らない
・音楽再生中は音楽がフェードアウトしながらサウンドがフェードインするから音が小さくなる

マナーモードはAudioToolboxの場合どうしようもないので、あきらめる。

音楽再生中は、標準のMusicアプリなら再生中か調べられるので、
再生中だったらいったん止めてサウンドを再生し、
その後、音楽を再度スタートする方法でOKだった。

    MPMusicPlayerController *appMusicPlayer = [MPMusicPlayerController iPodMusicPlayer];
    MPMusicPlaybackState state = appMusicPlayer.playbackState;
    if (state == MPMusicPlaybackStatePlaying) {
        [appMusicPlayer pause];
        sleep(1);
    }
    AudioServicesPlaySystemSound (SoundID);

    if (state == MPMusicPlaybackStatePlaying) {
        sleep(1);
        [appMusicPlayer play];
    }

音楽を止めてからサウンドを再生する前と、
サウンドの再生が終わってから音楽を再生するまでに
スリープを入れた方が吉。

レジュームに対応しているアプリだったらサウンド再生前に以下を実行して

[[AVAudioSession sharedInstance] setActive:YES error: &activationError];

サウンド再生後に以下を実行する。

[[AVAudioSession sharedInstance] setActive:YES error: &activationError];

こうしておくと、他のアプリの音が中断して自分のアプリのサウンドを再生し、
その後他のアプリの音が再開する事もある。
(詳細はよく分かっていない・・・要調査)

■簡単なサウンドを非同期で繰り返し再生したいとき。

    // サウンドファイルへのURLを作成
    NSString* path =[NSString stringWithFormat:@"/System/Library/Audio/UISounds/%d", 1000];
    // 音声ファイルパスからURLを生成
    NSURL* url = [NSURL fileURLWithPath:path];
    // AVAudioPlayerのインスタンス生成
    AVAudioPlayer *avPlayer = [ [AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];

    // 再生する音の時間を取得
    NSTimeInterval intervalTime = avPlayer.duration;
    
    if (avPlayer.duration == 0) {  // 再生する音がない場合(サイレントなど)
        intervalTime += 1.0f;
    }
    
    // 非同期のスレッドを作成
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
    
    MPMusicPlayerController *appMusicPlayer = [MPMusicPlayerController iPodMusicPlayer];
    MPMusicPlaybackState state = appMusicPlayer.playbackState;

    if (state == MPMusicPlaybackStatePlaying) {    // Musicが再生中の時
        [appMusicPlayer pause];
        sleep(1);
    }
    
    // 通知処理を別スレッドで実行
    dispatch_async(queue, ^{
        
        NSTimeInterval elapsedTime  = 0;
        for (int i = 0; i < 10; i++) {
            AudioServicesPlaySystemSound(1000);
            [NSThread sleepForTimeInterval:intervalTime];
        }
        dispatch_async(dispatch_get_main_queue(), ^{
            
            sleep(1);
            
            if (state == MPMusicPlaybackStatePlaying) {
                [appMusicPlayer play];  // Musicが再生中だったら再開する
             }
        });
    });

注意点
・非同期スレッドで実行するコマンドによって、
 アプリがバックグラウンド中にサウンドが再生されなくなる

[locationManager stopUpdatingLocation];

このコマンドを非同期スレッドで実行すると、バックグラウンド中にサウンドが再生されない(なぜ?)
メインスレッドの「dispatch_async(dispatch_get_main_queue(){」の中で実行すると問題ないのだが。