Android4.0.3中的提示音

一、ToneGenerator的使用

参照com.android.contacts.dialpad.DialpadFragment

ToneGenerator只能播放在ToneGenerator中定义好的TONE_TYPE。

1、常量申明

/** Tone音的长度,单位:milliseconds */
private static final int TONE_LENGTH_MS = 150;
/** 主音量的比例:以80%的主音量播放Tone音 */
private static final int TONE_RELATIVE_VOLUME = 80;
/** 主音量的音频种别 */
private static final int DIAL_TONE_STREAM_TYPE =AudioManager.STREAM_MUSIC;

2、变量申明

// Tone音播放器
private ToneGenerator mToneGenerator;
// Tone相关的同步锁
private Object mToneGeneratorLock = new Object();
// 设定中的Tone音播放设置
private boolean mDTMFToneEnabled;

3、Tone的初始化

public void onResume() {
    super.onResume();
    // 读取设定的值
    mDTMFToneEnabled =Settings.System.getInt(getActivity().getContentResolver(),
           Settings.System.DTMF_TONE_WHEN_DIALING, 1) == 1;
 
    // 失败了也无所谓,不是啥重要的东西
    synchronized (mToneGeneratorLock) {
        if (mToneGenerator == null) {
            try {
                // we want the user to be ableto control the volume of the dial tones
                // outside of a call, so we usethe stream type that is also mapped to the
                // volume control keys for thisactivity
                mToneGenerator = newToneGenerator(DIAL_TONE_STREAM_TYPE, TONE_RELATIVE_VOLUME);
               getActivity().setVolumeControlStream(DIAL_TONE_STREAM_TYPE);
            } catch (RuntimeException e) {
                Log.w(TAG, "Exceptioncaught while creating local tone generator: " + e);
                mToneGenerator = null;
            }
        }
    }
}

4、释放Tone资源

public voidonPause() {
    super.onPause();
 
    synchronized (mToneGeneratorLock) {
        if (mToneGenerator != null) {
            mToneGenerator.release();
            mToneGenerator = null;
        }
    }
}

5、播放Tone音

/**
 * 播放TONE_LENGTH_MS milliseconds的Tone音.
 * 只有在设定中选择了播放Tone,并且不是静音模式才会播放Tone音。
 * @param tone a tone code from {@linkToneGenerator}
 */
void playTone(int tone) {
    // 设定中没有选中的话,就不播
    if (!mDTMFToneEnabled) {
        return;
    }
 
    // 静音模式的时候也不播,需要每次都检查,因为没有Activity切换也能设成静音模式
    // 设定中的那个就不需要,因为要设定必须要先切入设定Activity才行
    AudioManager audioManager =
            (AudioManager)getActivity().getSystemService(Context.AUDIO_SERVICE);
    int ringerMode =audioManager.getRingerMode();
    if ((ringerMode == AudioManager.RINGER_MODE_SILENT)
        || (ringerMode ==AudioManager.RINGER_MODE_VIBRATE)) {
        return;
    }
 
    synchronized (mToneGeneratorLock) {
        if (mToneGenerator == null) {
            Log.w(TAG, "playTone:mToneGenerator == null, tone: " + tone);
            return;
        }
 
        // Start the new tone (will stop anyplaying tone)
        mToneGenerator.startTone(tone,TONE_LENGTH_MS);
    }
}


 二、ToneGenerator的实现

相关代码位置:

ToneGenerator.java:ICS/frameworks/base/media/java/

Android_media_ToneGenerator.cpp:ICS/frameworks/base/core/jni/

ToneGenerator.cpp:ICS/frameworks/base/media/libmedia/

1、ToneGenerator.java

定义了多种ToneType,提供了java的接口

2、Android_media_ToneGenerator.cpp

将Java层的请求转发给Native层。

android_media_ToneGenerator_native_setup中的有句话看不懂:

ToneGenerator *lpToneGen= new ToneGenerator(streamType, AudioSystem::linearToLog(volume),true);
// change this value tochange volume scaling
static const float dBPerStep= 0.5f;
// shouldn't need totouch these
static const floatdBConvert = -dBPerStep * 2.302585093f / 20.0f;
static const floatdBConvertInverse = 1.0f / dBConvert;
 
floatAudioSystem::linearToLog(int volume)
{
    // float v = volume ? exp(float(100 -volume) * dBConvert) : 0;
    // LOGD("linearToLog(%d)=%f",volume, v);
    // return v;
    return volume ? exp(float(100 - volume) *dBConvert) : 0;
}

算出来的值会直接设到AudioTrack中,可是AudioTrack中的音量应该是个0~1.0f的百分比才对,为啥需要这么个公式呢,难道是Bug。应该测试一下!!

3、ToneGenerator.cpp

根据定义的Tone因的频率,长度等信息生成音频数据,最后交给AudioTrack播放。

三、AudioPolicyService中的mTonePlaybackThread

  本来以为这个线程是专门处理Tone音设备的,可是根据上面一看原来是直接走AudioTrack的。这就奇怪了,并且AudioSystem中也没有提供对应的接口,这就更奇怪了,难道它没准备让外面的人用。再一检索,发现原来它是提供给AudioPolicyManagerBase使用的一个非同期播放Tone音的接口。

  经过AudioCommandThread的处理,最终还是交给ToneGenerator来处理。

四、RingtoneManager与Ringtone

播放铃声的类,没具体看,最后是通过MediaPlayer来播放的。

五、结论

本来还以为会有个单独硬件来处理Tone音的,最后发现竟然是自动生成后,通过AudioTrack来处理的。

据说是因为硬件生成的Tone音很难听,所以才用软件来生成的。

你可能感兴趣的:(android)