Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android AudioManager AUDIOFOCUS

android AudioManager AUDIOFOCUS

編輯:關於Android編程

現在開始做音樂播放器的模塊,遇到了幾個問題

當播放音樂的過程中,去調節音量或者情景模式中的鈴聲設置,結果會有兩種聲音同時響起。引起此問題的原因是音樂焦點問題沒弄清

 

 

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  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 */
}

 


 

 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved