Skip to content

Commit

Permalink
fix(core): use fasteners read-write lock implementation for the persi…
Browse files Browse the repository at this point in the history
…stent store - closes #158
  • Loading branch information
sassanh committed Aug 11, 2024
1 parent 43deb5c commit 9cb0bc3
Show file tree
Hide file tree
Showing 24 changed files with 248 additions and 280 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/integration_delivery.yml
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ jobs:
steps:
- uses: actions/checkout@v4
name: Checkout
with:
lfs: true
# with: TODO: this, it consumes lfs bandwidth and should be used only for releases
# lfs: true

- uses: actions/setup-python@v5
name: Setup Python
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- feat(rpi-connect): implement `rpi-connect` under `Remote` menu - closes #139
- fix(core): update manager downloads the latest `install.sh` and runs it to do the update - closes #152
- feat(core): add signal management for ubo_app process - closes #156
- fix(core): use fasteners read-write lock implementation for the persistent store - closes #158

## Version 0.15.5

Expand Down
225 changes: 118 additions & 107 deletions poetry.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ adafruit-circuitpython-veml7700 = "^1.1.22"
# RPi dependencies
rpi-lgpio = { version = "^0.6", markers = "platform_machine=='aarch64'" }
piper-tts = { version = "^1.2.0", markers = "sys_platform=='linux'" }
fasteners = "^0.19"

[tool.poetry.group.dev]
optional = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@
"icon": "󰄱",
"is_short": false,
"key": null,
"label": "Orca",
"label": "Picovoice",
"opacity": null,
"progress": null
}
Expand All @@ -403,7 +403,7 @@
"icon": "󰔊",
"is_short": false,
"key": null,
"label": "Orca Settings",
"label": "Picovoice Settings",
"opacity": null,
"progress": null,
"sub_menu": {
Expand All @@ -428,7 +428,7 @@
],
"placeholder": null,
"sub_heading": "Set the access key\nCurrent value: Fake",
"title": "Orca Settings"
"title": "Picovoice Settings"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@
"icon": "󰄱",
"is_short": false,
"key": null,
"label": "Orca",
"label": "Picovoice",
"opacity": null,
"progress": null
}
Expand All @@ -403,7 +403,7 @@
"icon": "󰔊",
"is_short": false,
"key": null,
"label": "Orca Settings",
"label": "Picovoice Settings",
"opacity": null,
"progress": null,
"sub_menu": {
Expand All @@ -428,7 +428,7 @@
],
"placeholder": null,
"sub_heading": "Set the access key\nCurrent value: Fake",
"title": "Orca Settings"
"title": "Picovoice Settings"
}
}
],
Expand Down
2 changes: 1 addition & 1 deletion ubo_app/menu_app/menu_notification_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def dismiss(_: object = None) -> None:
VoiceReadTextAction(
text=notification.extra_information.text,
piper_text=notification.extra_information.piper_text,
orca_text=notification.extra_information.orca_text,
picovoice_text=notification.extra_information.picovoice_text,
),
)

Expand Down
16 changes: 6 additions & 10 deletions ubo_app/services/000-audio/reducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,7 @@ def reducer(

if isinstance(action, AudioSetVolumeAction):
if action.device == AudioDevice.OUTPUT:
return CompleteReducerResult(
state=replace(state, playback_volume=action.volume),
events=[
AudioPlayChimeEvent(name=Chime.VOLUME_CHANGE),
],
)
return replace(state, playback_volume=action.volume)
if action.device == AudioDevice.INPUT:
return replace(state, capture_volume=action.volume)
elif isinstance(action, AudioChangeVolumeAction):
Expand All @@ -63,6 +58,7 @@ def reducer(
),
),
],
events=[AudioPlayChimeEvent(name=Chime.VOLUME_CHANGE)],
)
if action.device == AudioDevice.INPUT:
return replace(
Expand All @@ -74,13 +70,13 @@ def reducer(
)
elif isinstance(action, AudioSetMuteStatusAction):
if action.device == AudioDevice.OUTPUT:
return replace(state, is_playback_mute=action.mute)
return replace(state, is_playback_mute=action.is_mute)
if action.device == AudioDevice.INPUT:
return CompleteReducerResult(
state=replace(state, is_capture_mute=action.mute),
state=replace(state, is_capture_mute=action.is_mute),
actions=[
StatusIconsRegisterAction(
icon='󰍭' if action.mute else '󰍬',
icon='󰍭' if action.is_mute else '󰍬',
priority=AUDIO_MIC_STATE_ICON_PRIORITY,
id=AUDIO_MIC_STATE_ICON_ID,
),
Expand All @@ -91,7 +87,7 @@ def reducer(
state=state,
actions=[
AudioSetMuteStatusAction(
mute=not state.is_playback_mute
is_mute=not state.is_playback_mute
if action.device == AudioDevice.OUTPUT
else not state.is_capture_mute,
device=action.device,
Expand Down
22 changes: 17 additions & 5 deletions ubo_app/services/000-audio/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,6 @@ def _run_async_in_thread(
def init_service() -> None:
audio_manager = AudioManager()

register_persistent_store(
'audio_state',
lambda state: state.audio,
)

dispatch(
StatusIconsRegisterAction(
icon='󰍭',
Expand Down Expand Up @@ -79,3 +74,20 @@ def _(is_mute: bool) -> None: # noqa: FBT001
width=event.width,
),
)

register_persistent_store(
'audio_state:playback_volume',
lambda state: state.audio.playback_volume,
)
register_persistent_store(
'audio_state:is_playback_mute',
lambda state: state.audio.is_playback_mute,
)
register_persistent_store(
'audio_state:capture_volume',
lambda state: state.audio.capture_volume,
)
register_persistent_store(
'audio_state:is_capture_mute',
lambda state: state.audio.is_capture_mute,
)
2 changes: 1 addition & 1 deletion ubo_app/services/000-keypad/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ def on_button_event(*, index: int, status: ButtonStatus) -> None:
dispatch(
AudioSetMuteStatusAction(
device=AudioDevice.INPUT,
mute=status == 'pressed',
is_mute=status == 'pressed',
),
)

Expand Down
2 changes: 1 addition & 1 deletion ubo_app/services/010-voice/reducer.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def reducer(
VoiceSynthesizeTextEvent(
text=action.text,
piper_text=action.piper_text or action.text,
orca_text=action.orca_text or action.text,
picovoice_text=action.picovoice_text or action.text,
speech_rate=action.speech_rate,
),
],
Expand Down
64 changes: 32 additions & 32 deletions ubo_app/services/010-voice/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
import struct
from asyncio import CancelledError
from queue import Queue
from threading import Lock
from typing import TYPE_CHECKING, Any, cast

import fasteners
import pvorca
from piper.voice import PiperVoice # pyright: ignore [reportMissingModuleSource]
from redux import FinishEvent
Expand Down Expand Up @@ -36,24 +36,24 @@


class _Context:
orca_instance: pvorca.Orca | None = None
picovoice_instance: pvorca.Orca | None = None
piper_voice: PiperVoice | None = None
orca_lock: Lock = Lock()
picovoice_lock = fasteners.ReaderWriterLock()

def cleanup(self: _Context) -> None:
dispatch(VoiceUpdateAccessKeyStatus(is_access_key_set=False))
with self.orca_lock:
if self.orca_instance:
self.orca_instance.delete()
self.orca_instance = None
with self.picovoice_lock.write_lock():
if self.picovoice_instance:
self.picovoice_instance.delete()
self.picovoice_instance = None

def set_access_key(self: _Context, access_key: str) -> None:
dispatch(VoiceUpdateAccessKeyStatus(is_access_key_set=True))
with self.orca_lock:
with self.picovoice_lock.write_lock():
if access_key:
if self.orca_instance:
self.orca_instance.delete()
self.orca_instance = pvorca.create(access_key)
if self.picovoice_instance:
self.picovoice_instance.delete()
self.picovoice_instance = pvorca.create(access_key)

def load_piper(self: _Context) -> None:
self.piper_voice = PiperVoice.load(
Expand Down Expand Up @@ -94,7 +94,7 @@ def clear_access_key() -> None:


@view(lambda state: state.voice.selected_engine)
def _engine(engine: str) -> str:
def _engine(engine: VoiceEngine) -> VoiceEngine:
return engine


Expand All @@ -104,7 +104,7 @@ def _engine(engine: str) -> str:
def synthesize_and_play(event: VoiceSynthesizeTextEvent) -> None:
"""Synthesize the text."""
engine = _engine()
if engine == 'piper':
if engine == VoiceEngine.PIPER:
text = event.piper_text
if not _context.piper_voice:
return
Expand Down Expand Up @@ -138,25 +138,25 @@ def synthesize_and_play(event: VoiceSynthesizeTextEvent) -> None:
),
)
unsubscribe()
elif engine == 'orca':
with _context.orca_lock:
if not _context.orca_instance:
elif engine == VoiceEngine.PICOVOICE:
with _context.picovoice_lock.read_lock():
if not _context.picovoice_instance:
return
rate = _context.orca_instance.sample_rate
rate = _context.picovoice_instance.sample_rate

audio_sequence = _context.orca_instance.synthesize(
text=event.orca_text,
audio_sequence = _context.picovoice_instance.synthesize(
text=event.picovoice_text,
speech_rate=event.speech_rate,
)
sample = b''.join(struct.pack('h', sample) for sample in audio_sequence[0])
dispatch(
AudioPlayAudioAction(
sample=sample,
channels=1,
rate=rate,
width=2,
),
)
sample = b''.join(struct.pack('h', sample) for sample in audio_sequence[0])
dispatch(
AudioPlayAudioAction(
sample=sample,
channels=1,
rate=rate,
width=2,
),
)


@autorun(lambda state: state.voice.is_access_key_set)
Expand Down Expand Up @@ -186,7 +186,7 @@ def _menu_sub_heading(_: bool | None) -> str:

ENGINE_LABELS = {
VoiceEngine.PIPER: 'Piper',
VoiceEngine.ORCA: 'Orca',
VoiceEngine.PICOVOICE: 'Picovoice',
}


Expand Down Expand Up @@ -221,7 +221,7 @@ def _engine_selector() -> None:
VoiceReadTextAction(
text={
VoiceEngine.PIPER: 'Piper voice engine selected',
VoiceEngine.ORCA: 'Orca voice engine selected',
VoiceEngine.PICOVOICE: 'Picovoice voice engine selected',
}[engine],
engine=engine,
),
Expand Down Expand Up @@ -269,10 +269,10 @@ def init_service() -> None:
),
),
SubMenuItem(
label='Orca Settings',
label='Picovoice Settings',
icon='󰔊',
sub_menu=HeadedMenu(
title='Orca Settings',
title='Picovoice Settings',
heading='󰔊 Picovoice',
sub_heading=_menu_sub_heading,
items=_menu_items,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ async def create_wireless_connection(self: CreateWirelessConnectionPage) -> None
extra_information=NotificationExtraInformation(
text='Go to your phone settings, choose QR code and hold it in '
'front of the camera to scan it.',
orca_text='Go to your phone settings, choose {QR|K Y UW AA R} '
picovoice_text='Go to your phone settings, choose {QR|K Y UW AA R} '
'code and hold it in front of the camera to scan it.',
),
)
Expand Down
Loading

0 comments on commit 9cb0bc3

Please sign in to comment.