android13-audio-AudioTrack-写数据流程

Android 13 中 AudioTrack 写数据的调用流程是一个从应用层到 HAL 层的完整数据通路。以下是详细的调用流程分析:

  1. Java 层调用入口

应用层写入数据

// 应用代码

AudioTrack audioTrack = new AudioTrack(...);

audioTrack.play();

byte[] audioData = new byte[bufferSize];

int bytesWritten = audioTrack.write(audioData, 0, audioData.length,

AudioTrack.WRITE_BLOCKING);

  1. Java Framework 层

AudioTrack.write() 方法

// frameworks/base/media/java/android/media/AudioTrack.java

public int write(@NonNull byte[] audioData, int offsetInBytes, int sizeInBytes,

@WriteMode int writeMode) {

复制代码
// 参数验证
if (audioData == null) {
    throw new IllegalArgumentException("audioData is null");
}

// 调用 Native 方法
return native_write_byte(audioData, offsetInBytes, sizeInBytes, writeMode);

}

  1. JNI 层转换

JNI 方法映射

// frameworks/base/core/jni/android_media_AudioTrack.cpp

static const JNINativeMethod gMethods[] = {

{"native_write_byte", "([BIII)I", (void *)android_media_AudioTrack_write_byte},

{"native_write_short", "([SIII)I", (void *)android_media_AudioTrack_write_short},

{"native_write_float", "([FIII)I", (void *)android_media_AudioTrack_write_float},

};

JNI write 实现

static jint android_media_AudioTrack_write_byte(JNIEnv *env, jobject thiz,

jbyteArray javaData,

jint offsetInBytes,

jint sizeInBytes,

jint writeMode) {

复制代码
// 获取 Native AudioTrack 对象
AudioTrack *lpTrack = getAudioTrack(env, thiz);
if (lpTrack == NULL) {
    jniThrowException(env, "java/lang/IllegalStateException", NULL);
    return 0;
}

// 处理 Java 数组
jbyte *nativeData = env->GetByteArrayElements(javaData, NULL);
jbyte *data = nativeData + offsetInBytes;

// 调用 Native write 方法
ssize_t written = lpTrack->write(data, sizeInBytes, 
                                writeMode == WRITE_BLOCKING);

env->ReleaseByteArrayElements(javaData, nativeData, JNI_ABORT);
return (jint)written;

}

  1. Native AudioTrack 层

Native write 方法

// frameworks/av/media/libaudioclient/AudioTrack.cpp

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) {

// 状态检查

if (mState != STATE_ACTIVE && mState != STATE_STOPPING) {

return INVALID_OPERATION;

}

复制代码
// 共享内存写入路径
if (mSharedBuffer != 0) {
    return writeToSharedBuffer(buffer, userSize, blocking);
}

// 流模式写入路径
return writeToPipe(buffer, userSize, blocking);

}

  1. 共享内存写入路径

writeToSharedBuffer 实现

ssize_t AudioTrack::writeToSharedBuffer(const void* buffer, size_t userSize, bool blocking) {

audio_track_cblk_t* cblk = mCblk;

复制代码
// 获取可写缓冲区
uint32_t framesReady = cblk->framesReady();
if (framesReady == 0) {
    if (!blocking) {
        return WOULD_BLOCK;
    }
    // 等待缓冲区可用
    cblk->waitAvailableFrames(userSize / mFrameSize);
}

// 拷贝数据到共享内存
size_t sizeToWrite = min(userSize, framesReady * mFrameSize);
memcpy(cblk->buffer(mCblk->user), buffer, sizeToWrite);

// 更新写位置
cblk->stepUser(sizeToWrite / mFrameSize);

return sizeToWrite;

}

  1. 流模式写入路径

writeToPipe 实现

ssize_t AudioTrack::writeToPipe(const void* buffer, size_t userSize, bool blocking) {

size_t bytesWritten = 0;

复制代码
while (bytesWritten < userSize) {
    // 获取音频缓冲区
    Buffer audioBuffer;
    status_t status = obtainBuffer(&audioBuffer, 
                                  blocking ? &kForever : &kNonBlocking);
    
    if (status != OK) {
        if (status == WOULD_BLOCK && !blocking) {
            break;
        }
        return status;
    }
    
    // 计算本次写入大小
    size_t toWrite = audioBuffer.size;
    if (toWrite > userSize - bytesWritten) {
        toWrite = userSize - bytesWritten;
    }
    
    // 拷贝数据到音频缓冲区
    memcpy(audioBuffer.i8, 
           static_cast<const char*>(buffer) + bytesWritten, 
           toWrite);
    
    // 释放缓冲区给 AudioFlinger
    releaseBuffer(&audioBuffer);
    bytesWritten += toWrite;
}

return bytesWritten;

}

  1. obtainBuffer 实现

获取音频缓冲区

status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, const struct timespec requested) {
audio_track_cblk_t
cblk = mCblk;

复制代码
// 检查是否有可用缓冲区
uint32_t framesAvail = cblk->framesAvailable();
if (framesAvail == 0) {
    if (requested == &kNonBlocking) {
        return WOULD_BLOCK;
    }
    // 等待缓冲区可用
    cblk->waitFramesAvailable(framesAvail, requested);
}

// 设置缓冲区参数
audioBuffer->raw = cblk->buffer(cblk->user);
audioBuffer->frameCount = framesAvail;
audioBuffer->size = framesAvail * mFrameSize;

return OK;

}

  1. Binder IPC 调用到 AudioFlinger

IAudioTrack Binder 接口

// frameworks/av/media/libaudioclient/IAudioTrack.cpp

class BpAudioTrack : public BpInterface {

public:

virtual status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount) {

Parcel data, reply;

data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());

// 序列化参数

remote()->transact(OBTAIN_BUFFER, data, &reply);

// 反序列化结果

return reply.readInt32();

}

};

  1. AudioFlinger 服务端处理

Track::obtainBuffer 实现

// frameworks/av/services/audioflinger/Tracks.cpp

status_t AudioFlinger::Track::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) {

// 检查轨道状态

if (mState == PAUSED || mState == STOPPED) {

return INVALID_OPERATION;

}

复制代码
// 从线程的混音缓冲区分配
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
    return thread->obtainBuffer(this, audioBuffer, waitCount);
}

return BAD_VALUE;

}

  1. PlaybackThread 缓冲区管理

obtainBuffer 实现

// frameworks/av/services/audioflinger/Threads.cpp

status_t AudioFlinger::PlaybackThread::obtainBuffer(

AudioFlinger::Track* track, Buffer* audioBuffer, int32_t waitCount) {

复制代码
// 获取轨道的缓冲区信息
size_t frameCount = track->frameCount();
void* buffer = track->buffer();

// 检查是否有足够的空间
if (mMixBufferStatus != MIXBUFFER_READY) {
    return WOULD_BLOCK;
}

// 设置返回的缓冲区
audioBuffer->raw = buffer;
audioBuffer->frameCount = frameCount;
audioBuffer->size = frameCount * mFrameSize;

return OK;

}

  1. 完整的调用序列图

    AudioTrack.write() [Java]

    native_write_byte() [JNI]

    AudioTrack::write() [Native C++]

    obtainBuffer() [获取缓冲区]

    IAudioTrack::obtainBuffer() [Binder IPC]

    AudioFlinger::Track::obtainBuffer()

    PlaybackThread::obtainBuffer()

    memcpy() [数据拷贝到共享内存]

    releaseBuffer() [通知 AudioFlinger 数据就绪]

    AudioFlinger 混音循环处理数据

  2. 快速路径优化

快速混合器路径

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) {

// 检查是否可以使用快速路径

if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {

return fastWrite(buffer, userSize, blocking);

}

复制代码
return normalWrite(buffer, userSize, blocking);

}

ssize_t AudioTrack::fastWrite(const void* buffer, size_t userSize, bool blocking) {

// 使用无锁环形缓冲区

return mFastBuffer->write(buffer, userSize);

}

  1. 错误处理和状态管理

错误处理逻辑

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) {

// 检查各种错误条件

if (buffer == NULL || userSize == 0) {

return BAD_VALUE;

}

复制代码
if (mState == STATE_UNINITIALIZED) {
    return INVALID_OPERATION;
}

if (mTransfer != TRANSFER_SYNC) {
    return INVALID_OPERATION;
}

// 实际写入逻辑...

}

  1. 性能统计和监控

写入统计

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) {

nsecs_t startTime = systemTime();

复制代码
ssize_t written = actualWrite(buffer, userSize, blocking);

nsecs_t endTime = systemTime();

// 更新统计信息
mTotalBytesWritten += (written > 0 ? written : 0);
mTotalWriteTime += (endTime - startTime);
mWriteCount++;

// 跟踪性能
if (ATRACE_ENABLED()) {
    ATRACE_INT("AudioTrackWriteBytes", written);
}

return written;

}

  1. 调试和日志

详细调试信息

ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) {

if (LOG_IO_VERBOSE) {

ALOGV("write: buffer=%p, userSize=%zu, blocking=%d, state=%d",

buffer, userSize, blocking, mState);

}

复制代码
ssize_t result = actualWrite(buffer, userSize, blocking);

if (result != userSize) {
    ALOGW("write: wrote %zd of %zu bytes", result, userSize);
}

return result;

}

总结:Android 13 中 AudioTrack 的写数据调用流程是一个复杂的多层级过程,涉及 Java 层、JNI、Native 层、Binder IPC、共享内存管理等多个组件。数据最终通过共享内存传递给 AudioFlinger 进行混音和硬件输出,整个过程经过高度优化以支持低延迟和高性能的音频播放。

相关推荐
阿巴斯甜8 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker8 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95279 小时前
Andorid Google 登录接入文档
android
黄林晴10 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android