В цифре без проблем можно регулировать звук. Так же, например, регулируется звук в цифре на процессоре ;)
Вид для печати
В авто через этот хаб смартфон (nexus5) заряжался очень медленно, при прослушивании музыки заряд оставался примерно на том же уровне.
Дома подключал мышь и зарядку из розетки: мышь работает и смартфон заряжается уверенно.
Возможно дело было в плохой автозарядке из прикуривателя. Он и без хаба, напррямую в смарт, медленно заряжал :)
Все устройства регулируют громкость именно в цифре при подаче на USB-DAC. На стороне ОС происходит арифметическое уменьшение амплитуды PCM-потока, пропорциональное уровню задаваемой громкости. При 100% громкости ваш поток уходит на USB-DAC неизменным. Цифровая регулировка с точки зрения качества - это плохо. Из-за снижения амплитуды сигнала по сути теряется его разрядность. Возрастает погрешность (ступенчатость) из-за того, что используется не весь динамический диапазон цифры. Сигнал по амплитуде становится более дискретным. Но если мы перед снижением громкости будем 16 бит переводить в 24 бита прибавлением младших разрядов, то получим необходимый "запас точности" семплирования, и искажений уже не услышим. Что и делается в некоторых процессорах. Процессор, какой бы цифровой поток не получил, всегда апсемплит его в бОльшую разрядность и увеличивает частоту дискретизации. И все обработки навешиваются уже с минимальными искажениями - так же как и при студийной обработке.
aluver, это всё круто, только вот за счёт чего происходит изменение амплитуды? Готовые тексты в интернетах я и сам могу найти
Вопрос не совсем понятен. Программно конечно же. В андроиде, например, за это обычно по умолчанию отвечает AudioManager, а может отвечать и альса - смотря какая конфигурация или как ее настроить... Все можно найти в тех же "интернетах"... ;)
Чистая арифметика. PCM поток - это просто 44100 значений амплитуды звукового сигнала в секунду, каждое из которых описано 16-битной цифрой. Уменьшил громкость вполовину - софт делит все значения амплитуды потока на 2.
Как мне кажется, aluver, в двух своих ответах все очень правильно описал!
В Android-системах с полноценной ALSA установка громкости может происходить и средствами звукового адаптера (через параметры микшера), что выясняется через изучения кода AudioHAL-библиотеки:
, что предопределено на уровне AudioFlinger, через который по умолчанию оперирует AudioManager (в частности, AudioSystem::setStreamVolume):Код:status_t ALSAMixer::setMasterVolume(float volume)
{
mixer_info_t *info = mixerMasterProp[SND_PCM_STREAM_PLAYBACK].mInfo;
if (!info || !info->elem) return INVALID_OPERATION;
long minVol = info->min;
long maxVol = info->max;
// Make sure volume is between bounds.
long vol = minVol + volume * (maxVol - minVol);
if (vol > maxVol) vol = maxVol;
if (vol < minVol) vol = minVol;
info->volume = vol;
snd_mixer_selem_set_playback_volume_all (info->elem, vol);
return NO_ERROR;
}
...
status_t ALSAMixer::setVolume(uint32_t device, float left, float right)
{
LOGD("ALSAMixer::setVolume left = %f , right = %f", left, right);
for (int j = 0; mixerProp[j][SND_PCM_STREAM_PLAYBACK].device; j++)
if (mixerProp[j][SND_PCM_STREAM_PLAYBACK].device & device) {
mixer_info_t *info = mixerProp[j][SND_PCM_STREAM_PLAYBACK].mInfo;
if (!info || !info->elem) return INVALID_OPERATION;
long minVol = info->min;
long maxVol = info->max;
// Make sure volume is between bounds.
long vol = minVol + left * (maxVol - minVol);
if (vol > maxVol) vol = maxVol;
if (vol < minVol) vol = minVol;
//add by chenjq
snd_ctl_elem_info_t *ctl_info;
snd_hctl_elem_t *hctl_elem;
unsigned int Nmax = 6, N = left * 5 + 1, *tlv;
float dB_min, dB_max, dB_vol, dB_step, e = 2.71828;
int err;
if (((selem_none_t *)snd_mixer_elem_get_private(info->elem))->ctls[CTL_GLOBAL_VOLUME].elem) {
hctl_elem = ((selem_none_t *)snd_mixer_elem_get_private(info->elem))->ctls[CTL_GLOBAL_VOLUME].elem;
} else if (((selem_none_t *)snd_mixer_elem_get_private(info->elem))->ctls[CTL_PLAYBACK_VOLUME].elem) {
hctl_elem = ((selem_none_t *)snd_mixer_elem_get_private(info->elem))->ctls[CTL_PLAYBACK_VOLUME].elem;
} else if (((selem_none_t *)snd_mixer_elem_get_private(info->elem))->ctls[CTL_CAPTURE_VOLUME].elem) {
hctl_elem = ((selem_none_t *)snd_mixer_elem_get_private(info->elem))->ctls[CTL_CAPTURE_VOLUME].elem;
} else {
LOGE("snd_mixer_elem_get_private(info->elem)->ctls[type].elem type error");
goto __skip_tlv;
}
snd_ctl_elem_info_alloca(&ctl_info);
if ((err = snd_hctl_elem_info(hctl_elem, ctl_info)) < 0) { //snd_hctl_elem_t
LOGE("snd_hctl_elem_info error: %s", snd_strerror(err));
goto __skip_tlv;
}
if (!snd_ctl_elem_info_is_tlv_readable(ctl_info))
goto __skip_tlv;
tlv = (unsigned int *)malloc(4096);
if ((err = snd_hctl_elem_tlv_read(hctl_elem, tlv, 4096)) < 0) {
LOGE("element TLV read error: %s", snd_strerror(err));
free(tlv);
goto __skip_tlv;
}
/*
* change vol to fix setting incall volume error
*/
dB_min = (int)tlv[2];
dB_step = tlv[3] & 0xffff;
dB_min /= 100;
dB_step /= 100;
dB_max = dB_min + dB_step * (info->max - info->min);
dB_vol = 20 * log((Nmax * pow(e, dB_min / 20) + N * (pow(e, dB_max / 20) - pow(e, dB_min / 20))) / Nmax);
vol = (long)(info->min + (dB_vol - dB_min) / dB_step);
LOGD("min = %d.%02ddB, step = %d.%02ddB, mute = %d",
((int)tlv[2]) / 100, (((int)tlv[2]) ? -((int)tlv[2]) : ((int)tlv[2])) % 100,
(tlv[3] & 0xffff) / 100, ((tlv[3] & 0xffff) ? -(tlv[3] & 0xffff) : (tlv[3] & 0xffff)) % 100,
(tlv[3] >> 16) & 1);
LOGD("dB_min = %f, dB_step = %f, dB_max = %f, dB_vol = %f",
dB_min,
dB_step,
dB_max,
dB_vol);
LOGD("N = %d, vol = %ld", N, vol);
free(tlv);
__skip_tlv:
//add by chenjq end
info->volume = vol;
snd_mixer_selem_set_playback_volume_all (info->elem, vol);
}
return NO_ERROR;
}
Следовательно, управление громкостью звука в системах с Android OS может быть передано звуковому адаптеру, в котором данная функция реализована аппаратно.Код:status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
audio_io_handle_t output)
{
if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
af->setStreamVolume(stream, value, output);
return NO_ERROR;
}
...
status_t AudioFlinger::setMasterVolume(float value)
{
status_t ret = initCheck();
if (ret != NO_ERROR) {
return ret;
}
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
Mutex::Autolock _l(mLock);
mMasterVolume = value;
// Set master volume in the HALs which support it.
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
AutoMutex lock(mHardwareLock);
AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
if (dev->canSetMasterVolume()) {
dev->hwDevice()->set_master_volume(dev->hwDevice(), value);
}
mHardwareStatus = AUDIO_HW_IDLE;
// Now set the master volume in each playback thread. Playback threads
// assigned to HALs which do not have master volume support will apply
// master volume during the mix operation. Threads with HALs which do
// support master volume will simply ignore the setting.
for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterVolume(value);
return NO_ERROR;
}