html Flask将pyaudio发送到浏览器

mspsb9vt  于 2023-02-14  发布在  其他
关注(0)|答案(1)|浏览(139)

我发送我的服务器麦克风的音频到浏览器(主要是像this后,但与一些修改选项)。
一切都很好,直到你去移动的或safari,在那里它根本不工作.我曾尝试使用类似howler的东西来照顾前端,但没有成功(仍然在chrome和电脑上工作,但在手机Safari/Chrome/etc上不工作). <audio> ... </audio>在chrome上工作正常,但只在电脑上.

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

如何发送在任何浏览器中都有效的“实时”波形生成音频源?
编辑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响应中使用一些头文件,但是经过几个小时的调试,我似乎找不到任何解决这个问题的方法。

ecfsfe2w

ecfsfe2w1#

我猜苹果要求对没有给定内容长度的数据执行RFC7233 HTTP范围请求。否则下载在第一个块后停止。
为此,您可以添加如下回应标头信息:

Accept-Ranges: bytes
Content-Range: bytes <start>-<end>/*

并返回HTTP代码206 PARTIAL CONTENT。这样一来,浏览器就可以在需要时请求媒体流的块。此外,您还应该评估每个请求的Range属性,因为音频控件可以用于在流中导航。为此,您需要在服务器中保留一定数量的音频数据以满足此要求。此外,您的应用程序应允许多线程。
有关于herehere等SO上的流视频内容的讨论。您可以尝试为您的音频流实现相同的内容。
我知道这不是全部的解决办法,但我希望它能给你指明正确的方向。

相关问题