Streaming Langsung Audio dengan Python & Flask

Saat ini saya sedang berjuang dengan implementasi aplikasi web streaming langsung sederhana menggunakan Python dan Flask. Tampaknya saya tidak dapat melakukan streaming audio rekaman langsung dari input mikrofon server ke halaman web.

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

Saya mencoba mendapatkan Potongan mikrofon saat ini menggunakan audio_processing.py dan menggunakan hasil untuk merespons sampel saat ini kepada pengguna. Streaming video berfungsi cukup baik. Adakah yang tahu, apa yang saya lakukan salah di sini?

Salam baik, Felix


person F. Geißler    schedule 28.06.2018    source sumber
comment
Sekadar catatan singkat, Anda tidak boleh terus-menerus membuka aliran PyAudio; yaitu mengaturnya dalam panggilan fungsi init atau yang serupa, sebelum streaming dimulai. Kemudian akses objek aliran untuk membacanya saat Anda membutuhkannya dengan metode record() Anda. Atau setidaknya tutup jika ingin tetap membukanya.   -  person WoodyDev    schedule 28.06.2018
comment
Ya, Anda benar, saya mengubah kodenya sedikit. Saya baru-baru ini menambahkan prosedur perekaman pyAudio ke server.py ke dalam generateAudio(). Fungsi tersebut seharusnya berfungsi dengan baik sekarang. Satu-satunya masalah adalah, fungsi byte() tidak didukung di Python2.7 yang saat ini saya gunakan. Apakah Anda tahu cara menulis fungsi serupa di 2.7? Tidak dapat menemukan solusi siap pakai :/   -  person F. Geißler    schedule 28.06.2018
comment
Halo @F.Geißler, saya ingin melihat bagaimana Anda memanggil titik akhir @app.route(/audio_feed) di html Anda. Baru dalam pengaturan ini. Akan sangat membantu.   -  person Rajesh Rajamani    schedule 21.04.2021


Jawaban (1)


berikut adalah contoh yang berfungsi dengan mikrofon internal perangkat Anda: maaf karena tidak dapat menjelaskan banyak hal, tetapi inilah yang saya temukan untuk aplikasi saya!

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 - di bawah folder templat di direktori saat ini

<!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
Usahakan tidak hanya memposting kode jawaban tetapi jelaskan juga kepada OP apa yang salah dengan kodenya - person dWinder; 08.05.2019
comment
Tentu ! akan ingat sobat! telah mengeditnya sedikit - person Pytholabs; 08.05.2019
comment
Hai, Saya mencoba mengaturnya dan saya bisa memutarnya, tetapi ada suara gelombang persegi yang keras menutupi audio. Rekaman Pyaudio ke file dengan pengkodean yang sama sepertinya tidak berpengaruh, jadi menurut saya ada yang salah dengan streaming pasca-rekaman. Masukan apa pun tentang hal ini akan sangat membantu. Saya telah mencoba mengubah jumlah saluran dan mencoba semua perangkat input di mesin saya. - person Mr. Negi; 16.01.2020
comment
Anda hanya seharusnya mengirim header satu kali; kode ini mengirimkan header dengan setiap potongan. Hal ini menyebabkan suara gelombang persegi yang keras yang diperhatikan oleh @Mr.Negi. - person zzxx53; 03.02.2020
comment
Saya menerapkan perubahan yang Anda sarankan dan memverifikasi bahwa itu berhasil, saya telah mengirimkan permintaan edit dengan perubahan jawabannya, karena saya tidak memiliki reputasi yang cukup untuk mengedit tanpa konfirmasi. Terima kasih telah memberikan wawasan Anda di sini, sebagai non-spesialis streaming audio, saya tidak menyangka ini masalahnya. - person Mr. Negi; 05.02.2020