From 2a6f1131516cdeb9a8a57d2a8cf4d1f2b315f364 Mon Sep 17 00:00:00 2001 From: Chris Rogers Date: Sun, 14 Apr 2019 10:11:52 -0400 Subject: [PATCH] Add function to acknowledge success non-verbally --- mycroft/configuration/mycroft.conf | 3 ++- mycroft/res/snd/acknowledge.mp3 | Bin 0 -> 6268 bytes mycroft/skills/core.py | 24 +++++++++++++++++++++- mycroft/util/__init__.py | 32 ++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 mycroft/res/snd/acknowledge.mp3 diff --git a/mycroft/configuration/mycroft.conf b/mycroft/configuration/mycroft.conf index 7c35091a48..d827bc1e65 100644 --- a/mycroft/configuration/mycroft.conf +++ b/mycroft/configuration/mycroft.conf @@ -44,7 +44,8 @@ // File locations of sounds to play for system events "sounds": { "start_listening": "snd/start_listening.wav", - "end_listening": "snd/end_listening.wav" + "end_listening": "snd/end_listening.wav", + "acknowledge": "snd/acknowledge.mp3" }, // Mechanism used to play WAV audio files diff --git a/mycroft/res/snd/acknowledge.mp3 b/mycroft/res/snd/acknowledge.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..efb06b4975178a91399f14329f6f5c40420e0706 GIT binary patch literal 6268 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 C3#+XF literal 0 HcmV?d00001 diff --git a/mycroft/skills/core.py b/mycroft/skills/core.py index 06febb605a..7d630709b5 100644 --- a/mycroft/skills/core.py +++ b/mycroft/skills/core.py @@ -44,7 +44,9 @@ from mycroft.skills.settings import SkillSettings from mycroft.skills.skill_data import (load_vocabulary, load_regex, to_alnum, munge_regex, munge_intent_parser, read_vocab_file) -from mycroft.util import camel_case_split, resolve_resource_file +from mycroft.util import (camel_case_split, + resolve_resource_file, + play_audio_file) from mycroft.util.log import LOG MainModule = '__init__' @@ -1648,6 +1650,26 @@ class MycroftSkill: for e in list(self.scheduled_repeats): self.cancel_scheduled_event(e) + def acknowledge(self): + """ Acknowledge a successful request. + + This method plays a sound to acknowledge a request that does not + require a verbal response. This is intended to provide simple feedback + to the user that their request was handled successfully. + """ + file = resolve_resource_file( + self.config_core.get('sounds').get('acknowledge')) + + if not file: + LOG.warning("Could not find 'acknowledge' audio file!") + return + + process = play_audio_file(file) + if process: + process.wait() + else: + LOG.warning("Unable to play 'acknowledge' audio file!") + ####################################################################### # FallbackSkill base class diff --git a/mycroft/util/__init__.py b/mycroft/util/__init__.py index 4db7e00fc3..1b19dae6d1 100644 --- a/mycroft/util/__init__.py +++ b/mycroft/util/__init__.py @@ -18,7 +18,7 @@ import socket import subprocess import pyaudio -from os.path import join, expanduser +from os.path import join, expanduser, splitext from threading import Thread from time import sleep @@ -93,6 +93,36 @@ def resolve_resource_file(res_name): return None # Resource cannot be resolved +def play_audio_file(uri: str): + """ Play an audio file. + + This wraps the other play_* functions, choosing the correct one based on + the file extension. The function will return directly and play the file + in the background. + + Arguments: + uri: uri to play + + Returns: subprocess.Popen object. None if the format is not supported or + an error occurs playing the file. + + """ + extension_to_function = { + '.wav': play_wav, + '.mp3': play_mp3, + '.ogg': play_ogg + } + _, extension = splitext(uri) + play_function = extension_to_function.get(extension.lower()) + if play_function: + return play_function(uri) + else: + LOG.error("Could not find a function capable of playing {uri}." + " Supported formats are {keys}." + .format(uri=uri, keys=list(extension_to_function.keys()))) + return None + + def play_wav(uri): """ Play a wav-file.