android AudioManager AUDIOFOCUS

來源:互聯網
上載者:User

標籤:

如今開始做音樂播放器的模組。遇到了幾個問題

當播放音樂的過程中,去調節音量或者情景模式中的鈴聲設定,結果會有兩種聲音同一時候響起。

引起此問題的解決辦法是音樂焦點問題沒弄清

現分析一下音樂焦點的幾個屬性:原始碼在frameworks/base/media/java/andorid/media/AudioManager.java中


public static final int AUDIOFOCUS_NONE = 0;


指示申請得到的Audio Focus不知道會持續多久,通常是長期佔有。獲得了Audio Focus;
public static final int AUDIOFOCUS_GAIN = 1;

指示要申請的AudioFocus是臨時性的,會非常快用完釋放的;

public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;

不但說要申請的AudioFocus是臨時性的。還指示當前正在使用AudioFocus的能夠繼續播放,僅僅是要“duck”一下(減少音量)。

public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;

public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;

AudioManager.OnAudioFocusChangeListener是申請成功之後監聽AudioFocus使用方式的Listener,興許假設有別的程式要競爭AudioFocus,都是通過這個Listener的onAudioFocusChange()方法來通知這個Audio Focus的使用者的。


失去了Audio Focus,並將會持續非常長的時間

public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN; 

臨時失去Audio Focus,並會非常快再次獲得。必須停止Audio的播放。可是由於可能會非常快再次獲得AudioFocus。這裡能夠不釋放Media資源;

public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;

臨時失去AudioFocus,可是能夠繼續播放,只是要在減少音量。

public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
            -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;


看看剛才改動的一個問題:

問題描寫敘述:播放音樂時鬧鐘到來,把鬧鐘放在後台時進入檔案管理工具播放音頻。鬧鐘仍然在響應,鬧鐘和音樂同一時候響起;


問題分析:在鬧鐘鈴聲響起時,沒有去做音頻焦點的處理

解決方式:在packages/apps/deskclock/src/com/android/deskclock/alarms/AlarmKlaxon.java檔案裡加上焦點處理

改動後的原始碼:


package com.android.deskclock.alarms;import android.content.Context;import android.content.res.AssetFileDescriptor;import android.media.AudioManager;import android.media.MediaPlayer;import android.media.MediaPlayer.OnErrorListener;import android.media.RingtoneManager;import android.net.Uri;import android.os.Vibrator;import com.android.deskclock.Log;import com.android.deskclock.R;import com.android.deskclock.provider.AlarmInstance;import java.io.IOException;/*add by leo.tan 20140717 for bugzilla 20064 start */import android.os.Handler;import android.media.AudioManager.OnAudioFocusChangeListener;import android.os.Message;/*add by <span id="summary_alias_container"><span id="short_desc_nonedit_display"></span></span> leo.tan 20140717 for bugzilla 20064 end *//** * Manages playing ringtone and vibrating the device. */public class AlarmKlaxon {    private static final long[] sVibratePattern = new long[] { 500, 500 }; // Volume suggested by media team for in-call alarms.    private static final float IN_CALL_VOLUME = 0.125f;    private static boolean sStarted = false;    private static MediaPlayer sMediaPlayer = null;/*add by leo.tan 20140717 for bugzilla 20064 start */ private static final int FOCUSCHANGE = 3000;    private static final int FADEDOWN = 5;    private static final int FADEUP = 6;    private static final int RETRY_REQUEST_FOCUS = 7;    private static final int OVER_SHORT_VIBRATOR = 8;    private static OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {        public void onAudioFocusChange(int focusChange) {            android.util.Log.v("AlarmKlaxon", "mAudioFocusListener::focusChange-->" + focusChange);            mHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();        }    };/*add by leo.tan 20140717 for bugzilla 20064 end */    public static void stop(Context context) {        Log.v("AlarmKlaxon.stop()");        if (sStarted) {            sStarted = false;            // Stop audio playing            if (sMediaPlayer != null) {                sMediaPlayer.stop();                AudioManager audioManager = (AudioManager)                        context.getSystemService(Context.AUDIO_SERVICE);                audioManager.abandonAudioFocus(null);                sMediaPlayer.release();                sMediaPlayer = null;            }/*add by leo.tan 20140717 for bugzilla 20064 start */ final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);                        audioManager.abandonAudioFocus(mAudioFocusListener);/*add by leo.tan 20140717 for bugzilla 20064 end */            ((Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE)).cancel();        }    }    public static void start(final Context context, AlarmInstance instance,            boolean inTelephoneCall) {        Log.v("AlarmKlaxon.start()");        // Make sure we are stop before starting        stop(context);        if (!AlarmInstance.NO_RINGTONE_URI.equals(instance.mRingtone)) {            Uri alarmNoise = instance.mRingtone;            // Fall back on the default alarm if the database does not have an            // alarm stored.            if (alarmNoise == null) {                alarmNoise = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);                if (Log.LOGV) {                    Log.v("Using default alarm: " + alarmNoise.toString());                }            }           TODO: Reuse mMediaPlayer instead of creating a new one and/or use RingtoneManager.            sMediaPlayer = new MediaPlayer();            sMediaPlayer.setOnErrorListener(new OnErrorListener() {                @Override                public boolean onError(MediaPlayer mp, int what, int extra) {                    Log.e("Error occurred while playing audio. Stopping AlarmKlaxon.");                    AlarmKlaxon.stop(context);                    return true;                }            });           try {                // Check if we are in a call. If we are, use the in-call alarm                // resource at a low volume to not disrupt the call.                if (inTelephoneCall) {                    Log.v("Using the in-call alarm");                    sMediaPlayer.setVolume(IN_CALL_VOLUME, IN_CALL_VOLUME);                    setDataSourceFromResource(context, sMediaPlayer, R.raw.in_call_alarm);                } else {                    sMediaPlayer.setDataSource(context, alarmNoise);                }                startAlarm(context, sMediaPlayer);            }catch (Exception ex) {                Log.v("Using the fallback ringtone");                // The alarmNoise may be on the sd card which could be busy right                // now. Use the fallback ringtone.                try {                    // Must reset the media player to clear the error state.                    sMediaPlayer.reset();                    setDataSourceFromResource(context, sMediaPlayer, R.raw.fallbackring);                    startAlarm(context, sMediaPlayer);                } catch (Exception ex2) {                    // At this point we just don't play anything.                    Log.e("Failed to play fallback ringtone", ex2);                }            }        }        if (instance.mVibrate && !inTelephoneCall) {            Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);            vibrator.vibrate(sVibratePattern, 0);        }        sStarted = true;    }    // Do the common stuff when starting the alarm.    private static void startAlarm(Context context, MediaPlayer player) throws IOException {        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);        // do not play alarms if stream volume is 0 (typically because ringer mode is silent).        if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {            player.setAudioStreamType(AudioManager.STREAM_ALARM);            player.setLooping(true);            player.prepare();            audioManager.requestAudioFocus(null,                    AudioManager.STREAM_ALARM, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);            player.start();        }    /*add by leo.tan 20140717 for bugzilla 20064 start */    //在這個地方進行焦點的請求     final int requestResult = audioManager.requestAudioFocus(mAudioFocusListener,                AudioManager.STREAM_ALARM,                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);    /*add by leo.tan 20140717 for bugzilla 20064 end */    }    private static void setDataSourceFromResource(Context context, MediaPlayer player, int res)            throws IOException {        AssetFileDescriptor afd = context.getResources().openRawResourceFd(res);        if (afd != null) {            player.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());            afd.close();        }    }    /*add by leo.tan 20140717 for bugzilla 20064 start */private static void setVolume(float vol) {        if(sMediaPlayer != null){            sMediaPlayer.setVolume(vol, vol);           }       }    //用handler來對焦點進行處理    private static Handler mHandler = new Handler() {        public void handleMessage(Message msg) {            switch (msg.what) {                case FOCUSCHANGE: {                    switch (msg.arg1) {                        case AudioManager.AUDIOFOCUS_LOSS:                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:                        case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:                            mHandler.removeMessages(FADEUP);                            mHandler.sendEmptyMessage(FADEDOWN);                            break;                        case AudioManager.AUDIOFOCUS_GAIN:                            mHandler.removeMessages(FADEDOWN);                            mHandler.sendEmptyMessage(FADEUP);                            break;                    }                    break;                }               case FADEDOWN:                    // Turn off the sound                    setVolume(0.0f);                    break;                case FADEUP:                    // Turn on the sound                    setVolume(1.0f);                    break;            }        }    };/*add by leo.tan 20140717 for bugzilla 20064 end */}<span id="summary_alias_container"></span>





android AudioManager AUDIOFOCUS

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.