zoukankan      html  css  js  c++  java
  • android AudioManager AUDIOFOCUS

    如今開始做音乐播放器的模块。遇到了几个问题

    当播放音乐的过程中,去调节音量或者情景模式中的铃声设置,结果会有两种声音同一时候响起。

    引起此问题的解决办法是音乐焦点问题没弄清

    现分析一下音乐焦点的几个属性:源代码在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>





  • 相关阅读:
    移动端1px问题
    js几种数组排序及sort的实现
    从零开始搭建vue移动端项目到上线
    Maven项目常见错误解决方法汇总
    重读《Java编程思想》
    ubuntu开发环境下eclipse的alt+/自动补全功能不能用
    Linux环境下解压rar文件
    Ubuntu 16.04下deb文件的安装
    优化Ubuntu 16.04系统的几件事
    Ubuntu16.04 安装 “宋体,微软雅黑,Consolas雅黑混合版编程字体” 等 Windows 7 下的字体
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/5202048.html
Copyright © 2011-2022 走看看