惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
博客园 - 三生石上(FineUI控件)
Martin Fowler
Martin Fowler
WordPress大学
WordPress大学
D
Docker
S
SegmentFault 最新的问题
博客园 - 聂微东
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Last Week in AI
Last Week in AI
M
MIT News - Artificial intelligence
F
Fortinet All Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The GitHub Blog
The GitHub Blog
GbyAI
GbyAI
L
LangChain Blog
Vercel News
Vercel News
博客园 - 叶小钗
MongoDB | Blog
MongoDB | Blog
Stack Overflow Blog
Stack Overflow Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Cloudflare Blog
Engineering at Meta
Engineering at Meta
T
Threat Research - Cisco Blogs
T
Threatpost
Scott Helme
Scott Helme
T
Tailwind CSS Blog
Latest news
Latest news
Stack Overflow Blog
Stack Overflow Blog
Blog — PlanetScale
Blog — PlanetScale
The Register - Security
The Register - Security
罗磊的独立博客
P
Proofpoint News Feed
腾讯CDC
S
Schneier on Security
雷峰网
雷峰网
A
About on SuperTechFans
T
Tenable Blog
F
Full Disclosure
Cyberwarzone
Cyberwarzone
博客园_首页
有赞技术团队
有赞技术团队
K
Kaspersky official blog

文章列表

游戏玩后感:ReLief:献给亲爱的你 我的周边(谷子)分享 游戏玩后感:Kanon 简谱:致真实的你 《Rust中常见的有关生命周期的误解》学习笔记 简谱:StarMap 简谱:かく咲きたらばいと恋ひめやも 简谱:东风 简谱:无法诉说的思念 简谱:Girlish 游戏玩后感:时钟机关的Layline 简谱:风之琶音 简谱:星空的记忆 简谱:因为遇见了你 简谱:月童 番茄简谱脚本转调器 游戏玩后感:青空下的约定:Refine 游戏玩后感:在这苍穹展翅 书籍读后感:控制论与科学方法论 游戏玩后感:恋爱表达式 游戏玩后感:樱之诗 MLIR-tutorial学习笔记 游戏玩后感:潜伏之赤途 游戏玩后感:纯爱咖啡厅:帕露菲重制版 游戏玩后感:智以泪聚 游戏玩后感:初雪樱 游戏玩后感:告别回忆:从今以后 游戏玩后感:梦灯花 游戏玩后感:金辉恋曲四重奏 游戏玩后感:五彩斑斓的世界 昇腾310P使用记录 游戏玩后感:AIR 游戏玩后感:弹丸论破 游戏玩后感:流景之海的艾佩莉亚 Xilinx_HLS上板过程记录 游戏玩后感:告别回忆2 游戏玩后感:恋爱绮谭 Faiss和Rapidsai_Raft使用记录 游戏玩后感:近月少女的礼仪 游戏玩后感:樱色之云,绯色之恋 游戏玩后感:幸运草的约定 游戏玩后感:星之梦、候鸟和丸子与银河龙 游戏玩后感:白色相簿2 Windows上使用VTune分析PyTorchExtension调用的Cpp程序 SpinalHDL上板过程记录 游戏玩后感:仰望夜空的星辰 最简单的算卦方法之一:梅花易数法 游戏玩后感:苍之彼方的四重奏 krkr引擎解包工具介绍 自定义CUDA实现PyTorch算子的四种简单方法 游戏玩后感:星空的记忆 游戏玩后感:9nine 游戏玩后感:AtriMyDearMoments 游戏玩后感:极限脱出 游戏玩后感:魔女的夜宴 SSH实现多跳代理 动漫观后感:向山进发 flv重封装H264、AAC流 动漫观后感:夏日重现 CSP模板 游戏玩后感:海沙风云 动漫观后感:灵能百分百 游戏玩后感:交响乐之雨 游戏玩后感:爱上火车LastRun 游戏玩后感:LittleBustersEX 游戏玩后感:SummerPockets 游戏玩后感:逆转裁判 Ultra96V2开发板简单使用 SpinalWorkshop实验笔记(三) SpinalWorkshop实验笔记(二) SpinalWorkshop实验笔记(一) TestOS移植K210开发板 rCore-Tutorial-Book-v3学习笔记(七) 动漫观后感:凉宫春日的忧郁 rCore-Tutorial-Book-v3学习笔记(♭七) 动漫观后感:吹响吧上低音号 使用OpenCV对图片进行特征点检测和匹配 git基本操作
PYNQ开发板上使用USB声卡+OSS兼容层播放音频
VnYzm · 2021-10-22 · via

PYNQ开发板上使用USB声卡+OSS兼容层播放音频需要经过联网装库,编译驱动模块,运行三个步骤。

联网装库

首先需要将PYNQ开发板连上网,才能安装所需的库。方法是在电脑上设置共享网络,但要注意大部分操作系统在共享网络的时候无法自己指定本机IP,所以需要修改PYNQ开发板的IP来适应电脑自动设置的IP。设置共享网络的方法网上教程有很多,这里不再赘述。

设置完共享网络后,注意不要关闭开发板,因为电脑的IP已经改了,如果重启开发板网关不对SSH就连不上了。这时需要查看电脑的ip(注意是有线局域网下的ip),Windows下使用ipconfig,Linux下使用ifconfig。如我的Ubuntu在有线局域网下的ip是10.42.0.1,由于网关是255.255.255.0,所以PYNQ开发板的IP必须设置为10.42.0.*。在我的环境下,设置IP的方法是编辑/etc/network/interfaces.d/eth0,然后将其中的address这一行的IP地址修改为10.42.0.2。

然后禁用再启用一下电脑的有线网功能并重启开发板,尝试能否连进去,连进去以后再尝试ping外网,都可以才算成功。接下来就可以装库了,执行:

sudo apt update
sudo apt install alsa-base alsa-utils alsa-oss bc

编译驱动模块

下载内核源代码,我PYNQ上的Linux内核版本为5.4.0,可以在xilinx的linux内核仓库下载,其他版本的内核源码也可以在该仓库的其他分支下载。

下载并传到开发板上后,执行:

unzip linux-xlnx-xlnx_rebase_v5.4_2020.1.zip

解压结束后进入该文件夹,然后需要将当前系统的内核配置文件复制过来,执行:

sudo cp /lib/modules/$(uname -r)/build/.config .

配置需要编译的驱动模块,执行:

make menuconfig

进入Device Drivers -> Sound card support -> Advanced Linux Sound Architecture -> USB sound devices,光标移至USB Audio/MIDI driver,按M键选择编译此模块,保存然后一直按Esc键退出。执行以下命令:

make prepare
make -C . M=sound

编译驱动模块,生成扩展名为ko的模块文件,将它们复制到内核文件夹中:

sudo mkdir -p /lib/modules/$(uname -r)/kernel/sound/core
sudo mkdir -p /lib/modules/$(uname -r)/kernel/sound/usb
sudo cp sound/core/*.ko /lib/modules/$(uname -r)/kernel/sound/core
sudo cp sound/usb/*.ko /lib/modules/$(uname -r)/kernel/sound/usb

然后安装这些模块:

sudo depmod

之后插上USB声卡,驱动模块应该会自动加载,可以用命令lsmod查看模块是否被成功加载,在我的系统上被加载的有以下4个模块:

Module                  Size  Used by
snd_usb_audio         167936  0
snd_hwdep              16384  1 snd_usb_audio
snd_usbmidi_lib        24576  1 snd_usb_audio
snd_rawmidi            24576  1 snd_usbmidi_lib

如果没有自动加载,可以手动加载:

sudo modprobe snd-usb-audio

此时可以查看声卡是否已被识别:

sudo aplay -l

如果输出中出现card 1,则需要配置一下声卡编号,因为alsa音频库默认使用的声卡是0号声卡,而USB声卡被分配的编号是1,所以需要修改alsa的配置文件,路径为/usr/share/alsa/alsa.conf,在里面找到defaults.pcm.card 0这一行,把0改成1。

这时候应该可以播放音乐了:

sudo aplay test.wav

运行

目前我们使用的音频驱动库一般是alsa,oss驱动库已经被淘汰了。但是相比于alsa,oss可能编程更简单一点,因为可以直接以传统文件读写的方式播放音乐;而且有很多老程序使用的是oss。为此,alsa提供了对oss的兼容,主要有两种方式,一种是加载驱动模块snd-pcm-oss,这种方式可以从内核层面将对oss的操作转发成对alsa的操作,使用范围广;另一种是安装alsa-oss库,然后在运行使用oss的程序时使用LD_PRELOAD把对oss的文件操作替换成这个库里对alsa的操作,只能替换固定的几个文件操作(像openat就不能替换),但是原理简单,不用编译驱动模块。

目前我不知道为什么编译出来的snd-pcm-oss模块用不了,运行时总是说找不到函数符号,但是它的依赖模块能编译出来的我都已经编译并加载了,不知道是不是链接有什么问题。所以只能用alsa-oss库,这里给出示例程序:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/soundcard.h>
int main() {    
    // 打开设备文件
    int fd = open("/dev/dsp", O_RDWR);
    if (fd < 0) {
        perror("open error\n"); return 1;
    }

    // test.wav为16位,双声道,采样率为20000的波形文件
    int bit = 16, rate = 20000, channel = 2;

    ioctl(fd, SOUND_PCM_WRITE_BITS, &bit);
    ioctl(fd, SOUND_PCM_WRITE_RATE, &rate);
    ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &channel);

    /*打开音乐文件*/
    int fp = open("test.wav", O_RDONLY);
    if(fp < 0){
        perror("open fp error!\n"); return 1;
    }

    /*求文件的大小*/
    //这里直接给出了,要计算可以用fstat函数或fseek+ftell函数
    int len = 800180;

    char *buf = (char *)malloc(len);
    memset(buf, 0, len);

    // 读文件到buf中
    int rd = read(fp, buf, len);
    if(rd < 0){
        perror("read wav error!\n"); return 1;
    }
    close(fp);

    // 把buf写到设备文件中
    int wr = write(fd, buf, len);
    if(wr < 0){
        perror("write dsp error!\n"); return 1;
    }

    free(buf); buf = NULL;
    return 0;
}

可以看到这里打开声卡直接用文件/dev/dsp,这个文件在使用alsa音频驱动库时是不存在的,alsa-oss需要你加载libaoss.so这个动态库并用库里的open函数替换掉这个open操作,而它自己的open函数里会进行检查,如果尝试打开oss的声卡文件,就会执行alsa的操作,否则按原来的文件打开方式,其他文件操作函数也是一样。所以假设上面的测试文件编译出来的程序为audio,则运行时执行:

sudo LD_PRELOAD=libaoss.so ./audio