Skip to content

Commit 888e9cd

Browse files
committed
Connection handling changes and tweaks for PluginSource changes
1 parent 3c4992c commit 888e9cd

File tree

1 file changed

+24
-35
lines changed

1 file changed

+24
-35
lines changed

music_assistant/providers/vban_receiver/__init__.py

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
"""
2-
VBAN protocol receiver plugin for Music Assistant.
3-
4-
We tie a single player to a single VBAN session name.
5-
The provider has multi instance support,
6-
so multiple players can be linked to multiple VBAN streams.
7-
"""
1+
"""VBAN protocol receiver plugin for Music Assistant."""
82

93
from __future__ import annotations
104

@@ -14,19 +8,18 @@
148
from contextlib import suppress
159
from typing import TYPE_CHECKING, cast
1610

17-
from aiovban.asyncio import AsyncVBANClient
1811
from aiovban.asyncio.util import BackPressureStrategy
1912
from aiovban.enums import VBANSampleRate
2013
from music_assistant_models.config_entries import ConfigEntry, ConfigValueOption
2114
from music_assistant_models.enums import (
2215
ConfigEntryType,
2316
ContentType,
24-
MediaType,
2517
ProviderFeature,
2618
StreamType,
2719
)
2820
from music_assistant_models.errors import SetupFailedError
2921
from music_assistant_models.media_items import AudioFormat
22+
from music_assistant_models.streamdetails import StreamMetadata
3023

3124
from music_assistant.constants import (
3225
CONF_BIND_IP,
@@ -36,9 +29,10 @@
3629
from music_assistant.helpers.util import (
3730
get_ip_addresses,
3831
)
39-
from music_assistant.models.player import PlayerMedia
4032
from music_assistant.models.plugin import PluginProvider, PluginSource
4133

34+
from .vban import AsyncVBANClientMod
35+
4236
if TYPE_CHECKING:
4337
from aiovban.asyncio.device import VBANDevice
4438
from aiovban.asyncio.streams import VBANIncomingStream
@@ -189,8 +183,8 @@ def __init__(
189183
self._pcm_audio_format: str = cast("str", self.config.get_value(CONF_PCM_AUDIO_FORMAT))
190184
self._pcm_sample_rate: int = cast("int", self.config.get_value(CONF_PCM_SAMPLE_RATE))
191185

192-
self._vban_receiver: AsyncVBANClient | None = None
193-
self._vban_device: VBANDevice | None = None
186+
self._vban_receiver: AsyncVBANClientMod | None = None
187+
self._vban_sender: VBANDevice | None = None
194188
self._vban_stream: VBANIncomingStream | None = None
195189

196190
self._source_details = PluginSource(
@@ -207,11 +201,9 @@ def __init__(
207201
bit_depth=_get_supported_pcm_formats()[self._pcm_audio_format],
208202
channels=2,
209203
),
210-
metadata=PlayerMedia(
211-
"VBAN Receiver",
212-
artist=self._sender_host,
204+
metadata=StreamMetadata(
213205
title=self._vban_stream_name,
214-
media_type=MediaType.PLUGIN_SOURCE,
206+
artist=self._sender_host,
215207
),
216208
stream_type=StreamType.CUSTOM,
217209
)
@@ -228,36 +220,31 @@ def instance_name_postfix(self) -> str | None:
228220

229221
async def handle_async_init(self) -> None:
230222
"""Handle async initialization of the provider."""
231-
self._vban_receiver = AsyncVBANClient(ignore_audio_streams=False)
223+
self._vban_receiver = AsyncVBANClientMod(ignore_audio_streams=False)
232224
try:
233-
result = await self._vban_receiver.listen(self._bind_ip, self._bind_port)
225+
self._udp_socket_task = asyncio.create_task(
226+
self._vban_receiver.listen(self._bind_ip, self._bind_port)
227+
)
234228
except OSError as err:
235229
raise SetupFailedError(f"Failed to start VBAN receiver plugin: {err}") from err
236-
else:
237-
self._udp_socket_fut = result
238230

239-
self._vban_device = self._vban_receiver.register_device(self._sender_host, self._bind_port)
240-
if self._vban_device:
241-
self._vban_stream = self._vban_device.receive_stream(
231+
self._vban_sender = self._vban_receiver.register_device(self._sender_host)
232+
if self._vban_sender:
233+
self._vban_stream = self._vban_sender.receive_stream(
242234
self._vban_stream_name, back_pressure_strategy=BackPressureStrategy.DRAIN_OLDEST
243235
)
244236

245237
async def unload(self, is_removed: bool = False) -> None:
246238
"""Handle close/cleanup of the provider."""
247239
self.logger.debug("Unloading plugin")
248240
if self._vban_receiver:
249-
self.logger.info("Closing UDP transport")
250-
# Can raise an uncatchable exception due to bug in aiovban library.
241+
self.logger.debug("Closing UDP transport")
251242
self._vban_receiver.close()
252-
253-
if self._udp_socket_fut and not self._udp_socket_fut.done():
254-
self._udp_socket_fut.cancel()
255243
with suppress(asyncio.CancelledError):
256-
await self._udp_socket_fut
244+
await self._udp_socket_task
257245

258-
self._udp_socket_fut = None
259246
self._vban_receiver = None
260-
self._vban_device = None
247+
self._vban_sender = None
261248
self._vban_stream = None
262249
await asyncio.sleep(0.1)
263250

@@ -268,21 +255,23 @@ def get_source(self) -> PluginSource:
268255
async def get_audio_stream(self, player_id: str) -> AsyncGenerator[bytes, None]:
269256
"""Yield raw PCM chunks from the VBANIncomingStream queue."""
270257
self.logger.debug(
271-
"Sending VBAN PCM audio stream for Player: %s//Stream: %s//Config: %s",
258+
"Getting VBAN PCM audio stream for Player: %s//Stream: %s//Config: %s",
272259
player_id,
273260
self._vban_stream_name,
274-
self._source_details.audio_format.output_format_str, # type: ignore[union-attr]
261+
self._source_details.audio_format.output_format_str,
275262
)
276263
while (
277-
self._source_details.in_use_by and self._vban_stream and not self._udp_socket_fut.done()
264+
self._source_details.in_use_by
265+
and self._vban_stream
266+
and not self._udp_socket_task.done()
278267
):
279268
try:
280269
packet = await self._vban_stream.get_packet()
281270
except asyncio.QueueShutDown: # type: ignore[attr-defined]
282271
self.logger.error(
283272
"Found VBANIncomingStream queue shut down when attempting to get VBAN packet"
284273
)
285-
raise
274+
break
286275

287276
# Skip processing full null packets.
288277
# pipewire vban-send module constantly sends full null VBAN packets when a "Stream"

0 commit comments

Comments
 (0)