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

Update for ovos-utils 0.0.X compat. #224

Merged
merged 6 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion ovos_plugin_manager/ocp.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
from ovos_plugin_manager.utils import PluginTypes
from ovos_plugin_manager.templates.ocp import OCPStreamExtractor
from ovos_plugin_manager.templates.media import AudioPlayerBackend, VideoPlayerBackend, WebPlayerBackend
from ovos_utils.log import LOG
from functools import lru_cache

from ovos_plugin_manager.utils import find_plugins

try:
from ovos_plugin_manager.templates.media import AudioPlayerBackend, VideoPlayerBackend, WebPlayerBackend
except ImportError:
LOG.warning("Please install ovos-utils~=0.1 for `AudioPlayerBackend`, "
"`VideoPlayerBackend`, and `WebPlayerBackend` imports.")


def find_ocp_plugins() -> dict:
"""
Expand Down
205 changes: 197 additions & 8 deletions ovos_plugin_manager/templates/audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,66 @@
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_bus_client import Message
from ovos_bus_client.message import dig_for_message
from ovos_utils import classproperty
from ovos_utils.log import log_deprecation
from ovos_utils.ocp import PlaybackType, TrackState
from ovos_utils.log import log_deprecation, LOG
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):
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
"""Base class for all audio backend implementations.

Arguments:
config (dict): configuration dict for the instance
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
Expand Down Expand Up @@ -58,14 +98,23 @@ 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

def supported_uris(self):
"""List of supported uri types.

Returns:
list: Supported uri's
"""

def clear_list(self):
"""Clear playlist."""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
msg = Message('ovos.common_play.playlist.clear')
self.bus.emit(msg)

@abstractmethod
def add_list(self, tracks):
"""Add tracks to backend's playlist.

Expand Down Expand Up @@ -97,6 +146,49 @@ def _uri2meta(uri):
}
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
"""

def stop(self):
"""Stop playback.

Stops the current playback.

Returns:
bool: True if playback was stopped, otherwise False
"""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved

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.
"""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
msg = Message('ovos.common_play.pause')
self.bus.emit(msg)

def resume(self):
"""Resume paused playback.

Resumes playback after being paused.
"""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
msg = Message('ovos.common_play.resume')

def next(self):
"""Skip to next track in playlist."""
self.bus.emit(Message("ovos.common_play.next"))
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -105,6 +197,103 @@ def previous(self):
"""Skip to previous track in playlist."""
self.bus.emit(Message("ovos.common_play.previous"))
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved

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 miliseconds
"""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
length = 0
msg = self._format_msg('ovos.common_play.get_track_length')
info = self.bus.wait_for_response(msg, timeout=1)
if info:
length = info.data.get("length", 0)
return length

def get_track_position(self):
"""
get current position in miliseconds
"""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
pos = 0
msg = self._format_msg('ovos.common_play.get_track_position')
info = self.bus.wait_for_response(msg, timeout=1)
if info:
pos = info.data.get("position", 0)
return pos

def set_track_position(self, milliseconds):
"""Go to X position.
Arguments:
milliseconds (int): position to go to in milliseconds
"""
msg = self._format_msg('ovos.common_play.set_track_position',
{"position": milliseconds})
self.bus.emit(msg)

def seek_forward(self, seconds=1):
"""Skip X seconds.

Arguments:
seconds (int): number of seconds to seek, if negative rewind
"""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
msg = self._format_msg('ovos.common_play.seek',
{"seconds": seconds})
self.bus.emit(msg)

def seek_backward(self, seconds=1):
"""Rewind X seconds.

Arguments:
seconds (int): number of seconds to seek, if negative jump forward.
"""
NeonDaniel marked this conversation as resolved.
Show resolved Hide resolved
msg = self._format_msg('ovos.common_play.seek',
{"seconds": seconds * -1})
self.bus.emit(msg)

def track_info(self):
"""Request information of current playing track.
Returns:
Dict with track info.
"""
msg = self._format_msg('ovos.common_play.track_info')
response = self.bus.wait_for_response(msg)
return response.data if response else {}

def shutdown(self):
"""Perform clean shutdown.

Implements any audio backend specific shutdown procedures.
"""
self.stop()

def _format_msg(self, msg_type, msg_data=None):
# this method ensures all skills are .forward from the utterance
# that triggered the skill, this ensures proper routing and metadata
msg_data = msg_data or {}
msg = dig_for_message()
if msg:
msg = msg.forward(msg_type, msg_data)
else:
msg = Message(msg_type, msg_data)
# at this stage source == skills, lets indicate audio service took over
sauce = msg.context.get("source")
if sauce == "skills":
msg.context["source"] = "audio_service"
return msg


class RemoteAudioBackend(AudioBackend):
"""Base class for remote audio backends.
Expand Down
3 changes: 2 additions & 1 deletion ovos_plugin_manager/templates/media.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from ovos_bus_client.message import Message
from ovos_utils.log import LOG
from ovos_utils.messagebus import FakeBus

from ovos_utils.ocp import MediaState, PlayerState, TrackState


Expand All @@ -18,6 +17,8 @@ class MediaBackend(metaclass=ABCMeta):
"""

def __init__(self, config=None, bus=None):
if MediaState is None:
raise RuntimeError("Please update to ovos-utils~=0.1.")
self._now_playing = None # single uri
self._track_start_callback = None
self.supports_mime_hints = False
Expand Down
2 changes: 1 addition & 1 deletion requirements/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ovos-utils < 0.2.0, >=0.1.0a8
ovos-utils < 0.2.0, >=0.0.38
ovos-bus-client < 0.2.0, >=0.0.9a3
ovos-config < 0.2.0, >=0.0.12
combo_lock~=0.2
Expand Down
3 changes: 2 additions & 1 deletion requirements/test.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pytest
pytest-timeout
pytest-cov
ovos-translate-server-plugin
ovos-translate-server-plugin
ovos-utils>=0.1.0a8
Loading