Android tinyalsa深度解析之pcm_close调用流程与实战(一百零四)

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

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

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
更多原创,欢迎关注:Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

      • [🌻1. 前言](#🌻1. 前言)
      • [🌻2. 用法与应用场景](#🌻2. 用法与应用场景)
      • [🌻3. 调用流程剖析](#🌻3. 调用流程剖析)
        • [3.1 核心步骤](#3.1 核心步骤)
        • [3.2 涉及核心时序图](#3.2 涉及核心时序图)
      • [🌻4. 实战应用案例](#🌻4. 实战应用案例)
      • [🌻5. 用法总结](#🌻5. 用法总结)

🌻1. 前言

本篇目的:Android tinyalsa深度解析之 pcm_close 调用流程与实战。

🌻2. 用法与应用场景

pcm_closetinyalsa 库中用于关闭 PCM 设备并释放所有相关资源的终点函数。它不仅负责用户态内存的回收,更重要的是触发内核驱动释放物理硬件资源。

  • 用法int pcm_close(struct pcm *pcm);
  • 返回值 :成功返回 0。若传入指针无效,函数会安全返回。
  • 应用场景
  1. 结束音频会话:在播放或录音任务完成后,正常关闭设备节点。
  2. 错误处理路径 :当 pcm_open 成功但后续的 pcm_prepare 或数据读写发生严重错误时,必须调用此函数进行资源清理。
  3. 动态路由切换:在 Android 系统切换音频路径(如 Speaker 切换至有线耳机)时,HAL 层通常需要关闭当前的 PCM 实例并重新配置。

🌻3. 调用流程剖析

3.1 核心步骤
  1. 指针合法性校验 :检查传入的 pcm 是否为 NULL 或指向 bad_pcmtinyalsa 的设计确保了对非法句柄调用 close 也不会导致系统崩溃。
  2. 停止流传输 :如果设备仍处于 RUNNING 状态,底层驱动会在关闭文件描述符前尝试停止 DMA 传输。
  3. 解映射 MMAP 缓冲区 :检查 pcm->mmap_buffer。如果用户以 PCM_MMAP 模式打开设备,pcm_close 会自动调用 munmap 释放映射的内存块。
  4. 触发内核 Release :执行系统调用 close(pcm->fd)。这会进入内核 ALSA 核心层,调用驱动的 release 回调函数,进而关闭硬件功放或重置硬件寄存器。
  5. 内存释放 :调用 free(pcm) 销毁用户态的结构体实例,完成最后的清理工作。

关键技术:坏句柄安全回收
tinyalsapcm_open 失败时也会返回一个结构体(fd 为 -1)。pcm_close 能够识别这种"坏句柄"并仅释放内存而不尝试执行内核关闭操作,这简化了 HAL 层的异常处理逻辑。

3.2 涉及核心时序图

Audio Codec/DMA Kernel ALSA Core VFS (close syscall) tinyalsa (pcm_close) Audio HAL Audio Codec/DMA Kernel ALSA Core VFS (close syscall) tinyalsa (pcm_close) Audio HAL alt [MMAP 模式已启用] 调用 pcm_close(pcm) 1. 验证 pcm 指针及状态 2. munmap(pcm->>mmap_buffer) 3. close(pcm->>fd) 触发 snd_pcm_release 停止 DMA, 降低功耗 硬件已重置 返回 4. free(pcm) 释放结构体 返回 0


🌻4. 实战应用案例

此 Demo 展示了在 Android HAL 开发中,如何规范地使用 pcm_close 并通过指针置空防止野指针异常。

c 复制代码
#include <tinyalsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>

/**
 * 模拟 HAL 层安全释放音频流的逻辑
 */
void hal_pcm_release(struct pcm **pp_pcm) {
    if (pp_pcm == NULL || *pp_pcm == NULL) {
        return;
    }

    /* 1. 执行 tinyalsa 关闭操作 */
    printf("HAL: Closing pcm device...\n");
    int ret = pcm_close(*pp_pcm);

    if (ret != 0) {
        printf("HAL: Warning - pcm_close returned error code %d\n", ret);
    }

    /* 2. 极其重要:手动将原指针置为 NULL
     * 防止 HAL 层其他线程误用已释放的内存 (Use-After-Free)
     */
    *pp_pcm = NULL;
    printf("HAL: Resource cleanup complete.\n");
}

int main() {
    struct pcm_config config = {
        .channels = 2,
        .rate = 44100,
        .period_size = 1024,
        .period_count = 4,
        .format = PCM_FORMAT_S16_LE
    };

    // 打开设备 (声卡 0, 设备 0, 播放模式)
    struct pcm *out_stream = pcm_open(0, 0, PCM_OUT, &config);

    if (out_stream && pcm_is_ready(out_stream)) {
        printf("HAL: Audio session started.\n");
        // ... 此处执行音频数据写入 pcm_write ...
    }

    // 无论打开成功还是失败,最终都要调用清理函数
    hal_pcm_release(&out_stream);

    return 0;
}

🌻5. 用法总结

特性 详情描述
内存管理 完全清理 。内部集成了对 mmap 缓冲区和 pcm 结构体本身的 free
调用配对 必须与 pcm_open 配对。漏掉 close 会导致声卡被占用(Device Busy)以及系统 fd 泄露。
线程安全 非线程安全 。严禁在主线程 close 的同时在另一线程执行 pcm_write,需在 HAL 层加锁。
硬件状态 重置硬件。该函数执行后,内核通常会关闭相关的 DAC/ADC 电源以节省功耗。
容错性 高容忍度。可以安全处理未成功 ready 的 pcm 指针,不会造成内核异常。
相关推荐
weixin_411191842 小时前
LifecycleEventObserver和DefaultLifecycleObserver使用
android
、BeYourself2 小时前
Intent :跳转与数据传递的正确打开方式
android·android-studio
灵感菇_2 小时前
Android 列表控件全面解析:ListView 与 RecyclerView
android·ui
2601_949809593 小时前
flutter_for_openharmony家庭相册app实战+照片详情实现
android·java·flutter
fundroid3 小时前
Kotlin 泛型进阶:in、out 与 reified 实战
android·开发语言·kotlin
Android系统攻城狮3 小时前
Android tinyalsa深度解析之pcm_open调用流程与实战(一百零三)
android·pcm·tinyalsa·音频进阶·音频性能实战·android hal
2501_944448003 小时前
Flutter for OpenHarmony衣橱管家App实战:意见反馈功能实现
android·javascript·flutter
风流倜傥唐伯虎3 小时前
./gradlew assembleDebug和gradle build区别
android·android studio
有位神秘人3 小时前
Android中获取当前设备的宽高与屏幕密度等数据的工具类
android