日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Android音频(9)——音量调节

發(fā)布時(shí)間:2024/6/21 26 生活家
生活随笔 收集整理的這篇文章主要介紹了 Android音频(9)——音量调节 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、音量相關(guān)概念

1. 相關(guān)術(shù)語解釋

track volume : 單個(gè)App設(shè)置音量時(shí)設(shè)置的是這個(gè),它只影響本App的音量。
stream volume :設(shè)置某一stream的音量,Android系統(tǒng)中支持10種stream。
stream volume alias:設(shè)置的是同一組stream的音量,比如使用某個(gè)音量調(diào)節(jié)滑動(dòng)條設(shè)置的音量。比如設(shè)置媒體音,所有App的媒體音都受到影響(但是電話音,
鬧鐘音不受影響)。
master volume :設(shè)置它等于設(shè)置所有的stream volume和track volume。它可以寫到聲卡里面去,控制所有聲音的音量。也可以不寫到聲卡里面去,而是作為一個(gè)乘數(shù)因子來影響所有的音量。

2. 華為Honor8音量設(shè)置

設(shè)置-->聲音-->音量,設(shè)置界面列出了鈴聲、媒體、鬧鐘、通話,四個(gè)設(shè)置滾動(dòng)條,稱為四個(gè)stream type,四組。
Android系統(tǒng)中有10種stream,在system/core/include/system/audio.h中定義。但把這10種stream分成組,屬于同一組的stream具有相同的別名(alias)。
一個(gè)音量調(diào)節(jié)滑動(dòng)條具有一個(gè)alias,具有相同alias的stream都會(huì)受到這個(gè)滑動(dòng)條的影響。

3. 聲音播放的兩種路徑

(1)MixerThread
對(duì)于MixerThread(多個(gè)App共用一個(gè)聲卡進(jìn)行混音的的),APP對(duì)音量的設(shè)置不會(huì)影響到聲卡的硬件音量,而只會(huì)影響APP的音頻數(shù)據(jù)的幅值(變小或放大),
這些音頻數(shù)據(jù)最終被混合后傳給聲卡。多個(gè)APP本身的音量設(shè)置互不影響。

(2)DirectOutputThread
對(duì)于DirectOutputThread(對(duì)于HDMI的,單個(gè)音頻應(yīng)用程序獨(dú)占使用一個(gè)聲卡的),同一時(shí)間里只有一個(gè)APP、只有一個(gè)AudioTrack使用它,
所以該AudioTrack的音量可以被DirectOutputThread直接用來設(shè)置硬件音量,這種聲卡使用的不多。

若audio_policy.conf中的output的參數(shù)信息(會(huì)被解析成一個(gè)output profile)中有"flags AUDIO_OUTPUT_FLAG_DIRECT"就表示這個(gè)聲卡可以
被某個(gè)App獨(dú)占。這個(gè)App就會(huì)以DirectOutputThread的形式來使用這個(gè)聲卡。

4. APP設(shè)置音量時(shí)互不影響, 這是AudioTrack volume

5. stream volume
可以引申出來: 各種stream的音量也可以單獨(dú)設(shè)置、互不影響。比如"音樂音量"不應(yīng)該影響到"來電振鈴"、"鬧鐘"、"通話"的音量。

6. 有的手機(jī)音量控制界面有5種滑動(dòng)條,用于設(shè)置某種類型的聲音音量,但是Android系統(tǒng)創(chuàng)建AudioTrack時(shí)可以指定10種stream type,
必須分組,在Android源碼中稱之為"別名", 即alias。
比如在電話中, 以下5種stream的alias都是STREAM_RING,那么對(duì)應(yīng)的滑動(dòng)條即可控制這5種stream的音量。
STREAM_SYSTEM
STREAM_RING
STREAM_NOTIFICATION
STREAM_SYSTEM_ENFORCED
STREAM_DTMF

6. 無論是AudioTrack volume、stream volume, 都是單獨(dú)設(shè)置. master volume 可以設(shè)置所有的AudioTrack volume和stream volume,也可
直接用來控制聲卡的寄存器。

7. 混音:
app1: data1_mix = data1_in * master_volume * stream1_volume * AudioTrack1_volume

app2: data2_mix = data2_in * master_volume * stream2_volume * AudioTrack2_volume

混合在一起: data_mix = data1_mix + data2_mix 然后把混合后的數(shù)據(jù)寫給硬件。

二、AudioFlinger層調(diào)節(jié)音量流程

1. AudioFlinger層調(diào)節(jié)音量流程
a. AudioFlinger對(duì)master volume, stream volume的初始化與設(shè)置
b. PlaybackThread對(duì)master volume, stream volume的初始化與設(shè)置
c. AudioTrack volume的設(shè)置
d. 這3種音量的使用

2. AudioFlinger類中有關(guān)成員:
stream_type_t mStreamTypes[AUDIO_STREAM_CNT];
//存儲(chǔ)master volume
float mMasterVolume;
//存儲(chǔ)是否靜音
bool mMasterMute;

2. playbackThread類中:
stream_type_t mStreamTypes[AUDIO_STREAM_CNT + 1]; //為DuplicatingThread的OutputTrack多出一項(xiàng)
bool mMasterMute;
float mMasterVolume; //來源于AudioFlinger中的同名的變量

3. AudioTrack類中(App端)
float mVolume[2]; //兩項(xiàng),分別表示App設(shè)置的左右聲道的音量

4. stream volume和audioTreack中的volume只是軟件上的處理,masterVolue中保存的值若HAL提供了相應(yīng)的寫函數(shù)就會(huì)寫給硬件。

5. DuplicatingThread可以用于在兩個(gè)聲卡上播放出同樣的聲音。

6. 加載HAL時(shí)設(shè)置為初始化值

AudioFlinger::loadHwModule(const char *name) //AudioFlinger.cpp
    loadHwModule_l(name);
        //調(diào)用HAL的open函數(shù),得到一個(gè)audio_hw_device_t
        audio_hw_device_t *dev;
        load_audio_interface(name, &dev);
            //if_name來自audio_policy.conf,是"primary",AUDIO_HARDWARE_MODULE_ID是"audio"
            //最后組合成的名字就是: audio.primary.tiny4412.so
            hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod);
            audio_hw_device_open(mod, dev);
        //若HAL提供了get_master_volume就獲取硬件的值賦給mMasterVolume
        mMasterVolume = dev->get_master_volume(dev, &mv)
        //若HAL提供了get_master_mute就獲取硬件的值賦給mMasterMute
        mMasterMute = dev->get_master_mute(dev, &mm)
        //若存在對(duì)應(yīng)的函數(shù)則調(diào)用設(shè)置
        dev->set_master_volume(dev, mMasterVolume)
        dev->set_master_mute(dev, mMasterMute)

audio_hw_device_t里面有masterVolume的存取函數(shù):
typedef struct audio_hw_device audio_hw_device_t;
int (*set_master_mute)(struct audio_hw_device *dev, bool mute);
int (*get_master_mute)(struct audio_hw_device *dev, bool *mute);


AudioFlinger中還提供了函數(shù)設(shè)置MasterVolume和MasterMute
AudioFlinger::setMasterVolume(float value)
AudioFlinger::setMasterMute(bool muted)

AudioFlinger中的setStreamVolume
AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output)
    mStreamTypes[stream].volume = value;
    AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value) //Threads.cpp
        mStreamTypes[stream].volume = value;
        broadcast_l();

PlaybackThread中的初始值都是來自AudioFlinger
AudioFlinger::PlaybackThread::PlaybackThread()
    mMasterVolume = audioFlinger->masterVolume_l();
    mMasterMute = audioFlinger->masterMute_l();
    //對(duì)于數(shù)組的每一項(xiàng)都執(zhí)行
    mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
    mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);

AudioTrack中的
AudioTrack::setVolume(float left, float right) //AudioTrack.cpp
    mVolume[AUDIO_INTERLEAVE_LEFT] = left;
    mVolume[AUDIO_INTERLEAVE_RIGHT] = right;
    //
    mProxy->setVolumeLR(gain_minifloat_pack(gain_from_float(left), gain_from_float(right)));
        //mProxy = new AudioTrackClientProxy(cblk, buffers, frameCount, mFrameSizeAF);
        //僅僅是把這個(gè)數(shù)據(jù)記錄在mVolumeLR域中而已。Cblk就是共享內(nèi)存的頭部。
        mCblk->mVolumeLR = volumeLR; //AudioTrackShared.h

7. App中的AudioTrack與SurfaceFlinger中的mTracks中的對(duì)應(yīng)項(xiàng)通過共享內(nèi)存進(jìn)行通信,這個(gè)mProxy就是共享內(nèi)存的代理類。

8. App去設(shè)置音量只需要執(zhí)行AudioTrack::setVolume就可以了。它會(huì)把設(shè)置的值放在自己的私有成員里面,也會(huì)放到共享內(nèi)存的頭部。

9. 低16bit是左聲道數(shù)據(jù),高16bit是右聲道數(shù)據(jù)

10. AudioMixer中的音量如何保存:音量有整數(shù)表示方式也有float表示方式,float表示方式是未來的發(fā)展趨勢(shì)

三、音量鍵和Setting界面調(diào)節(jié)音量流程

1. 對(duì)于seekBar控件,當(dāng)滑動(dòng)滑動(dòng)條的時(shí)候,onProgressRefresh(AbsSeekBar.java)就會(huì)被調(diào)用,通過seekBar設(shè)置音量的兩種方法:
① 重寫onProgressRefresh
② 添加Listener

2. seekBar是通過packages目錄下的 notification_settings.xml 文件畫出來的,packages/apps/Settings/res/xml/notification_settings.xml

<!-- Media volume -->
<com.android.settings.notification.VolumeSeekBarPreference
        android:key="media_volume"
        android:icon="@drawable/ic_audio_vol_24dp"
        android:title="@string/media_volume_option_title" />

<!-- Alarm volume -->
<com.android.settings.notification.VolumeSeekBarPreference
        android:key="alarm_volume"
        android:icon="@drawable/ic_audio_alarm_24dp"
        android:title="@string/alarm_volume_option_title" />

<!-- Ring volume -->
<com.android.settings.notification.VolumeSeekBarPreference
        android:key="ring_volume"
        android:icon="@drawable/ring_notif"
        android:title="@string/ring_volume_option_title" />

<!-- Notification volume -->
<com.android.settings.notification.VolumeSeekBarPreference
        android:key="notification_volume"
        android:icon="@drawable/ring_notif"
        android:title="@string/notification_volume_option_title" />

View Code

3. 音量鍵和Setting界面調(diào)節(jié)音量流程

a. 音量鍵處理流程
音量鍵: 
  如果APP沒有重寫它的處理函數(shù),音量鍵的處理將交給 PhoneFallbackEventHandler 來處理,它會(huì)調(diào)用AudioService.adjustSuggestedStreamVolume
  調(diào)整"推薦的流"的音量

a.1 如何獲得"推薦的流": stream = getActiveStreamType(...)

a.2 音量設(shè)置的"alias"如何起作用: 
     set volume for stream; // 設(shè)置"推薦的流"的音量
     
     if (mStreamVolumeAlias[other stream] == stream)
         set volume for other stream;  // 設(shè)置同屬一個(gè)alias的其他流的音量
         
     對(duì)于不同的設(shè)備(電話、TV、平板), mStreamVolumeAlias指向不同的數(shù)組

a.3 怎么設(shè)置流的音量:
    設(shè)置audioflinger中的數(shù)組:   mStreamTypes[stream].volume = value;
    設(shè)置PlaybackThread中的數(shù)組: mStreamTypes[stream].volume = value;
    

b. 音量滑動(dòng)條處理流程

b.1 通過下面文件定義音量滑動(dòng)條:
packages/apps/Settings/res/xml/notification_settings.xml
   該文件定義了多個(gè)VolumeSeekBarPreference,每個(gè)VolumeSeekBarPreference要跟一個(gè)SeekBar綁定

b.2 在VolumeSeekBarPreference的綁定函數(shù)onBindView中,設(shè)置了對(duì)應(yīng)的SeekBar的SeekBarChangeListener (一個(gè)SeekBarVolumizer對(duì)象)

b.3 當(dāng)SeekBar被滑動(dòng)時(shí), 它的onProgressRefresh被調(diào)用,該函數(shù)會(huì)調(diào)用 mOnSeekBarChangeListener.onProgressChanged

b.4 mOnSeekBarChangeListener.onProgressChanged去設(shè)置音量

b.5 每一個(gè)SeekBar對(duì)應(yīng)一個(gè)stream,滑動(dòng)SeekBar時(shí)會(huì)設(shè)置該stream的音量,也會(huì)去設(shè)置同屬一個(gè)alias(同一分組)的其他stream的音量
    
c. 兩者最終都會(huì)調(diào)用AudioService.java的代碼發(fā)出MSG:
            sendMsg(mAudioHandler,
                    MSG_SET_DEVICE_VOLUME,
                    SENDMSG_QUEUE,
                    device,
                    0,
                    streamState,
                    0);

參考:
Android官方setting文檔:https://developer.android.google.cn/guide/topics/ui/settings

android5.0設(shè)置模塊音量調(diào)節(jié)流程:https://blog.csdn.net/fireness/article/details/46738643

Android音量調(diào)節(jié)的實(shí)現(xiàn)(RingtoneManager和RingerVolumePreference):https://blog.csdn.net/liranke/article/details/6683000

android設(shè)置中拖動(dòng)音量條調(diào)節(jié)音量流程(android5.1):https://blog.csdn.net/qq_28534581/article/details/77337599

Android 音量控制流程分析:https://blog.csdn.net/kehyuanyu/article/details/49153223

總結(jié)

以上是生活随笔為你收集整理的Android音频(9)——音量调节的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。