Clean up forked_daapd volume saving/setting in async_play_media (#35584)

* Clean up volume saving/setting in async_play_media

* Set source to pipe when queued externally

* Add server version requirement to error string
pull/35828/head
uvjustin 2020-05-15 01:42:00 +08:00 committed by Franck Nijhof
parent 506dd1d423
commit cc431b9f14
No known key found for this signature in database
GPG Key ID: D62583BA8AB11CA3
4 changed files with 59 additions and 22 deletions

View File

@ -237,7 +237,7 @@ class ForkedDaapdMaster(MediaPlayerDevice):
self._track_info = defaultdict(
str
) # _track info is found by matching _player data with _queue data
self._last_outputs = None # used for device on/off
self._last_outputs = [] # used for device on/off
self._last_volume = DEFAULT_UNMUTE_VOLUME
self._player_last_updated = None
self._pipe_control_api = {}
@ -349,6 +349,13 @@ class ForkedDaapdMaster(MediaPlayerDevice):
):
self._tts_requested = False
self._tts_queued = True
if (
self._queue["count"] >= 1
and self._queue["items"][0]["data_kind"] == "pipe"
and self._queue["items"][0]["title"] in KNOWN_PIPES
): # if we're playing a pipe, set the source automatically so we can forward controls
self._source = f"{self._queue['items'][0]['title']} (pipe)"
self._update_track_info()
event.set()
@ -407,6 +414,7 @@ class ForkedDaapdMaster(MediaPlayerDevice):
async def async_turn_on(self):
"""Restore the last on outputs state."""
# restore state
await self._api.set_volume(volume=self._last_volume * 100)
if self._last_outputs:
futures = []
for output in self._last_outputs:
@ -418,19 +426,16 @@ class ForkedDaapdMaster(MediaPlayerDevice):
)
)
await asyncio.wait(futures)
else:
selected = []
for output in self._outputs:
selected.append(output["id"])
await self._api.set_enabled_outputs(selected)
else: # enable all outputs
await self._api.set_enabled_outputs(
[output["id"] for output in self._outputs]
)
async def async_turn_off(self):
"""Pause player and store outputs state."""
await self.async_media_pause()
if any(
[output["selected"] for output in self._outputs]
): # only store output state if some output is selected
self._last_outputs = self._outputs
self._last_outputs = self._outputs
if any([output["selected"] for output in self._outputs]):
await self._api.set_enabled_outputs([])
async def async_toggle(self):
@ -613,8 +618,12 @@ class ForkedDaapdMaster(MediaPlayerDevice):
url = self._api.full_url(url)
return url
async def _set_tts_volumes(self):
async def _save_and_set_tts_volumes(self):
if self.volume_level: # save master volume
self._last_volume = self.volume_level
self._last_outputs = self._outputs
if self._outputs:
await self._api.set_volume(volume=self._tts_volume * 100)
futures = []
for output in self._outputs:
futures.append(
@ -623,7 +632,6 @@ class ForkedDaapdMaster(MediaPlayerDevice):
)
)
await asyncio.wait(futures)
await self._api.set_volume(volume=self._tts_volume * 100)
async def _pause_and_wait_for_callback(self):
"""Send pause and wait for the pause callback to be received."""
@ -641,14 +649,12 @@ class ForkedDaapdMaster(MediaPlayerDevice):
"""Play a URI."""
if media_type == MEDIA_TYPE_MUSIC:
saved_state = self.state # save play state
if any([output["selected"] for output in self._outputs]): # save outputs
self._last_outputs = self._outputs
await self._api.set_enabled_outputs([]) # turn off outputs
saved_mute = self.is_volume_muted
sleep_future = asyncio.create_task(
asyncio.sleep(self._tts_pause_time)
) # start timing now, but not exact because of fd buffer + tts latency
await self._pause_and_wait_for_callback()
await self._set_tts_volumes()
await self._save_and_set_tts_volumes()
# save position
saved_song_position = self._player["item_progress_ms"]
saved_queue = (
@ -678,7 +684,9 @@ class ForkedDaapdMaster(MediaPlayerDevice):
_LOGGER.warning("TTS request timed out")
self._tts_playing_event.clear()
# TTS done, return to normal
await self.async_turn_on() # restores outputs
await self.async_turn_on() # restore outputs and volumes
if saved_mute: # mute if we were muted
await self.async_mute_volume(True)
if self._use_pipe_control(): # resume pipe
await self._api.add_to_queue(
uris=self._sources_uris[self._source], clear=True

View File

@ -16,7 +16,7 @@
"websocket_not_enabled": "forked-daapd server websocket not enabled.",
"wrong_host_or_port": "Unable to connect. Please check host and port.",
"wrong_password": "Incorrect password.",
"wrong_server_type": "Not a forked-daapd server.",
"wrong_server_type": "The forked-daapd integration requires a forked-daapd server with version >= 27.0.",
"unknown_error": "Unknown error."
},
"abort": {

View File

@ -9,7 +9,7 @@
"websocket_not_enabled": "forked-daapd server websocket not enabled.",
"wrong_host_or_port": "Unable to connect. Please check host and port.",
"wrong_password": "Incorrect password.",
"wrong_server_type": "Not a forked-daapd server."
"wrong_server_type": "The forked-daapd integration requires a forked-daapd server with version >= 27.0."
},
"flow_title": "forked-daapd server: {name} ({host})",
"step": {

View File

@ -111,7 +111,7 @@ SAMPLE_PLAYER_STOPPED = {
"item_progress_ms": 5,
}
SAMPLE_TTS_QUEUE = {
SAMPLE_QUEUE_TTS = {
"version": 833,
"count": 1,
"items": [
@ -127,11 +127,31 @@ SAMPLE_TTS_QUEUE = {
"length_ms": 0,
"track_number": 1,
"media_kind": "music",
"data_kind": "url",
"uri": "tts_proxy_somefile.mp3",
}
],
}
SAMPLE_QUEUE_PIPE = {
"version": 833,
"count": 1,
"items": [
{
"id": 12322,
"title": "librespot-java",
"artist": "some artist",
"album": "some album",
"album_artist": "The xx",
"length_ms": 0,
"track_number": 1,
"media_kind": "music",
"data_kind": "pipe",
"uri": "pipeuri",
}
],
}
SAMPLE_CONFIG = {
"websocket_port": 3688,
"version": "25.0",
@ -272,7 +292,7 @@ async def get_request_return_values_fixture():
"config": SAMPLE_CONFIG,
"outputs": SAMPLE_OUTPUTS_ON,
"player": SAMPLE_PLAYER_PAUSED,
"queue": SAMPLE_TTS_QUEUE,
"queue": SAMPLE_QUEUE_TTS,
}
@ -630,7 +650,9 @@ async def pipe_control_api_object_fixture(
return pipe_control_api.return_value
async def test_librespot_java_stuff(hass, pipe_control_api_object):
async def test_librespot_java_stuff(
hass, get_request_return_values, mock_api_object, pipe_control_api_object
):
"""Test options update and librespot-java stuff."""
state = hass.states.get(TEST_MASTER_ENTITY_NAME)
assert state.attributes[ATTR_INPUT_SOURCE] == "librespot-java (pipe)"
@ -652,6 +674,13 @@ async def test_librespot_java_stuff(hass, pipe_control_api_object):
)
state = hass.states.get(TEST_MASTER_ENTITY_NAME)
assert state.attributes[ATTR_INPUT_SOURCE] == SOURCE_NAME_DEFAULT
# test pipe getting queued externally changes source
get_request_return_values["queue"] = SAMPLE_QUEUE_PIPE
updater_update = mock_api_object.start_websocket_handler.call_args[0][2]
await updater_update(["queue"])
await hass.async_block_till_done()
state = hass.states.get(TEST_MASTER_ENTITY_NAME)
assert state.attributes[ATTR_INPUT_SOURCE] == "librespot-java (pipe)"
async def test_librespot_java_play_media(hass, pipe_control_api_object):