| import subprocess |
|
|
| import numpy as np |
|
|
|
|
| def ffmpeg_stream(youtube_url, sampling_rate=16_000, chunk_duration_ms=5000, pad_duration_ms=200): |
| """ |
| Helper function to read an audio file through ffmpeg. |
| """ |
| chunk_len = int(sampling_rate * chunk_duration_ms / 1000) |
| pad_len = int(sampling_rate * pad_duration_ms / 1000) |
| read_chunk_len = chunk_len + pad_len * 2 |
|
|
| ar = f"{sampling_rate}" |
| ac = "1" |
| format_for_conversion = "f32le" |
| dtype = np.float32 |
| size_of_sample = 4 |
|
|
| ffmpeg_command = [ |
| "ffmpeg", |
| "-i", |
| "pipe:", |
| "-ac", |
| ac, |
| "-ar", |
| ar, |
| "-f", |
| format_for_conversion, |
| "-hide_banner", |
| "-loglevel", |
| "quiet", |
| "pipe:1", |
| ] |
|
|
| ytdl_command = ["yt-dlp", "-f", "bestaudio", youtube_url, "--quiet", "-o", "-"] |
|
|
| try: |
| ffmpeg_process = subprocess.Popen(ffmpeg_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=-1) |
| ytdl_process = subprocess.Popen(ytdl_command, stdout=ffmpeg_process.stdin) |
| except FileNotFoundError: |
| raise ValueError("ffmpeg was not found but is required to stream audio files from filename") |
|
|
| acc = b"" |
| leftover = np.zeros((0,), dtype=np.float32) |
| while ytdl_process.poll() is None: |
| buflen = read_chunk_len * size_of_sample |
|
|
| raw = ffmpeg_process.stdout.read(buflen) |
| if raw == b"": |
| break |
|
|
| if len(acc) + len(raw) > buflen: |
| acc = raw |
| else: |
| acc += raw |
|
|
| audio = np.frombuffer(acc, dtype=dtype) |
| audio = np.concatenate([leftover, audio]) |
| if len(audio) < pad_len * 2: |
| |
| break |
| yield audio |
|
|
| leftover = audio[-pad_len * 2 :] |
| read_chunk_len = chunk_len |