当前位置: 首页 > news >正文

QT-播放原始PCM音频流

QT +=  multimedia

audioplay.h

/*************************************************************************
接口描述:原始音频播放类
拟制:
接口版本:V1.0
时间:20220922
说明:
*************************************************************************/#ifndef AUDIOPLAY_H
#define AUDIOPLAY_H#include <QAudioFormat>
#include <QAudioOutput>
#include <QMutex>
#include <QThread>class AudioThread;
class AudioPlay : public QObject
{Q_OBJECT
public:explicit AudioPlay(QObject *parent = nullptr);~AudioPlay();public:void inputVoice(char *pcVoice, int nLen);   //PCM数据输入void setSampleRate(int nSampleRate);        //设置采样率void stop();                                //停止播放signals:void sendDataSignal(QByteArray qbaData);void inputVoiceSignal(QByteArray qbaData);void setSampleRateSignal(int nSampleRate);void stopAudio();private slots:void audioStateChanged(QAudio::State state);private:QAudioFormat m_audioFormat;int m_nSampleRate;bool m_bAudioOpen;QAudioOutput *m_pAudioOutput;AudioThread *m_pAudioThread;QThread *m_pThread;private:void audioPlay();void setFormat();void releaseAudio();
};class AudioDevice : public QIODevice
{Q_OBJECT
public:explicit AudioDevice(QObject *parent = nullptr);public:void inputData(char *pcData, int nLen);void start();void stop();// QIODevice interface
protected:qint64 readData(char *data, qint64 maxlen);qint64 writeData(const char *data, qint64 len);qint64 bytesAvailable() const;private:QByteArray m_qbaAudioBuffer;
};class AudioThread : public QObject
{Q_OBJECT
public:explicit AudioThread(QAudioOutput *pAudioOutput, QObject *parent = nullptr);~AudioThread();public slots:void inputData(QByteArray qbaData);private:QAudioOutput *m_pAudioOutput;AudioDevice *m_pAudioDevice;
};#endif // AUDIOPLAY_H

audioplay.cpp

#include "audioplay.h"
#include <QDebug>static QMutex m_mutex;AudioPlay::AudioPlay(QObject *parent): QObject(parent)
{m_nSampleRate = 8000;m_bAudioOpen = false;m_pAudioOutput = nullptr;m_pAudioThread = nullptr;setFormat();m_pThread = new QThread;m_pThread->start();connect(this,&AudioPlay::inputVoiceSignal,this,[&](QByteArray qbaData) {if (!m_bAudioOpen) {audioPlay();}emit sendDataSignal(qbaData);},Qt::QueuedConnection);connect(this,&AudioPlay::setSampleRateSignal,this,[&](int nSampleRate) {if (m_nSampleRate != nSampleRate) {m_nSampleRate = nSampleRate;setFormat();}},Qt::QueuedConnection);connect(this, &AudioPlay::stopAudio, this, [&] {m_bAudioOpen = false;releaseAudio();});
}AudioPlay::~AudioPlay()
{releaseAudio();m_pThread->exit();if (m_pThread != nullptr) {m_pThread->deleteLater();m_pThread = nullptr;}
}void AudioPlay::inputVoice(char *pcVoice, int nLen)
{emit inputVoiceSignal(QByteArray(pcVoice, nLen));
}void AudioPlay::setSampleRate(int nSampleRate)
{emit setSampleRateSignal(nSampleRate);
}void AudioPlay::stop()
{emit stopAudio();
}void AudioPlay::audioStateChanged(QAudio::State state)
{switch (state) {case QAudio::IdleState:m_bAudioOpen = false;releaseAudio();setFormat();break;default:break;}
}void AudioPlay::audioPlay()
{QList<QAudioDeviceInfo> outputDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioOutput);if (outputDevices.size() <= 0) {return;}if (m_pAudioOutput == nullptr) {m_pAudioOutput = new QAudioOutput(m_audioFormat);connect(m_pAudioOutput, &QAudioOutput::stateChanged, this, &AudioPlay::audioStateChanged);if (m_pAudioThread) {m_pAudioThread->deleteLater();m_pAudioThread = nullptr;}m_pAudioThread = new AudioThread(m_pAudioOutput);m_pAudioThread->moveToThread(m_pThread);connect(this,&AudioPlay::sendDataSignal,m_pAudioThread,&AudioThread::inputData,Qt::QueuedConnection);}m_bAudioOpen = true;
}void AudioPlay::setFormat()
{if (m_pAudioOutput != nullptr) {m_pAudioOutput->reset();m_pAudioOutput->start();}//设置采样率m_audioFormat.setSampleRate(m_nSampleRate);//设置通道数m_audioFormat.setChannelCount(1);//设置采样大小,一般为8位或16位m_audioFormat.setSampleSize(16);//设置编码方式m_audioFormat.setCodec("audio/pcm");//设置字节序m_audioFormat.setByteOrder(QAudioFormat::LittleEndian);//设置样本数据类型m_audioFormat.setSampleType(QAudioFormat::SignedInt);
}void AudioPlay::releaseAudio()
{if (m_pAudioThread != nullptr) {m_pAudioThread->deleteLater();m_pAudioThread = nullptr;}if (m_pAudioOutput != nullptr) {m_pAudioOutput->stop();m_pAudioOutput->deleteLater();m_pAudioOutput = nullptr;}
}AudioDevice::AudioDevice(QObject *parent): QIODevice(parent)
{QMutexLocker locker(&m_mutex);m_qbaAudioBuffer.clear();
}void AudioDevice::inputData(char *pcData, int nLen)
{QMutexLocker locker(&m_mutex);m_qbaAudioBuffer.append(pcData, nLen);
}void AudioDevice::start()
{if (!this->isOpen()) {open(QIODevice::ReadOnly);}
}void AudioDevice::stop()
{QMutexLocker locker(&m_mutex);m_qbaAudioBuffer.clear();this->close();
}qint64 AudioDevice::bytesAvailable() const
{QMutexLocker locker(&m_mutex);qint64 llReturn = m_qbaAudioBuffer.size() + QIODevice::bytesAvailable();return llReturn;
}qint64 AudioDevice::readData(char *data, qint64 maxlen)
{QMutexLocker locker(&m_mutex);memset(data, 0, maxlen);if (m_qbaAudioBuffer.size() < maxlen) {maxlen = m_qbaAudioBuffer.size();}if (maxlen > 0) {memcpy(data, m_qbaAudioBuffer.left(maxlen).data(), maxlen);m_qbaAudioBuffer.remove(0, maxlen);}return maxlen;
}qint64 AudioDevice::writeData(const char *data, qint64 len)
{Q_UNUSED(data);Q_UNUSED(len);return 0;
}AudioThread::AudioThread(QAudioOutput *pAudioOutput, QObject *parent): QObject(parent)
{m_pAudioOutput = nullptr;m_pAudioDevice = nullptr;m_pAudioDevice = new AudioDevice(this);m_pAudioDevice->start();m_pAudioOutput = pAudioOutput;m_pAudioOutput->start(m_pAudioDevice);
}AudioThread::~AudioThread()
{if (m_pAudioDevice != nullptr) {m_pAudioDevice->stop();m_pAudioDevice->deleteLater();m_pAudioDevice = nullptr;}
}void AudioThread::inputData(QByteArray qbaData)
{if (m_pAudioDevice != nullptr) {m_pAudioDevice->inputData(qbaData.data(), qbaData.size());}
}

相关文章:

QT-播放原始PCM音频流

QT multimedia audioplay.h /************************************************************************* 接口描述&#xff1a;原始音频播放类 拟制&#xff1a; 接口版本&#xff1a;V1.0 时间&#xff1a;20220922 说明&#xff1a; ********************************…...

【杂谈】聊聊我是如何从Java转入Web3的

我先说说我基本的一个情况吧&#xff1a; 我是之前是一位从业了传统web2行业三年的Java开发&#xff0c;在2018年尾才开始去关注区块链的&#xff0c;之前虽然也有混迹在币圈&#xff0c;但是没怎么关注到币圈的内在运行逻辑。 后面因为当时元宇宙和Web3的概念特别火&a…...

ArrayList

目录 1.ArrayList简介 2.ArrayList的构造 2.1ArrayList() 2.2ArrayList(Collection c) 2.3ArrayList(int initialCapacity) 3.ArrayList常见操作 4.ArrayList的遍历的遍历 1.ArrayList简介 在集合框架中&#xff0c; ArrayList 是一个普通的类&#xff0c;实现了 List…...

不重启Docker能添加自签SSL证书镜像仓库吗?

应用背景 在企业应用Docker规划初期配置非安全镜像仓库时&#xff0c;有时会遗漏一些仓库没配置&#xff0c;但此时应用程序已经在Docker平台上部署起来了&#xff0c;体量越大就越不会让人去直接重启Docker。 那么&#xff0c;不重启Docker能添加自签SSL证书镜像仓库吗&…...

Ajax介绍

1.与服务器进行数据交换&#xff1a;通过 Ajax 可以给服务器发送请求&#xff0c;并获取服务器响应的数据。 2.异步交互&#xff1a;可以在 不重新加载整个页面 的情况下&#xff0c;与服务器交换数据并 更新部分网页 的技术&#xff0c;如&#xff1a; 搜索联想、用户名是否可…...

docker 学习--02 常用命令

docker 学习–02 常用命令 docker 学习-- 01 基础知识 docker 学习-- 03 环境安装&#xff08;win10&#xff09; 文章目录 docker 学习--02 常用命令1. 帮助启动类命令1.1启动docker1.2 停止docker1.3 重启docker1.4 查看docker1.5 设置开机自启1.6 查看docker概要信息1.7 查…...

socks5 保障网络安全与爬虫需求的完美融合

Socks5代理&#xff1a;跨足网络安全和爬虫领域的全能选手 Socks5代理作为一种通用的网络协议&#xff0c;为多种应用场景提供了强大的代理能力。它不仅支持TCP和UDP的数据传输&#xff0c;还具备更高级的安全特性&#xff0c;如用户身份验证和加密通信。在网络安全中&#xf…...

构建智能医疗未来:人工智能在线上问诊系统开发中的应用

随着人工智能技术的飞速发展&#xff0c;医疗领域也正在逐步迎来一场革命性的变革。其中&#xff0c;人工智能在在线上问诊系统开发中的应用&#xff0c;正为医疗产业带来全新的可能性。本文将深入探讨如何利用代码构建智能医疗未来&#xff0c;以提升线上问诊系统的效率、准确…...

css3-grid:grid 布局 / 基础使用

一、理解 grid 二、理解 css grid 布局 CSS Grid布局是一个二维的布局系统&#xff0c;它允许我们通过定义网格和网格中每个元素的位置和尺寸来进行页面布局。CSS Grid是一个非常强大的布局系统&#xff0c;它不仅可以用于构建网格布局&#xff0c;还可以用于定位元素&#xf…...

如何在windows电脑安装多个tomcat服务器和乱码问题

前提条件安装jdk 以17版本为例&#xff0c;将jdk8卸载干净 1.首先进入tomcat官网下载 tomcat网址 这里下载tomcat10为例子 1.1 这里选择方式一 下载解压版 2.解压后拷贝三份 分别命名为 8081、 8082、 8083 3.分别对每个tomcat执行以下操作 3.1 找到tomcat所在webapps文…...

flutter:webview_flutter的简单使用

前言 最近在研究如何在应用程序中嵌入Web视图&#xff0c;发现有两个库不错。 一个是官方维护、一个是第三方维护。因为没说特别的需求&#xff0c;就使用了官方库&#xff0c;实现一些简单功能是完全ok的 基本使用 官方文档 https://pub-web.flutter-io.cn/packages/webv…...

Ansys Zemax | 手机镜头设计 - 第 1 部分:光学设计

本文是 3 篇系列文章的一部分&#xff0c;该系列文章将讨论智能手机镜头模组设计的挑战&#xff0c;从概念、设计到制造和结构变形的分析。本文是三部分系列的第一部分&#xff0c;将专注于OpticStudio中镜头模组的设计、分析和可制造性评估。&#xff08;联系我们获取文章附件…...

jvm从入门到精通

jvm 1.jvm与java体系结构​​​​​​​...

[NLP]LLM 训练时GPU显存耗用量估计

以LLM中最常见的Adam fp16混合精度训练为例&#xff0c;分析其显存占用有以下四个部分&#xff1a; GPT-2含有1.5B个参数&#xff0c;如果用fp16格式&#xff0c;只需要1.5G*2Byte3GB显存, 但是模型状态实际上需要耗费1.5B*1624GB. 比如说有一个模型参数量是1M&#xff0c;在…...

Unity引擎使用InteriorCubeMap采样制作假室内效果

Unity引擎制作假室内效果 大家好&#xff0c;我是阿赵。   这次来介绍一种使用CubeMap做假室内效果的方式。这种技术名叫InteriorCubeMap&#xff0c;是UE引擎自带的节点效果。我这里是在Unity引擎里面的实现。 一、效果展示 这个假室内效果&#xff0c;要动态看才能看出效…...

Gin安装解决国内go 与 热加载

get 方式安装超时问题&#xff0c;国内直接用官网推荐的下面这个命令大概率是安装不成功的 go get -u github.com/gin-gonic/gin 可以在你的项目目录下执行下面几个命令&#xff1a; 比如我的项目在E:\Oproject\zl cmd E:\Oproject\zl>就在目录下执行 go env -w GO111…...

安防监控视频云存储平台EasyCVRH.265转码功能更新:新增分辨率配置

安防视频集中存储EasyCVR视频监控综合管理平台可以根据不同的场景需求&#xff0c;让平台在内网、专网、VPN、广域网、互联网等各种环境下进行音视频的采集、接入与多端分发。在视频能力上&#xff0c;视频云存储平台EasyCVR可实现视频实时直播、云端录像、视频云存储、视频存储…...

Linux 创建用户赋予root权限,并限定登录ip

1.创建jms用户 创建组 groupadd jms创建用户 -g 指定分组 useradd -m -d /home/jms jms -g jms -s /bin/bash设置用户密码 passwd jms2.赋予root权限 编辑文件 vim /etc/sudoers添加如下内容 jms ALL(ALL:ALL) NOPASSWD: ALL3.限定登录ip 编辑文件&#xff0c;在末尾添…...

基于令牌级 BERT 嵌入的趋势生成句子级嵌入

一、说明 句子&#xff08;短语或段落&#xff09;级别嵌入通常用作许多 NLP 分类问题的输入&#xff0c;例如&#xff0c;在垃圾邮件检测和问答 &#xff08;QA&#xff09; 系统中。在我上一篇文章发现不同级别的BERT嵌入的趋势中&#xff0c;我讨论了如何生成一个向量表示&a…...

计算机视觉目标检测性能指标

目录 精确率&#xff08;Precision&#xff09;和召回率&#xff08;Recall&#xff09; F1分数&#xff08;F1 Score&#xff09; IoU&#xff08;Intersection over Union&#xff09; P-R曲线&#xff08;Precision-Recall Curve&#xff09;和 AP mAP&#xff08;mean…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?

现有的 Redis 分布式锁库&#xff08;如 Redisson&#xff09;相比于开发者自己基于 Redis 命令&#xff08;如 SETNX, EXPIRE, DEL&#xff09;手动实现分布式锁&#xff0c;提供了巨大的便利性和健壮性。主要体现在以下几个方面&#xff1a; 原子性保证 (Atomicity)&#xff…...

nnUNet V2修改网络——暴力替换网络为UNet++

更换前,要用nnUNet V2跑通所用数据集,证明nnUNet V2、数据集、运行环境等没有问题 阅读nnU-Net V2 的 U-Net结构,初步了解要修改的网络,知己知彼,修改起来才能游刃有余。 U-Net存在两个局限,一是网络的最佳深度因应用场景而异,这取决于任务的难度和可用于训练的标注数…...

Ubuntu系统复制(U盘-电脑硬盘)

所需环境 电脑自带硬盘&#xff1a;1块 (1T) U盘1&#xff1a;Ubuntu系统引导盘&#xff08;用于“U盘2”复制到“电脑自带硬盘”&#xff09; U盘2&#xff1a;Ubuntu系统盘&#xff08;1T&#xff0c;用于被复制&#xff09; &#xff01;&#xff01;&#xff01;建议“电脑…...