Skip to content

Commit

Permalink
fix/several_OCP_issues (#481)
Browse files Browse the repository at this point in the history
* refactor/handle_new_SEIs

requires OpenVoiceOS/ovos-utils#246

relates to OpenVoiceOS/ovos-ocp-audio-plugin#114

* fix/state_update

player state wouldnt sync with old OCP, we need to listen to track state messages

remove result filtering when a skill is explicitly requested

* less log spam

* handle OCP not reporting the stopped state

* allow older ovos-utils
  • Loading branch information
JarbasAl authored May 25, 2024
1 parent e0ac2bc commit 7465411
Showing 1 changed file with 47 additions and 11 deletions.
58 changes: 47 additions & 11 deletions ovos_core/intent_services/ocp_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import time
from os.path import join, dirname
from threading import RLock
from typing import List, Tuple, Optional
from typing import List, Tuple, Optional, Union

from ovos_classifiers.skovos.classifier import SklearnOVOSClassifier
from ovos_classifiers.skovos.features import ClassifierProbaVectorizer, KeywordFeaturesVectorizer
Expand All @@ -19,9 +19,15 @@
from ovos_utils import classproperty
from ovos_utils.log import LOG
from ovos_utils.messagebus import FakeBus
from ovos_utils.ocp import MediaType, PlaybackType, PlaybackMode, PlayerState, OCP_ID, MediaEntry, Playlist, MediaState
from ovos_utils.ocp import (MediaType, PlaybackType, PlaybackMode, PlayerState, OCP_ID,
MediaEntry, Playlist, MediaState, TrackState)
from ovos_workshop.app import OVOSAbstractApplication

try:
from ovos_utils.ocp import dict2entry
except ImportError: # older ovos-utils
dict2entry = MediaEntry.from_dict


class OCPFeaturizer:
# ignore_list accounts for "noise" keywords in the csv file
Expand Down Expand Up @@ -172,6 +178,7 @@ def register_ocp_api_events(self):
self.bus.on("ovos.common_play.search", self.handle_search_query)
self.bus.on("ovos.common_play.play_search", self.handle_play_search)
self.bus.on('ovos.common_play.status.response', self.handle_player_state_update)
self.bus.on('ovos.common_play.track.state', self.handle_track_state_update)
self.bus.on('ovos.common_play.SEI.get.response', self.handle_get_SEIs)

self.bus.on('ovos.common_play.register_keyword', self.handle_skill_keyword_register)
Expand All @@ -183,7 +190,7 @@ def register_ocp_api_events(self):
self.bus.on("mycroft.audio.service.pause", self._handle_legacy_audio_pause)
self.bus.on("mycroft.audio.service.resume", self._handle_legacy_audio_resume)
self.bus.on("mycroft.audio.service.stop", self._handle_legacy_audio_stop)
self.bus.emit(Message("ovos.common_play.status")) # sync on launch
self.bus.emit(Message("ovos.common_play.status")) # sync player state on launch

def register_ocp_intents(self):
intent_files = self.load_resource_files()
Expand Down Expand Up @@ -302,6 +309,21 @@ def handle_skill_keyword_deregister(self, message: Message):
# we need to keep the keyword available to the classifier
# OCPFeaturizer.ocp_keywords.deregister_entity(kw_label)

def handle_track_state_update(self, message: Message):
"""ovos.common_play.track.state"""
state = message.data.get("state")
if state is None:
raise ValueError(f"Got state update message with no state: "
f"{message}")
if isinstance(state, int):
state = TrackState(state)
if self.player_state != PlayerState.PLAYING and \
state in [TrackState.PLAYING_AUDIO, TrackState.PLAYING_AUDIOSERVICE,
TrackState.PLAYING_VIDEO, TrackState.PLAYING_WEBVIEW,
TrackState.PLAYING_MPRIS]:
self.player_state = PlayerState.PLAYING
LOG.info(f"OCP PlayerState: {self.player_state}")

def handle_player_state_update(self, message: Message):
"""
Handles 'ovos.common_play.status' messages with player status updates
Expand Down Expand Up @@ -567,6 +589,9 @@ def handle_stop_intent(self, message: Message):
else:
LOG.info("Requesting OCP to stop")
self.ocp_api.stop()
# old ocp doesnt report stopped state ...
# TODO - remove this once proper events are emitted
self.player_state = PlayerState.STOPPED

def handle_next_intent(self, message: Message):
if self.use_legacy_audio:
Expand Down Expand Up @@ -731,14 +756,19 @@ def _should_resume(self, phrase: str, lang: str) -> bool:
return False

# search
def filter_results(self, results: list, phrase: str, lang: str,
media_type: MediaType = MediaType.GENERIC) -> list:

def normalize_results(self, results: list) -> List[Union[MediaEntry, Playlist]]:
# support Playlist and MediaEntry objects in tracks
for idx, track in enumerate(results):
if isinstance(track, dict):
results[idx] = MediaEntry.from_dict(track)
try:
results[idx] = dict2entry(track)
except Exception as e:
LOG.error(f"got an invalid track: {track}")
results[idx] = None
return [r for r in results if r]

def filter_results(self, results: list, phrase: str, lang: str,
media_type: MediaType = MediaType.GENERIC) -> list:
# ignore very low score matches
l1 = len(results)
results = [r for r in results
Expand Down Expand Up @@ -808,9 +838,15 @@ def _search(self, phrase: str, media_type: MediaType, lang: str,
skills=skills):
results += r["results"]

LOG.debug(f"Got {len(results)} results")
results = self.filter_results(results, phrase, lang, media_type)
LOG.debug(f"Got {len(results)} usable results")
results = self.normalize_results(results)

if not skills:
LOG.debug(f"Got {len(results)} results")
results = self.filter_results(results, phrase, lang, media_type)
LOG.debug(f"Got {len(results)} usable results")
else: # no filtering if skill explicitly requested
LOG.debug(f"Got {len(results)} usable results from {skills}")

self.bus.emit(Message("ovos.common_play.search.end"))
return results

Expand Down Expand Up @@ -865,7 +901,7 @@ def select_best(self, results: list) -> MediaEntry:

for res in results:
if isinstance(res, dict):
res = MediaEntry.from_dict(res)
res = dict2entry(res)
if not best or res.match_confidence > best.match_confidence:
best = res
ties = [best]
Expand Down

0 comments on commit 7465411

Please sign in to comment.