def start(self, config_lock, notification_queue_in, notification_queue_out,
              effect_queue, audio_queue):

        self._config_lock = config_lock
        self._config = ConfigService.instance(self._config_lock).config

        self._notification_queue_in = notification_queue_in
        self._notification_queue_out = notification_queue_out
        self._effect_queue = effect_queue
        print("Effect queue id DeviceManager " + str(id(self._effect_queue)))
        self._audio_queue = audio_queue

        #Init FPS Limiter
        self._fps_limiter = FPSLimiter(200)

        self._skip_routine = False
        self._devices = {}
        self.init_devices()
        self.start_devices()

        self.start_time = time.time()
        self.ten_seconds_counter = time.time()

        while True:
            self.routine()
    def start(self, config_lock, notification_queue_in, notification_queue_out,
              effect_queue, audio_queue):
        self.logger = logging.getLogger(__name__)

        self._config_lock = config_lock
        self._config = ConfigService.instance(self._config_lock).config

        self._notification_queue_in = QueueWrapper(notification_queue_in)
        self._notification_queue_out = QueueWrapper(notification_queue_out)
        self._effect_queue = QueueWrapper(effect_queue)
        self._audio_queue = QueueWrapper(audio_queue)

        # Init FPS Limiter.
        self._fps_limiter = FPSLimiter(120)

        self._skip_routine = False
        self._devices = {}
        self.init_devices()
        self.start_devices()

        self.start_time = time()
        self.ten_seconds_counter = time()

        while True:
            try:
                self.routine()
            except KeyboardInterrupt:
                break
    def refresh(self):
        self.logger.debug("Refreshing effects...")
        self._initialized_effects = {}

        self._fps_limiter = FPSLimiter(self._device.device_config["FPS"])

        # Notify the master component, that I'm finished.
        self._device.device_notification_queue_out.put(
            NotificationEnum.config_refresh_finished)
        self.logger.debug("Effects refreshed.")
    def start(self, device):
        self.logger = logging.getLogger(__name__)

        self._device = device
        self._led_strip = self._device.device_config["led_strip"]

        self.logger.info(
            f'Starting Output service... Device: {self._device.device_config["device_name"]}'
        )

        # Initial config load.
        self._config = self._device.config

        self._output_queue = self._device.output_queue
        self._device_notification_queue_in = self._device.device_notification_queue_in
        self._device_notification_queue_out = self._device.device_notification_queue_out

        self.ten_seconds_counter = time()
        self.sec_ten_seconds_counter = time()
        self.start_time = time()

        # Init FPS Limiter.
        self._fps_limiter = FPSLimiter(self._device.device_config["fps"])

        self._skip_output = False
        self._cancel_token = False

        self._available_outputs = {
            OutputsEnum.output_dummy: OutputDummy,
            OutputsEnum.output_raspi: OutputRaspi,
            OutputsEnum.output_udp: OutputUDP
        }

        current_output_enum = OutputsEnum[
            self._device.device_config["output_type"]]
        self.logger.debug(f"Found output: {current_output_enum}")
        self._current_output = self._available_outputs[current_output_enum](
            self._device)

        self.logger.debug(
            f'Output component started. Device: {self._device.device_config["device_name"]}'
        )

        while not self._cancel_token:
            try:
                self.output_routine()
            except KeyboardInterrupt:
                break
Пример #5
0
    def start(self, device):
        self._device = device

        print("Starting Output service.. Device: " +
              self._device.device_config["DEVICE_NAME"])

        # Initial config load.
        self._config = self._device.config

        self._output_queue = self._device.output_queue
        self._device_notification_queue_in = self._device.device_notification_queue_in
        self._device_notification_queue_out = self._device.device_notification_queue_out

        self.ten_seconds_counter = time.time()
        self.sec_ten_seconds_counter = time.time()
        self.start_time = time.time()

        #Init FPS Limiter
        self._fps_limiter = FPSLimiter(self._device.device_config["FPS"])

        self._skip_output = False
        self._cancel_token = False

        self._available_outputs = {
            OutputsEnum.output_dummy: OutputDummy,
            OutputsEnum.output_raspi: OutputRaspi,
            OutputsEnum.output_udp: OutputUDP
        }

        current_output_enum = OutputsEnum[
            self._device.device_config["OUTPUT_TYPE"]]
        print("Found output: " + str(current_output_enum))
        self._current_output = self._available_outputs[current_output_enum](
            self._device)

        print("Output component started. Device: " +
              self._device.device_config["DEVICE_NAME"])

        while not self._cancel_token:
            self.output_routine()
class OutputService():
    def start(self, device):
        self._device = device

        print(f'Starting Output service... Device: {self._device.device_config["DEVICE_NAME"]}')

        # Initial config load.
        self._config = self._device.config

        self._output_queue = self._device.output_queue
        self._device_notification_queue_in = self._device.device_notification_queue_in
        self._device_notification_queue_out = self._device.device_notification_queue_out

        self.ten_seconds_counter = time.time()
        self.sec_ten_seconds_counter = time.time()
        self.start_time = time.time()

        # Init FPS Limiter.
        self._fps_limiter = FPSLimiter(self._device.device_config["FPS"])

        self._skip_output = False
        self._cancel_token = False

        self._available_outputs = {
            OutputsEnum.output_dummy: OutputDummy,
            OutputsEnum.output_raspi: OutputRaspi,
            OutputsEnum.output_udp: OutputUDP
        }

        current_output_enum = OutputsEnum[self._device.device_config["OUTPUT_TYPE"]]
        print(f"Found output: {current_output_enum}")
        self._current_output = self._available_outputs[current_output_enum](self._device)

        print(f'Output component started. Device: {self._device.device_config["DEVICE_NAME"]}')

        while not self._cancel_token:
            self.output_routine()

    def output_routine(self):
        # Limit the fps to decrease lags caused by 100 percent CPU.
        self._fps_limiter.fps_limiter()

        # Check the nofitication queue.
        if not self._device_notification_queue_in.empty():
            self._current_notification_in = self._device_notification_queue_in.get()

        if hasattr(self, "_current_notification_in"):
            if self._current_notification_in is NotificationEnum.config_refresh:
                self.refresh()
            elif self._current_notification_in is NotificationEnum.process_continue:
                self._skip_output = False
            elif self._current_notification_in is NotificationEnum.process_pause:
                self._skip_output = True
            elif self._current_notification_in is NotificationEnum.process_stop:
                self.stop()

        # Reset the current in notification, to do it only one time.
        self._current_notification_in = None

        # Skip the output sequence, for example to "pause" the process.
        if self._skip_output:
            if not self._output_queue.empty():
                skip_output_queue = self._output_queue.get()
                del skip_output_queue
            return

        # Check if the queue is empty and stop if its empty.
        if not self._output_queue.empty():
            current_output_array = self._output_queue.get()
            self._current_output.show(current_output_array)

        self.end_time = time.time()

        if time.time() - self.ten_seconds_counter > 10:
            self.ten_seconds_counter = time.time()
            self.time_dif = self.end_time - self.start_time
            self.fps = 1 / self.time_dif
            print(f'Output Service | FPS: {self.fps} | Device: {self._device.device_config["DEVICE_NAME"]}')

        self.start_time = time.time()

    def stop(self):
        self._cancel_token = True
        self._current_output.clear()

    def refresh(self):
        print("Refreshing output...")

        # Refresh the config,
        self._config = self._device.config

        # Notify the master component, that I'm finished.
        self._device_notification_queue_out.put(NotificationEnum.config_refresh_finished)

        print("Output refreshed.")
Пример #7
0
    def init_audio_service(self, show_output=False):
        try:
            # Initial config load.
            ConfigService.instance(self._config_lock).load_config()
            self._config = ConfigService.instance(self._config_lock).config

            # Init FPS Limiter.
            self._fps_limiter = FPSLimiter(120)

            # Init pyaudio.
            self._py_audio = pyaudio.PyAudio()

            self._skip_routine = False

            self._numdevices = self._py_audio.get_device_count()
            self._default_device_id = self._py_audio.get_default_input_device_info()['index']
            self._devices = []

            self.log_output(show_output, logging.INFO, "Found the following audio sources:")

            # Select the audio device you want to use.
            selected_device_list_index = self._config["general_settings"]["DEVICE_ID"]

            # Check if the index is inside the list.
            foundMicIndex = False

            # For each audio device, add to list of devices.
            for i in range(0, self._numdevices):
                try:
                    device_info = self._py_audio.get_device_info_by_host_api_device_index(0, i)

                    if device_info["maxInputChannels"] >= 1:
                        self._devices.append(device_info)
                        self.log_output(show_output, logging.INFO, f'{device_info["index"]} - {device_info["name"]} - {device_info["defaultSampleRate"]}')

                        if device_info["index"] == selected_device_list_index:
                            foundMicIndex = True
                except Exception as e:
                    self.log_output(show_output, logging.ERROR, "Could not get device infos.")
                    self.logger.exception(f"Unexpected error in AudioProcessService: {e}")

            # Could not find a mic with the selected mic id, so I will use the first device I found.
            if not foundMicIndex:
                self.log_output(show_output, logging.ERROR, "********************************************************")
                self.log_output(show_output, logging.ERROR, "*                      Error                           *")
                self.log_output(show_output, logging.ERROR, "********************************************************")
                self.log_output(show_output, logging.ERROR, f"Could not find the mic with the id: {selected_device_list_index}")
                self.log_output(show_output, logging.ERROR, "Using the first mic as fallback.")
                self.log_output(show_output, logging.ERROR, "Please change the id of the mic inside the config.")
                selected_device_list_index = self._devices[0]["index"]

            for device in self._devices:
                if device["index"] == selected_device_list_index:
                    self.log_output(show_output, logging.INFO, f"Selected ID: {selected_device_list_index}")
                    self.log_output(show_output, logging.INFO, f'Using {device["index"]} - {device["name"]} - {device["defaultSampleRate"]}')
                    self._device_id = device["index"]
                    self._device_name = device["name"]
                    self._device_rate = self._config["general_settings"]["DEFAULT_SAMPLE_RATE"]
                    self._frames_per_buffer = self._config["general_settings"]["FRAMES_PER_BUFFER"]
                    self.n_fft_bins = self._config["general_settings"]["N_FFT_BINS"]

            self.start_time_1 = time()
            self.ten_seconds_counter_1 = time()
            self.start_time_2 = time()
            self.ten_seconds_counter_2 = time()

            self._dsp = DSP(self._config)

            self.audio = np.empty((self._frames_per_buffer), dtype="int16")

            # Reinit buffer queue
            self.audio_buffer_queue = Queue(2)

            # callback function to stream audio, another thread.
            def callback(in_data, frame_count, time_info, status):
                if self._skip_routine:
                    return (self.audio, pyaudio.paContinue)

                try:
                    self.audio_buffer_queue.put(in_data)
                except Exception as e:
                    pass

                self.end_time_1 = time()

                if time() - self.ten_seconds_counter_1 > 10:
                    self.ten_seconds_counter_1 = time()
                    time_dif = self.end_time_1 - self.start_time_1
                    fps = 1 / time_dif
                    self.logger.info(f"Callback | FPS: {fps:.2f}")

                self.start_time_1 = time()

                return (self.audio, pyaudio.paContinue)

            self.log_output(show_output, logging.DEBUG, "Starting Open Audio Stream...")
            self.stream = self._py_audio.open(
                format=pyaudio.paInt16,
                channels=1,
                rate=self._device_rate,
                input=True,
                input_device_index=self._device_id,
                frames_per_buffer=self._frames_per_buffer,
                stream_callback=callback
            )
        except Exception as e:
            self.logger.error("Could not init AudioService.")
            self.logger.exception(f"Unexpected error in init_audio_service: {e}")
class DeviceManager():
    def start(self, config_lock, notification_queue_in, notification_queue_out,
              effect_queue, audio_queue):
        self.logger = logging.getLogger(__name__)

        self._config_lock = config_lock
        self._config = ConfigService.instance(self._config_lock).config

        self._notification_queue_in = QueueWrapper(notification_queue_in)
        self._notification_queue_out = QueueWrapper(notification_queue_out)
        self._effect_queue = QueueWrapper(effect_queue)
        self._audio_queue = QueueWrapper(audio_queue)

        # Init FPS Limiter.
        self._fps_limiter = FPSLimiter(120)

        self._skip_routine = False
        self._devices = {}
        self.init_devices()
        self.start_devices()

        self.start_time = time()
        self.ten_seconds_counter = time()

        while True:
            try:
                self.routine()
            except KeyboardInterrupt:
                break

    def routine(self):
        # Check the effect queue.
        if not self._effect_queue.empty():
            current_effect_item = self._effect_queue.get_blocking()
            self.logger.debug(
                f"Device Manager received new effect: {current_effect_item.effect_enum} {current_effect_item.device_id}"
            )
            current_device = self._devices[current_effect_item.device_id]
            current_device.effect_queue.put_blocking(current_effect_item)

        if not self._notification_queue_in.empty():
            current_notification_item = self._notification_queue_in.get_blocking(
            )
            self.logger.debug(
                f"Device Manager received new notification: {current_notification_item.notification_enum} - {current_notification_item.device_id}"
            )

            if current_notification_item.notification_enum is NotificationEnum.config_refresh:

                devices_count_before_reload = len(
                    self._config["device_configs"].keys())
                self.logger.debug(
                    f"Device count before: {devices_count_before_reload}")
                self.reload_config()
                devices_count_after_reload = len(
                    self._config["device_configs"].keys())
                self.logger.debug(
                    f"Device count after: {devices_count_after_reload}")

                if (devices_count_before_reload != devices_count_after_reload):
                    self.reinit_devices()

                if (current_notification_item.device_id == "all_devices"):
                    for key, value in self._devices.items():
                        self.restart_device(key)
                else:
                    self.restart_device(current_notification_item.device_id)
                self._notification_queue_out.put_blocking(
                    NotificationItem(NotificationEnum.config_refresh_finished,
                                     current_notification_item.device_id))

            elif current_notification_item.notification_enum is NotificationEnum.process_continue:
                self._skip_routine = False
            elif current_notification_item.notification_enum is NotificationEnum.process_pause:
                self._skip_routine = True

        # Limit the fps to decrease lags caused by 100 percent CPU.
        self._fps_limiter.fps_limiter()

        if self._skip_routine:
            return

        audio_data = self.get_audio_data()
        self.refresh_audio_queues(audio_data)

        self.end_time = time()

        if time() - self.ten_seconds_counter > 10:
            self.ten_seconds_counter = time()
            self.time_dif = self.end_time - self.start_time
            self.fps = 1 / self.time_dif
            self.logger.info(f"FPS: {self.fps:.2f}")

        self.start_time = time()

    def get_audio_data(self):
        audio_data = None
        if not self._audio_queue.empty():
            audio_data = self._audio_queue.get_blocking()
        return audio_data

    def refresh_audio_queues(self, audio_data):
        if audio_data is None:
            return
        for key, value in self._devices.items():
            audio_copy = copy.deepcopy(audio_data)
            value.audio_queue.put_none_blocking(audio_data)

    def init_devices(self):
        self.logger.debug("Entering init_devices()")
        self._color_service_global = ColorServiceGlobal(self._config)

        for key in self._config["device_configs"].keys():
            device_id = key
            self.logger.debug(f"Init device with device id: {device_id}")
            self._devices[device_id] = Device(
                self._config, self._config["device_configs"][device_id],
                self._color_service_global)
        self.logger.debug("Leaving init_devices()")

    def reinit_devices(self):
        self.logger.debug("Entering reinit_devices()")
        for key, value in self._devices.items():
            self.stop_device(key)
        self._devices = {}
        self.init_devices()
        self.start_devices()
        self.logger.debug("Leaving reinit_devices()")

    def start_devices(self):
        for key, value in self._devices.items():
            self.logger.debug(f"Starting device: {key}")
            value.start_device()

    def reload_config(self):
        self.logger.debug("Entering reload_config()")
        ConfigService.instance(self._config_lock).load_config()
        self._config = ConfigService.instance(self._config_lock).config
        self.logger.debug("Leaving reload_config()")

    def restart_device(self, device_id):
        self.logger.debug(f"Restarting {device_id}")
        self._devices[device_id].refresh_config(
            self._config, self._config["device_configs"][device_id])
        self.logger.debug(f"Restarted {device_id}")

    def stop_device(self, device_id):
        self.logger.debug(f"Stopping {device_id}")
        self._devices[device_id].stop_device()
        self.logger.debug(f"Stopped {device_id}")
    def start(self, device):
        """
        Start the effect service process.
        You can change the effect by adding a new effect enum inside the enum_queue.
        """
        self.logger = logging.getLogger(__name__)

        self._device = device
        self.logger.info(
            f'Starting Effect Service component from device: {self._device.device_config["DEVICE_NAME"]}'
        )

        self.ten_seconds_counter = time()
        self.start_time = time()

        self._fps_limiter = FPSLimiter(self._device.device_config["FPS"])

        self._available_effects = {
            EffectsEnum.effect_off: EffectOff,
            EffectsEnum.effect_single: EffectSingle,
            EffectsEnum.effect_gradient: EffectGradient,
            EffectsEnum.effect_fade: EffectFade,
            EffectsEnum.effect_sync_fade: EffectSyncFade,
            EffectsEnum.effect_slide: EffectSlide,
            EffectsEnum.effect_bubble: EffectBubble,
            EffectsEnum.effect_twinkle: EffectTwinkle,
            EffectsEnum.effect_pendulum: EffectPendulum,
            EffectsEnum.effect_rods: EffectRods,
            EffectsEnum.effect_advanced_scroll: EffectAdvancedScroll,
            EffectsEnum.effect_scroll: EffectScroll,
            EffectsEnum.effect_energy: EffectEnergy,
            EffectsEnum.effect_wavelength: EffectWavelength,
            EffectsEnum.effect_bars: EffectBars,
            EffectsEnum.effect_power: EffectPower,
            EffectsEnum.effect_beat: EffectBeat,
            EffectsEnum.effect_wave: EffectWave,
            EffectsEnum.effect_beat_slide: EffectBeatSlide,
            EffectsEnum.effect_spectrum_analyzer: EffectSpectrumAnalyzer,
            EffectsEnum.effect_vu_meter: EffectVuMeter,
            EffectsEnum.effect_wiggle: EffectWiggle,
            EffectsEnum.effect_direction_changer: EffectDirectionChanger,
            EffectsEnum.effect_beat_twinkle: EffectBeatTwinkle,
            EffectsEnum.effect_segment_color: EffectSegmentColor
        }

        self._initialized_effects = {}
        self._current_effect = {}

        try:
            # Get the last effect and set it.
            last_effect_string = self._device.device_config["effects"][
                "last_effect"]
            self._current_effect = EffectsEnum[last_effect_string]
        except Exception:
            self.logger.exception(
                "Could not parse last effect. Set effect to off.")
            self._current_effect = EffectsEnum.effect_off

        # A token to cancel the while loop.
        self._cancel_token = False
        self._skip_effect = False
        self.logger.info(
            f'Effects component started. Device: {self._device.device_config["DEVICE_NAME"]}'
        )

        while not self._cancel_token:
            try:
                self.effect_routine()
            except KeyboardInterrupt:
                break

        self.logger.info(
            f'Effects component stopped. Device: {self._device.device_config["DEVICE_NAME"]}'
        )
class EffectService():
    def start(self, device):
        """
        Start the effect service process.
        You can change the effect by adding a new effect enum inside the enum_queue.
        """
        self.logger = logging.getLogger(__name__)

        self._device = device
        self.logger.info(
            f'Starting Effect Service component from device: {self._device.device_config["DEVICE_NAME"]}'
        )

        self.ten_seconds_counter = time()
        self.start_time = time()

        self._fps_limiter = FPSLimiter(self._device.device_config["FPS"])

        self._available_effects = {
            EffectsEnum.effect_off: EffectOff,
            EffectsEnum.effect_single: EffectSingle,
            EffectsEnum.effect_gradient: EffectGradient,
            EffectsEnum.effect_fade: EffectFade,
            EffectsEnum.effect_sync_fade: EffectSyncFade,
            EffectsEnum.effect_slide: EffectSlide,
            EffectsEnum.effect_bubble: EffectBubble,
            EffectsEnum.effect_twinkle: EffectTwinkle,
            EffectsEnum.effect_pendulum: EffectPendulum,
            EffectsEnum.effect_rods: EffectRods,
            EffectsEnum.effect_advanced_scroll: EffectAdvancedScroll,
            EffectsEnum.effect_scroll: EffectScroll,
            EffectsEnum.effect_energy: EffectEnergy,
            EffectsEnum.effect_wavelength: EffectWavelength,
            EffectsEnum.effect_bars: EffectBars,
            EffectsEnum.effect_power: EffectPower,
            EffectsEnum.effect_beat: EffectBeat,
            EffectsEnum.effect_wave: EffectWave,
            EffectsEnum.effect_beat_slide: EffectBeatSlide,
            EffectsEnum.effect_spectrum_analyzer: EffectSpectrumAnalyzer,
            EffectsEnum.effect_vu_meter: EffectVuMeter,
            EffectsEnum.effect_wiggle: EffectWiggle,
            EffectsEnum.effect_direction_changer: EffectDirectionChanger,
            EffectsEnum.effect_beat_twinkle: EffectBeatTwinkle,
            EffectsEnum.effect_segment_color: EffectSegmentColor
        }

        self._initialized_effects = {}
        self._current_effect = {}

        try:
            # Get the last effect and set it.
            last_effect_string = self._device.device_config["effects"][
                "last_effect"]
            self._current_effect = EffectsEnum[last_effect_string]
        except Exception:
            self.logger.exception(
                "Could not parse last effect. Set effect to off.")
            self._current_effect = EffectsEnum.effect_off

        # A token to cancel the while loop.
        self._cancel_token = False
        self._skip_effect = False
        self.logger.info(
            f'Effects component started. Device: {self._device.device_config["DEVICE_NAME"]}'
        )

        while not self._cancel_token:
            try:
                self.effect_routine()
            except KeyboardInterrupt:
                break

        self.logger.info(
            f'Effects component stopped. Device: {self._device.device_config["DEVICE_NAME"]}'
        )

    def effect_routine(self):
        # Limit the fps to decrease lags caused by 100 percent CPU.
        self._fps_limiter.fps_limiter()

        # Check the notification queue.
        if not self._device.device_notification_queue_in.empty():
            self._current_notification_in = self._device.device_notification_queue_in.get(
            )
            self.logger.debug(
                f'Effects Service has a new notification in. Notification: {self._current_notification_in} | Device: {self._device.device_config["DEVICE_NAME"]}'
            )

        if hasattr(self, "_current_notification_in"):
            if self._current_notification_in is NotificationEnum.config_refresh:
                self.refresh()
            elif self._current_notification_in is NotificationEnum.process_continue:
                self._skip_effect = False
            elif self._current_notification_in is NotificationEnum.process_pause:
                self._skip_effect = True
            elif self._current_notification_in is NotificationEnum.process_stop:
                self.stop()

        # Reset the current in notification, to do it only one time.
        self._current_notification_in = None

        # Skip the effect sequence, for example, to "pause" the process.
        if self._skip_effect:
            return

        # Check if the effect changed.
        if not self._device.effect_queue.empty():
            new_effect_item = self._device.effect_queue.get()
            self._current_effect = new_effect_item.effect_enum
            self.logger.debug(
                f"New effect found: {new_effect_item.effect_enum}")

        # Something is wrong here, no effect set. So skip until we get new information.
        if self._current_effect is None:
            self.logger.error("Effect Service | Could not find effect.")
            return

        if (not (self._current_effect in self._initialized_effects.keys())):
            if self._current_effect in self._available_effects.keys():
                self._initialized_effects[
                    self._current_effect] = self._available_effects[
                        self._current_effect](self._device)
            else:
                self.logger.error(
                    f"Could not find effect: {self._current_effect}")

        self.end_time = time()
        if time() - self.ten_seconds_counter > 10:
            self.ten_seconds_counter = time()
            self.time_dif = self.end_time - self.start_time
            self.fps = 1 / self.time_dif
            self.logger.info(
                f'FPS: {self.fps:.2f} | Device: {self._device.device_config["DEVICE_NAME"]}'
            )

        self.start_time = time()

        self._initialized_effects[self._current_effect].run()

    def stop(self):
        self.logger.info("Stopping effect component...")
        self.cancel_token = True

    def refresh(self):
        self.logger.debug("Refreshing effects...")
        self._initialized_effects = {}

        self._fps_limiter = FPSLimiter(self._device.device_config["FPS"])

        # Notify the master component, that I'm finished.
        self._device.device_notification_queue_out.put(
            NotificationEnum.config_refresh_finished)
        self.logger.debug("Effects refreshed.")
    def init_audio_service(self, show_output=False):
        try:
            # Initial config load.
            ConfigService.instance(self._config_lock).load_config()
            self._config = ConfigService.instance(self._config_lock).config

            # Init FPS Limiter.
            self._fps_limiter = FPSLimiter(120)
            self._skip_routine = False
            self._devices = AudioInfo.get_audio_devices(self._py_audio)

            self.log_output(show_output, logging.INFO,
                            "Found the following audio sources:")

            # Select the audio device you want to use.
            selected_device_list_index = 0
            try:
                mic_id = self._config["general_settings"]["device_id"]
                if mic_id != "no_mic":
                    selected_device_list_index = int(mic_id)
            except Exception as e:
                self.logger.exception(f"Could not parse audio id: {e}")

            # Check if the index is inside the list.
            self.selected_device = None
            # For each audio device, add to list of devices.
            for current_audio_device in self._devices:

                if current_audio_device.id == selected_device_list_index:
                    self.selected_device = current_audio_device

            self.logger.debug(f"Selected Device: {self.selected_device}")

            # Could not find a mic with the selected mic id, so I will use the first device I found.
            if self.selected_device is None:
                self.log_output(
                    show_output, logging.ERROR,
                    "********************************************************")
                self.log_output(
                    show_output, logging.ERROR,
                    "*                      Error                           *")
                self.log_output(
                    show_output, logging.ERROR,
                    "********************************************************")
                self.log_output(
                    show_output, logging.ERROR,
                    f"Could not find the mic with the id: {selected_device_list_index}"
                )
                self.log_output(show_output, logging.ERROR,
                                "Using the first mic as fallback.")
                self.log_output(
                    show_output, logging.ERROR,
                    "Please change the id of the mic inside the config.")
                self.selected_device = self._devices[0]

            self._device_rate = self._config["general_settings"][
                "default_sample_rate"]
            self._frames_per_buffer = self._config["general_settings"][
                "frames_per_buffer"]
            self.n_fft_bins = self._config["general_settings"]["n_fft_bins"]
            self.log_output(
                show_output, logging.INFO,
                f"Selected Device: {self.selected_device.to_string()}")

            # Init Timer
            self.start_time_1 = time()
            self.ten_seconds_counter_1 = time()
            self.start_time_2 = time()
            self.ten_seconds_counter_2 = time()

            self._dsp = DSP(self._config)

            self.audio = np.empty((self._frames_per_buffer), dtype="int16")

            # Reinit buffer queue
            self.audio_buffer_queue = QueueWrapper(Queue(2))

            # callback function to stream audio, another thread.
            def callback(in_data, frame_count, time_info, status):
                if self._skip_routine:
                    return (self.audio, pyaudio.paContinue)

                self.audio_buffer_queue.put_none_blocking(in_data)

                self.end_time_1 = time()

                if time() - self.ten_seconds_counter_1 > 10:
                    self.ten_seconds_counter_1 = time()
                    time_dif = self.end_time_1 - self.start_time_1
                    fps = 1 / time_dif
                    self.logger.info(f"Callback | FPS: {fps:.2f}")

                self.start_time_1 = time()

                return (self.audio, pyaudio.paContinue)

            self.log_output(show_output, logging.DEBUG,
                            "Starting Open Audio Stream...")
            self.stream = self._py_audio.open(
                format=pyaudio.paInt16,
                channels=1,
                rate=self._device_rate,
                input=True,
                input_device_index=self.selected_device.id,
                frames_per_buffer=self._frames_per_buffer,
                stream_callback=callback)
        except Exception as e:
            self.logger.error("Could not init AudioService.")
            self.logger.exception(
                f"Unexpected error in init_audio_service: {e}")
Пример #12
0
    def start(self, device):
        """
        Start the effect service process. You can change the effect by add a new effect enum inside the enum_queue.
        """

        self._device = device
        print("Start Effect Service component from device: " +
              self._device.device_config["DEVICE_NAME"])

        self.ten_seconds_counter = time.time()
        self.start_time = time.time()

        self._fps_limiter = FPSLimiter(self._device.device_config["FPS"])

        self._available_effects = {
            EffectsEnum.effect_off: EffectOff,
            EffectsEnum.effect_single: EffectSingle,
            EffectsEnum.effect_gradient: EffectGradient,
            EffectsEnum.effect_fade: EffectFade,
            EffectsEnum.effect_sync_fade: EffectSyncFade,
            EffectsEnum.effect_slide: EffectSlide,
            EffectsEnum.effect_bubble: EffectBubble,
            EffectsEnum.effect_twinkle: EffectTwinkle,
            EffectsEnum.effect_pendulum: EffectPendulum,
            EffectsEnum.effect_rods: EffectRods,
            EffectsEnum.effect_advanced_scroll: EffectAdvancedScroll,
            EffectsEnum.effect_scroll: EffectScroll,
            EffectsEnum.effect_energy: EffectEnergy,
            EffectsEnum.effect_wavelength: EffectWavelength,
            EffectsEnum.effect_bars: EffectBars,
            EffectsEnum.effect_power: EffectPower,
            EffectsEnum.effect_beat: EffectBeat,
            EffectsEnum.effect_wave: EffectWave,
            EffectsEnum.effect_beat_slide: EffectBeatSlide,
            EffectsEnum.effect_spectrum_analyzer: EffectSpectrumAnalyzer,
            EffectsEnum.effect_vu_meter: EffectVuMeter,
            EffectsEnum.effect_wiggle: EffectWiggle,
            EffectsEnum.effect_direction_changer: EffectDirectionChanger,
            EffectsEnum.effect_beat_twinkle: EffectBeatTwinkle
        }

        self._initialized_effects = {}
        self._current_effect = {}

        try:
            # Get the last effect and set it.
            last_effect_string = self._device.device_config["effects"][
                "last_effect"]
            self._current_effect = EffectsEnum[last_effect_string]

        except Exception:
            print("Could not parse last effect. Set effect to off.")
            self._current_effect = EffectsEnum.effect_off

        # A token to cancle the while loop
        self._cancel_token = False
        self._skip_effect = False
        print("Effects component started. Device: " +
              self._device.device_config["DEVICE_NAME"])

        while not self._cancel_token:
            #try:
            self.effect_routine()
            #except Exception as e:
            #    print("Error in Effect Service. Routine Restarted. Exception: " + str(e))

        print("Effects component stopped. Device: " +
              self._device.device_config["DEVICE_NAME"])
class DeviceManager:
    def start(self, config_lock, notification_queue_in, notification_queue_out,
              effect_queue, audio_queue):

        self._config_lock = config_lock
        self._config = ConfigService.instance(self._config_lock).config

        self._notification_queue_in = notification_queue_in
        self._notification_queue_out = notification_queue_out
        self._effect_queue = effect_queue
        print("Effect queue id DeviceManager " + str(id(self._effect_queue)))
        self._audio_queue = audio_queue

        #Init FPS Limiter
        self._fps_limiter = FPSLimiter(200)

        self._skip_routine = False
        self._devices = {}
        self.init_devices()
        self.start_devices()

        self.start_time = time.time()
        self.ten_seconds_counter = time.time()

        while True:
            self.routine()

    def routine(self):
        # Check the effect queue
        if not self._effect_queue.empty():
            current_effect_item = self._effect_queue.get()
            print("Device Manager received new effect: " +
                  str(current_effect_item.effect_enum) +
                  current_effect_item.device_id)
            current_device = self._devices[current_effect_item.device_id]
            current_device.effect_queue.put(current_effect_item)

        if not self._notification_queue_in.empty():
            current_notification_item = self._notification_queue_in.get()
            print("Device Manager received new notification: " +
                  str(current_notification_item.notification_enum) + " - " +
                  str(current_notification_item.device_id))

            if current_notification_item.notification_enum is NotificationEnum.config_refresh:

                devices_count_before_reload = len(
                    self._config["device_configs"].keys())
                print("Device count before: " +
                      str(devices_count_before_reload))
                self.reload_config()
                devices_count_after_reload = len(
                    self._config["device_configs"].keys())
                print("Device count after: " + str(devices_count_after_reload))

                if (devices_count_before_reload != devices_count_after_reload):
                    self.reinit_devices()

                if (current_notification_item.device_id == "all_devices"):
                    for key, value in self._devices.items():
                        self.restart_device(key)
                else:
                    self.restart_device(current_notification_item.device_id)
                self._notification_queue_out.put(
                    NotificationItem(NotificationEnum.config_refresh_finished,
                                     current_notification_item.device_id))

            elif current_notification_item.notification_enum is NotificationEnum.process_continue:
                self._skip_routine = False
            elif current_notification_item.notification_enum is NotificationEnum.process_pause:
                self._skip_routine = True

        # Limit the fps to decrease laggs caused by 100 percent cpu
        self._fps_limiter.fps_limiter()

        if self._skip_routine:
            return

        audio_data = self.get_audio_data()
        self.refresh_audio_queues(audio_data)

        self.end_time = time.time()

        if time.time() - self.ten_seconds_counter > 10:
            self.ten_seconds_counter = time.time()
            self.time_dif = self.end_time - self.start_time
            self.fps = 1 / self.time_dif
            print("Device Manager | FPS: " + str(self.fps))

        self.start_time = time.time()

    def get_audio_data(self):
        audio_data = None
        if not self._audio_queue.empty():
            audio_data = self._audio_queue.get()

        return audio_data

    def refresh_audio_queues(self, audio_data):
        if audio_data is None:
            return
        for key, value in self._devices.items():
            if value.audio_queue.full():
                try:
                    pre_audio_data = value.audio_queue.get(False)
                    del pre_audio_data
                except:
                    #print("Empty audio queue of devices.")
                    pass

            audio_copy = copy.deepcopy(audio_data)
            try:
                value.audio_queue.put(audio_copy, block=True, timeout=0.33)
            except:
                pass

    def init_devices(self):
        print("Enter init_devices()")

        self._color_service_global = ColorServiceGlobal(self._config)

        for key in self._config["device_configs"].keys():
            device_id = key
            print("Init device with device id:" + device_id)
            self._devices[device_id] = Device(
                self._config, self._config["device_configs"][device_id],
                self._color_service_global)
        print("Leave init_devices()")

    def reinit_devices(self):
        print("Enter reinit_devices()")
        for key, value in self._devices.items():
            self.stop_device(key)
        self._devices = {}
        self.init_devices()
        self.start_devices()
        print("Leave reinit_devices()")

    def start_devices(self):
        for key, value in self._devices.items():
            print("Start device:" + key)
            value.start_device()

    def reload_config(self):
        print("Enter reload_config()")
        ConfigService.instance(self._config_lock).load_config()
        self._config = ConfigService.instance(self._config_lock).config
        print("Leave reload_config()")

    def restart_device(self, device_id):
        print("Restart " + device_id)
        self._devices[device_id].refresh_config(
            self._config, self._config["device_configs"][device_id])
        print("Restarted " + device_id)

    def stop_device(self, device_id):
        print("Stop " + device_id)
        self._devices[device_id].stop_device()
        print("Stopped " + device_id)
    def init_audio_service(self):
        # Initial config load.
        ConfigService.instance(self._config_lock).load_config()
        self._config = ConfigService.instance(self._config_lock).config

        #Init FPS Limiter
        self._fps_limiter = FPSLimiter(100)

        # Init pyaudio
        self._py_audio = pyaudio.PyAudio()

        self._skip_routine = False

        self._numdevices = self._py_audio.get_device_count()
        self._default_device_id = self._py_audio.get_default_input_device_info(
        )['index']
        self._devices = []

        print("Found the following audio sources:")

        # Select the audio device you want to use.
        selected_device_list_index = self._config["general_settings"][
            "DEVICE_ID"]

        # check if the index is inside the list
        foundMicIndex = False

        #for each audio device, add to list of devices
        for i in range(0, self._numdevices):
            try:
                device_info = self._py_audio.get_device_info_by_host_api_device_index(
                    0, i)

                if device_info["maxInputChannels"] >= 1:
                    self._devices.append(device_info)
                    print(
                        str(device_info["index"]) + " - " +
                        str(device_info["name"]) + " - " +
                        str(device_info["defaultSampleRate"]))

                    if device_info["index"] == selected_device_list_index:
                        foundMicIndex = True
            except Exception as e:
                print("Could not get device infos.")
                print("Unexpected error in AudioProcessService :" + str(e))

        # Could not find a mic with the selected mic id, so i will use the first device I found.
        if not foundMicIndex:
            print("********************************************************")
            print("*                      Error                           *")
            print("********************************************************")
            print("Could not find the mic with the id: " +
                  str(selected_device_list_index))
            print("Use the first mic as fallback.")
            print("Please change the id of the mic inside the config.")
            selected_device_list_index = self._devices[0]["index"]

        for device in self._devices:
            if device["index"] == selected_device_list_index:
                print("Selected ID: " + str(selected_device_list_index))
                print("Use " + str(device["index"]) + " - " +
                      str(device["name"]) + " - " +
                      str(device["defaultSampleRate"]))
                self._device_id = device["index"]
                self._device_name = device["name"]
                self._device_rate = self._config["general_settings"][
                    "DEFAULT_SAMPLE_RATE"]
                self._frames_per_buffer = self._config["general_settings"][
                    "FRAMES_PER_BUFFER"]

        self.start_time_1 = time.time()
        self.ten_seconds_counter_1 = time.time()
        self.start_time_2 = time.time()
        self.ten_seconds_counter_2 = time.time()

        self._dsp = DSP(self._config)

        self.audio = np.empty((self._frames_per_buffer), dtype="int16")

        self.audio_buffer_queue = Queue(2)

        # callback function to stream audio, another thread.
        def callback(in_data, frame_count, time_info, status):

            if self._skip_routine:
                return (self.audio, pyaudio.paContinue)

            try:
                self.audio_buffer_queue.put(in_data)
            except:
                pass
#
            self.end_time_1 = time.time()

            if time.time() - self.ten_seconds_counter_1 > 10:
                self.ten_seconds_counter_1 = time.time()
                time_dif = self.end_time_1 - self.start_time_1
                fps = 1 / time_dif
                print("Audio Service Callback | FPS: " + str(fps))

            self.start_time_1 = time.time()

            return (self.audio, pyaudio.paContinue)

        print("Start open Audio stream")
        self.stream = self._py_audio.open(
            format=pyaudio.paInt16,
            channels=1,
            rate=self._device_rate,
            input=True,
            input_device_index=self._device_id,
            frames_per_buffer=self._frames_per_buffer,
            stream_callback=callback)
class OutputService():
    def start(self, device):
        self.logger = logging.getLogger(__name__)

        self._device = device
        self._led_strip = self._device.device_config["led_strip"]

        self.logger.info(
            f'Starting Output service... Device: {self._device.device_config["device_name"]}'
        )

        # Initial config load.
        self._config = self._device.config

        self._output_queue = self._device.output_queue
        self._device_notification_queue_in = self._device.device_notification_queue_in
        self._device_notification_queue_out = self._device.device_notification_queue_out

        self.ten_seconds_counter = time()
        self.sec_ten_seconds_counter = time()
        self.start_time = time()

        # Init FPS Limiter.
        self._fps_limiter = FPSLimiter(self._device.device_config["fps"])

        self._skip_output = False
        self._cancel_token = False

        self._available_outputs = {
            OutputsEnum.output_dummy: OutputDummy,
            OutputsEnum.output_raspi: OutputRaspi,
            OutputsEnum.output_udp: OutputUDP
        }

        current_output_enum = OutputsEnum[
            self._device.device_config["output_type"]]
        self.logger.debug(f"Found output: {current_output_enum}")
        self._current_output = self._available_outputs[current_output_enum](
            self._device)

        self.logger.debug(
            f'Output component started. Device: {self._device.device_config["device_name"]}'
        )

        while not self._cancel_token:
            try:
                self.output_routine()
            except KeyboardInterrupt:
                break

    def output_routine(self):
        # Limit the fps to decrease lags caused by 100 percent CPU.
        self._fps_limiter.fps_limiter()

        # Check the notification queue.
        if not self._device_notification_queue_in.empty():
            self._current_notification_in = self._device_notification_queue_in.get_blocking(
            )

        if hasattr(self, "_current_notification_in"):
            if self._current_notification_in is NotificationEnum.config_refresh:
                self.refresh()
            elif self._current_notification_in is NotificationEnum.process_continue:
                self._skip_output = False
            elif self._current_notification_in is NotificationEnum.process_pause:
                self._skip_output = True
            elif self._current_notification_in is NotificationEnum.process_stop:
                self.stop()

        # Reset the current in notification, to do it only one time.
        self._current_notification_in = None

        # Skip the output sequence, for example to "pause" the process.
        if self._skip_output:
            if not self._output_queue.empty():
                skip_output_queue = self._output_queue.get_blocking()
                del skip_output_queue
            return

        # Check if the queue is empty and stop if its empty.
        if not self._output_queue.empty():
            current_output_array = self._output_queue.get_blocking()
            # Add another Array of LEDS for White Channel
            if "SK6812" in self._led_strip and len(current_output_array) == 3:
                current_output_array = np.vstack(
                    (current_output_array,
                     np.zeros(self._device.device_config["led_count"])))

            self._current_output.show(current_output_array)

        self.end_time = time()

        if time() - self.ten_seconds_counter > 10:
            self.ten_seconds_counter = time()
            self.time_dif = self.end_time - self.start_time
            self.fps = 1 / self.time_dif
            self.logger.info(
                f'FPS: {self.fps:.2f} | Device: {self._device.device_config["device_name"]}'
            )

        self.start_time = time()

    def stop(self):
        self._cancel_token = True
        self._current_output.clear()

    def refresh(self):
        self.logger.debug("Refreshing output...")

        # Refresh the config,
        self._config = self._device.config

        # Notify the master component, that I'm finished.
        self._device_notification_queue_out.put_blocking(
            NotificationEnum.config_refresh_finished)

        self.logger.debug("Output refreshed.")