Xamarin.Android で音楽の音量を下げてから効果音を再生する

カーナビでよくある、音楽流しながらナビしてると、ガイダンス中は音楽のボリュームを一時的に下げて、案内の音声を再生するってやつ。

に回答したので、その関連でやってみた。

//MainActivity.cs
[Activity(Label = "AudioFocusSample", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity, AudioManager.IOnAudioFocusChangeListener
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.Main);

        var audioManager = (AudioManager)GetSystemService(Context.AudioService);

        // 先に効果音を読み込んでおく
        var soundPool = new SoundPool(1, Stream.Music, 0);
        var soundId = soundPool.Load(ApplicationContext, Resource.Raw.cat, 0);
        // SoundPool は再生完了のコールバックがないので、事前に長さを得ておく
        var duration = GetSoundDuration(Resource.Raw.cat);

        FindViewById<Button>(Resource.Id.buttonRequestFocus).Click += async (sender, e) => 
        {
            // ダッキングを許可する AudioFocus を要求
            var result = audioManager.RequestAudioFocus(this, Stream.Music, AudioFocus.GainTransientMayDuck);
            if (result == AudioFocusRequest.Granted)
            {
                // 効果音を再生する
                soundPool.Play(soundId, 1.0f, 1.0f, 0, 0, 1.0f);
                // 再生完了まで待つ
                await Task.Delay((int)duration);
                // AudioFocus を開放
                audioManager.AbandonAudioFocus(this);
            }
        };
    }

    // 音声の再生長さを得る
    private long GetSoundDuration(int rawId)
    {
        using (var player = MediaPlayer.Create(ApplicationContext, rawId))
        {
            return player.Duration;
        }
    }

    // IOnAudioFocusChangeListener の実装(RequestAudioFocus のために必要)
    public void OnAudioFocusChange([GeneratedEnum] AudioFocus focusChange)
    {
       // 今回は使用しない
    }
}

効果音 Resource.Raw.cat は、 On-Jin ~音人~ さんのを使わせてもらいました。

音量を小さくする=絞る=ダッキング、というのがなかなか連想しづらいので辿りつけない。 Android の音声再生は、他に MediaPlayer とか AudioTrack もあるし、リモコンなど外部からの操作のため?に BroadcastReceiver を使わないといけないし。

サンプルアプリはこちら。

次は Xamarin.iOS でやってみる。

参考