การสตรีมเสียงสดด้วย Python และ Flask

ขณะนี้ฉันกำลังดิ้นรนกับการใช้งานเว็บแอปพลิเคชันสตรีมมิงสดที่เรียบง่ายโดยใช้ Python และ Flask ดูเหมือนว่าฉันไม่สามารถสตรีมเสียงที่บันทึกสดของฉันจากอินพุตไมโครโฟนของเซิร์ฟเวอร์ไปยังหน้าเว็บได้

server.py

from flask import Flask, render_template, Response
import cv2
import framework
import pyaudio
import audio_processing as audioRec

FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 1024

audio = pyaudio.PyAudio()


app = Flask(__name__)


@app.route('/')
def index():
    """Video streaming home page."""
    return render_template('index.html')


# Stream routing
@app.route('/video_feed')
def video_feed():
    """Video streaming route. Put this in the src attribute of an img tag."""
    return Response(generateVideo(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


@app.route("/audio_feed")
def audio_feed():
    """Audio streaming route. Put this in the src attribute of an audio tag."""
    return Response(generateAudio(),
                    mimetype="audio/x-wav")


# Stream generating
def generateVideo():
    """Video streaming generator function."""
    cap = cv2.VideoCapture(0)
    while (cap.isOpened()):
        ret, frame = cap.read()
        output = framework.streamer(frame, 'final')
        cv2.imwrite('signals/currFrame.jpg', output)
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + open('signals/currFrame.jpg', 'rb').read() + b'\r\n')


def generateAudio():
    """Audio streaming generator function."""
    currChunk = audioRec.record()
    data_to_stream = genHeader(44100, 32, 1, 200000) + currChunk
    yield data_to_stream

    # with open("signals/audio.wav", "rb") as fwav:
    #     data = fwav.read(1024)
    #     while data:
    #         yield data
    #         data = fwav.read(1024)


def genHeader(sampleRate, bitsPerSample, channels, samples):
    datasize = samples * channels * bitsPerSample // 8
    o = bytes("RIFF",'ascii')                                               # (4byte) Marks file as RIFF
    o += (datasize + 36).to_bytes(4,'little')                               # (4byte) File size in bytes excluding this and RIFF marker
    o += bytes("WAVE",'ascii')                                              # (4byte) File type
    o += bytes("fmt ",'ascii')                                              # (4byte) Format Chunk Marker
    o += (16).to_bytes(4,'little')                                          # (4byte) Length of above format data
    o += (1).to_bytes(2,'little')                                           # (2byte) Format type (1 - PCM)
    o += (channels).to_bytes(2,'little')                                    # (2byte)
    o += (sampleRate).to_bytes(4,'little')                                  # (4byte)
    o += (sampleRate * channels * bitsPerSample // 8).to_bytes(4,'little')  # (4byte)
    o += (channels * bitsPerSample // 8).to_bytes(2,'little')               # (2byte)
    o += (bitsPerSample).to_bytes(2,'little')                               # (2byte)
    o += bytes("data",'ascii')                                              # (4byte) Data Chunk Marker
    o += (datasize).to_bytes(4,'little')                                    # (4byte) Data size in bytes
    return o




if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, threaded=True)

audio_processing.py

import pyaudio

FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
CHUNK = 1024

audio = pyaudio.PyAudio()


def record():
    # start Recording
    stream = audio.open(format=FORMAT, channels=CHANNELS,
                    rate=RATE, input=True,
                    frames_per_buffer=CHUNK)
    # print "recording..."
    data = stream.read(CHUNK)
    return data

ฉันกำลังพยายามรับไมโครโฟนปัจจุบันโดยใช้ audio_processing.py และใช้ Yield เพื่อตอบสนองตัวอย่างปัจจุบันให้กับผู้ใช้ สตรีมวิดีโอทำงานได้ค่อนข้างดี ใครรู้บ้างว่าฉันทำอะไรผิดที่นี่?

ขอแสดงความนับถือเฟลิกซ์


person F. Geißler    schedule 28.06.2018    source แหล่งที่มา
comment
โปรดทราบว่าคุณไม่ควรเปิดสตรีม PyAudio อย่างต่อเนื่อง เช่น ตั้งค่าในการเรียกใช้ฟังก์ชัน init หรืออะไรที่คล้ายกัน ก่อนที่การสตรีมจะเริ่มต้น จากนั้นเข้าถึงออบเจ็กต์สตรีมเพื่ออ่านเมื่อคุณต้องการด้วยเมธอด record() ของคุณ หรืออย่างน้อยก็ปิดมันถ้าคุณต้องการเปิดมันต่อไป   -  person WoodyDev    schedule 28.06.2018
comment
ใช่ คุณพูดถูก ฉันเปลี่ยนรหัสเล็กน้อย ฉันเพิ่งเพิ่มขั้นตอนการบันทึก pyAudio ไปยัง server.py ใน GenerateAudio() ฟังก์ชั่นควรทำงานได้อย่างถูกต้องในขณะนี้ ปัญหาเดียวคือ Python2.7 ไม่รองรับฟังก์ชัน byte() ที่ฉันใช้อยู่ คุณมีความคิดว่าจะเขียนฟังก์ชันที่คล้ายกันใน 2.7 ได้อย่างไร? ไม่พบวิธีแก้ปัญหาที่สร้างไว้ล่วงหน้า :/   -  person F. Geißler    schedule 28.06.2018
comment
สวัสดี @F.Geißler ฉันอยากรู้ว่าคุณเรียกจุดสิ้นสุด @app.route(/audio_feed) ใน html ของคุณได้อย่างไร ใหม่สำหรับการตั้งค่านี้ จะช่วยได้มาก.   -  person Rajesh Rajamani    schedule 21.04.2021


คำตอบ (1)


นี่คือตัวอย่างการทำงานกับไมโครโฟนในตัวของอุปกรณ์ของคุณ ขออภัยที่ไม่สามารถอธิบายได้มาก แต่นี่คือสิ่งที่ฉันคิดออกสำหรับแอปของฉัน

app.py

from flask import Flask, Response,render_template
import pyaudio

app = Flask(__name__)


FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
CHUNK = 1024
RECORD_SECONDS = 5


audio1 = pyaudio.PyAudio()



def genHeader(sampleRate, bitsPerSample, channels):
    datasize = 2000*10**6
    o = bytes("RIFF",'ascii')                                               # (4byte) Marks file as RIFF
    o += (datasize + 36).to_bytes(4,'little')                               # (4byte) File size in bytes excluding this and RIFF marker
    o += bytes("WAVE",'ascii')                                              # (4byte) File type
    o += bytes("fmt ",'ascii')                                              # (4byte) Format Chunk Marker
    o += (16).to_bytes(4,'little')                                          # (4byte) Length of above format data
    o += (1).to_bytes(2,'little')                                           # (2byte) Format type (1 - PCM)
    o += (channels).to_bytes(2,'little')                                    # (2byte)
    o += (sampleRate).to_bytes(4,'little')                                  # (4byte)
    o += (sampleRate * channels * bitsPerSample // 8).to_bytes(4,'little')  # (4byte)
    o += (channels * bitsPerSample // 8).to_bytes(2,'little')               # (2byte)
    o += (bitsPerSample).to_bytes(2,'little')                               # (2byte)
    o += bytes("data",'ascii')                                              # (4byte) Data Chunk Marker
    o += (datasize).to_bytes(4,'little')                                    # (4byte) Data size in bytes
    return o

@app.route('/audio')
def audio():
    # start Recording
    def sound():

        CHUNK = 1024
        sampleRate = 44100
        bitsPerSample = 16
        channels = 2
        wav_header = genHeader(sampleRate, bitsPerSample, channels)

        stream = audio1.open(format=FORMAT, channels=CHANNELS,
                        rate=RATE, input=True,input_device_index=1,
                        frames_per_buffer=CHUNK)
        print("recording...")
        #frames = []
        first_run = True
        while True:
           if first_run:
               data = wav_header + stream.read(CHUNK)
               first_run = False
           else:
               data = stream.read(CHUNK)
           yield(data)

    return Response(sound())

@app.route('/')
def index():
    """Video streaming home page."""
    return render_template('index.html')


if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True, threaded=True,port=5000)

index.html - ใต้โฟลเดอร์เทมเพลตในไดเร็กทอรีปัจจุบัน

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <audio controls>
        <source src="{{ url_for('audio') }}" type="audio/x-wav;codec=pcm">
        Your browser does not support the audio element.
    </audio>
</body>
</html>
person Pytholabs    schedule 08.05.2019
comment
พยายามอย่าโพสต์รหัสเพียงตอบเท่านั้น แต่ยังอธิบาย OP ว่ามีอะไรผิดปกติกับรหัสของเขาด้วย - person dWinder; 08.05.2019
comment
แน่นอน ! จะจำเพื่อน! ได้แก้ไขมันเล็กน้อย - person Pytholabs; 08.05.2019
comment
สวัสดี ฉันกำลังพยายามตั้งค่านี้และฉันสามารถเล่นได้ แต่มีเสียงคลื่นสี่เหลี่ยมดังซ้อนทับเสียง การบันทึก Pyaudio เป็นไฟล์ที่มีการเข้ารหัสเดียวกันดูเหมือนจะไม่มีผลใดๆ ดังนั้นฉันคิดว่ามีบางอย่างผิดปกติกับการบันทึกหลังการสตรีม ข้อมูลใด ๆ เกี่ยวกับสิ่งที่อาจเป็นประโยชน์ ฉันได้ลองเปลี่ยนจำนวนช่องสัญญาณและลองใช้อุปกรณ์อินพุตทั้งหมดในเครื่องของฉันแล้ว - person Mr. Negi; 16.01.2020
comment
คุณควรส่งส่วนหัวเพียงครั้งเดียวเท่านั้น รหัสนี้ส่งส่วนหัวไปทุกอัน สิ่งนี้ทำให้เกิดเสียงคลื่นสี่เหลี่ยมดังที่ @Mr.Negi สังเกตเห็น - person zzxx53; 03.02.2020
comment
ฉันใช้การเปลี่ยนแปลงที่คุณแนะนำและยืนยันว่าใช้งานได้ ฉันได้ส่งคำขอแก้ไขพร้อมกับการเปลี่ยนแปลงคำตอบ เนื่องจากฉันไม่มีชื่อเสียงเพียงพอที่จะแก้ไขโดยไม่ได้รับการยืนยัน ขอขอบคุณที่ให้ข้อมูลเชิงลึกที่นี่ ในฐานะที่ไม่ใช่ผู้เชี่ยวชาญด้านการสตรีมเสียง ฉันไม่รู้ว่านี่คือปัญหา - person Mr. Negi; 05.02.2020