A bit of cleanup for the dummy audio before MR

This commit is contained in:
Jono Targett 2023-06-14 11:49:52 +09:30
parent 87bd553bb8
commit b84f02dd89
5 changed files with 96 additions and 95 deletions

View File

@ -4,25 +4,26 @@ import time
import sys
import os
class FileRadio(Streamer):
PORT = 8554
REST_PATH = 'sample'
def __init__(self, path):
super().__init__()
self.path = path
self.basename = os.path.basename(self.path)
self.name, self.ext = os.path.splitext(self.basename)
super().__init__()
def _stream_path(self):
return f":{FileRadio.PORT}/sample/{self.name}"
def _stream_thread(self):
self.playback = subprocess.Popen(
[
'/usr/bin/ffmpeg', '-re', '-stream_loop', '-1', '-i',
f"{self.path}", '-c', 'copy',
'-f', 'rtsp', f"rtsp://localhost{self._stream_path()}"
'/usr/bin/ffmpeg',
'-re', # http://trac.ffmpeg.org/wiki/StreamingGuide#The-reflag
'-stream_loop', '-1', # Loop the stream indefinitely
'-i', self.path,
'-c', 'copy',
'-f', 'rtsp',
self.stream_address('localhost')
],
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
@ -42,6 +43,7 @@ class FileRadio(Streamer):
self.playback = None
if __name__ == '__main__':
fr = FileRadio('./data/sampleaudio/taunt.mp3')
fr.start_stream()

View File

@ -194,19 +194,8 @@ def radio_info(radio):
return str(e), 400
# Youtube shit
tubes = {}
@app.route('/tuuube/report')
def tuuube_report():
"""List the tuuube streams opened and their streaming status.
---
responses:
200:
description: JSON
"""
return jsonify({id:{'active':tube.is_streaming(),'playing':tube.is_playing()} for id,tube in tubes.items()})
@app.route('/tuuube/<id>/start')
def start_tuuube_stream(id):
"""Start streaming from a youtube source.
@ -215,7 +204,13 @@ def start_tuuube_stream(id):
---
parameters:
- name: id
description: The youtube video ID. That is the part following the `watch?v=` in the URL. For example, dQw4w9WgXcQ.
description:
The youtube video ID. That is the part following the `watch?v=` in the URL. For example, `dQw4w9WgXcQ`.\n
Other good options are - \n
`BaW_jenozKc`, yt_dlp package test video.\n
`b2je8uBlgFM`, stereo audio test.\n
`LDU_Txk06tM`, crab rave, a commonly used audio fidelity test.\n
`sPT_epMLkwQ`, Kilsyth CFA major factory fire dispatch radio traffic.
in: path
type: string
required: true

View File

@ -7,19 +7,19 @@ import subprocess
import struct
from soapyhelpers import *
from samplerates import *
from streamer import Streamer, is_alive
class Radio:
class Radio(Streamer):
REST_PATH = 'radio'
FORMAT = 'CS16'
SAMPLES = 8192
PORT = 8554
def __init__(self, name, device_info):
super().__init__()
self.name = name
self.device_info = device_info
self.run = False
self.thread = None
self.device = soapy.Device(device_info)
if self.device is None:
raise RuntimeError("Failed to connect to radio device")
@ -83,31 +83,9 @@ class Radio:
'uarts': self.device.listUARTs(),
}
def is_streaming(self):
return True if (self.thread and self.thread.is_alive()) else False
def start_stream(self):
if self.is_streaming():
raise RuntimeError('Stream thread is already running')
self.run = True
self.thread = Thread(target=self._stream_thread, daemon=True, args=())
self.thread.start()
def end_stream(self):
if self.thread is None:
raise RuntimeError('No stream thread to terminate')
self.run = False
self.thread.join()
self.thread = None
def _stream_thread(self):
self._init_stream()
def is_alive(subprocess):
return (subprocess.poll() is None)
while self.run:
# Check that the child processes are still running
if (not is_alive(self.demod)) or (not is_alive(self.playback)):
@ -136,8 +114,12 @@ class Radio:
def _init_stream(self):
self.playback = subprocess.Popen(
[
'/usr/bin/ffmpeg', '-f', 's16le', '-ar', str(self.output_rate), '-ac', '2', '-i', '-',
'-f', 'rtsp', f"rtsp://localhost{self._stream_path()}"
'/usr/bin/ffmpeg',
'-f', 's16le',
'-ar', str(self.output_rate),
'-ac', '2',
'-i', '-',
'-f', 'rtsp', self.stream_address()
],
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
@ -145,7 +127,12 @@ class Radio:
)
self.demod = subprocess.Popen(
['/usr/bin/python3', 'fm_demod.py', '-f', 'CS16', '-s', str(self.sample_rate), '-d', str(self.output_rate)],
[
'/usr/bin/python3', 'fm_demod.py',
'-f', 'CS16',
'-s', str(self.sample_rate),
'-d', str(self.output_rate)
],
stdin=subprocess.PIPE,
stdout=self.playback.stdin,
stderr=subprocess.DEVNULL
@ -176,8 +163,6 @@ class Radio:
self.playback.wait()
self.playback = None
def _stream_path(self):
return f":{Radio.PORT}/radio/{self.name}"
"""
@ -201,4 +186,4 @@ if __name__ == '__main__':
print('Ending stream...')
sdr.end_stream()
print('Stream ended.')
print('Stream ended.')

View File

@ -1,12 +1,29 @@
from threading import Thread
import yaml
with open('mediamtx.yml', 'r') as config_file:
MEDIASERVER_CONFIG = yaml.safe_load(config_file)
def is_alive(subprocess):
return True if (subprocess and subprocess.poll() is None) else False
class Streamer:
PROTOCOL = 'rtsp'
REST_PATH = 'stream'
def __init__(self):
self.run = False
self.thread = None
self.name = None
def stream_path(self):
return f"{MEDIASERVER_CONFIG['rtspAddress']}/{type(self).REST_PATH}/{self.name}"
def stream_address(self, host):
return f"{Streamer.PROTOCOL}://{host}{self.stream_path()}"
def is_streaming(self):
return True if (self.thread and self.thread.is_alive()) else False
@ -26,3 +43,9 @@ class Streamer:
self.run = False
self.thread.join()
self.thread = None
if __name__ == '__main__':
from pprint import pprint
pprint(MEDIASERVER_CONFIG)

View File

@ -1,63 +1,61 @@
#! /usr/bin/env python3
"""
# Install issues?
https://stackoverflow.com/a/27481870
https://stackoverflow.com/a/66024755
sudo apt purge youtube-dl
sudo pip3 install youtube-dl
https://stackoverflow.com/a/75504772
python3 -m pip install --force-reinstall https://github.com/yt-dlp/yt-dlp/archive/master.tar.gz
We aren't using either the apt or the pip repositories for the youtube_dl
as there is a known bug affecting those two versions. The youtube API has changed
since their release, causing downloads to fail.
Make sure you use the ./setup.sh script to obtain the latest github release of
yt_dlp, as this version carries the latest fixes.
"""
#import youtube_dl
import yt_dlp as youtube_dl
from streamer import Streamer, is_alive
import subprocess
import time
import sys
import os
class Tuuube(Streamer):
PORT = 8554
REST_PATH = 'tuuube'
def __init__(self, id):
self.id = id
self.playback = None
def __init__(self, name):
super().__init__()
self.name = name
self.playback = None
def is_playing(self):
return is_alive(self.playback)
def _stream_path(self):
return f":{Tuuube.PORT}/tuuube/{self.id}"
def source_path(self):
return f"/tmp/{self.name}.mp3"
def _stream_thread(self):
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': f'/tmp/{self.id}.%(ext)s',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
if not os.path.exists(self.source_path()) or not os.path.isfile(self.source_path()):
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': f'/tmp/{self.name}.%(ext)s', # yt_dlp will append %(ext) if not specified,
'postprocessors': [{ # resulting in `/tmp/file.mp3.mp3` :/
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
'preferredquality': '192',
}],
}
try:
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([f'https://www.youtube.com/watch?v={self.id}'])
except Exception as e:
print(f'File sourcing failed, aborting stream. {e}', file=sys.stderr)
self.run = False
return
try:
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([f'https://www.youtube.com/watch?v={self.name}'])
except Exception as e:
print(f'File sourcing failed, aborting stream. {e}', file=sys.stderr)
self.run = False
return
self.playback = subprocess.Popen(
[
'/usr/bin/ffmpeg', '-re', '-stream_loop', '-1', '-i',
f"/tmp/{self.id}.mp3", '-c', 'copy',
'-f', 'rtsp', f"rtsp://localhost{self._stream_path()}"
'/usr/bin/ffmpeg',
'-re',
'-stream_loop', '-1',
'-i', self.source_path(),
'-c', 'copy',
'-f', 'rtsp',
self.stream_address('localhost')
],
stdin=subprocess.PIPE,
stdout=subprocess.DEVNULL,
@ -65,7 +63,7 @@ class Tuuube(Streamer):
)
while self.run:
if not self.is_playing():
if not is_alive(self.playback):
print('Playback failed, aborting stream.', file=sys.stderr)
break
time.sleep(0.1)
@ -79,9 +77,7 @@ class Tuuube(Streamer):
if __name__ == '__main__':
#tube = Tuuube('dQw4w9WgXcQ')
tube = Tuuube('BaW_jenozKc')
tube.start_stream()
while True: