庐山派摄像头与音频同时使用时的音频电音问题

Viewed 46

问题描述


我试图让庐山派检测物体的同时播报一些语音,使用的是最新固件,目前可以播放音频但摄像头与音频播放同时使用时出现了音频杂音的问题,我这里复用了Mediamanager可能方法不对?我也想过播放音频的时候暂停摄像头,但之后的摄像头重启就总是失败,好像说是音频播放后Mediamanager的全局状态被污染,AI抓帧通道chn2缓冲池被清空且无法重建。补充一些信息:WIN11系统,单独播放音频或单独使用摄像机不会出现问题。我目前认为的原因是PipeLine(摄像头)和PyAudio(音频播放)共享MediaManager资源时产生冲突。尝试了多种方案:1资源复用方案:尝试让AudioService复用PipeLine的MediaManager 2单流复用方案:尝试创建持久化音频流复用 3参数调优方案:调整chunk大小、音频参数等 4异步播放方案:使用线程异步播放(这个没杂音但音频一顿一顿的很慢,后边布不慢了还是有杂音),都不能解决问题。所以要怎么办啊?有没有大神指点一下,感激不尽。

复现步骤


在使用摄像头的同时播放音频

硬件板卡


庐山派

软件版本


CanMV_K230_LCKFB_micropython_v1.3-147-g46fd58c_nncase_v2.9.0

其他信息


尝试了多种方案:1资源复用方案:尝试让AudioService复用PipeLine的MediaManager 2单流复用方案:尝试创建持久化音频流复用 3参数调优方案:调整chunk大小、音频参数等 4异步播放方案:使用线程异步播放(这个没杂音但音频一顿一顿的很慢,后边布不慢了还是有杂音),都不能解决问题。

2 Answers

import os
import time
import gc
from libs.PipeLine import PipeLine
from media.pyaudio import PyAudio
import media.wave as wave

def _exists(p):
try:
os.stat(p)
return True
except:
return False

def play_audio_simple(filename):
"""简单音频播放函数"""
try:
if not _exists(filename):
print(f"音频文件不存在: {filename}")
return False

    wf = wave.open(filename, 'rb')
    CHUNK = int(wf.get_framerate()/25)  # 官方标准chunk大小
    
    print(f"播放音频: {filename}, {wf.get_framerate()}Hz, chunk={CHUNK}")

    p = PyAudio()
    p.initialize(CHUNK)
    # 复用PipeLine的MediaManager,不重新初始化

    stream = p.open(format=p.get_format_from_width(wf.get_sampwidth()),
                channels=wf.get_channels(),
                rate=wf.get_framerate(),
                output=True, 
                frames_per_buffer=CHUNK)

    stream.volume(vol=85)

    # 播放循环
    data = wf.read_frames(CHUNK)
    while data:
        stream.write(data)
        data = wf.read_frames(CHUNK)

    print("音频播放完成")
    return True

except Exception as e:
    print(f"音频播放错误: {e}")
    return False
finally:
    try:
        stream.stop_stream()
        stream.close()
        p.terminate()
        wf.close()
    except:
        pass

def main():
print("=== K230 摄像头+音频播放电音测试 ===")

# 摄像头参数
display_mode = "hdmi"
rgb888p_size = [640, 480]  # 简化分辨率

# 创建摄像头PipeLine
print("初始化摄像头系统...")
pl = PipeLine(rgb888p_size=rgb888p_size, display_mode=display_mode)
pl.create()
display_size = pl.get_display_size()
print(f"摄像头初始化完成,显示分辨率: {display_size}")

# 测试音频文件路径(请替换为实际存在的wav文件)
test_audio_files = [
    "/data/system_audio/welcome.wav",
    "/sdcard/test1.wav", 
    "/sdcard/test2.wav"
]

# 找到存在的音频文件
audio_file = None
for file_path in test_audio_files:
    if _exists(file_path):
        audio_file = file_path
        break

if not audio_file:
    print("未找到测试音频文件,请将wav文件放置到以下位置之一:")
    for path in test_audio_files:
        print(f"  - {path}")
    return

print(f"使用测试音频: {audio_file}")

# 主循环:摄像头工作 + 定时播放音频
frame_count = 0
audio_interval = 100  # 每100帧播放一次音频(约3-4秒间隔)

try:
    print("开始测试循环...")
    print("现象说明:")
    print("- 单独播放音频:音质清晰")
    print("- 单独运行摄像头:画面正常")
    print("- 摄像头+音频同时运行:出现电音杂音")
    print("按Ctrl+C停止测试\n")
    
    while True:
        # 模拟摄像头工作:获取帧数据
        try:
            img = pl.get_frame()  # 获取摄像头帧
            pl.show_image()       # 显示画面
            frame_count += 1
            
            # 定时播放音频测试
            if frame_count % audio_interval == 0:
                print(f"\n--- 第{frame_count//audio_interval}次音频播放测试 ---")
                success = play_audio_simple(audio_file)
                if success:
                    print("✓ 音频播放完成\n")
                else:
                    print("✗ 音频播放失败\n")
                
                # 短暂延迟
                time.sleep(0.5)
            
            # 垃圾回收
            if frame_count % 50 == 0:
                gc.collect()
                
        except Exception as e:
            print(f"摄像头处理错误: {e}")
            time.sleep(0.1)
            continue

except KeyboardInterrupt:
    print("\n用户停止测试")
except Exception as e:
    print(f"系统错误: {e}")
finally:
    # 清理资源
    pl.destroy()
    print("系统清理完成")

if name == "main":
main()