一、目的

相信不少同学都见过以前那种很小的MP3播放器(暴露年龄),高级一点的还带一个小的单色液晶屏,想必理工科男都想自己设计一款这样的一款播放器。

那么如何才能设计实现一个简单的音乐播放器呢?

本文不讲述跟硬件相关的知识点,例如mcu选型、codec选型,着重于软件设计相关的内容。

二、分析

当我们播放一首歌曲时,首先我们需要考虑歌曲哪里来,是本地文件系统中读取音频文件还是从网络上下载音频流(例如HTTP流或者现在比较流行的m3u8流)还是其他动态输出音频数据的设备或软件实体?为了描述方便,我们可以称之为预处理,即负责原始数据的获取。

接下来,我们需要分析这个音频的基本特征,一般需要考虑这个音频流是否需要解包、是否需要解码、是否需要重采样,例如大家常见的MP3其实是MPEG 1 Layer 3的一种规范定义的音频压缩方式,还有在windows上比较流行的WAV以及WMA文件。同样为了描述方便,我们可以将这一过程统称为解码,即负责原始数据的解包解码。

最后,就是PCM数据播放了,一般情况下解码端会输出音频的基本信息,例如采样率、通道数、量化位数,播放设备的开启需要这些信息,我们称之为播放设备管理(暂停、恢复、终止)。

关于基本音频特征的相关知识点我会在后续的博文中一一讲解。

至此,通过上面的分析我们可以得到这样一个简单的播放器软件框架,如下图:

图中每个圆形实体分别代表用户、预处理、解码、播放模块。

用户模块去其实就是开发者使用播放器提供的相关接口的用户业务层代码,一个基本的播放器必须提供播放、暂停、恢复、停止四个接口,另外还需要提供一个播放完成的通知接口,图中我们以事件反馈的方式提供。

为了方便,我们可以将这个整个播放过程使用单线程这种方式来实现,但是此种方式会有很大的缺点:

  • 所有处理过程耦合在一起,不利于后续的功能的扩充,例如现在需要在解包解码与播放之间添加一个重采样的过程,这个时候不仅解包模块需要修改,播放模块也要修改,不符合模块解耦的设计要义。
  • 嵌入式设备的处理能力有限,无法在一个while循环里面在给定时间内完成所有的操作,这就导致用户感官上的卡顿体验,例如播放的过程中就不能进行预处理和解码,一般情况下播放必须按照采样率规定的时钟进行播放,才播放一段PCM数据期间,其他各个模块都不能继续执行。

鉴于此我们在上图实现时可以采用多线程方式,那么这个时候就需要线程间的同步。

为了实现简单,我们可以采用pipeline配合消息传递机制来进行线程间同步。举例来讲,当预处理器收到用户播放请求时,预处理器开始工作并在解析出音频特征信息后,例如知道需要播放的音频是MP3还是AAC,那么将此信息传递给解包解码线程,由它负责处理后续的操作,当解包解码线程解析出PCM参数时,传递给播放线程,由播放线程负责后续的播放,即预处理驱动解码,解码再驱动播放。

在上图中我们可以看到蓝色箭头代表音频数据的流动,并且可以看到消息也是从前往后往后流动的,上一级控制下一级,这种方式在实现上也很简单,通常我们会是使用消息队列、邮箱或者其他线程间通信机制。

至此,我们其实就已经将一个音频播放器的软件架构就已经设计好了,后面无非就是具体实现。

但是如果仔细推敲这个设计,你会发现其实这种流水线式消息传递是存在问题的,举例来说如果用户需要暂停播放,这个时候暂停的消息是直接控制播放设备的,即不往播放设备中写数据,则设备不发声;某个时刻由于预处理过慢,还没有获取到音频信息或者解包解码线程还没有拿到足够的数据解析出PCM信息,那么播放线程是不工作的,也就是说用户的暂停操作不能及时得到处理,虽然感官上设备不放音,呈现给用户的时设备没有在放音,就可以认为是已经暂停。

有些同学就说既然是因为暂停的消息直接控制播放设备才导致这样的问题,那么我为什么不将暂停消息发给其他模块呢?

其实这边涉及到一个缓冲问题。

上图中我们看到各个模块间不仅有消息传递也有音频数据传递,如果暂停请求不直接去控制播放设备,由于播放设备是从解码和播放之间的数据缓冲中拿数据,那么不控制播放设备,播放设备就可以从这个缓冲中取出数据去播放,如果这个缓冲很大,用户的暂停请求就不能快速得到响应。

基于以上分析,这种设计适合于那种单个播放对象的场景。如果某类场景中需要两个播放对象间快速切换,例如A在播放,此时需要暂停A,立刻去播放B,那么B的播放就会受到A的暂停响应速度的影响。有读者会问那什么样场景中会有这样的需求呢,请关注后续的博文。

但是这种解耦设计的方式是可取的,只是在消息传递方式上需要再次斟酌。

接下来让我们再分析分析每个模块的设计实现。

预处理上面也说了是负责数据的获取,那么这个数据有可能是本地文件流也有可能是网络流(通过HTTP或者其他网络协议获取)。那么我们就可以对它进行抽象,例如我们可以设计这样一套接口:

typedef struct {char *target;int (*throw_info)(char *info, void *userdata);int (*throw_data)(const char *buf, int len, void *userdata);void *userdata;
} play_preprocessor_cfg_t;typedef struct play_preprocessor {const char *type;int (*init)(play_preprocessor_t *pp, play_preprocessor_cfg_t *cfg);play_preprocessor_err_t (*poll)(play_preprocessor_t *pp, int timeout);void (*destroy)(play_preprocessor_t *pp);void *priv;
} play_preprocessor_t;

开发者也可以实现特定预处理器的这些接口,并且在获取音频特征时通过throw_info接口抛出此信息,通过throw_data接口抛出原始音频数据。

另外解码解包和播放模块也可以实现类似的接口设计,这样整个播放器就可以支持插件配置,完成各种各样的播放请求。

关于如何优化消息传递方式,由于涉及到公司具体实现方案,不方便详细描述,但是我们可以往状态机的方向上思考思考,相信你肯定会有一个不错的解决方案。

至此一个简单播放器框架就设计完成了。

嵌入式平台音频播放器设计(基础篇)相关推荐

  1. 嵌入式平台音频播放器设计(数据缓冲)

    一.目的 在之前的博文中我们分析过播放器整体的软件框架,本文在其基础上继续探讨数据缓冲机制. 二.设计 在播放设计中,我们需要考虑两类数据的调度管理,一类是事件类的管理,一类是音频数据的管理. 例如在 ...

  2. 嵌入式linux音频播放器设计,基于嵌入式Linux下Madplay音频播放器设计论文.docx

    基于嵌入式Linux下Madplay音频播放器设计论文 滁州职业技术学院计算机应用技术专业毕业论文PAGE I 滁州职业技术学院信息工程系--2015届计算机应用专业毕业论文 姓 名: 周杰 班 级: ...

  3. 毕业设计 嵌入式 MP3音乐播放器设计与实现

    文章目录 1 简介 2 绪论 2.1 课题背景与目的 3 系统设计 3.1 系统架构 3.2 软件部分设计 3.3 实现效果 3.4 部分相关代码 4 最后 1 简介 Hi,大家好,学长今天向大家介绍 ...

  4. 基于android平台多媒体播放器的设计与实现,基于Android的多媒体音乐播放器设计论文...

    中图分类号:TP317 文献标识码:A 文章编号:1009-3044(2016)03-0240-02 随着计算机网络与手机的迅速发展,各种音乐资源成为人们生活中必不可少的一部分,音乐播放软件成了手机必 ...

  5. linux 音频播放器源码,Linux的音频播放器的设计源代码.doc

    Linux的音频播放器的设计源代码 嵌入式操作系统 课程设计 源代码 设计题目: 基于Linux的音频播放器的设计 院 系: ********* 班 级: ******** 组 别: 第1组 学 号: ...

  6. linux 音频播放器源码,基于Linux的音频播放器的设计 源代码.doc

    嵌入式操作系统 课程设计 源代码 设计题目: 基于Linux的音频播放器的设计 院 系: ********* 班 级: ******** 组 别: 第1组 学 号: ****** 姓 名: 起止日期: ...

  7. Windows平台RTSP播放器/RTMP播放器设计需要考虑的几个点

    我们在实现Windows平台RTSP播放器或RTMP播放器的时候,需要考虑的点很多,比如多实例设计.多绘制模式兼容.软硬解码支持.快照.RTSP下TCP-UDP自动切换等,以下就其中几个方面,做个大概 ...

  8. web音频播放器_Web设计:如何创建一个时尚的Web音频播放器

    我仍然记得在2000年代初,在线播放富媒体(音频和视频)时遇到了很多限制. 很容易就将开始视为理所当然,尤其是自从今天以来,我们有很多商店可以播放音频,例如last.fm或播放视频,例如Youtube ...

  9. android 音乐播放器mv播放功能,Android 音视频学习基础Android最简单的音频播放器| 神农笔记...

    /* *最简单的基于FFmpeg的音频播放器 *Simplest FFmpeg Audio Player *本程序实现了音频的解码和播放. * */ #include #include extern ...

最新文章

  1. arguments don‘t support automatic differentiation, but one of the arguments
  2. 上交大计算机导师俞凯,WLA青科聊高考①|偶像剧“男主”、上海交大教授俞凯的学霸人生...
  3. oracle数据库计数器,DM 达梦数据库 表的 行计数器(COUNTER)属性
  4. python综合管理系统_学生综合信息管理系统
  5. RHEL5 RHEL6 差异 1
  6. 机器学习06神经网络--学习
  7. 二、项目运行环境【PMP 】
  8. Stanford NLP 第六课: Long Short Term Memory
  9. JMX监测JVM报错
  10. netron神经网络可视化
  11. 面向对象之封装的成本价值
  12. Android Baseline小tip
  13. slackware简介
  14. m_map投影_MATLAB——m_map指南(1)
  15. 常用图像处理相关图像数据库
  16. 中国各个朝代的历史地图
  17. convexHull实现
  18. imp的用法及注意事项
  19. 微信:item_search_seller - 搜索公众号列表
  20. 谭民机器人_机器人技术研究进展_谭民

热门文章

  1. python今日头条新闻爬虫_头条爬虫最新资讯
  2. Three.js实战项目 商场漫游
  3. excel填充空格技巧
  4. C/C++参考选题[2023-02-23]
  5. JavaWeb12_JQuery_广告的自动显示与隐藏
  6. 如何给销售团队分配客户资源,CRM软件让资源最大化利用
  7. 千锋教育python2104期总结day6
  8. 自动化测试环境搭建python+selenium
  9. 时空序列预测:SimVP: Simpler yet Better Video Prediction解读
  10. 【Python】python面向对象编程