Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request / discussion : New event after end of TTS (keep led on during TTS) #63

Closed
llluis opened this issue Jan 18, 2024 · 5 comments
Closed

Comments

@llluis
Copy link
Contributor

llluis commented Jan 18, 2024

Hello @synesthesiam.
I'm using the event server to control the leds and would like to keep them on while aplay is being executed, i.e., while the TTS return is being played.

Right now TTS audio chunk is sent to the queue and there's no event tracking when the audio was played. The last event is the AudioStop but it's received when the server is finished sending chunks, not when the actual play ended.

One possible solution is the desconnection of the sound client here:

I made some tests and it works as expected is this scenario.
What would you say? Any other suggestion?

@synesthesiam
Copy link
Contributor

A Wyoming audio output system is supposed to send a played message when the audio is finished playing, but I'm not sure of a good way to tell when aplay is done playing the audio its received.
This may be something that is only possible through the ALSA API itself.

@llluis
Copy link
Contributor Author

llluis commented Jan 19, 2024

Thanks for the feedback @synesthesiam.
I tested with the code in the PR and it works perfectly, but I don't know if it's respecting the standards.

@MrSco
Copy link

MrSco commented Jan 23, 2024

There were a couple gaps in feedback from the led status colors so I made a couple modifications to 2mic_service.py to handle Error event when no speech text detected (flash purple) and cyan while the assist is processing/playing audio back as a response...

IMG_4879.MOV
IMG_4880.MOV

...

from wyoming.tts import Synthesize
from wyoming.audio import AudioStop
from wyoming.snd import Played

...

...

class LEDsEventHandler(AsyncEventHandler):
    """Event handler for clients."""

    def __init__(
        self,
        cli_args: argparse.Namespace,
        leds: "APA102",
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)

        self.cli_args = cli_args
        self.client_id = str(time.monotonic_ns())
        self.leds = leds
        self.previous_event = None 

        _LOGGER.debug("Client connected: %s", self.client_id)

    async def handle_event(self, event: Event) -> bool:
        _LOGGER.debug(event)

        if StreamingStarted.is_type(event.type):
            self.color(_YELLOW)
        elif Detection.is_type(event.type):
            self.color(_BLUE)
            await asyncio.sleep(1.0)  # show for 1 sec
        elif VoiceStarted.is_type(event.type):
            self.color(_YELLOW)
        elif Transcript.is_type(event.type):
            self.color(_GREEN)
            await asyncio.sleep(1.0)  # show for 1 sec
        elif StreamingStopped.is_type(event.type):
            self.color(_BLACK)
        elif RunSatellite.is_type(event.type):
            self.color(_BLACK)
        elif SatelliteConnected.is_type(event.type):
            # Flash
            for _ in range(3):
                self.color(_GREEN)
                await asyncio.sleep(0.3)
                self.color(_BLACK)
                await asyncio.sleep(0.3)
        elif SatelliteDisconnected.is_type(event.type):
            self.color(_RED)
        elif Error.is_type(event.type):            
            # Flash
            for _ in range(3):
                self.color(_PURPLE)
                await asyncio.sleep(0.3)
                self.color(_BLACK)
                await asyncio.sleep(0.3)
        # While the assist is responding with audio, the LEDs should be cyan
        elif Synthesize.is_type(event.type):
            self.color(_CYAN)
        # When the assist is done responding with audio, the LEDs should be black
        elif Played.is_type(event.type) and AudioStop.is_type(self.previous_event):
            self.color(_BLACK)
            
        self.previous_event = event.type 
        
        return True

...

@synesthesiam
Copy link
Contributor

Merged #100

@sayam93
Copy link

sayam93 commented Nov 15, 2024

There were a couple gaps in feedback from the led status colors so I made a couple modifications to 2mic_service.py to handle Error event when no speech text detected (flash purple) and cyan while the assist is processing/playing audio back as a response...

IMG_4879.MOV
IMG_4880.MOV
...

from wyoming.tts import Synthesize
from wyoming.audio import AudioStop
from wyoming.snd import Played

...

...

class LEDsEventHandler(AsyncEventHandler):
    """Event handler for clients."""

    def __init__(
        self,
        cli_args: argparse.Namespace,
        leds: "APA102",
        *args,
        **kwargs,
    ) -> None:
        super().__init__(*args, **kwargs)

        self.cli_args = cli_args
        self.client_id = str(time.monotonic_ns())
        self.leds = leds
        self.previous_event = None 

        _LOGGER.debug("Client connected: %s", self.client_id)

    async def handle_event(self, event: Event) -> bool:
        _LOGGER.debug(event)

        if StreamingStarted.is_type(event.type):
            self.color(_YELLOW)
        elif Detection.is_type(event.type):
            self.color(_BLUE)
            await asyncio.sleep(1.0)  # show for 1 sec
        elif VoiceStarted.is_type(event.type):
            self.color(_YELLOW)
        elif Transcript.is_type(event.type):
            self.color(_GREEN)
            await asyncio.sleep(1.0)  # show for 1 sec
        elif StreamingStopped.is_type(event.type):
            self.color(_BLACK)
        elif RunSatellite.is_type(event.type):
            self.color(_BLACK)
        elif SatelliteConnected.is_type(event.type):
            # Flash
            for _ in range(3):
                self.color(_GREEN)
                await asyncio.sleep(0.3)
                self.color(_BLACK)
                await asyncio.sleep(0.3)
        elif SatelliteDisconnected.is_type(event.type):
            self.color(_RED)
        elif Error.is_type(event.type):            
            # Flash
            for _ in range(3):
                self.color(_PURPLE)
                await asyncio.sleep(0.3)
                self.color(_BLACK)
                await asyncio.sleep(0.3)
        # While the assist is responding with audio, the LEDs should be cyan
        elif Synthesize.is_type(event.type):
            self.color(_CYAN)
        # When the assist is done responding with audio, the LEDs should be black
        elif Played.is_type(event.type) and AudioStop.is_type(self.previous_event):
            self.color(_BLACK)
            
        self.previous_event = event.type 
        
        return True

...

Hi there!

Need a little help.

Is this also required?

from wyoming.error import Error

Also, do these look fine?

_CYAN = (0, 255, 255)
_PURPLE = (128, 0, 128)

Lastly, is this working for you?

        elif SatelliteDisconnected.is_type(event.type):
            self.color(_RED)

Please let me know.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants