自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(252)
  • 资源 (11)
  • 收藏
  • 关注

原创 我写了一个分析 Linux 平台打开文件描述符跨进程传递的工具

Linux 系统的设计中,继承了 Unix “一切皆文件” (Everything is a file) 的思想,系统中的众多对象,都可以表示为文件,可以对它们执行文件操作,如。工具对于分析 eventfd 的跨进程传递比较有效,其它一些文件类型,可能很少有跨进程传递的需要,如 epollfd 等,只能提供一些提示性信息。跨进程传递打开的文件描述符时,不同进程间的文件描述符的数值不一定完全一样,这常常给相关的调试带来障碍。目录下,有一个对应的文件描述它的基本信息,不同类型的文件,这些信息有一些差异。

2025-05-03 21:03:34 885

原创 PipeWire 音频设计与实现分析四——事件循环的设计与实现

PipeWire 的事件循环基于两个插件的 4 个接口实现,它们是插件的接口,插件的和。PipeWire 的 SPA 系统功能,即接口,用对象描述,系统功能方法集用对象描述,这两个类型定义 (位于对象的字段将指向对象。PipeWire 提供了一些宏,由对象调用的各个方法,这些宏的定义 (位于SPA 系统功能用来执行文件操作以及访问时钟,包括文件读写、poll、关闭、pollfd 操作、timerfd 操作、eventfd 操作和 signalfd 操作等。插件的和接口,分别用和。

2025-03-29 09:37:39 819

原创 PipeWire 音频设计与实现分析三——日志子系统

SPA 框架中,避免插件内部执行分配内存的操作,以避免不同的内存分配机制可能引入的分配内存的时间消耗不可控的问题。PipeWire 的绝大部分功能组件都设计为可动态加载的,可动态加载的对象分为两类,一是插件,默认位于。函数尝试打开插件目录下的插件库文件,直到打开成功或遍历完了所有插件目录。函数接受传入的 SPA 插件库路径为空,当为空时,库路径取。库路径是插件的动态链接库文件相对于插件目录的路径,但去掉。的链表中取下来,关闭动态链接库的 handle,释放。函数,它是插件的入口点,这个函数的声明 (位于。

2025-03-29 09:34:40 854

原创 PipeWire 音频设计与实现分析二——SPA 插件

SPA 框架中,避免插件内部执行分配内存的操作,以避免不同的内存分配机制可能引入的分配内存的时间消耗不可控的问题。PipeWire 的绝大部分功能组件都设计为可动态加载的,可动态加载的对象分为两类,一是插件,默认位于。函数尝试打开插件目录下的插件库文件,直到打开成功或遍历完了所有插件目录。函数接受传入的 SPA 插件库路径为空,当为空时,库路径取。库路径是插件的动态链接库文件相对于插件目录的路径,但去掉。的链表中取下来,关闭动态链接库的 handle,释放。函数,它是插件的入口点,这个函数的声明 (位于。

2025-03-29 09:33:03 867

原创 PipeWire 音频设计与实现分析一——介绍

PipeWire 是一个基于图的媒体处理引擎,一个可以运行多媒体节点图的媒体服务器,是 Linux 的音频/视频总线,它管理 Linux 系统中,不同应用程序对音频和视频设备的共享访问。它提供了一个本地客户端音频 API,但也提供兼容层来支持使用常见的音频 API,包括 ALSA、PulseAudio 和 JACK。PipeWire 在媒体节点图的处理方面,采用机制与策略分离的设计。PipeWire 主守护进程运行媒体节点图,是机制而不是策略。

2025-03-29 09:20:23 1006

原创 Linux 系统蓝牙音频服务实现分析

HSP 是蓝牙协议栈中最早的耳机配置文件,主要用于支持蓝牙耳机和手机之间的基本音频通信,它支持单声道音频传输(通常用于语音通话),和基本的远程控制功能(如接听/挂断电话),主要用于简单的蓝牙耳机,功能较为基础。HFP 是 HSP 的升级版,提供了更丰富的功能,主要用于支持免提设备(如车载蓝牙系统)与手机之间的通信,它支持单声道音频传输(语音通话),更复杂的远程控制功能(如音量控制、重拨、拒接电话等),电话状态信息(如电池电量、信号强度等),及多方通话和语音识别,主要用于车载蓝牙系统、高端蓝牙耳机等。

2025-03-15 18:46:11 1023 1

原创 Linux 蓝牙音频软件栈实现分析

蓝牙协议栈是实现蓝牙通信功能的软件架构,它由多个层次组成,每一层负责特定的功能。蓝牙协议栈的设计遵循蓝牙标准 (由蓝牙技术联盟定义),支持多种蓝牙配置文件 (Profiles),以满足不同的应用场景 (如音频传输、文件传输、健康设备、键盘鼠标这样的输入输出设备等)。蓝牙各个应用场景的实现,如音频传输、文件传输和键盘鼠标这样的输入设备,与系统中常规的这些功能的实现大为不同。

2025-03-15 18:42:00 966

原创 PipeWire:Linux 的音频/视频总线

十多年来,一直服务于 Linux 桌面,作为其主要的音频混音和路由守护程序 - 以及它的音频 API。不幸的是,PulseAudio 的内部架构并不适合日益增长的沙盒化的应用程序用例,尽管已经有人尝试对其进行修改。,一个新的守护进程从这些尝试中横空而出,将在即将到来的 Fedora 34 发行版中。这是一个即将到来的转变,值得一看。说到转换,2007 年末 Fedora 8 自己向 PulseAudio 的转换并不顺利。长期使用 Linux 的用户仍然记得,这个守护进程被会破坏音频的软件。

2025-03-15 16:28:08 766

原创 深入 PipeWire

随着它的成熟,PipeWire 项目正在慢慢地变得流行。它的文档依然相对稀少,但正在逐渐增长。然而,让项目外部的人尝试用他们自己的语言来理解和解释它总是一个好主意,重申想法,从他们自己的角度来看待它。在之前的一篇文章中,我讨论了 Unix 上的通用音频栈,并有一节提到了 PipeWire。不幸的是,因为当时我没有找到足够的文档,并且无法理解一些概念,我认为我没有对项目进行公正的处理,甚至可能混淆了某些部分。

2025-03-04 23:19:22 955

原创 PipeWire 简介

是一个底层的多媒体框架,旨在替代 PulseAudio 和 JACK 这些 Linux 平台更为传统的音频服务器,它聚焦于处理多媒体数据 (主要是音频、视频和 MIDI),提供更灵活和高效的音频、视频处理能力。PipeWire 项目的创始人及最核心贡献者是,他是一位著名的软件工程师和开源开发者,特别是在多媒体和音视频领域。除了 PipeWire 项目,

2025-02-28 19:56:14 882

原创 时钟抖动定义和测量方法

抖动是一组信号边沿与其理想值的时序变化。时钟信号中的抖动通常是由系统中的噪声或其他干扰引起的。影响因素包括热噪声、电源变化、负载条件、设备噪声以及附近电路耦合的干扰。

2024-12-24 19:51:47 1495 1

原创 VLC 播放的音视频数据处理流水线搭建

VLC 用对象直接或间接管理音视频播放有关的各种资源,包括等,这个类型定义 (位于是个抽象类型,VLC 中这个类型的具体实现为,后者定义 (位于播放 VLC 播放列表中的一个音视频流的时候,音视频流的播放通过PlayItem()函数定义 (位于函数接收类型的p_item参数,这个类型定义 (位于类型包含一个类型为的字段p_input,其中包含要播放的音视频流的各种信息,如 URI,名称,基础流的个数及格式等,类型的详细定义 (位于PlayItem()函数主要是调用函数创建对象,并调用。

2024-11-29 23:12:57 1199

原创 VLC 插件的使用

不同功能的功能描述不同,VLC 模块的激活回调函数的参数列表和返回值可能也不同。函数:根据“能力”(capability)和名称查找模块,即查找具备某种“能力”(capability)的特定名称的模块,并通过模块的激活回调函数获得具体的功能描述对象。函数创建了模块“银行”,并加载了所有插件之后,需要不同功能的模块的地方,根据需要通过模块相关的接口函数,获得所需的模块。函数捞取所有 VLC 模块的列表,一个个地对比模块的名称和传入的所需模块的名称,找到名称匹配的模块并返回。等字段,遍历各个重定向的 URL。

2024-11-27 20:19:26 1053

原创 VLC 插件加载管理分析

VLC 插件分为动态插件和静态插件,静态插件直接链接进 VLC 核心,动态插件则在 VLC 可执行文件的链接信息中,无法看到对它们的直接依赖,它们通过动态链接加载机制加载。函数计算所有插件的模块配置的总数,为所有各个模块配置指针分配空间,将各个模块配置指针复制到新分配的模块配置指针数组中,对模块配置指针数组进行排序。VLC 插件/模块框架加载插件时,通过。,则首先在插件缓存中查找插件,查找所用的 key 即为插件文件相对于插件根目录的相对路径,如果找到了,且缓存中的信息不够新,则销毁对应的。

2024-11-26 09:48:20 1357

原创 alsa-lib 插件 dsnoop 实现简单分析

alsa-lib 提供的 API 接口和 Android 等系统中使用的 tinyalsa 提供的 API 接口差异巨大,alsa-lib 的复杂度及支持的功能特性,与 tinyalsa 的有着数量级上的差异。插件机制及 dmix 和 dsnoop 等内置 PCM 插件是 alsa-lib 支持的众多高级特性的一部分。ALSA 音频内核设备驱动,在特定时刻只能运行在特定模式和一组参数下,通常只能支持由单个应用程序打开。

2024-10-08 23:00:00 1416

原创 Linux 平台 PulseAudio 音频播放数据通路 II

是 PulseAudio 音频服务中使用的基本的音频数据内存管理机制,它的基本思路是,预先分配一块巨大的内存,将这一大块内存分割为大小相等的小内存块,每次需要音频数据缓冲区时,则取一个小内存块来用。音频数据的传递和处理中,所需的音频数据缓冲区大小并不会经常剧烈变化,因而将内存池的内存划分为大小相等的小内存块对于兼顾音频数据缓冲区的分配/释放效率和内存利用率是值得的。函数处理传入的队列最大长度等参数,使它们对齐到音频帧大小,且不同的长度,如队列最大长度、队列目标长度、最小请求长度等保持合适的相对大小关系。

2024-10-08 18:40:49 1080

原创 Linux 平台 PulseAudio 音频播放数据通路 I

Linux 内核中,音频子系统由 ALSA 框架实现,用户空间应用程序通过 ALSA 框架向 devtmpfs 虚拟文件系统,即目录下导出的一组紧密相关的设备文件,如和等与 Linux 内核音频子系统交互,包括传递数据,及对硬件设备层的音频数据通路进行控制。ALSA 项目,在用户空间提供了 alsa-lib 库,以方便应用程序访问音频设备。alsa-lib 提供了一组音频设备领域的标准 API,其实现中通过open()read()write()ioctl()mmap()和poll()

2024-08-15 20:05:56 1915

原创 Linux GNOME 桌面系统音频设置实现

将 gnome-control-center 的源码克隆到本地,切换到合适的分支,安装 meson 和 ninja 构建工具,并解决依赖问题之后,构建 gnome-control-center 的过程比较简单。Linux 系统音频设置相关信息的获取和展示,大体如上所述,即向 pulseaudio 服务订阅各种信息,在 pulseaudio 的回调中,读取它们,并通过 GNOME Settings 应用的。对象的对应类型的 stream 的哈希表中,并被添加到它的 all_streams 哈希表中。

2024-06-08 09:45:00 1830 1

原创 ALSA 用例配置

可以使用Define或块来定义和改变变量。DefineDefine {结果将存储到变量rval1中作为hello,存储到变量rval2中作为regex(每个匹配的子字符串都存储到带有序列号后缀的单独变量中)。例如可以使用引用替换变量。

2024-06-07 20:30:00 1740

原创 Alsa UCM

最复杂的部分是需要创建的HiFi文件的实际内容。该文件基本上是启用/禁用 mixer 混频器的脚本和从一个输入/输出移动到另一个输入/输出的命令的集合。这是一个用例文件的最小示例。Value {块定义了启用/禁用这个用例需要运行的命令。这主要是用来使整个 mixer 混频器在启动时处于已知状态,所以在这里为 mixer 混频器中的所有 controls 控件设置一个值可能是个好主意。本节中的命令均为cset命令。这些命令对应于你常常通过 alsa-utils 包中的amixer工具使用的命令。;;

2024-06-07 19:30:00 2459

原创 SOF项目简介

Sound Open Firmware SDK 由许多成分组成,可以定制这些成分以用于固件/软件开发生命周期。定制允许 “最适合” 的开发方法,其中 SDK 可以针对特定流程或环境进行优化。有些 SDK 成分是可选的,而其他成分可以有多次选择,如下图所示。图 2:SDK 示例配置显示了运行 Linux 操作系统的 Intel Apollo Lake 平台上的 SOF 开发流程。请注意编译器工具链的选择和可选的 DSP 仿真器的选择。

2024-03-31 10:01:41 1314

原创 拓扑 2.0

0123!type "pga"

2024-03-03 09:36:10 1093

原创 高通 AudioReach 框架简介

从实现上,AudioReach 的 Linux ASoC 驱动是 AudioReach 能力的代理,或者适配器,它通过核间通信机制和 DSP 上运行的 AudioReach 通信,对于 Linux 内核,它实现 ASoC 的 PCM 和 compress 接口,向用户空间提供访问音频能力必不可少设备文件等接口。除了运行于 DSP 的 AudioReach 和它的 Linux ASoC 驱动程序,拓扑配置是整个子系统运行的另一个组成部分,Audioreach 的拓扑配置文件可以参考。

2024-03-01 19:15:15 3768

原创 ALSA 拓扑

ALSA 拓扑给音频驱动程序提供了一种在运行时,从用户空间加载它们的混音器,路由,PCM 和能力,而无需修改任何驱动程序源码的方法。其目标是编写一次驱动程序,而在拓扑中处理变化和差异。

2024-02-23 22:17:46 1134

原创 ALSA Compress-Offload API

从 ALSA API 的早期开始,它就被定义为支持 PCM,或考虑到了 IEC61937 等固定比特率的载荷。参数和返回值以帧计算是常态,这使得扩展已有的 API 以支持压缩数据流充满挑战。最近这些年,音频数字信号处理器 (DSP) 常常被集成进片上系统 (SoC) 设计中,且 DSPs 也常被集成进音频编解码器 (这里的音频编解码器与 AAC 之类的音频数据压缩方案不同,它是指主要用于完成模拟信号和数字信号转换的器件) 中。与基于主机的处理相比,在 DSP 这样的处理器上处理压缩数据可以显著降低功耗。

2023-12-09 11:14:13 1176

原创 深入浅出 Linux 中的 ARM IOMMU SMMU III

系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存,但最终会调到 DMA 子系统的等接口。等接口通过 DMA IOMMU 的回调分配内存,并为经过 IOMMU 的 DMA 内存访问准备转换表。之后经过 IOMMU 的 DMA 内存访问所需的所有工作都已完成。音频子系统 ALSA 的驱动程序,通过等函数为 DMA 分配内存,这些函数定义 (位于和函数用于DMA 内存,两者的区别在于,前者为单个子流预分配,后者为某个 PCM 下的所有子流预分配。它们都通过函数为某个子流预分配内存。

2023-12-02 07:57:19 2364

原创 深入浅出 Linux 中的 ARM IOMMU SMMU II

要使系统 I/O 设备的 DMA 内存访问能通过 IOMMU,需要将系统 I/O 设备和 IOMMU 设备绑定起来,也就是执行 SMMU 驱动中的系统 I/O 设备探测。总线发现系统 I/O 设备并和对应的驱动程序绑定,与 IOMMU 设备驱动程序注册并为 IOMMU 设备执行探测初始化的相对顺序不固定,可能系统 I/O 设备先被发现并和对应的驱动程序绑定,也可能 IOMMU 设备驱动程序注册及为 IOMMU 设备执行探测初始化先进行。创建系统 I/O 设备和 IOMMU 设备间的链接。

2023-11-25 09:55:25 2287

原创 深入浅出 Linux 中的 ARM IOMMU SMMU I

在计算机系统架构中,与传统的用于 CPU 访问内存的管理的 MMU 类似,IOMMU (Input Output Memory Management Unit) 将来自系统 I/O 设备的 DMA 请求传递到系统互连之前,它会先转换请求的地址,并对系统 I/O 设备的内存访问事务进行管理和限制。IOMMU 将设备可见的虚拟地址 (IOVA) 映射到物理内存地址。不同的硬件体系结构有不同的 IOMMU 实现,ARM 平台的 IOMMU 是 SMMU (System Memory Management)。

2023-11-22 19:01:21 3027

原创 Linux 内核音频数据传递主要流程

这里的可用空间大小是站在用户空间应用程序的视角来说的,即对于播放来说,可用空间大小指还可以向 DMA buffer 写入的数据量,对于录制来说,则指可以从 DMA buffer 读取的数据量。大多数情况下,音频设备会同时提供播放和录制功能,用于播放和录制的 PCM 设备文件是一起导出的,播放和录制的 PCM 设备文件的文件操作也是一起定义的,其中索引为。操作分别拷贝各个 channel 的数据,传入的音频数据保存在多个不同的缓冲区中,每个通道一个,音频数据通过指针数组的方式传递。操作用于执行数据拷贝。

2023-08-06 10:14:58 2501

原创 Linux 内核 ASoC DMA 引擎驱动程序

Linux 内核 ASoC 框架,在概念上将嵌入式音频系统拆分为多个可复用的组件驱动程序,包括 Codec 类驱动程序、平台类驱动程序和机器类驱动程序。在实现上,机器类驱动程序用和结构描述,属于平台类驱动程序的 DMA 引擎驱动程序由结构描述,codec 类驱动程序和 I2S 等驱动程序,由和等结构描述。除平台类驱动程序外的各种驱动程序都通过 component 抽象组织在一起,即这些驱动程序都作为注册给 Linux 内核 ASoC 框架,Linux 内核 ASoC 框架为它们各自创建结构对象,并保存在。

2023-07-29 09:48:47 1197

原创 Linux 内核 ASoC 基本数据结构

Linux 内核 ASoC 框架建立了新的抽象,并通过一些中间层,将这些抽象接入 ALSA 音频框架。Linux 内核 ASoC 设备驱动的结构如下图:Linux 内核 ASoC 设备驱动程序在 Linux 内核中扮演多个角色。Linux 内核 ASoC 设备驱动程序在初始化阶段向内核注册某个总线类型的设备驱动程序,总线负责相应的设备发现。这里的总线不一定是真实的硬件总线,如 PCI 等,也可能是虚拟的,如 platform 等。总线在发现设备之后,会记录发现的设备,并尝试匹配注册的驱动程序。

2023-07-23 18:27:39 979

原创 Linux 内核设备树时钟绑定

这种绑定依然处于开发中,并且基于 benh[1] 的一些实验性工作。时钟信号源可以由设备树中的任何节点表示。这些节点被指定为时钟提供者。时钟消费者节点使用phandle和时钟指示符对将时钟提供者输出连接到时钟输入。与 gpio 指示符类似,时钟指示符是 0 个、1 个或多个标识设备上的时钟输出的元素的数组。时钟指示符的长度由时钟提供者节点中的属性值定义。

2023-07-14 22:29:59 1969

原创 Linux ALSA 核心简单分析

Linux 内核 ALSA 框架通过向用户空间导出多个设备文件,以使用户空间程序可以与内核的音频子系统交互,可以访问音频硬件设备。

2023-07-14 22:27:48 659

原创 Android Java 音频采集 AudioRecord

在 Android Java 应用中,一般用管理从平台的音频输入设备采集音频数据所需的资源。音频采集和音频播放密切关系,Android 系统中 Java和AudioTrack在许多方面,都有着很高的相似性,无论是代码的目录组织,还是整个类的接口设计和实现结构,但它们也有着不小的区别。对比来看 Java和AudioTrack的实现,有助于我们对音频的播放和采集做更好地理解。的 Java 代码位于,它的 JNI 代码位于。Java 层类实现基于库,该库位于。

2023-04-29 19:52:34 3273 1

原创 Android 中的跨进程数据块传递

Android 的 Binder 进程间通信机制主要用于实现远程过程调用 RPC,Android 系统中进程之间的大块数据传递,如音频数据,出于效率等原因,一般不直接用 Binder 机制。

2023-04-29 19:00:53 1431

原创 Android Java 播放音频 AudioTrack

【很多同学读 Android 系统的源码时感觉比较费力,一定会觉得是自己水平不够见识有限认知水平不足,觉得自己需要多学习多努力多下功夫,但 Android 系统源码质量之烂简直超乎想象。尽管 Android 系统确实实现了很多功能、特性,提供了很多亮点,但不可否认,把 Android 系统的代码称为屎山,可能都有点侮辱屎山了。关于 Android 的音频数据处理,音频播放和采集是两个紧密相关的过程,但这两个过程又有着巨大的差别。

2023-04-19 19:59:14 3352 1

原创 Android 中的混音器 AudioMixer 实现分析

Android 混音器 AudioMixer 实现分析。

2023-04-12 18:56:19 3895 1

原创 Android 中打开音频流所用的配置

对于通道掩码(通道数),如果是直接输出 (Direct Output),则通道数越小优先级越高,否则,通道数越大优先级越高;对于采样率,如果是直接输出 (Direct Output),则采样率越小优先级越高,否则,采样率越大优先级越高。Android 中打开音频输出流,所需的主要参数采样率、通道掩码(通道数)、采样格式、增益和标记来自于传入的。音频策略配置文件,更具地说,来自于音频策略配置文件中的。的标记和增益直接来自于音频策略配置文件的。对象,后者的构造函数的定义 (位于。在音频策略配置文件中,

2023-04-08 18:44:21 1233

原创 Android 中 libnbaio 库的设计和实现

在整个 Android 系统中,找不到使用它们的地方,随着 Android 系统的发展,它们大概已处于年久失修不可用的状态。的缩写) 库主要是为非阻塞的音频 I/O 设计的,但现在它也包含了一些接口的阻塞实现,因而它的主要作用也变成了为各种音频 I/O 设施提供统一的读写接口。对象在构造时,需要传入最大帧数,音频数据格式,和可选的一块用于交换数据的缓冲区。如果是同步写入,没有足够的空间写入全部数据时,会根据当前缓冲区中已经写入的数据的水位计算休眠时间,并休眠等待,否则返回实际写入的音频帧个数。

2023-04-03 20:28:11 894

原创 Android 音频设备信息加载

Android 系统的守护进程 audioserver 中运行着多个与音频相关的系统服务,主要包括和,当需要支持 AAudio 的 MMap 模式时,会运行。需要启动服务时,audioserver 程序会 fork 一个进程运行其它那些系统服务,在父进程中运行,并将进程名修改为。

2023-03-24 21:31:26 2302 1

QUIC 加密协议规范中文版

QUIC 是一种新型的高效的安全的网络协议。这份文档是 QUIC 的加密协议的规范中文版翻译。

2018-07-23

HPACK 协议规范中文版

HTTP/2 协议的一些关键特性包括:二进制分帧,连接复用,首部压缩等。首部压缩是 HTTP/2 用于减少多请求执行时数据传输量的方法。这份文档是 HTTP/2 首部压缩部分,即 HPACK 的协议规范。

2018-07-23

HTTP/2规范中文版

这份文档是 HTTP/2 协议 RFC 规范的中文版翻译,协议规范完整定义了 HTTP/2 协议的行为和特性。

2018-07-23

Real-Time Streaming Protocol Version 2.0

Real-Time Streaming Protocol Version 2.0 协议规范

2017-08-19

RTP Payload Format for H.264 Video

RTP 传输 H.264 视频的 IETF 规范。

2017-08-19

Advance Bash Scripting Guide

Advance Bash Scripting Guide

2007-11-04

Programming Perl

Programming PerlProgramming PerlProgramming Perl

2007-11-04

GNU Linux Tools Summary

GNU Linux Tools GNU Linux Tools SummarySummaryGNU Linux Tools Summary

2007-11-04

BSD Hacks

BSD HacksBSD HacksBSD Hacks

2007-11-04

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除