Flask 将 pyaudio 发送到浏览器

2023-12-30

我正在将服务器麦克风的音频发送到浏览器(主要是this https://stackoverflow.com/a/56037682/4871482发布但有一些修改的选项)。

一切都工作正常,直到你转到手机或野生动物园,它根本不起作用。我尝试过使用类似的东西howler https://howlerjs.com/处理前端但没有成功(仍然可以在 Chrome 和计算机上使用,但不能在手机 Safari/Chrome/等上使用)。<audio> ... </audio>在 Chrome 中运行良好,但仅在计算机上运行。

function play_audio() {
  var sound = new Howl({
    src: ['audio_feed'],
    format: ['wav'],
    html5: true,
    autoplay: true
  });
  sound.play();
}

如何发送可在任何浏览器中运行的“实时”wav 生成的音频源?

编辑230203:

我已将错误范围缩小到标题(至少我认为是导致错误的原因)。

应该使用什么标头才能使声音在所有浏览器中可用?

就拿这个简单的app.py例如:

from flask import Flask, Response, render_template
import pyaudio
import time

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html', headers={'Content-Type': 'text/html'})

def generate_wav_header(sampleRate, bitsPerSample, channels):
    datasize = 2000*10**6
    o = bytes("RIFF",'ascii')
    o += (datasize + 36).to_bytes(4,'little')
    o += bytes("WAVE",'ascii')
    o += bytes("fmt ",'ascii')
    o += (16).to_bytes(4,'little')
    o += (1).to_bytes(2,'little')
    o += (channels).to_bytes(2,'little')
    o += (sampleRate).to_bytes(4,'little')
    o += (sampleRate * channels * bitsPerSample // 8).to_bytes(4,'little')
    o += (channels * bitsPerSample // 8).to_bytes(2,'little')
    o += (bitsPerSample).to_bytes(2,'little')
    o += bytes("data",'ascii')
    o += (datasize).to_bytes(4,'little')
    return o

def get_sound(InputAudio):

    FORMAT = pyaudio.paInt16
    CHANNELS = 2
    CHUNK = 1024
    SAMPLE_RATE = 44100
    BITS_PER_SAMPLE = 16

    wav_header = generate_wav_header(SAMPLE_RATE, BITS_PER_SAMPLE, CHANNELS)

    stream = InputAudio.open(
        format=FORMAT,
        channels=CHANNELS,
        rate=SAMPLE_RATE,
        input=True,
        input_device_index=1,
        frames_per_buffer=CHUNK
    )

    first_run = True
    while True:
       if first_run:
           data = wav_header + stream.read(CHUNK)
           first_run = False
       else:
           data = stream.read(CHUNK)
       yield(data)


@app.route('/audio_feed')
def audio_feed():

    return Response(
        get_sound(pyaudio.PyAudio()),
        content_type = 'audio/wav',
    )

if __name__ == '__main__':
    app.run(debug=True)

index.html 看起来像这样:

<html>
  <head>
    <title>Test audio</title>
  </head>
  <body>
    <button onclick="play_audio()">
      Play audio
    </button>
    <div id="audio-feed"></div>
  </body>
<script>

  function play_audio() {
    var audio_div = document.getElementById('audio-feed');
    const audio_url = "{{ url_for('audio_feed') }}"
    audio_div.innerHTML = "<audio controls><source src="+audio_url+" type='audio/x-wav;codec=pcm'></audio>";
  }

</script>
</html>

启动 Flask 开发服务器python app.py并用chrome进行测试,如果你有麦克风,你会听到输入声音(最好是耳机,否则你会得到声音循环)。火狐浏览器也运行得很好。

但如果您在 iPhone 上的任何浏览器上尝试使用相同的应用程序,您将听不到声音,MacOS 上的 safari 也是如此。

没有错误,您可以看到音频的字节流正在 safari 中下载,但仍然没有声音。

是什么原因造成的?我认为我应该在 audio_feed 响应中使用某种标头,但经过数小时的调试,我似乎找不到任何相关内容。

编辑230309:

@Markus 指出要遵循RFC7233 HTTP Range Request。大概就是这样。虽然 Firefox、Chrome 以及可能更多的桌面浏览器会发送byte=0-作为标头请求,iOS 上使用的 safari 和浏览器发送byte=0-1作为标头请求。


已编辑 2023-03-12

事实证明,将音频直播流转换为mp3就足够了。为此,您可以使用ffmpeg https://ffmpeg.org/。可执行文件必须在服务器进程的执行路径中可用。以下是使用 Windows 笔记本电脑作为服务器、iPad 上的 Safari 作为客户端进行测试的工作草案:

from subprocess import Popen, PIPE
from threading import Thread
from flask import Flask, Response, render_template
import pyaudio

FORMAT = pyaudio.paFloat32
CHANNELS = 1
CHUNK_SIZE = 4096
SAMPLE_RATE = 44100
BITS_PER_SAMPLE = 16

app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html', headers={'Content-Type': 'text/html'})


def read_audio(inp, audio):
    while True:
        inp.write(audio.read(num_frames=CHUNK_SIZE))


def response():
    a = pyaudio.PyAudio().open(
        format=FORMAT,
        channels=CHANNELS,
        rate=SAMPLE_RATE,
        input=True,
        input_device_index=1,
        frames_per_buffer=CHUNK_SIZE
    )

    c = f'ffmpeg -f f32le -acodec pcm_f32le -ar {SAMPLE_RATE} -ac {CHANNELS} -i pipe: -f mp3 pipe:'
    p = Popen(c.split(), stdin=PIPE, stdout=PIPE)
    Thread(target=read_audio, args=(p.stdin, a), daemon=True).start()

    while True:
        yield p.stdout.readline()


@app.route('/audio_feed', methods=['GET'])
def audio_feed():
    return Response(
        response(),
        headers={
            # NOTE: Ensure stream is not cached.
            'Cache-Control': 'no-cache, no-store, must-revalidate',
            'Pragma': 'no-cache',
            'Expires': '0',
        },
        mimetype='audio/mpeg')


if __name__ == "__main__":
    app.run(host='0.0.0.0')

In index.html将类型更改为audio/mp3:

<!DOCTYPE html>
<html>
  <head>
    <title>Test audio</title>
  </head>
  <body>
    <button onclick="play_audio()">
      Play audio
    </button>
    <div id="audio-feed"></div>
  </body>
<script>
  function play_audio() {
    var audio_div = document.getElementById('audio-feed');
    const audio_url = "{{ url_for('audio_feed') }}"
    audio_div.innerHTML = "<audio preload='all' controls><source src=" + audio_url + " type='audio/mp3'></audio>";
  }
</script>
</html>

免责声明:这只是一个基本演示。它为每次调用打开一个音频 ffmpeg 子进程audio_feed处理程序。它不会缓存多个请求的数据,不会删除未使用的线程,也不会删除未使用的数据。

Credits: 如何使用 python 将 wav 转换为 mp3? https://stackoverflow.com/questions/25469161/how-to-convert-wav-to-mp3-in-live-using-python

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flask 将 pyaudio 发送到浏览器 的相关文章

  • 使用 Pytest 的参数化添加测试功能的描述

    当其中一个测试失败时 可以在测试正在测试的内容的参数化中添加描述 快速了解测试失败的原因 有时您不知道测试失败的原因 您必须查看代码 通过每个测试的描述 您就可以知道 例如 pytest mark parametrize num1 num2
  • 是否有一个包可以维护所有带有符号的货币列表?

    是否有一个 python 包提供所有 或相当完整 货币的列表与符号 如美元的 有优秀的pycountry 贪财的 https github com limist py moneyed and ccy http code google com
  • 仅在 Chrome 上我收到此错误:Uncaught TypeError: Illegal constructor [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 当我在 Chrome 上加载 jQuery 时 我会收到此错误 Uncaught TypeError Illegal constr
  • 如何将 sql 数据输出到 QCalendarWidget

    我希望能够在日历小部件上突出显示 SQL 数据库中的一天 就像启动程序时突出显示当前日期一样 在我的示例中 它是红色突出显示 我想要发生的是 当用户按下突出显示的日期时 数据库中日期旁边的文本将显示在日历下方的标签上 这是我使用 QT De
  • 如何使用 opencv python 计算乐高积木上的孔数?

    我正在开发我的 python 项目 我需要计算每个乐高积木组件中有多少个孔 我将从输入 json 文件中获取有关需要计算哪个程序集的信息 如下所示 img 001 red 0 blue 2 white 1 grey 1 yellow 1 r
  • 如何在 Python 中的函数入口、内部和退出处进行日志记录

    我希望能够使用 Python 日志记录工具在我的代码中进行简单且一致的日志记录 我能够执行以下操作 我希望所有现有 未来的模块和函数都有 输入 和 完成 日志消息 我不想添加相同的代码片段来定义日志记录参数 如下所示don t want t
  • 哪些 HTML 元素不能包含子节点?

    我一直在寻找一份详尽的清单 但在任何地方都找不到 为了避免必须仔细阅读规范 有谁知道它们是什么 我认为可以包含子元素的补充元素列表也很有用 XHTML 1 和 HTML5 之间的列表有何不同 您可以在以下位置找到 void 元素 不能有任何
  • 使用标签或 href 传递 Django 数据

    我有一个包含链接的表 当单击该链接进行更多操作时 我想将一些数据传递给我的函数 my html table tbody for query in queries tr td value a href internal my func que
  • Python 2 的 `exceptions` 模块在 Python3 中丢失了,它的内容到哪里去了?

    一位朋友提到 对于 Python 2 假设您在命令行上的路径环境变量中有它 pydoc exceptions 非常有用 知道它应该可以为他每周节省几分钟的网络查找时间 我自己每周都会用谷歌搜索一次例外层次结构 所以这对我来说也是一个有用的提
  • App Engine 实体到字典

    将 google app engine 实体 在 python 中 复制到字典对象的好方法是什么 我正在使用 db Expando 对象 所有属性均为扩展属性 Thanks 有一个名为foo尝试 foo dict
  • 检索 geodjango 多边形对象的边界框

    如何在 geodjango 中获取 MultiPolygon 对象的边界框 在 API 中找不到任何内容http geodjango org docs geos html http geodjango org docs geos html
  • 为正则表达式编写解析器

    即使经过多年的编程 我很羞愧地说我从未真正完全掌握正则表达式 一般来说 当问题需要正则表达式时 我通常可以 在一堆引用语法之后 想出一个合适的正则表达式 但我发现自己越来越频繁地使用这种技术 所以 自学并理解正则表达式properly 我决
  • 将字符串中的随机字符转换为大写

    我尝试随机附加文本字符串 这样就不只是有像这样的输出 gt gt gt david 我最终会得到类似的东西 gt gt gt DaViD gt gt gt dAviD 我现在的代码是这样的 import random import stri
  • Discord.py 嵌入中禁用按钮/冻结按钮

    I m trying to make a replica of this bot in which when I press any of the buttons below it shows a dropdown menu and you
  • 基于值而不是类型的单次调度

    我在 Django 上构建 SPA 并且有一个庞大的功能 其中包含许多功能if用于检查我的对象字段的状态名称的语句 像这样 if self state new do some logic if self state archive do s
  • 将时间添加到日期时间

    我有一个像这样的日期字符串 然后使用strptime 所以就像这样 my time datetime datetime strptime 07 05 15 m d Y 现在我想添加 23 小时 59 分钟my time 我努力了 timed
  • 如何在 scikit 中加载 CSV 数据并将其用于朴素贝叶斯分类

    尝试加载自定义数据以在 Scikit 中执行 NB 分类 需要帮助将示例数据加载到 Scikit 中 然后执行 NB 如何加载目标的分类值 使用相同的数据进行训练和测试 或使用完整的数据集进行测试 Sl No Member ID Membe
  • 如何在连接到 Heroku PostgreSQL 的 Flask 应用程序上处理更多并发用户?

    Heroku 上的 Flask API 有许多端点 它们在将 json 化结果返回给客户端之前在我的 Heroku PostgreSQL 数据库上运行查询 我当前的计划是 Hobby Basic 层 因此数据库最多只能处理 20 个连接 如
  • Jquery 以编程方式更改

    文本

    编辑 解决方案是将其添加到个人资料页面而不是性别页面 profile live pageinit function event p pTest text localStorage getItem gender 我在列表视图中有一个带有一些文
  • 水平和垂直居中 div 位于页面中间,页眉和页脚粘在页面顶部和底部

    我正在尝试制作一个具有固定高度页眉和页脚的页面 页眉位于屏幕顶部 100 宽度 页脚位于底部 100 宽度 我想将一个具有可变高度内容的 div 居中放置在页眉和页脚之间的空间中 在下面的 jsfiddle 中 如果内容比空格短 它会起作用

随机推荐

  • 在 PHP 中向日期添加三个月

    我有一个变量叫做 effectiveDate包含日期2012 03 26 我试图在此日期基础上增加三个月 但没有成功 这是我尝试过的 effectiveDate strtotime 3 months strtotime effectiveD
  • 按上下文获取所有标签以实现 acts-as-taggable-on

    We use https github com mbleigh acts as taggable on https github com mbleigh acts as taggable on对于我们的 Rails 应用程序 我们遇到了问题
  • 如何与 React Test Renderer / Jest 渲染的组件交互

    我正在使用 Jest 和快照测试 我想做的是渲染一个组件ReactTestRenderer 然后模拟单击其中的按钮 然后验证快照 ReactTestRenderer 返回的对象create呼叫有一个getInstance函数允许我直接调用它
  • 不兼容的片段类型

    你好 我在 android 中有一个小应用程序 我在其中使用带导航抽屉的片段作为菜单 但现在我想在用户单击某些内容时在片段对话框弹出窗口中显示 并且出现以下错误 主要活动 private void displayView int posit
  • shell 脚本参数非位置

    有没有办法将非位置参数提供给 shell 脚本 意思是明确指定某种标志 myscript sh value1 value2 myscript sh val1 value1 val2 value2 您可以使用getopts 但我不喜欢它 因为
  • MySQL 错误 1241:操作数应包含 1 列

    我正在尝试将表1中的数据插入表2中 insert into table2 Name Subject student id result select Name Subject student id result from table1 表2
  • 在.Net Framework中使用最新版本的System.Net.Http

    最新版本System Net Http https www nuget org packages System Net Http nuget 上的版本是 4 3 4 但即使是最新的 Net Framework 4 8 也附带了该库的 4 2
  • 拼写检查等统计句子建议模型

    已经有可用的拼写检查模型 可以帮助我们根据经过训练的正确拼写语料库找到建议的正确拼写 是否可以将粒度从字母表增加到 单词 以便我们可以有均匀的短语建议 这样如果输入了错误的短语 那么它应该从正确短语的语料库中建议最接近的正确短语 当然它是从
  • Google 地图信息窗口中的 YouTube 视频

    我正在尝试将 YouTube 视频放入 Google 地图 v3 信息窗口中 它在 Firefox 和 Internet Explorer 中运行良好 It does not在 Safari 和 Chrome 中工作 在这些浏览器中 定位已
  • 在 Activity.onCreate(..) 中显示警报

    我是 Android 新手 这是我的第一个问题 所以请放轻松 是否可以检查 Activity 的 onCreate 内的某些条件并显示 AlertDialog 我在 Oncreate 中匿名创建一个 AlertDialog 并在该实例上调用
  • 使用 R Markdown 的 Beamer 演示

    我正在使用 R Markdown 来制作投影仪演示我对幻灯片水平有疑问 我选择法兰克福主题 该主题允许制定演示计划 标题中的项目符号 我的问题 当我输入 slide level 2 时 我有内容 但没有演示文稿的计划 当我输入 slide
  • 如何从命令行将错误列表(或任何自定义查询)从 TFS 导出到 Excel?

    我需要将错误列表从 Team Foundation Server 导出到 Excel 手动执行此操作很简单 但我需要命令行版本 因为该任务需要自动化 有人知道该怎么做吗 回答你原来的问题 在 TFS 中添加新查询 创建查询并单击 保存 这应
  • 使用 Visual Studio 创建 MSI 并强制所有用户

    我使用 Visual Studio 2015 带有 Visual Studio 安装程序插件 创建了一个安装程序 目标是始终使用相同的本地资源运行应用程序 无论谁登录 因此我们的目标是 CommonAppDataFolder Win10 上
  • 淡出旧元素,淡入新元素

    我是新来反应并尝试过反应动画 http facebook github io react docs animation html 当在 TransitionGroup 中添加或删除元素时 它们非常有用 但是 如果我用类似的元素替换单个元素
  • 非活动类中的警报对话框

    我有一个代码可以检查一些数据并在非活动类中显示警报 但是在运行应用程序时崩溃并且不显示警报对话框 我使用下面的代码 if str isEmpty strPort isEmpty new AlertDialog Builder Mtx get
  • Kivy (Python) - 椭圆点击事件

    我正在尝试翻译的开头一个简单的画布应用程序 https bloom510 github io pitch canvas 我用 JavaScript 编写了 Kivy 框架 我已经能够沿着圆的周长分布顶点 但是无论是用 Python 还是 K
  • 即使在 conda 中安装后也无法导入 Poppler

    我正在尝试使用 pdf 渲染包 Poppler 我在这里找到了相同的 Anaconda 安装 https anaconda org conda forge poppler https anaconda org conda forge pop
  • Python读取文件时出现UnicodeDecodeError,如何忽略错误并跳转到下一行?

    我必须将文本文件读入Python 文件编码为 file bi test csv text plain charset us ascii 这是第三方文件 我每天都会收到一个新文件 所以我宁愿不更改它 该文件包含非 ascii 字符 例如 我需
  • Laravel - 有没有办法将 whereHas 和 with 结合起来

    我目前面临一个小问题 我只想在存在特定条件的关系时返回模型 这与 whereHas 方法配合得很好 m Model whereHas programs function q q gt active 但是 将关系称为这样的属性将为我提供所有内
  • Flask 将 pyaudio 发送到浏览器

    我正在将服务器麦克风的音频发送到浏览器 主要是this https stackoverflow com a 56037682 4871482发布但有一些修改的选项 一切都工作正常 直到你转到手机或野生动物园 它根本不起作用 我尝试过使用类似