Starting and stopping of local audio playback working through REST API
This commit is contained in:
parent
59ca70b20b
commit
0b559a8f85
92
radio.py
92
radio.py
@ -3,6 +3,9 @@ import SoapySDR as soapy
|
|||||||
import prefixed
|
import prefixed
|
||||||
from formats import *
|
from formats import *
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
class Radio:
|
class Radio:
|
||||||
@ -11,9 +14,6 @@ class Radio:
|
|||||||
|
|
||||||
def __init__(self, device_info):
|
def __init__(self, device_info):
|
||||||
self.device_info = device_info
|
self.device_info = device_info
|
||||||
self.stream = None
|
|
||||||
self.buffer = None
|
|
||||||
self.port = None
|
|
||||||
self.run = False
|
self.run = False
|
||||||
self.thread = None
|
self.thread = None
|
||||||
|
|
||||||
@ -21,7 +21,6 @@ class Radio:
|
|||||||
if self.device is None:
|
if self.device is None:
|
||||||
raise RuntimeError("Failed to connect to radio device")
|
raise RuntimeError("Failed to connect to radio device")
|
||||||
|
|
||||||
|
|
||||||
def configure(self, frequency):
|
def configure(self, frequency):
|
||||||
frequency = int(prefixed.Float(frequency))
|
frequency = int(prefixed.Float(frequency))
|
||||||
sample_rate = 384000
|
sample_rate = 384000
|
||||||
@ -41,31 +40,14 @@ class Radio:
|
|||||||
'gain-mode': 'auto' if self.device.getGainMode(soapy.SOAPY_SDR_RX, 0) else 'manual',
|
'gain-mode': 'auto' if self.device.getGainMode(soapy.SOAPY_SDR_RX, 0) else 'manual',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def start_stream(self):
|
def start_stream(self):
|
||||||
if self.thread:
|
if self.thread:
|
||||||
raise RuntimeError('Stream thread is already running')
|
raise RuntimeError('Stream thread is already running')
|
||||||
|
|
||||||
self.buffer = np.array([0] * Radio.SAMPLES * 2, TYPES[Radio.FORMAT])
|
|
||||||
self.stream = self.device.setupStream(soapy.SOAPY_SDR_RX, FORMATS[Radio.FORMAT])
|
|
||||||
self.device.activateStream(self.stream)
|
|
||||||
|
|
||||||
self.run = True
|
self.run = True
|
||||||
self.thread = Thread(target=self._stream_thread, daemon=True, args=())
|
self.thread = Thread(target=self._stream_thread, daemon=True, args=())
|
||||||
self.thread.start()
|
self.thread.start()
|
||||||
|
|
||||||
|
|
||||||
def _stream_thread(self):
|
|
||||||
while self.run:
|
|
||||||
result = self.device.readStream(self.stream, [self.buffer], Radio.SAMPLES)
|
|
||||||
|
|
||||||
if result.ret < 1:
|
|
||||||
print('Stream read failed, exiting.', file=sys.stderr)
|
|
||||||
self.keep_going = False
|
|
||||||
|
|
||||||
self._cleanup_stream()
|
|
||||||
|
|
||||||
|
|
||||||
def end_stream(self):
|
def end_stream(self):
|
||||||
if self.thread is None:
|
if self.thread is None:
|
||||||
raise RuntimeError('No stream thread to terminate')
|
raise RuntimeError('No stream thread to terminate')
|
||||||
@ -74,8 +56,72 @@ class Radio:
|
|||||||
self.thread.join()
|
self.thread.join()
|
||||||
self.thread = None
|
self.thread = None
|
||||||
|
|
||||||
|
def _stream_thread(self):
|
||||||
|
self._init_stream()
|
||||||
|
|
||||||
|
while self.run:
|
||||||
|
result = self.device.readStream(self.stream, [self.buffer], Radio.SAMPLES)
|
||||||
|
|
||||||
|
if result.ret < 1:
|
||||||
|
print('Stream read failed, exiting.', file=sys.stderr)
|
||||||
|
self.keep_going = False
|
||||||
|
|
||||||
|
read_size = int(result.ret * 2)
|
||||||
|
self.demod.stdin.write(
|
||||||
|
struct.pack(PACKINGS[Radio.FORMAT] % read_size,
|
||||||
|
*self.buffer[:read_size])
|
||||||
|
)
|
||||||
|
|
||||||
|
self._cleanup_stream()
|
||||||
|
|
||||||
|
def _init_stream(self):
|
||||||
|
self.playback = subprocess.Popen(
|
||||||
|
['/usr/bin/sox', '-t', 'raw', '-r', '32000', '-b', '16', '-c', '2', '-L', '-e', 'signed-integer', '-', '-d'],
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.DEVNULL
|
||||||
|
)
|
||||||
|
|
||||||
|
self.demod = subprocess.Popen(
|
||||||
|
['/usr/bin/python3', 'fm_demod.py', '-f', 'CS16', '-s', '384k', '-d', '32k'],
|
||||||
|
stdin=subprocess.PIPE,
|
||||||
|
stdout=self.playback.stdin,
|
||||||
|
stderr=subprocess.DEVNULL
|
||||||
|
)
|
||||||
|
|
||||||
|
self.buffer = np.array([0] * Radio.SAMPLES * 2, TYPES[Radio.FORMAT])
|
||||||
|
self.stream = self.device.setupStream(soapy.SOAPY_SDR_RX, FORMATS[Radio.FORMAT])
|
||||||
|
self.device.activateStream(self.stream)
|
||||||
|
|
||||||
def _cleanup_stream(self):
|
def _cleanup_stream(self):
|
||||||
#shutdown the stream
|
# Cleanup the streaming objects in the reverse order to the _init method.
|
||||||
self.device.deactivateStream(self.stream)
|
self.device.deactivateStream(self.stream)
|
||||||
self.device.closeStream(self.stream)
|
self.device.closeStream(self.stream)
|
||||||
|
self.buffer = None
|
||||||
|
|
||||||
|
self.demod.kill()
|
||||||
|
self.playback.kill()
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Quick and dirty test of the Radio class.
|
||||||
|
"""
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import time
|
||||||
|
|
||||||
|
sdr = Radio({'driver': 'sdrplay'})
|
||||||
|
|
||||||
|
print('Configuring...')
|
||||||
|
sdr.configure('105.5M')
|
||||||
|
print('Configured.')
|
||||||
|
|
||||||
|
print('Starting stream...')
|
||||||
|
sdr.start_stream()
|
||||||
|
print('Stream started.')
|
||||||
|
|
||||||
|
# Let the stream play for a while
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
print('Ending stream...')
|
||||||
|
sdr.end_stream()
|
||||||
|
print('Stream ended.')
|
||||||
Loading…
Reference in New Issue
Block a user