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

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

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

notification_settings.xml(/packages/apps/Settings/res/xml)

<com.android.settings.notification.VolumeSeekBarPreference
        android:key="media_volume"
        android:icon="@*android:drawable/ic_audio_vol"
        android:title="@string/media_volume_option_title" />


<com.android.settings.notification.VolumeSeekBarPreference
        android:key="alarm_volume"
        android:icon="@*android:drawable/ic_audio_alarm"
        android:title="@string/alarm_volume_option_title" />


<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);
}

@Override
public 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 void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{    
    sp 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;
}

你可能感兴趣的:(android_audio)