1、引言

aac 是很常见的音频格式,压缩率比mp3 还高,H5 支持从audio 标签文件读取aac 文件并播放,但不支持从网络流中直接读取。这里借助webassembly 技术,将aac 转码成pcm码流,再借助web audio api 实现aac音频播放。主要用到的开源库有faad、pcm-player

2、编译

进入faad 官网,http://www.linuxfromscratch.org/blfs/view/svn/multimedia/faad2.html,下载faad源码包并解压,cd 到工程目录

cd faad2-2_10_0/
mkdir dist
emconfigure ./configure --prefix=$(pwd)/dist --disable-shared --without-xmms --without-drm --without-mpeg4ip
emmake make
make install

make install 完成后会在dist 目录生成lib、include 等目录,里面存放了faad 头文件和库,复制到路径备用。

3、faad 使用

一般来说,我不会直接js 调用faad 库api,而是在外面封装一层,只暴露一些必要的接口。

 NeAACDecOpen

创建一个编码器并返回一个NeAACDecHandle类型句柄

NeAACDecHandle NeAACDecOpen(void)NeAACDecClose(NeAACDecHandle );

  NeAACDecInit2

初始化函数,小于0表示失败

NEAACDECAPI char NeAACDecInit2(NeAACDecHandle hDecoder,unsigned char *pBuffer,unsigned long SizeOfDecoderSpecificInfo,unsigned long *samplerate,unsigned char *channels);

参数

hDecoder 

NeAACDecOpen 创建的句柄

pBuffer

指向缓存空间,用于保存转换后的pcm 数据

SizeOfDecoderSpecificInfo

输入aac 音频的大小

sampleRate

音频采样率

channels 

音频通道数

NeAACDecDecode

void* NeAACDecDecode(NeAACDecHandle hpDecoder,NeAACDecFrameInfo *hInfo,unsigned char *buffer,unsigned long buffer_size)

hpDecoder 

NeAACDecOpen创建的句柄

NeAACDecFrameInfo

NeAACDecFrameInfo 指针

buffer

指向输入AAC音频的缓存区

buffer_size

输入AAC音频大小

NeAACDecClose

void NeAACDecClose(NeAACDecHandle hpDecoder)

C端完整代码

#include <memory.h>
#include <stdlib.h>
#include "faad.h"
#include <stdbool.h>
#include <string.h>
#include <emscripten.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <unistd.h>bool hasInit = false;NeAACDecHandle decoder = 0;
NeAACDecFrameInfo frame_info;void PrintArry(unsigned char *buffer, unsigned int size)
{int i;char data[1024*1024];for(i = 0;i < size;i++){data[i] = buffer[i];}data[i + 1] = '\0';
}int init_decoder(unsigned char* inBuffer, size_t size)
{  unsigned char channels;unsigned long sampleRate;memset(&frame_info, 0, sizeof(frame_info));decoder = NeAACDecOpen();NeAACDecInit(decoder, inBuffer, size, &sampleRate, &channels);//printf("init_decoder初始化完毕\n");hasInit = true;return 0;
}int feedData(unsigned char* out_data, unsigned char* buffer, unsigned int size)
{int ret = 0;if (!hasInit){init_decoder(buffer, size);}unsigned char *out_buffer = (unsigned char*)NeAACDecDecode(decoder, &frame_info, buffer, size);//printf("frame_info.error %d\n",frame_info.error);if (frame_info.error > 0){      return frame_info.error;}else if(out_buffer && frame_info.samples > 0)//解码成功{ret = frame_info.samples * frame_info.channels;for(int i = 0;i < ret;i++){out_data[i] = out_buffer[i];}}return ret;
}void destroyDecoder()
{hasInit = false;NeAACDecClose(decoder);
}

4、html 调用

再次进行编译,将C编译成 最终目标wasm

export TOTAL_MEMORY=10485760
rm *.js *.wasmexport EXPORTED_FUNCTIONS="[    \'_malloc' \,'_free' \,'_destroyDecoder' \,'_feedData'   \
]"export LIBRARY_FUNCTIONS="[\'malloc', \'free'    \
]"#
emcc aac.c  \
-O3 \
-s WASM=1 \
-I /usr/local -lfaad -lm -L ./lib  \
-s TOTAL_MEMORY=${TOTAL_MEMORY} \
-s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE="${LIBRARY_FUNCTIONS}" \
-s EXPORTED_FUNCTIONS="${EXPORTED_FUNCTIONS}" \
-o aac.js

最后html 调用

<html><head><link rel="shortcut icon" href="#"></head><script type="text/javascript" src="pcm-player.js"></script><script type="text/javascript" src="helper.js"></script><script src="https://cdn.bootcss.com/vConsole/3.2.0/vconsole.min.js"></script><body>请点击一下屏幕,才能播放声音</body><script>var decodeCount = 1;var isFinish = false;var socketURL = "ws://192.168.11.66:9101";socketURL = "ws://127.0.0.1:8080";let vConsole = new VConsole();var player = new PCMPlayer({encoding: '16bitInt',channels: 2,sampleRate: 44100,flushingTime: 22,debug:false});FaadModule = {};FaadModule.onRuntimeInitialized = function() {console.log("Wasm 加载成功!")isFinish = true;}function closeDecoder()//关闭解码器{FaadModule._destroyDecoder();}function decodeAAC(data){var retPtr = FaadModule._malloc(4 * 5 * 1024);//接收的数据var inputPtr = FaadModule._malloc(4 * data.length);//输入数据for( i =0;i < data.length;i++){FaadModule.HEAPU8[(inputPtr)+i] = data[i];//转换为堆数据}var pcmLen = FaadModule._feedData(retPtr, inputPtr, data.length);if(pcmLen >= 0){//console.log("%d帧 aac 解码成功, %d", decodeCount, pcmLen);var pcmData = new Uint8Array(pcmLen);     for(i = 0;i < pcmLen;i++){pcmData[i] = FaadModule.HEAPU8[(retPtr)+i]}player.feed(pcmData);}else{console.log("%d帧 aac 解码失败, %d", decodeCount, pcmLen);}decodeCount++;FaadModule._free(inputPtr);FaadModule._free(retPtr);}var ws = new WebSocket(socketURL);ws.binaryType = 'arraybuffer';ws.addEventListener('open', function (event) {console.log("发送配置帧");ws.send(ConfigChannel("RK3923C1201900139"));});ws.addEventListener('message',function(event) {  var input = new Uint8Array(event.data);if(input[0] == 0xff){//console.log("音频数据");if(isFinish){var time = new Date().getTime();decodeAAC(input);//console.log("音频解码耗时:%d ms", new Date().getTime() - time);}}else{//console.log("视频数据");}});</script><script type="text/javascript" src="aac.js"></script>
</html>

 注: chrome 浏览器可能需要点击以下才有声音,跟web-audio api有关 有关。

附件:web端播放aac音频

Webassembly 学习3 -- 打造web端的aac 播放器相关推荐

  1. Web端H.265播放器研发解密

    音视频编解码对于前端工程师是一个比较少涉足的领域,涉及到流媒体技术中的文本.图形.图像.音频和视频多种理论知识的学习,才能够应用到具体实践中,本团队在多媒体领域深耕两年多,才算是有一定产出,我们自研w ...

  2. Web端H.265播放器研发解密 1

    音视频编解码对于前端工程师是一个比较少涉足的领域,涉及到流媒体技术中的文本.图形.图像.音频和视频多种理论知识的学习,才能够应用到具体实践中,本团队在多媒体领域深耕两年多,才算是有一定产出,我们自研w ...

  3. 跟着源码一起学:手把手教你用WebSocket打造Web端IM聊天

    本文作者芋艿,原题"芋道 Spring Boot WebSocket 入门",本次有修订和改动. 一.引言 WebSocket如今在Web端即时通讯技术应用里使用广泛,不仅用于传统 ...

  4. 完整打造一个多功能音乐播放器项目(初步设想跟酷狗类似)

    本人目前准备利用闲暇时间打造一个完整的音乐播放器项目,主要用于学习及分享!原创不易,转载请注明出处. 这是一个什么样的音乐播放器呢?整体的架构跟酷狗差不多吧,我的方式呢,是一个个组件一个个模块先做好, ...

  5. Discuz论坛web网页mp3音频播放器源码下载

    最近在做一个DZ论坛的搭建,在前几天的时候遇到Flash+Js的幻灯片的问题,特写了一篇<JS+Flash焦点图轮播源代码(2屏,3屏,多屏)>来记录论坛搭建过程遇到的一些技术性问题,以便 ...

  6. Navidrome - 开源音乐服务器【打造属于自己的音乐播放器】「端口映射」随时随地想听就听

    转载自cpolar极点云文章:Navidrome - 开源音乐服务器[打造属于自己的音乐播放器]「端口映射」随时随地想听就听 1. 前言 不知从何时开始,我们能用的音乐软件越来越少,笔者使用小米手机很 ...

  7. 使用Vitamio打造自己的Android万能播放器(2)—— 手势控制亮度、音量、缩放

    前言 本章继续完善播放相关播放器的核心功能,为后续扩展打好基础. 声明 欢迎转载,但请保留文章原始出处:)  博客园:http://www.cnblogs.com 农民伯伯: http://over1 ...

  8. 使用Vitamio打造自己的Android万能播放器(7)——在线播放(下载视频)

    前言 本章将实现非常实用的功能--下载在线视频.涉及到多线程.线程更新UI等技术,还需思考产品的设计,如何将新加的功能更好的融入到现有的产品中,并不是简单的加一个界面就行了,欢迎大家交流产品设计和技术 ...

  9. [转载]使用Vitamio打造自己的Android万能播放器(7)——在线播放(下载视频)...

    前言 本章将实现非常实用的功能--下载在线视频.涉及到多线程.线程更新UI等技术,还需思考产品的设计,如何将新加的功能更好的融入到现有的产品中,并不是简单的加一个界面就行了,欢迎大家交流产品设计和技术 ...

最新文章

  1. 3D惯导Lidar仿真
  2. leetcode-找出数组中重复的数字
  3. JS中for循环里面的闭包问题的原因及解决办法
  4. Fully Convolutional Networks
  5. windown下linux子系统的安装和卸载
  6. java jpa注解哪个包好,Spring Data JPA 中常用注解详解
  7. 洛谷——P1181 数列分段Section I
  8. linux之在当前目录下删除不包含aa的文件
  9. jquery:字符串转json对象,json对象转字符串
  10. 请编写一个c程序确定signed,unsigned的char,short,int和long变量取值范围
  11. fodora lianjie mysql_Fedora 16 下安装MySql 服务器及linux c 连接MySql
  12. Java私人学习笔记——第2章 数据类型和运算符
  13. Modbus驱动库—libmodbus驱动库的使用
  14. 怎么把程序下载到stc15w201s_STC15W201S系列
  15. 全民热议“10万彩礼结不了婚”的背后,百合网做了什么?
  16. 音频信号处理——DTW
  17. 【python】GUI thinter窗口最大化
  18. 对于配置JAVA_HOME
  19. Linux查看配置文件过滤无用的内容
  20. cpld xilinx 定义全局时钟_FPGA/CPLD设计工具:Xilinx ISE 5.x使用详解

热门文章

  1. java.lang.ClassCastException: cn.tedu.domain.User cannot be cast to java.lang.String
  2. 平面设计师应该要知道的素材网站
  3. SQL--group by嵌套查询
  4. BZOJ2251: [2010Beijing Wc]外星联络
  5. php生成pdf水印,使用 PHP 在 PDF 文档中加水印并进行文档加密
  6. 大佬总结的电磁兼容知识,EMC整改六步走,看完感觉太简单了点
  7. 虚拟现实VS增强现实,谁更受欢迎?
  8. eagle php,Eagle个人博客系统
  9. 从高通诉苹果的临时禁令看行为保全机制
  10. AI文件怎样转为cdr格式文件(二)