轉載自:http://blog.csdn.net/wan8180192/article/details/50705882
audiod 中經常遇到的場景是音量調整與輸出設備的切換,下面兩篇文章 針對這兩個場景分別分析一下
1,音量調整場景
android 音量調整,可以使用兩種方式:
軟件mixer的時候修改PCM data
控制DAC硬件的增益
第一種情況,如果是多路mix的情況,就是MixerThread進行軟件mixer,然後在mixer計算的時候來縮放PCM data,
首先,JNI層調用了AudioFlinger::setStreamVolume。
- status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output)
- {
- AutoMutex lock(mLock);
- PlaybackThread *thread = NULL;
- if (output) {
- thread = checkPlaybackThread_l(output); //獲得對應的PlaybackThread
- if (thread == NULL) {
- return BAD_VALUE;
- }
- }
- if (thread == NULL) {
- for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
- }
- } else {
- thread->setStreamVolume(stream, value); //繼續向下層設置
- }
- return NO_ERROR;
- }
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
AutoMutex lock(mLock);
PlaybackThread *thread = NULL;
if (output) {
thread = checkPlaybackThread_l(output); //獲得對應的PlaybackThread
if (thread == NULL) {
return BAD_VALUE;
}
}
if (thread == NULL) {
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
}
} else {
thread->setStreamVolume(stream, value); //繼續向下層設置
}
return NO_ERROR;
}
可以看到,最終是調用了PlaybackThread::setStreamVolume來繼續設置音量- void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
- {
- Mutex::Autolock _l(mLock);
- mStreamTypes[stream].volume = value;//把音量數據存起來
- broadcast_l();
- }
void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
Mutex::Autolock _l(mLock);
mStreamTypes[stream].volume = value;//把音量數據存起來
broadcast_l();
}
- AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l()
- {
- float typeVolume = mStreamTypes[track->streamType()].volume; //取出暫存的音量數據
- float v = masterVolume * typeVolume;
- AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
- uint32_t vlr = proxy->getVolumeLR();
- vl = vlr & 0xFFFF;
- vr = vlr >> 16;
- vl = (uint32_t)(v * vl) << 12;
- vr = (uint32_t)(v * vr) << 12;
- mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)vl); //設置給audioMixer
- mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)vr);
- }
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l()
{
float typeVolume = mStreamTypes[track->streamType()].volume; //取出暫存的音量數據
float v = masterVolume * typeVolume;
AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
uint32_t vlr = proxy->getVolumeLR();
vl = vlr & 0xFFFF;
vr = vlr >> 16;
vl = (uint32_t)(v * vl) << 12;
vr = (uint32_t)(v * vr) << 12;
mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)vl); //設置給audioMixer
mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)vr);
}
可以看到上述函數把參數設置到了audioMixer裏面,在audioMixer章節裏面,我們介紹過在audioMixer的實際操作函數是track__16BitsStereo這種函數,
對track__16BitsStereo的分析中,我們可以看到根據音量對PCM data進行實際的縮放
不再繼續贅述了。
對於第二種方式,控制DAC硬件的增益,主要用在了DirectOutputThread,中,因爲DirectOutputThread只有一路音頻,直接寫入HAL層,直接寫入硬件的,
所以需要直接調用硬件DAC芯片的控制接口來調整音量。
其主要流程如下:
和mixerThread的流程一樣,上層在調用了AudioFlinger::setStreamVolume之後,會調用prepareTracks_l函數
- AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prepareTracks_l(
- Vector< sp<Track> > *tracksToRemove
- )
- {
- // compute volume for this track
- processVolume_l(track, last);
- }
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prepareTracks_l(
Vector< sp<Track> > *tracksToRemove
)
{
// compute volume for this track
processVolume_l(track, last);
}
AT章節中,我們提到過prepareTracks_l函數,其中會調用processVolume_l來處理音量- void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack)
- {
- audio_track_cblk_t* cblk = track->cblk();
- float left, right;
- float typeVolume = mStreamTypes[track->streamType()].volume; //和mixerThread一樣,也是從mStreamTypes裏面取出音量數據
- float v = mMasterVolume * typeVolume;
- AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
- uint32_t vlr = proxy->getVolumeLR();
- float v_clamped = v * (vlr & 0xFFFF);
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- left = v_clamped/MAX_GAIN;
- v_clamped = v * (vlr >> 16);
- if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
- right = v_clamped/MAX_GAIN;
- if (lastTrack) {
- if (left != mLeftVolFloat || right != mRightVolFloat) {
- mLeftVolFloat = left;
- mRightVolFloat = right;
- uint32_t vl = (uint32_t)(left * (1 << 24));
- uint32_t vr = (uint32_t)(right * (1 << 24));
- if (mOutput->stream->set_volume) {
- mOutput->stream->set_volume(mOutput->stream, left, right); //向下層設置音量
- }
- }
- }
- }
void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack)
{
audio_track_cblk_t* cblk = track->cblk();
float left, right;
float typeVolume = mStreamTypes[track->streamType()].volume; //和mixerThread一樣,也是從mStreamTypes裏面取出音量數據
float v = mMasterVolume * typeVolume;
AudioTrackServerProxy *proxy = track->mAudioTrackServerProxy;
uint32_t vlr = proxy->getVolumeLR();
float v_clamped = v * (vlr & 0xFFFF);
if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
left = v_clamped/MAX_GAIN;
v_clamped = v * (vlr >> 16);
if (v_clamped > MAX_GAIN) v_clamped = MAX_GAIN;
right = v_clamped/MAX_GAIN;
if (lastTrack) {
if (left != mLeftVolFloat || right != mRightVolFloat) {
mLeftVolFloat = left;
mRightVolFloat = right;
uint32_t vl = (uint32_t)(left * (1 << 24));
uint32_t vr = (uint32_t)(right * (1 << 24));
if (mOutput->stream->set_volume) {
mOutput->stream->set_volume(mOutput->stream, left, right); //向下層設置音量
}
}
}
}
mOutput->stream->set_volume實際上調用的是 libhardware_legacy中的函數- static int out_set_volume(struct audio_stream_out *stream, float left, //調用libhardware_legacy中的函數
- float right)
- {
- struct legacy_stream_out *out =
- reinterpret_cast<struct legacy_stream_out *>(stream);
- return out->legacy_out->setVolume(left, right);
- }
static int out_set_volume(struct audio_stream_out *stream, float left, //調用libhardware_legacy中的函數
float right)
{
struct legacy_stream_out *out =
reinterpret_cast<struct legacy_stream_out *>(stream);
return out->legacy_out->setVolume(left, right);
}
然後就進入了HAL層代碼,HAL層代碼中最終調用了 ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);寫入驅動
由於商業機密,HAL層代碼不能貼出來。
到了內核中,則是按照以下調用序列,最終通過IIC總線,將音量控制命令寫入了DAC芯片中
- ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
- snd_ctl_elem_write_user
- snd_ctl_elem_write_user
- snd_ctl_elem_write
- wm8523_controls
- snd_soc_put_volsw
- snd_soc_update_bits_locked
ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
snd_ctl_elem_write_user
snd_ctl_elem_write_user
snd_ctl_elem_write
wm8523_controls
snd_soc_put_volsw
snd_soc_update_bits_locked
IIC總線寫入命令
關於驅動的流程我們在這裏不展開講,後續會單獨講解
其他系列可參考
http://blog.csdn.net/WAN8180192/article/category/6103460