简介: CSDN博客专家、《Android系统多媒体进阶实战》作者

博主新书推荐:《Android系统多媒体进阶实战》🚀
Android Audio工程师专栏地址: Audio工程师进阶系列原创干货持续更新中……】🚀
Android多媒体专栏地址: 多媒体系统工程师系列原创干货持续更新中……】🚀
专题一 二:AAOS车载系统+AOSP14系统攻城狮入门视频实战课 🚀
专题三:Android14 Binder之HIDL与AIDL通信实战课 🚀
专题四:Android15快速自定义与集成音效实战课 🚀
专题五:Android15音频策略实战课 🚀
专题六:Android15音频性能实战课(无声/杂音/断音/爆音实战案例) 🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🌻1. 前言

本篇目的:Linux PulseAudio 深度解析之 pa_stream_cancel_write 调用流程与实战。

要点概括

  • 核心功能:取消一次尚未提交的 Stream 写缓冲操作。
  • 工作机制:释放通过 pa_stream_begin_write 获取的共享内存写入区域,并丢弃未提交的数据。

🌻2. 用法与应用场景

pa_stream_cancel_write
是 PulseAudio 零拷贝写入模型中的重要接口之一。

在 PulseAudio 中:

  • pa_stream_begin_write
    用于申请共享内存写缓冲区
  • pa_stream_write
    用于真正提交数据
  • pa_stream_cancel_write
    用于放弃当前写操作

因此:

它本质是“撤销本次写入事务”。

函数原型

void pa_stream_cancel_write(
        pa_stream *s);

参数说明

s:
需要取消写入操作的 pa_stream

返回值

无返回值

应用场景

1. begin_write 后数据生成失败

例如:

pa_stream_begin_write(...)

成功后:

  • PCM 解码失败
  • 数据生成失败
  • 音频帧非法

此时需要:

pa_stream_cancel_write(stream);

放弃本次写缓冲。


2. 用户中断播放

例如:

  • 用户点击停止
  • 用户切歌
  • 用户关闭播放器

当前未提交的数据:

需要立即丢弃。


3. 音频同步失败

例如:

  • 时间戳错误
  • 音频时钟漂移
  • A/V Sync 失败

当前 Buffer 不再有效:

需要取消写入。


🌻3. 调用流程剖析

🌻3.1 核心步骤

1. 应用层申请写缓冲区
pa_stream_begin_write(
        stream,
        &data,
        &size);

2. libpulse 分配共享内存区域

内部会:

  • 分配 SHM Buffer
  • 返回可写内存指针

例如:

data

3. 应用层决定放弃写入

例如:

  • 数据异常
  • 用户停止播放
  • 解码失败

此时:

不再调用 pa_stream_write

4. 调用 cancel_write
pa_stream_cancel_write(stream);

5. libpulse 释放 Buffer

内部会:

  • 回收共享内存区域
  • 清空 pending write 状态
  • 丢弃当前未提交数据

🌻3.2 调用流程图

Application
应用程序

调用 pa_stream_begin_write

libpulse 分配 SHM Buffer

返回可写内存 data

是否继续写入?

调用 pa_stream_cancel_write

libpulse 回收 Buffer

丢弃未提交数据

调用 pa_stream_write

提交数据到服务端

🌻3.3 Cancel Write 生命周期图

pa_stream_begin_write

申请 SHM Buffer

获得 data 指针

数据是否有效?

pa_stream_cancel_write

释放共享内存 Buffer

丢弃当前 PCM 数据

pa_stream_write

提交到服务端

🌻4. 实战应用案例

#include <pulse/pulseaudio.h>
#include <stdio.h>

void write_pcm_data(pa_stream *stream) {

    void *data = NULL;
    size_t size = 4096;

    /*
     * 申请共享内存写缓冲
     */
    if (pa_stream_begin_write(
                stream,
                &data,
                &size) < 0) {

        fprintf(stderr,
                "begin_write failed\n");
        return;
    }

    /*
     * 模拟 PCM 解码失败
     */
    int decode_failed = 1;

    if (decode_failed) {

        printf("PCM decode failed\n");

        /*
         * 放弃本次写入
         */
        pa_stream_cancel_write(stream);

        return;
    }

    /*
     * 正常写入
     */
    pa_stream_write(
            stream,
            data,
            size,
            NULL,
            0,
            PA_SEEK_RELATIVE);
}

int main() {

    pa_stream *stream;

    /*
     * 假设 stream 已 READY
     */

    write_pcm_data(stream);

    return 0;
}

🌻5. 源码层核心原理

pa_stream_cancel_write
在 libpulse 中核心逻辑是:

回收当前 pending write buffer。

内部逻辑类似:

void pa_stream_cancel_write(
        pa_stream *s) {

    pa_assert(s);

    if (s->write_memblock) {

        pa_memblock_unref(
                s->write_memblock);

        s->write_memblock = NULL;
    }
}

你会发现:

它本质是在:

  • 回收 memblock
  • 清理 pending write
  • 放弃当前 SHM Buffer

并不会:

  • 向服务端提交数据
  • 播放 PCM
  • 发送 write packet

因此:

pa_stream_cancel_write
本质属于:

“零拷贝写入撤销接口”。

🌻6. 一句话总结

pa_stream_cancel_write
本质上是:

“撤销一次尚未提交的音频写事务”。

它负责:

  • 放弃当前 Buffer
  • 回收 SHM 内存
  • 丢弃无效 PCM 数据
  • 保持 Stream 写入状态一致性

是 PulseAudio 零拷贝写入模型中的核心安全接口之一。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐