I have code like what is shown below to get audio from microphone:
import pyaudio
p = pyaudio.PyAudio()
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 1024*10
RECORD_SECONDS = 10
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
send_via_socket(data) # function to send each frame to remote system
This code is working fine. However each data frame has a size of 4kb. That means 40kb of internet data is needed to send 1 sec of audio data.
It's only 6kb of data When I saved the 10 frames (1 second audio) to disc and convert it to mp3 using the pdub module.
How can I convert each wav frame to mp3 before sending via socket? (I just need to reduce the size of the frame to save network usage).
For example:
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK) # data =4kb
mp3_frame = wav_to_mp3(data) # mp3_frame should be 1kb or less
send_via_socket(mp3_frame) # function to send each frame to remote system
try python-audiotools. I think it will help you stream the audio file that you want.
From reading the code for pydub, it appears that an AudioSegment only allows an output to a file using the out_f variable. So, you can read the WAV file and encode each chunk to a file and then read the file and send it out, decoding it on the other end. However, this is not very efficient. I'd suggest actually extending pydub to handle streams and contributing to the project. The export code is pretty straightforward and I bet it would not be too difficult to do. The author would likely be grateful.
The code for AudioSegment is here:
https://github.com/jiaaro/pydub/blob/master/pydub/audio_segment.py
I was able to figure out a working approach using flask
and ffmpeg
...
import select
import subprocess
import numpy
from flask import Flask
from flask import Response
app = Flask(__name__)
def get_microphone_audio(num_samples):
# TODO: Add the above microphone code.
audio = numpy.random.rand(num_samples).astype(numpy.float32) * 2 - 1
assert audio.max() <= 1.0
assert audio.min() >= -1.0
assert audio.dtype == numpy.float32
return audio
def response():
pipe = subprocess.Popen(
'ffmpeg -f f32le -acodec pcm_f32le -ar 24000 -ac 1 -i pipe: -f mp3 pipe:'
.split(),
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
poll = select.poll()
poll.register(pipe.stdout, select.POLLIN)
while True:
pipe.stdin.write(get_synthetic_audio(24000).tobytes())
while poll.poll(0):
yield pipe.stdout.readline()
@app.route('/stream.mp3', methods=['GET'])
def stream():
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', port=8000, debug=True)
This solution allows for live streaming and is supported in Chrome, Firefox, and Safari.
This solution also worked for this similar question: How to stream MP3 chunks given a NumPy array in Python?