From dcd97cb58536ee14e65c5e00e2a6af9f14bbb129 Mon Sep 17 00:00:00 2001 From: Daniel McKnight Date: Wed, 8 May 2024 15:16:17 -0700 Subject: [PATCH] Revert changes from #207 per review --- ovos_plugin_manager/templates/audio.py | 200 ++++++++++++++++--------- 1 file changed, 132 insertions(+), 68 deletions(-) diff --git a/ovos_plugin_manager/templates/audio.py b/ovos_plugin_manager/templates/audio.py index d5151fd8..a7937a73 100644 --- a/ovos_plugin_manager/templates/audio.py +++ b/ovos_plugin_manager/templates/audio.py @@ -3,51 +3,18 @@ These classes can be used to create an Audioservice plugin extending OpenVoiceOS's media playback options. """ -from ovos_bus_client.message import Message +from abc import ABCMeta, abstractmethod -from ovos_plugin_manager.templates.media import AudioPlayerBackend as _AB from ovos_utils import classproperty -from ovos_utils.log import LOG, log_deprecation +from ovos_utils.log import log_deprecation +from ovos_utils.fakebus import FakeBus from ovos_utils.process_utils import RuntimeRequirements -try: - from ovos_utils.ocp import PlaybackType, TrackState -except ImportError: - LOG.warning("Please update to ovos-utils~=0.1.") - from enum import IntEnum - - class PlaybackType(IntEnum): - SKILL = 0 # skills handle playback whatever way they see fit, - # eg spotify / mycroft common play - VIDEO = 1 # Video results - AUDIO = 2 # Results should be played audio only - AUDIO_SERVICE = 3 ## DEPRECATED - used in ovos 0.0.7 - MPRIS = 4 # External MPRIS compliant player - WEBVIEW = 5 # webview, render a url instead of media player - UNDEFINED = 100 # data not available, hopefully status will be updated soon.. - - - class TrackState(IntEnum): - DISAMBIGUATION = 1 # media result, not queued for playback - PLAYING_SKILL = 20 # Skill is handling playback internally - PLAYING_AUDIOSERVICE = 21 ## DEPRECATED - used in ovos 0.0.7 - PLAYING_VIDEO = 22 # Skill forwarded playback to video service - PLAYING_AUDIO = 23 # Skill forwarded playback to audio service - PLAYING_MPRIS = 24 # External media player is handling playback - PLAYING_WEBVIEW = 25 # Media playback handled in browser (eg. javascript) - - QUEUED_SKILL = 30 # Waiting playback to be handled inside skill - QUEUED_AUDIOSERVICE = 31 ## DEPRECATED - used in ovos 0.0.7 - QUEUED_VIDEO = 32 # Waiting playback in video service - QUEUED_AUDIO = 33 # Waiting playback in audio service - QUEUED_WEBVIEW = 34 # Waiting playback in browser service - - log_deprecation("ovos_plugin_manager.templates.audio has been deprecated on ovos-audio, " "move to ovos_plugin_manager.templates.media", "0.1.0") -class AudioBackend(_AB): +class AudioBackend(metaclass=ABCMeta): """Base class for all audio backend implementations. Arguments: @@ -55,6 +22,12 @@ class AudioBackend(_AB): bus (MessageBusClient): OpenVoiceOS messagebus emitter """ + def __init__(self, config=None, bus=None): + self._track_start_callback = None + self.supports_mime_hints = False + self.config = config or {} + self.bus = bus or FakeBus() + @classproperty def runtime_requirements(self): """ skill developers should override this if they do not require connectivity @@ -90,52 +63,143 @@ def runtime_requirements(self): no_internet_fallback=True, no_network_fallback=True) - # methods below deprecated and handled by OCP directly - # playlists are no longer managed plugin side - # this is just a compat layer forwarding commands to OCP + @property + def playback_time(self): + return 0 + + @abstractmethod + def supported_uris(self): + """List of supported uri types. + + Returns: + list: Supported uri's + """ + + @abstractmethod def clear_list(self): """Clear playlist.""" - msg = Message('ovos.common_play.playlist.clear') - self.bus.emit(msg) + @abstractmethod def add_list(self, tracks): """Add tracks to backend's playlist. Arguments: tracks (list): list of tracks. """ - tracks = tracks or [] - if isinstance(tracks, (str, tuple)): - tracks = [tracks] - elif not isinstance(tracks, list): - raise ValueError - tracks = [self._uri2meta(t) for t in tracks] - msg = Message('ovos.common_play.playlist.queue', - {'tracks': tracks}) - self.bus.emit(msg) - - @staticmethod - def _uri2meta(uri): - if isinstance(uri, list): - uri = uri[0] - try: - from ovos_ocp_files_plugin.plugin import OCPFilesMetadataExtractor - return OCPFilesMetadataExtractor.extract_metadata(uri) - except: - meta = {"uri": uri, - "skill_id": "mycroft.audio_interface", - "playback": PlaybackType.AUDIO, # TODO mime type check - "status": TrackState.QUEUED_AUDIO, - } - return meta + + @abstractmethod + def play(self, repeat=False): + """Start playback. + + Starts playing the first track in the playlist and will contiune + until all tracks have been played. + + Arguments: + repeat (bool): Repeat playlist, defaults to False + """ + + @abstractmethod + def stop(self): + """Stop playback. + + Stops the current playback. + + Returns: + bool: True if playback was stopped, otherwise False + """ + + def set_track_start_callback(self, callback_func): + """Register callback on track start. + + This method should be called as each track in a playlist is started. + """ + self._track_start_callback = callback_func + + def pause(self): + """Pause playback. + + Stops playback but may be resumed at the exact position the pause + occured. + """ + + def resume(self): + """Resume paused playback. + + Resumes playback after being paused. + """ def next(self): """Skip to next track in playlist.""" - self.bus.emit(Message("ovos.common_play.next")) def previous(self): """Skip to previous track in playlist.""" - self.bus.emit(Message("ovos.common_play.previous")) + + def lower_volume(self): + """Lower volume. + + This method is used to implement audio ducking. It will be called when + OpenVoiceOS is listening or speaking to make sure the media playing isn't + interfering. + """ + + def restore_volume(self): + """Restore normal volume. + + Called when to restore the playback volume to previous level after + OpenVoiceOS has lowered it using lower_volume(). + """ + + def get_track_length(self): + """ + getting the duration of the audio in milliseconds + NOTE: not yet supported by mycroft-core + """ + + def get_track_position(self): + """ + get current position in milliseconds + NOTE: not yet supported by mycroft-core + """ + + def set_track_position(self, milliseconds): + """ + go to position in milliseconds + NOTE: not yet supported by mycroft-core + Args: + milliseconds (int): number of milliseconds of final position + """ + + def seek_forward(self, seconds=1): + """Skip X seconds. + + Arguments: + seconds (int): number of seconds to seek, if negative rewind + """ + + def seek_backward(self, seconds=1): + """Rewind X seconds. + + Arguments: + seconds (int): number of seconds to seek, if negative jump forward. + """ + + def track_info(self): + """Get info about current playing track. + + Returns: + dict: Track info containing atleast the keys artist and album. + """ + ret = {} + ret['artist'] = '' + ret['album'] = '' + return ret + + def shutdown(self): + """Perform clean shutdown. + + Implements any audio backend specific shutdown procedures. + """ + self.stop() class RemoteAudioBackend(AudioBackend):