diff --git a/broadcasters/__init__.py b/broadcasters/__init__.py index f21e78f..7cd0024 100644 --- a/broadcasters/__init__.py +++ b/broadcasters/__init__.py @@ -20,6 +20,7 @@ def start_outputs(system_queue, demo_output_queue): mqtt_q = Queue() + # TODO: Why do we pass system_queue to start_processing_output? mqtt_runner = mqtt.start_processing_output(system_queue, mqtt_q) logger.info("...done") except ValueError as e: @@ -38,10 +39,23 @@ def start_outputs(system_queue, demo_output_queue): logger.warning("Unable to import modules necessary to run MQTT output.") logger.warning("Program will continue to run without this output.") + logger.info("Loading sound output...") + from . import sound + + sound_q = Queue() + + # TODO: Why do we pass system_queue to start_processing_output? + sound_runner = sound.start_processing_output(system_queue, sound_q) + logger.info("...done") + while True: for payload in utils.get_all_from_queue(demo_output_queue): if mqtt_runner: mqtt_q.put(payload) next(mqtt_runner) + if sound_runner: + sound_q.put(payload) + next(sound_runner) + yield diff --git a/broadcasters/broadcast_message.py b/broadcasters/broadcast_message.py new file mode 100644 index 0000000..9e528c9 --- /dev/null +++ b/broadcasters/broadcast_message.py @@ -0,0 +1,20 @@ +from dataclasses import dataclass + + +@dataclass +class BroadcastSoundMessage: + """ + A dataclass to hold a broadcast message. + """ + + file: str + # channel: int + + +@dataclass +class BroadcastTextMessage: + """ + A dataclass to hold a broadcast message. + """ + + text: str diff --git a/broadcasters/mqtt.py b/broadcasters/mqtt.py index 1dba706..4cdf1f4 100644 --- a/broadcasters/mqtt.py +++ b/broadcasters/mqtt.py @@ -10,8 +10,8 @@ def start_processing_output(system_queue, mqtt_q): Called by the broadcaster module to initialize a connection to the desired MQTT broker. Args: - system_queue (Queue): The queue to put system output events in. - mqtt_q (Queue): The queue to put MQTT messages in. + system_queue (Queue): The queue to put system output events out. + mqtt_q (Queue): The queue to put MQTT messages out. """ def on_connect(client, userdata, flags, rc): @@ -67,6 +67,7 @@ def process(): client.loop(timeout=0.01) for item in utils.get_all_from_queue(mqtt_q): + # TODO: Only publish messages that this broadcaster cares about client.publish( "byu_sss/output", payload=str(item), diff --git a/broadcasters/sound.py b/broadcasters/sound.py new file mode 100644 index 0000000..0e4d7ae --- /dev/null +++ b/broadcasters/sound.py @@ -0,0 +1,37 @@ +from pathlib import Path + +from loguru import logger +from pygame import mixer + +from . import utils +from .broadcast_message import BroadcastSoundMessage + + +def start_processing_output(system_queue, sound_q): + """ + Called by the broadcaster module to initialize a connection to the desired MQTT broker. + + Args: + system_queue (Queue): The queue to put system output events out. + sound_q (Queue): The queue to put sound messages out. + """ + + sound_path = Path("sounds") + mixer.init() + + while True: + for item in utils.get_all_from_queue(sound_q): + # Filter out things that the sound broadcaster doesn't care about + if not isinstance(item, BroadcastSoundMessage): + continue + + logger.debug("Playing sound: {}", item.file) + + sound_file = sound_path / item.file + if not sound_file.exists(): + logger.error("Sound file does not exist: {}", sound_file) + continue + + mixer.Sound(str(sound_file)).play() + + yield diff --git a/demos/sound/main.py b/demos/sound/main.py new file mode 100644 index 0000000..02e92c2 --- /dev/null +++ b/demos/sound/main.py @@ -0,0 +1,72 @@ +from loguru import logger + +from broadcasters.broadcast_message import BroadcastSoundMessage +from demos.utils import get_all_from_queue +from display.segment_display import SegmentDisplay + + +class Sound: + """ + This demo shows developers how to use the sound broadcaster to play + sounds. This is not a very interesting demo and is not designed to be used + in kiosk mode. + """ + + demo_time = None + + def __init__(self, input_queue, output_queue, screen): + """ + Constructor + + Args: + input_queue (Queue): Queue to receive messages from the main thread + output_queue (Queue): Queue to send messages to the main thread + screen (Screen): Surface to draw on + """ + self.frame_rate = 30 + + self.input_queue = input_queue + self.output_queue = output_queue + self.screen = screen + + self.display = SegmentDisplay(self.screen) + + self.density = 15 + self.rain_length = 2 + + def run(self): + """Main loop""" + + self.screen.draw_text(5, 6, "Press a button to play sound".upper()) + self.display.draw() + yield + + while True: + for item in get_all_from_queue(self.input_queue): + logger.debug("Received: {}", item) + sound = None + + if item == "LEFT_P": + sound = "Menu_Navigate_00.wav" + elif item == "RIGHT_P": + sound = "Menu_Navigate_01.wav" + elif item == "UP_P": + sound = "Menu_Navigate_02.wav" + elif item == "DOWN_P": + sound = "Menu_Navigate_03.wav" + + if sound is None: + yield + continue + + self.display.undraw() + self.screen.draw_text(5, 6, "Playing sound {}".format(sound).upper()) + self.display.draw() + self.output_queue.put(BroadcastSoundMessage(file=sound)) + yield + + yield + + def stop(self): + """Stop the thread""" + pass diff --git a/sounds/Menu_Navigate_00.wav b/sounds/Menu_Navigate_00.wav new file mode 100644 index 0000000..d36ee07 Binary files /dev/null and b/sounds/Menu_Navigate_00.wav differ diff --git a/sounds/Menu_Navigate_01.wav b/sounds/Menu_Navigate_01.wav new file mode 100644 index 0000000..d05a235 Binary files /dev/null and b/sounds/Menu_Navigate_01.wav differ diff --git a/sounds/Menu_Navigate_02.wav b/sounds/Menu_Navigate_02.wav new file mode 100644 index 0000000..c043843 Binary files /dev/null and b/sounds/Menu_Navigate_02.wav differ diff --git a/sounds/Menu_Navigate_03.wav b/sounds/Menu_Navigate_03.wav new file mode 100644 index 0000000..0b3d4aa Binary files /dev/null and b/sounds/Menu_Navigate_03.wav differ