from datetime import timedelta import voluptuous as vol from homeassistant.components import media_source from homeassistant.components.media_player import ( async_process_play_media_url, BrowseMedia, MediaPlayerEntity, MediaPlayerEntityFeature, PLATFORM_SCHEMA, ) from homeassistant.const import STATE_PLAYING, STATE_IDLE, CONF_NAME from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.reload import async_setup_reload_service from homeassistant.helpers.typing import ConfigType from . import utils from .utils import DOMAIN PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( { vol.Required(CONF_NAME): cv.string, vol.Required("stream"): cv.string, vol.Required("audio"): cv.string, }, extra=vol.REMOVE_EXTRA, ) SCAN_INTERVAL = timedelta(seconds=60) async def async_setup_platform( hass: HomeAssistant, config: ConfigType, async_add_entities, discovery_info=None ) -> None: await async_setup_reload_service(hass, DOMAIN, ["media_player"]) player = WebRTCPlayer(**config) async_add_entities([player]) class WebRTCPlayer(MediaPlayerEntity): def __init__(self, name: str, stream: str, audio: str, **kwargs): self._attr_supported_features = ( MediaPlayerEntityFeature.PLAY_MEDIA | MediaPlayerEntityFeature.BROWSE_MEDIA | MediaPlayerEntityFeature.STOP ) self._attr_name = name self._attr_unique_id = stream self.audio = audio async def async_play_media(self, media_type: str, media_id: str, **kwargs) -> None: if media_source.is_media_source_id(media_id): sourced_media = await media_source.async_resolve_media( self.hass, media_id, self.entity_id ) media_id = sourced_media.url media_id = async_process_play_media_url(self.hass, media_id) if not media_type.startswith("#"): media_type = "#input=file" r = await async_get_clientsession(self.hass).post( utils.api_streams(self.hass), params={ "dst": self.unique_id, "src": f"ffmpeg:{media_id}#audio={self.audio}{media_type}", }, timeout=9, ) assert r.ok async def async_media_stop(self) -> None: r = await async_get_clientsession(self.hass).post( utils.api_streams(self.hass), params={"dst": self.unique_id, "src": ""}, timeout=3, ) assert r.ok async def async_update(self): try: r = await async_get_clientsession(self.hass).get( utils.api_streams(self.hass), params={"src": self.unique_id}, timeout=9 ) self._attr_available = r.ok resp = await r.json(content_type=None) playing = any("type" in p for p in resp["producers"]) self._attr_state = STATE_PLAYING if playing else STATE_IDLE except: pass async def async_browse_media( self, media_content_type: str = None, media_content_id: str = None ) -> BrowseMedia: return await media_source.async_browse_media(self.hass, media_content_id)