跳转至

音频录制与播放

OriginMan 扩展版中自带了一个扬声器与一个音频处理芯片,装配的位置置于OriginMan的后背。

相关示例放置在:/userdata/dev_ws/src/originman/originman_pydemo/audio

image-20220920222359026

驱动安装

在正式使用该音频相关设备时,需要让OriginMan主控识别音频设备,并从相关硬件接口中读取音频数据。

需要使用以下指令驱动音频设备:

insmod snd-soc-max98357a.ko 
insmod snd-soc-hobot-sound-machine.ko
Hint

OriginMan的镜像中,已经在开机自启动配置文件中设置好了如上指令,无须再次配置。

音频录制

完成驱动安装后,不妨尝试录制一段音频,执行以下指令:

arecord -Dhw:1,0 -c 2 -r 48000 -f S32_LE -t wav -d 10 test.wav

这条指令的作用是使用编号为 1 的声卡上的第 0 个子设备,以双声道、48000 Hz 的采样率、32 位有符号整数小端字节序的采样格式录制 10 秒的音频,并将录制结果保存为名为 test.wav 的 WAV 格式文件。

image-20220920222359026

如上图所示,录制结束后便会生成一个test.wav的音频文件。

Hint

当前音频处理器只支持上述格式的音频数据,不能更改通道和采样率。录制时间可以根据实际情况进行处理,10s内也可以通过Ctrl+C停止录制,也会保留音频文件。

音频播放

音频播放可以通过如下指令进行播放:

aplay -D hw:1,0 test.wav

aplay是系统内置的一个音频播放指令,hw:1,0如音频录制代表使用编号为 1 的声卡上的第 0 个子设备。

按下回车键后即可听到OriginMan正在播放刚刚的音频啦!

连续录制与播放

接下来让我们执行以下指令,进行连续录制与播放:

python3 /userdata/dev_ws/src/originman/originman_pydemo/audio/test_audio.py

# cd /userdata/dev_ws/src/originman/originman_pydemo/audio
# python3 test_audio.py

image-20220920222359026

这个python文件内容如下:

#!/usr/bin/env python3
import time
import subprocess
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from ros_robot_controller_sdk import Board
import logging

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class VoiceControlNode:
    def __init__(self):
        # 初始化Board
        self.board = Board()
        self.board.enable_reception()

        # 音频设备参数
        self.audio_device = "plughw:1,0"

    def play_audio(self, file_path):
        """播放音频文件"""
        try:
            cmd = ["aplay", "-D", self.audio_device, file_path]
            result = subprocess.run(cmd, check=True, capture_output=True, text=True)
            logging.info(f"Played {file_path}")
        except subprocess.CalledProcessError as e:
            logging.error(f"Error playing {file_path}: {e.stderr.strip()}")

    def record_audio(self, file_path, duration=2):
        """录制音频,默认为2秒"""
        try:
            cmd = [
                "arecord",
                "-D", self.audio_device,
                "-c", "2",
                "-r", "48000",
                "-f", "S32_LE",
                "-t", "wav",
                "-d", str(duration),
                file_path
            ]
            result = subprocess.run(cmd, check=True, capture_output=True, text=True)
            logging.info(f"Recorded {file_path}")
        except subprocess.CalledProcessError as e:
            logging.error(f"Error recording {file_path}: {e.stderr.strip()}")

    def run(self):
        """主循环,直接播放提示音、录制2秒并回放"""
        while True:
            self.play_audio("prompt.wav")  # 播放提示音
            self.record_audio("test.wav", duration=2)  # 录制2秒
            self.play_audio("test.wav")  # 回放录制的音频
            time.sleep(0.5)  # 短暂休眠,避免过于频繁循环

def main():
    # 输出代码使用说明
    logging.info("代码使用说明:")
    logging.info("1. 确保你的系统中已经安装了 `aplay` 和 `arecord` 工具,用于音频播放和录制。")
    logging.info("2. 确保 `prompt.wav` 文件存在于当前工作目录中,该文件将作为提示音播放。")
    logging.info("3. 运行此脚本后,程序将进入一个无限循环,每次循环会执行以下操作:")
    logging.info("   - 播放 `prompt.wav` 提示音。")
    logging.info("   - 录制2秒音频并保存为 `test.wav` 文件。")
    logging.info("   - 回放刚刚录制的 `test.wav` 文件。")
    logging.info("   - 短暂休眠0.5秒后,开始下一次循环。")
    logging.info("4. 若要停止程序,可在终端中按下 `Ctrl + C`。")

    node = VoiceControlNode()
    try:
        node.run()
    except KeyboardInterrupt:
        logging.info("Shutting down voice control")

if __name__ == "__main__":
    main()

其主要动作为,播放一个预制音频——"我在!",然后开始录音,录音结束后开始播放录音,使用到的函数都是基于aplay和arecord进行。

图片1