天天看点

AudioHardware::AudioStreamOutALSA::write

以数据为导向,分析代码,音频流程

ssize_t AudioHardware::AudioStreamOutALSA::write(const void* buffer, size_t bytes)
{
    //    LOGV("AudioStreamOutALSA::write(%p, %u)", buffer, bytes);
    status_t status = NO_INIT;
    const uint8_t* p = static_cast<const uint8_t*>(buffer);
    int ret;

    if (mHardware == NULL) return NO_INIT;

    { // scope for the lock

        AutoMutex lock(mLock);

        if (mStandby) {
            AutoMutex hwLock(mHardware->lock());

            LOGD("AudioHardware pcm playback is exiting standby.");
            acquire_wake_lock (PARTIAL_WAKE_LOCK, "AudioOutLock");获得PARTIAL_WAKE_LOCK,这个锁使得CPU在此代码之后不会进入低功耗,STRONG

            sp<AudioStreamInALSA> spIn = mHardware->getActiveInput_l();spIn是要写数据的指针
            while (spIn != 0) {如果有数据需要写
                int cnt = spIn->standbyCnt();
                mHardware->lock().unlock();
                // Mutex 请求顺序是 out -> in -> hw
                spIn->lock();
                mHardware->lock().lock();
                // make sure that another thread did not change input state
                // while the mutex is released
                if ((spIn == mHardware->getActiveInput_l()) &&
                        (cnt == spIn->standbyCnt())) {强制退出
                    LOGV("AudioStreamOutALSA::write() force input standby");
                    spIn->close_l();
                    break;
                }
                spIn->unlock();
                spIn = mHardware->getActiveInput_l();最后一次去获取ActiveInput,返回空,退出
            }
            spIn只有在仍然有活跃数据需要写,却被强制关闭情况下才不为0

            在写入数据之前,先打开输出通道
            open_l();

            if (spIn != 0) {被强制退出
                if (spIn->open_l() != NO_ERROR) {
                    spIn->doStandby_l();里面会释放掉PARTIAL_WAKE_LOCK
                }
                spIn->unlock();
            }
            if (mPcm == NULL) {PCM丢失?
                release_wake_lock("AudioOutLock");
                goto Error;
            }
            mStandby = false;下次不会进入while(mStandby),而直接跑到pcm_write
        }

        TRACE_DRIVER_IN(DRV_PCM_WRITE)
        ret = pcm_write(mPcm,(void*) p, bytes);
        TRACE_DRIVER_OUT

        if (ret == 0) {
            return bytes;返回写了多少byte数据,用于andioFlinger计算硬件sleep时间
        }
        LOGW("write error: %d", errno);
        status = -errno;
    }
Error:

    standby();

    // Simulate audio output timing in case of error
    usleep((((bytes * 1000) / frameSize()) * 1000) / sampleRate());

    return status;
}