mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
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
This commit is contained in:
parent
cb7b8d94c0
commit
9fd6db4b5f
@ -237,7 +237,7 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
self._track_info = defaultdict(
|
self._track_info = defaultdict(
|
||||||
str
|
str
|
||||||
) # _track info is found by matching _player data with _queue data
|
) # _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._last_volume = DEFAULT_UNMUTE_VOLUME
|
||||||
self._player_last_updated = None
|
self._player_last_updated = None
|
||||||
self._pipe_control_api = {}
|
self._pipe_control_api = {}
|
||||||
@ -349,6 +349,13 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
):
|
):
|
||||||
self._tts_requested = False
|
self._tts_requested = False
|
||||||
self._tts_queued = True
|
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()
|
self._update_track_info()
|
||||||
event.set()
|
event.set()
|
||||||
|
|
||||||
@ -407,6 +414,7 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
async def async_turn_on(self):
|
async def async_turn_on(self):
|
||||||
"""Restore the last on outputs state."""
|
"""Restore the last on outputs state."""
|
||||||
# restore state
|
# restore state
|
||||||
|
await self._api.set_volume(volume=self._last_volume * 100)
|
||||||
if self._last_outputs:
|
if self._last_outputs:
|
||||||
futures = []
|
futures = []
|
||||||
for output in self._last_outputs:
|
for output in self._last_outputs:
|
||||||
@ -418,19 +426,16 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
await asyncio.wait(futures)
|
await asyncio.wait(futures)
|
||||||
else:
|
else: # enable all outputs
|
||||||
selected = []
|
await self._api.set_enabled_outputs(
|
||||||
for output in self._outputs:
|
[output["id"] for output in self._outputs]
|
||||||
selected.append(output["id"])
|
)
|
||||||
await self._api.set_enabled_outputs(selected)
|
|
||||||
|
|
||||||
async def async_turn_off(self):
|
async def async_turn_off(self):
|
||||||
"""Pause player and store outputs state."""
|
"""Pause player and store outputs state."""
|
||||||
await self.async_media_pause()
|
await self.async_media_pause()
|
||||||
if any(
|
self._last_outputs = self._outputs
|
||||||
[output["selected"] for output in self._outputs]
|
if any([output["selected"] for output in self._outputs]):
|
||||||
): # only store output state if some output is selected
|
|
||||||
self._last_outputs = self._outputs
|
|
||||||
await self._api.set_enabled_outputs([])
|
await self._api.set_enabled_outputs([])
|
||||||
|
|
||||||
async def async_toggle(self):
|
async def async_toggle(self):
|
||||||
@ -613,8 +618,12 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
url = self._api.full_url(url)
|
url = self._api.full_url(url)
|
||||||
return 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:
|
if self._outputs:
|
||||||
|
await self._api.set_volume(volume=self._tts_volume * 100)
|
||||||
futures = []
|
futures = []
|
||||||
for output in self._outputs:
|
for output in self._outputs:
|
||||||
futures.append(
|
futures.append(
|
||||||
@ -623,7 +632,6 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
await asyncio.wait(futures)
|
await asyncio.wait(futures)
|
||||||
await self._api.set_volume(volume=self._tts_volume * 100)
|
|
||||||
|
|
||||||
async def _pause_and_wait_for_callback(self):
|
async def _pause_and_wait_for_callback(self):
|
||||||
"""Send pause and wait for the pause callback to be received."""
|
"""Send pause and wait for the pause callback to be received."""
|
||||||
@ -641,14 +649,12 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
"""Play a URI."""
|
"""Play a URI."""
|
||||||
if media_type == MEDIA_TYPE_MUSIC:
|
if media_type == MEDIA_TYPE_MUSIC:
|
||||||
saved_state = self.state # save play state
|
saved_state = self.state # save play state
|
||||||
if any([output["selected"] for output in self._outputs]): # save outputs
|
saved_mute = self.is_volume_muted
|
||||||
self._last_outputs = self._outputs
|
|
||||||
await self._api.set_enabled_outputs([]) # turn off outputs
|
|
||||||
sleep_future = asyncio.create_task(
|
sleep_future = asyncio.create_task(
|
||||||
asyncio.sleep(self._tts_pause_time)
|
asyncio.sleep(self._tts_pause_time)
|
||||||
) # start timing now, but not exact because of fd buffer + tts latency
|
) # start timing now, but not exact because of fd buffer + tts latency
|
||||||
await self._pause_and_wait_for_callback()
|
await self._pause_and_wait_for_callback()
|
||||||
await self._set_tts_volumes()
|
await self._save_and_set_tts_volumes()
|
||||||
# save position
|
# save position
|
||||||
saved_song_position = self._player["item_progress_ms"]
|
saved_song_position = self._player["item_progress_ms"]
|
||||||
saved_queue = (
|
saved_queue = (
|
||||||
@ -678,7 +684,9 @@ class ForkedDaapdMaster(MediaPlayerDevice):
|
|||||||
_LOGGER.warning("TTS request timed out")
|
_LOGGER.warning("TTS request timed out")
|
||||||
self._tts_playing_event.clear()
|
self._tts_playing_event.clear()
|
||||||
# TTS done, return to normal
|
# 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
|
if self._use_pipe_control(): # resume pipe
|
||||||
await self._api.add_to_queue(
|
await self._api.add_to_queue(
|
||||||
uris=self._sources_uris[self._source], clear=True
|
uris=self._sources_uris[self._source], clear=True
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
"websocket_not_enabled": "forked-daapd server websocket not enabled.",
|
"websocket_not_enabled": "forked-daapd server websocket not enabled.",
|
||||||
"wrong_host_or_port": "Unable to connect. Please check host and port.",
|
"wrong_host_or_port": "Unable to connect. Please check host and port.",
|
||||||
"wrong_password": "Incorrect password.",
|
"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."
|
"unknown_error": "Unknown error."
|
||||||
},
|
},
|
||||||
"abort": {
|
"abort": {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"websocket_not_enabled": "forked-daapd server websocket not enabled.",
|
"websocket_not_enabled": "forked-daapd server websocket not enabled.",
|
||||||
"wrong_host_or_port": "Unable to connect. Please check host and port.",
|
"wrong_host_or_port": "Unable to connect. Please check host and port.",
|
||||||
"wrong_password": "Incorrect password.",
|
"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})",
|
"flow_title": "forked-daapd server: {name} ({host})",
|
||||||
"step": {
|
"step": {
|
||||||
|
@ -111,7 +111,7 @@ SAMPLE_PLAYER_STOPPED = {
|
|||||||
"item_progress_ms": 5,
|
"item_progress_ms": 5,
|
||||||
}
|
}
|
||||||
|
|
||||||
SAMPLE_TTS_QUEUE = {
|
SAMPLE_QUEUE_TTS = {
|
||||||
"version": 833,
|
"version": 833,
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"items": [
|
"items": [
|
||||||
@ -127,11 +127,31 @@ SAMPLE_TTS_QUEUE = {
|
|||||||
"length_ms": 0,
|
"length_ms": 0,
|
||||||
"track_number": 1,
|
"track_number": 1,
|
||||||
"media_kind": "music",
|
"media_kind": "music",
|
||||||
|
"data_kind": "url",
|
||||||
"uri": "tts_proxy_somefile.mp3",
|
"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 = {
|
SAMPLE_CONFIG = {
|
||||||
"websocket_port": 3688,
|
"websocket_port": 3688,
|
||||||
"version": "25.0",
|
"version": "25.0",
|
||||||
@ -272,7 +292,7 @@ async def get_request_return_values_fixture():
|
|||||||
"config": SAMPLE_CONFIG,
|
"config": SAMPLE_CONFIG,
|
||||||
"outputs": SAMPLE_OUTPUTS_ON,
|
"outputs": SAMPLE_OUTPUTS_ON,
|
||||||
"player": SAMPLE_PLAYER_PAUSED,
|
"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
|
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."""
|
"""Test options update and librespot-java stuff."""
|
||||||
state = hass.states.get(TEST_MASTER_ENTITY_NAME)
|
state = hass.states.get(TEST_MASTER_ENTITY_NAME)
|
||||||
assert state.attributes[ATTR_INPUT_SOURCE] == "librespot-java (pipe)"
|
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)
|
state = hass.states.get(TEST_MASTER_ENTITY_NAME)
|
||||||
assert state.attributes[ATTR_INPUT_SOURCE] == SOURCE_NAME_DEFAULT
|
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):
|
async def test_librespot_java_play_media(hass, pipe_control_api_object):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user