我正在将服务器麦克风的音频发送到浏览器(主要是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
作为标头请求。