android设置中拖动音量条调节音量流程(android5.1)

来源:互联网 发布:windows光盘修复系统 编辑:程序博客网 时间:2024/05/16 14:59

前言:问题起源于客户通过SoundPool播放提示音,想要增大音量,硬件无法通过QACT查看音频参数,只能通过增大音源的办法,不过客户还是觉得轻了。中间需要我写个DEMO实验一下,但是上层怎样才能让硬件通过QACT看到音频参数,我实在是不知道,知道的同学可以留言指导我一下。
然后驱动就各种找碴,要我提供上层调节音量的流程,因为通过设置中拖动音量条是可以通过QACT看到参数的,并且也是短音频。所以我花了一番功夫追了下代码,现在记下来作为备用。(最后驱动通过一个列表查到SoundPool方法播放的是低延迟音频不经过DSP,明明驱动一眼能看到的东西非要我们上层查,真的烦!)

上层通过设置UI搜索到布局文件notification_settings.xml

notification_settings.xml(/packages/apps/Settings/res/xml)<!-- Media volume --><com.android.settings.notification.VolumeSeekBarPreference        android:key="media_volume"        android:icon="@*android:drawable/ic_audio_vol"        android:title="@string/media_volume_option_title" /><!-- Alarm volume --><com.android.settings.notification.VolumeSeekBarPreference        android:key="alarm_volume"        android:icon="@*android:drawable/ic_audio_alarm"        android:title="@string/alarm_volume_option_title" /><!-- Ring volume --><com.android.settings.notification.VolumeSeekBarPreference        android:key="ring_volume"        android:icon="@*android:drawable/ic_audio_ring_notif"        android:title="@string/ring_volume_option_title" />

通过代码构造UI,初始化时会重写onProgressChanged方法

VolumeSeekBarPreference.java(/packages/apps/Settings/src/com/android/settings/notification)private void init() {    ...    @Override    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {        if (mCallback != null) {                                mCallback.onStreamValueChanged(mStream, progress);            }        }    ...}

下面这个callback找了很久,其实很简单

SeekBarVolumizer.java(/frameworks/base/core/java/android/preference)public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {            if (fromTouch) {        postSetVolume(progress);    }    if (mCallback != null) {        mCallback.onProgressChanged(seekBar, progress, fromTouch);    }}public void onStopTrackingTouch(SeekBar seekBar) {            postStartSample();}private void postStartSample() {    if (mHandler == null) return;    mHandler.removeMessages(MSG_START_SAMPLE);    mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE),                isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0);}@Overridepublic boolean handleMessage(Message msg) {    switch (msg.what) {        case MSG_START_SAMPLE:            onStartSample();            break;    }}private void onStartSample() {    if (!isSamplePlaying()) {        if (mCallback != null) {            mCallback.onSampleStarting(this);        }        if (mRingtone != null) {            try {                mRingtone.play(); //走这里            } catch (Throwable e) {                Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);            }        }    }}Ringtone.java(/frameworks/base/media/java/android/media)/** * Plays the ringtone. */public void play() {    if (mLocalPlayer != null) {        // do not play ringtones if stream volume is 0        // (typically because ringer mode is silent).        if (mAudioManager.getStreamVolume(                AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {            mLocalPlayer.start(); //走这里        }    } else if (mAllowRemote && (mRemotePlayer != null)) {        final Uri canonicalUri = mUri.getCanonicalUri();        try {            mRemotePlayer.play(mRemoteToken, canonicalUri, mAudioAttributes);        } catch (RemoteException e) {            if (!playFallbackRingtone()) {                Log.w(TAG, "Problem playing ringtone: " + e);            }        }    } else {        if (!playFallbackRingtone()) {            Log.w(TAG, "Neither local nor remote playback available");        }    }}MediaPlayer.java(/frameworks/base/media/java/android/media)public void start() throws IllegalStateException {    if (isRestricted()) {        _setVolume(0, 0);    }    stayAwake(true);          _start();}private native void _start() throws IllegalStateException;android_media_MediaPlayer.cpp(/frameworks/base/media/jni){"_start",      "()V",        (void *)android_media_MediaPlayer_start},static voidandroid_media_MediaPlayer_start(JNIEnv *env, jobject thiz){        sp<MediaPlayer> mp = getMediaPlayer(env, thiz);    if (mp == NULL ) {        jniThrowException(env, "java/lang/IllegalStateException", NULL);        return;    }    process_media_player_call( env, thiz, mp->start(), NULL, NULL ); //mp->start()}

之后的流程请参考:
[Android] AudioTrack::start

另外,拖动音量条时会播放一段示例音,媒体、闹钟、铃声都不同,加载资源的地方在构造SeekBarVolumizer时就定了:

SeekBarVolumizer.java(/frameworks/base/core/java/android/preference)public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) {    mContext = context;    mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);    mStreamType = streamType;    mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);    mNotificationOrRing = isNotificationOrRing(mStreamType);    if (mNotificationOrRing) {        mRingerMode = mAudioManager.getRingerModeInternal();    }    mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);    mCallback = callback;    mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);    mMuted = mAudioManager.isStreamMute(mStreamType);    if (mCallback != null) {        mCallback.onMuted(mMuted);    }    if (defaultUri == null) { //根据不同流类型指定Uri资源        if (mStreamType == AudioManager.STREAM_RING) {            defaultUri = Settings.System.DEFAULT_RINGTONE_URI;        } else if (mStreamType == AudioManager.STREAM_NOTIFICATION) {            defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;        } else {            defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;        }    }    mDefaultUri = defaultUri;}
原创粉丝点击