Цитата Сообщение от aluver Посмотреть сообщение
Вопрос не совсем понятен. Программно конечно же. В андроиде, например, за это обычно по умолчанию отвечает AudioManager, а может отвечать и альса - смотря какая конфигурация или как ее настроить... Все можно найти в тех же "интернетах"...
Чистая арифметика. PCM поток - это просто 44100 значений амплитуды звукового сигнала в секунду, каждое из которых описано 16-битной цифрой. Уменьшил громкость вполовину - софт делит все значения амплитуды потока на 2.
В Android-системах с полноценной ALSA установка громкости может происходить и средствами звукового адаптера (через параметры микшера), что выясняется через изучения кода AudioHAL-библиотеки:
Код:
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;
}
, что предопределено на уровне AudioFlinger, через который по умолчанию оперирует AudioManager (в частности, AudioSystem::setStreamVolume):
Код:
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;
}
Следовательно, управление громкостью звука в системах с Android OS может быть передано звуковому адаптеру, в котором данная функция реализована аппаратно.