restructuring
This commit is contained in:
0
docker/docker-compose.yaml
Normal file
0
docker/docker-compose.yaml
Normal file
@@ -7,15 +7,16 @@ dependencies = [
|
|||||||
"bumble @ git+ssh://git@ssh.pstruebi.xyz:222/auracaster/bumble_mirror.git@12bcdb7770c0d57a094bc0a96cd52e701f97fece",
|
"bumble @ git+ssh://git@ssh.pstruebi.xyz:222/auracaster/bumble_mirror.git@12bcdb7770c0d57a094bc0a96cd52e701f97fece",
|
||||||
"lc3 @ git+ssh://git@ssh.pstruebi.xyz:222/auracaster/liblc3.git@7558637303106c7ea971e7bb8cedf379d3e08bcc",
|
"lc3 @ git+ssh://git@ssh.pstruebi.xyz:222/auracaster/liblc3.git@7558637303106c7ea971e7bb8cedf379d3e08bcc",
|
||||||
"sounddevice",
|
"sounddevice",
|
||||||
"aioconsole"
|
"aioconsole",
|
||||||
|
"quart == 0.20.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
test = [
|
test = [
|
||||||
"pytest >= 8.2",
|
"pytest >= 8.2",
|
||||||
|
"pytest-asyncio"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools>=61", "wheel", "setuptools_scm>=8"]
|
requires = ["setuptools>=61"] #, "wheel", "setuptools_scm>=8"
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|||||||
0
src/auracast/__init__.py
Normal file
0
src/auracast/__init__.py
Normal file
@@ -66,7 +66,7 @@ broadcast_de = AuracastBigConfig(
|
|||||||
name = 'Broadcast0',
|
name = 'Broadcast0',
|
||||||
language='deu',
|
language='deu',
|
||||||
program_info = 'Announcements German',
|
program_info = 'Announcements German',
|
||||||
audio_source = 'file:./auracast/testdata/announcement_de.wav',
|
audio_source = 'file:./testdata/announcement_de.wav',
|
||||||
)
|
)
|
||||||
|
|
||||||
broadcast_en = AuracastBigConfig(
|
broadcast_en = AuracastBigConfig(
|
||||||
@@ -75,7 +75,7 @@ broadcast_en = AuracastBigConfig(
|
|||||||
name = 'Broadcast1',
|
name = 'Broadcast1',
|
||||||
language='eng',
|
language='eng',
|
||||||
program_info = 'Announcements English',
|
program_info = 'Announcements English',
|
||||||
audio_source = 'file:./auracast/testdata/announcement_en.wav',
|
audio_source = 'file:./testdata/announcement_en.wav',
|
||||||
)
|
)
|
||||||
|
|
||||||
broadcast_fr = AuracastBigConfig(
|
broadcast_fr = AuracastBigConfig(
|
||||||
@@ -84,7 +84,7 @@ broadcast_fr = AuracastBigConfig(
|
|||||||
name = 'Broadcast2',
|
name = 'Broadcast2',
|
||||||
language='fra',
|
language='fra',
|
||||||
program_info = 'Announcements French',
|
program_info = 'Announcements French',
|
||||||
audio_source = 'file:./auracast/testdata/announcement_fr.wav',
|
audio_source = 'file:./testdata/announcement_fr.wav',
|
||||||
)
|
)
|
||||||
|
|
||||||
broadcast_es = AuracastBigConfig(
|
broadcast_es = AuracastBigConfig(
|
||||||
@@ -93,7 +93,7 @@ broadcast_es = AuracastBigConfig(
|
|||||||
name = 'Broadcast3',
|
name = 'Broadcast3',
|
||||||
language='spa',
|
language='spa',
|
||||||
program_info = 'Announcements Spanish',
|
program_info = 'Announcements Spanish',
|
||||||
audio_source = 'file:./auracast/testdata/announcement_es.wav',
|
audio_source = 'file:./testdata/announcement_es.wav',
|
||||||
)
|
)
|
||||||
|
|
||||||
broadcast_it = AuracastBigConfig(
|
broadcast_it = AuracastBigConfig(
|
||||||
@@ -102,5 +102,5 @@ broadcast_it = AuracastBigConfig(
|
|||||||
name = 'Broadcast4',
|
name = 'Broadcast4',
|
||||||
language='ita',
|
language='ita',
|
||||||
program_info = 'Announcements Italian',
|
program_info = 'Announcements Italian',
|
||||||
audio_source = 'file:./auracast/testdata/announcement_it.wav',
|
audio_source = 'file:./testdata/announcement_it.wav',
|
||||||
)
|
)
|
||||||
@@ -26,7 +26,6 @@ import struct
|
|||||||
from typing import cast, Any, AsyncGenerator, Coroutine, Dict, Optional, Tuple, List
|
from typing import cast, Any, AsyncGenerator, Coroutine, Dict, Optional, Tuple, List
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import lc3 # type: ignore # pylint: disable=E0401
|
import lc3 # type: ignore # pylint: disable=E0401
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
@@ -48,6 +47,7 @@ from bumble.device import Host, BIGInfoAdvertisement, AdvertisingChannelMap
|
|||||||
from bumble.audio import io as audio_io
|
from bumble.audio import io as audio_io
|
||||||
|
|
||||||
from auracast import auracast_config
|
from auracast import auracast_config
|
||||||
|
from auracast.utils.read_lc3_file import read_lc3_file
|
||||||
|
|
||||||
|
|
||||||
# modified from bumble
|
# modified from bumble
|
||||||
@@ -95,35 +95,6 @@ class ModWaveAudioInput(audio_io.ThreadedAudioInput):
|
|||||||
audio_io.WaveAudioInput = ModWaveAudioInput
|
audio_io.WaveAudioInput = ModWaveAudioInput
|
||||||
|
|
||||||
|
|
||||||
def read_lc3_file(filepath):
|
|
||||||
filepath = filepath.replace('file:', '')
|
|
||||||
with open(filepath, 'rb') as f_lc3:
|
|
||||||
header = struct.unpack('=HHHHHHHI', f_lc3.read(18))
|
|
||||||
if header[0] != 0xcc1c:
|
|
||||||
raise ValueError('Invalid bitstream file')
|
|
||||||
|
|
||||||
# found in liblc3 - decoder.py
|
|
||||||
samplerate = header[2] * 100
|
|
||||||
nchannels = header[4]
|
|
||||||
frame_duration = header[5] * 10
|
|
||||||
stream_length = header[7]
|
|
||||||
#lc3_frame_size = struct.unpack('=H', f_lc3.read(2))[0]
|
|
||||||
logging.info('Loaded lc3 file: %s', filepath)
|
|
||||||
logging.info('samplerate: %s', samplerate)
|
|
||||||
logging.info('nchannels %s', nchannels)
|
|
||||||
logging.info('frame_duration %s', frame_duration)
|
|
||||||
logging.info('stream_length %s', stream_length)
|
|
||||||
|
|
||||||
lc3_bytes= b''
|
|
||||||
while True:
|
|
||||||
b = f_lc3.read(2)
|
|
||||||
if b == b'':
|
|
||||||
break
|
|
||||||
lc3_frame_size = struct.unpack('=H', b)[0]
|
|
||||||
lc3_bytes += f_lc3.read(lc3_frame_size)
|
|
||||||
|
|
||||||
return lc3_bytes
|
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Logging
|
# Logging
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
@@ -318,51 +289,6 @@ async def init_broadcast(
|
|||||||
|
|
||||||
return bigs
|
return bigs
|
||||||
|
|
||||||
async def init_audio(
|
|
||||||
bigs,
|
|
||||||
global_config : auracast_config.AuracastGlobalConfig,
|
|
||||||
big_config: List[auracast_config.AuracastBigConfig]
|
|
||||||
):
|
|
||||||
for i, big in enumerate(bigs.values()):
|
|
||||||
audio_source = big_config[i].audio_source
|
|
||||||
input_format = big_config[i].input_format
|
|
||||||
|
|
||||||
if big_config[i].audio_source.endswith('.lc3'):
|
|
||||||
pass
|
|
||||||
elif big_config[i].precode_wav:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
audio_input = await audio_io.create_audio_input(audio_source, input_format)
|
|
||||||
|
|
||||||
audio_input.rewind = big_config[i].loop
|
|
||||||
pcm_format = await audio_input.open()
|
|
||||||
|
|
||||||
#try:
|
|
||||||
if pcm_format.channels != 1:
|
|
||||||
print("Only 1 channels PCM configurations are supported")
|
|
||||||
return
|
|
||||||
if pcm_format.sample_type == audio_io.PcmFormat.SampleType.INT16:
|
|
||||||
pcm_bit_depth = 16
|
|
||||||
elif pcm_format.sample_type == audio_io.PcmFormat.SampleType.FLOAT32:
|
|
||||||
pcm_bit_depth = None
|
|
||||||
else:
|
|
||||||
print("Only INT16 and FLOAT32 sample types are supported")
|
|
||||||
return
|
|
||||||
encoder = lc3.Encoder(
|
|
||||||
frame_duration_us=global_config.frame_duration_us,
|
|
||||||
sample_rate_hz=global_config.auracast_sampling_rate_hz,
|
|
||||||
num_channels=1,
|
|
||||||
input_sample_rate_hz=pcm_format.sample_rate,
|
|
||||||
)
|
|
||||||
lc3_frame_samples = encoder.get_frame_samples() # number of the pcm samples per lc3 frame
|
|
||||||
lc3_frame_size = global_config.octets_per_frame #encoder.get_frame_bytes(bitrate)
|
|
||||||
lc3_bytes_per_frame = lc3_frame_size #* 2 #multiplied by number of channels
|
|
||||||
|
|
||||||
big['pcm_bit_depth'] = pcm_bit_depth
|
|
||||||
big['lc3_bytes_per_frame'] = lc3_bytes_per_frame
|
|
||||||
big['lc3_frame_samples'] = lc3_frame_samples
|
|
||||||
big['audio_input'] = audio_input
|
|
||||||
big['encoder'] = encoder
|
|
||||||
|
|
||||||
class Streamer():
|
class Streamer():
|
||||||
"""
|
"""
|
||||||
@@ -563,10 +489,13 @@ async def broadcast(global_conf: auracast_config.AuracastGlobalConfig, big_conf:
|
|||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
import os
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.DEBUG,
|
level=logging.DEBUG,
|
||||||
format='%(module)s.py:%(lineno)d %(levelname)s: %(message)s'
|
format='%(module)s.py:%(lineno)d %(levelname)s: %(message)s'
|
||||||
)
|
)
|
||||||
|
os.chdir(os.path.dirname(__file__))
|
||||||
|
|
||||||
global_conf = auracast_config.global_base_config
|
global_conf = auracast_config.global_base_config
|
||||||
|
|
||||||
@@ -29,7 +29,15 @@ class Multicaster:
|
|||||||
self.big_conf = big_conf
|
self.big_conf = big_conf
|
||||||
self.device = None
|
self.device = None
|
||||||
self.bigs = None
|
self.bigs = None
|
||||||
self.streamer=None
|
self.streamer = None
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
streaming = self.streamer.is_streaming if self.streamer is not None else False
|
||||||
|
return {
|
||||||
|
'is_initialized': self.is_auracast_init,
|
||||||
|
'is_streaming': streaming,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def init_broadcast(self):
|
async def init_broadcast(self):
|
||||||
self.device_acm = multicast.create_device(self.global_conf)
|
self.device_acm = multicast.create_device(self.global_conf)
|
||||||
@@ -45,21 +53,14 @@ class Multicaster:
|
|||||||
self.device = device
|
self.device = device
|
||||||
self.is_auracast_init = True
|
self.is_auracast_init = True
|
||||||
|
|
||||||
async def init_audio(self):
|
|
||||||
await multicast.init_audio(
|
|
||||||
self.bigs,
|
|
||||||
self.global_conf,
|
|
||||||
self.big_conf
|
|
||||||
)
|
|
||||||
self.is_audio_init = True
|
|
||||||
self.streamer = multicast.Streamer(self.bigs)
|
|
||||||
|
|
||||||
def start_streaming(self):
|
def start_streaming(self):
|
||||||
|
self.streamer = multicast.Streamer(self.bigs, self.global_conf, self.big_conf)
|
||||||
self.streamer.start_streaming()
|
self.streamer.start_streaming()
|
||||||
|
|
||||||
def stop_streaming(self):
|
def stop_streaming(self):
|
||||||
if self.streamer is not None:
|
if self.streamer is not None:
|
||||||
self.streamer.stop_streaming()
|
self.streamer.stop_streaming()
|
||||||
|
self.streamer = None
|
||||||
|
|
||||||
async def reset(self):
|
async def reset(self):
|
||||||
await self.shutdown() # Manually triggering teardown
|
await self.shutdown() # Manually triggering teardown
|
||||||
@@ -74,10 +75,10 @@ class Multicaster:
|
|||||||
for big in self.bigs.values():
|
for big in self.bigs.values():
|
||||||
if big['advertising_set']:
|
if big['advertising_set']:
|
||||||
await big['advertising_set'].stop()
|
await big['advertising_set'].stop()
|
||||||
|
|
||||||
await self.device_acm.__aexit__(None, None, None) # Manually triggering teardown
|
await self.device_acm.__aexit__(None, None, None) # Manually triggering teardown
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# example commandline ui
|
# example commandline ui
|
||||||
async def command_line_ui(caster: Multicaster):
|
async def command_line_ui(caster: Multicaster):
|
||||||
while True:
|
while True:
|
||||||
@@ -100,7 +101,6 @@ async def command_line_ui(caster: Multicaster):
|
|||||||
await caster.reset()
|
await caster.reset()
|
||||||
await caster.init_broadcast()
|
await caster.init_broadcast()
|
||||||
await caster.init_audio()
|
await caster.init_audio()
|
||||||
|
|
||||||
elif command.strip().lower() == "init_audio":
|
elif command.strip().lower() == "init_audio":
|
||||||
await caster.init_audio()
|
await caster.init_audio()
|
||||||
|
|
||||||
@@ -139,7 +139,6 @@ async def main():
|
|||||||
|
|
||||||
caster = Multicaster(global_conf, big_conf)
|
caster = Multicaster(global_conf, big_conf)
|
||||||
await caster.init_broadcast()
|
await caster.init_broadcast()
|
||||||
await caster.init_audio()
|
|
||||||
|
|
||||||
await command_line_ui(caster)
|
await command_line_ui(caster)
|
||||||
|
|
||||||
34
src/auracast/multicast_control_client.py
Normal file
34
src/auracast/multicast_control_client.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
BASE_URL = "http://127.0.0.1:5000" # Adjust based on your actual API URL
|
||||||
|
|
||||||
|
def initialize():
|
||||||
|
response = requests.post(f"{BASE_URL}/init")
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def shutdown():
|
||||||
|
response = requests.post(f"{BASE_URL}/shutdown")
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def stop_audio():
|
||||||
|
response = requests.post(f"{BASE_URL}/stop_audio")
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def send_audio():
|
||||||
|
audio_data = {
|
||||||
|
"broadcast_de": "test_audio_data_de",
|
||||||
|
"broadcast_fr": "test_audio_data_fr"
|
||||||
|
}
|
||||||
|
response = requests.post(f"{BASE_URL}/stream_lc3", json=audio_data)
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_status():
|
||||||
|
response = requests.get(f"{BASE_URL}/status")
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("Initializing server:", initialize())
|
||||||
|
print("Sending audio:", send_audio())
|
||||||
|
print("Getting status:", get_status())
|
||||||
|
print("Stopping audio:", stop_audio())
|
||||||
|
print("Shutting down:", shutdown())
|
||||||
92
src/auracast/multicast_server.py
Normal file
92
src/auracast/multicast_server.py
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
from dataclasses import asdict
|
||||||
|
from quart import Quart, request, jsonify # TODO: evalute if classic flask should be used instead
|
||||||
|
from auracast import multicast_control
|
||||||
|
from auracast import auracast_config
|
||||||
|
|
||||||
|
app = Quart(__name__)
|
||||||
|
|
||||||
|
# Initialize the multicaster instance globally
|
||||||
|
global_conf = auracast_config.global_base_config
|
||||||
|
#global_conf.transport='serial:/dev/serial/by-id/usb-SEGGER_J-Link_001057705357-if02,1000000,rtscts' # transport for nrf54l15dk
|
||||||
|
global_conf.transport='serial:/dev/serial/by-id/usb-ZEPHYR_Zephyr_HCI_UART_sample_81BD14B8D71B5662-if00,115200,rtscts' #nrf52dongle hci_uart usb cdc
|
||||||
|
|
||||||
|
big_conf = { # TODO: use another dataclass for this to be able to iterate over the names
|
||||||
|
'broadcast_de': auracast_config.broadcast_de,
|
||||||
|
'broadcast_en': auracast_config.broadcast_en,
|
||||||
|
'broadcast_fr': auracast_config.broadcast_fr,
|
||||||
|
#auracast_config.broadcast_es,
|
||||||
|
#auracast_config.broadcast_it,
|
||||||
|
}
|
||||||
|
for conf in big_conf.values():
|
||||||
|
conf.loop = False
|
||||||
|
|
||||||
|
multicaster = multicast_control.Multicaster(
|
||||||
|
global_conf,
|
||||||
|
list(big_conf.values()),
|
||||||
|
)
|
||||||
|
|
||||||
|
@app.route('/init', methods=['POST'])
|
||||||
|
async def initialize():
|
||||||
|
"""Initializes the broadcasters."""
|
||||||
|
#data = await request.json
|
||||||
|
#global_conf = auracast_config.AuracastGlobalConfig.from_dict(data['global_config'])
|
||||||
|
#stream_configs = [auracast_config.AuracastBigConfig.from_dict(big) for big in data['big_configs']]
|
||||||
|
try:
|
||||||
|
await multicaster.init_broadcast()
|
||||||
|
return jsonify({"status": "initialized"}), 200
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
@app.route('/shutdown', methods=['POST'])
|
||||||
|
async def stop():
|
||||||
|
"""Stops broadcasting."""
|
||||||
|
try:
|
||||||
|
await multicaster.reset()
|
||||||
|
return jsonify({"status": "stopped"}), 200
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
@app.route('/stop_audio', methods=['POST'])
|
||||||
|
async def stop_audio():
|
||||||
|
"""Stops streaming."""
|
||||||
|
try:
|
||||||
|
multicaster.stop_streaming()
|
||||||
|
return jsonify({"status": "stopped"}), 200
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
|
||||||
|
@app.route('/stream_lc3', methods=['POST'])
|
||||||
|
async def send_audio():
|
||||||
|
"""Streams pre-coded LC3 audio.
|
||||||
|
# post data in the format
|
||||||
|
{
|
||||||
|
broadcast_de: b''
|
||||||
|
broadcast_fr: b''
|
||||||
|
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
post_data = await request.json
|
||||||
|
try:
|
||||||
|
for key, val in big_conf.items():
|
||||||
|
if key in post_data:
|
||||||
|
val.audio_source = post_data['key']
|
||||||
|
else:
|
||||||
|
val.audio_source = b''
|
||||||
|
|
||||||
|
multicaster.big_conf = list(big_conf.values())
|
||||||
|
multicaster.start_streaming()
|
||||||
|
return jsonify({"status": "audio_sent"}), 200
|
||||||
|
except Exception as e:
|
||||||
|
return jsonify({"error": str(e)}), 500
|
||||||
|
# TODO: Also a queue should be implemented - probably as its own endpoint,
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/status', methods=['GET'])
|
||||||
|
async def get_status():
|
||||||
|
"""Gets the current status of the multicaster."""
|
||||||
|
status = multicaster.get_status()
|
||||||
|
# TODO: also get queue status, announcements, samples etc.
|
||||||
|
return jsonify({"status": status}), 200
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||||
0
src/auracast/utils/__init__.py
Normal file
0
src/auracast/utils/__init__.py
Normal file
32
src/auracast/utils/read_lc3_file.py
Normal file
32
src/auracast/utils/read_lc3_file.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import logging
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
|
def read_lc3_file(filepath):
|
||||||
|
filepath = filepath.replace('file:', '')
|
||||||
|
with open(filepath, 'rb') as f_lc3:
|
||||||
|
header = struct.unpack('=HHHHHHHI', f_lc3.read(18))
|
||||||
|
if header[0] != 0xcc1c:
|
||||||
|
raise ValueError('Invalid bitstream file')
|
||||||
|
|
||||||
|
# found in liblc3 - decoder.py
|
||||||
|
samplerate = header[2] * 100
|
||||||
|
nchannels = header[4]
|
||||||
|
frame_duration = header[5] * 10
|
||||||
|
stream_length = header[7]
|
||||||
|
#lc3_frame_size = struct.unpack('=H', f_lc3.read(2))[0]
|
||||||
|
logging.info('Loaded lc3 file: %s', filepath)
|
||||||
|
logging.info('samplerate: %s', samplerate)
|
||||||
|
logging.info('nchannels %s', nchannels)
|
||||||
|
logging.info('frame_duration %s', frame_duration)
|
||||||
|
logging.info('stream_length %s', stream_length)
|
||||||
|
|
||||||
|
lc3_bytes= b''
|
||||||
|
while True:
|
||||||
|
b = f_lc3.read(2)
|
||||||
|
if b == b'':
|
||||||
|
break
|
||||||
|
lc3_frame_size = struct.unpack('=H', b)[0]
|
||||||
|
lc3_bytes += f_lc3.read(lc3_frame_size)
|
||||||
|
|
||||||
|
return lc3_bytes
|
||||||
71
tests/test_server.py
Normal file
71
tests/test_server.py
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import pytest
|
||||||
|
import asyncio
|
||||||
|
from quart import jsonify
|
||||||
|
from auracast import multicast_server
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def client():
|
||||||
|
"""Fixture to create and return a Quart test client."""
|
||||||
|
yield multicast_server.app.test_client()
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_initialize(client):
|
||||||
|
"""Tests the /init endpoint."""
|
||||||
|
#client = multicast_server.app.test_client()
|
||||||
|
response = await client.post('/init')
|
||||||
|
json_data = await response.get_json()
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert json_data["status"] == "initialized"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_shutdown(client):
|
||||||
|
"""Tests the /shutdown endpoint."""
|
||||||
|
response = await client.post('/shutdown')
|
||||||
|
json_data = await response.get_json()
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert json_data["status"] == "stopped"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_stop_audio(client):
|
||||||
|
"""Tests the /stop_audio endpoint."""
|
||||||
|
response = await client.post('/stop_audio')
|
||||||
|
json_data = await response.get_json()
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert json_data["status"] == "stopped"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_send_audio(client):
|
||||||
|
"""Tests the /stream_lc3 endpoint."""
|
||||||
|
test_audio_data = {
|
||||||
|
"broadcast_de": read_lc3_file(big.audio_source),
|
||||||
|
"broadcast_fr": b"test_audio_data_fr"
|
||||||
|
}
|
||||||
|
|
||||||
|
response = await client.post('/stream_lc3', json=test_audio_data)
|
||||||
|
json_data = await response.get_json()
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert json_data["status"] == "audio_sent"
|
||||||
|
|
||||||
|
# Ensure the audio data is correctly assigned
|
||||||
|
for key, val in multicast_server.big_conf.items():
|
||||||
|
if key in test_audio_data:
|
||||||
|
assert val.audio_source == test_audio_data[key]
|
||||||
|
else:
|
||||||
|
assert val.audio_source == b""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_get_status(client):
|
||||||
|
"""Tests the /status endpoint."""
|
||||||
|
response = await client.get('/status')
|
||||||
|
json_data = await response.get_json()
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert "status" in json_data
|
||||||
Reference in New Issue
Block a user