[QUESTION] How to cast m3u8 stream

I am creating an m3u8 stream that i want to be able to send to my Chromecast devices. I create the stream using ffmpeg.

I have an issue that the m3u8 file that is created is not able to be then casted. In the logs I see this error

Failed to cast media https://hass.externaldomain.com:8123/local/stream/stream.m3u8 from external_url (https://hass.externaldomain.com:8123). Please make sure the URL is: Reachable from the cast device and either a publicly resolvable hostname or an IP address

I can load that address (https://hass.externaldomain.com:8123/local/stream/stream.m3u8) in a browser and I can access it. I can open the address in VLC from my PC and it works fine. Casting though does not work.

Looking further by activating debugging on pychromecast compoents, I also see similar errors

2021-08-10 16:49:49 DEBUG (MainThread) [homeassistant.core] Bus:Handling <Event state_changed[L]: entity_id=media_player.office_speaker, old_state=<state media_player.office_speaker=idle; volume_level=0.5, is_volume_muted=False, media_content_id=https://hass.externaldomain.com:8123/local/stream/stream.m3u8, media_position=0, media_position_updated_at=2021-08-10T16:49:48.114822+10:00, app_id=CC1AD845, app_name=Default Media Receiver, entity_picture_local=None, friendly_name=Office speaker, supported_features=152463 @ 2021-08-10T16:49:48.116000+10:00>, new_state=<state media_player.office_speaker=playing; volume_level=0.5, is_volume_muted=False, media_content_id=https://hass.externaldomain.com:8123/local/stream/stream.m3u8, media_position=0, media_position_updated_at=2021-08-10T16:49:49.121109+10:00, app_id=CC1AD845, app_name=Default Media Receiver, entity_picture_local=None, friendly_name=Office speaker, supported_features=152463 @ 2021-08-10T16:49:49.122477+10:00>>

2021-08-10 16:49:50 DEBUG (Thread-19) [pychromecast.socket_client] [Office speaker(192.168.1.53):8009] Received: Message urn:x-cast:com.google.cast.media from f5774f5c-1c28-449c-909c-660db2e5a8b9 to sender-0: {'requestId': 8, 'type': 'LOAD_FAILED', 'detailedErrorCode': 311, 'itemId': 1}

Errorcode 311 is HLS_NETWORK_MASTER_PLAYLIST - Failed to retrieve the master playlist m3u8 file with three retries. Developers need to validate that their playlists are indeed available. It could be the case that a user that cannot reach the playlist as well.

The code I’ve used in the configuration yaml is:

    entity_id: media_player.office_speaker
    media_content_type: 'application/vnd.apple.mpegurl'
    media_content_id: 'https://hass.externaldomain.com:8123/local/stream/stream.m3u8'

I have tried with various media_content_type’s (audio, audio/mp4, audio/mpeg, application/x-mpegurl etc), but without luck.

If anyone has any idea why this would be the case?

Bump. Dealing with the same issue on live tv on https://github.com/JurajNyiri/PlexMeetsHomeAssistant/issues/39 .

@markcs Did you find any solution?

@JurajNyiri There is probably a smarter way of doing this, but I ended up installing an icecast server alongside Home Assistant and I have a few scripts to control that.

start_stream.sh

#!/bin/sh
URL=$1
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
PID=$SCRIPTPATH/pid
if [ -z "$URL" ]
then
      exit
else
      /usr/bin/ffmpeg -re -i "$URL" -loglevel error -f webm -content_type video/webm -r 30 -g 90 -s 1280x720 -quality realtime -speed 5 -threads 8 -row-mt 1 -tile-columns 2 -frame-parallel 1 -qmin 4 -qmax 48 -b:v 3000k icecast://source:username@icecast_servier_ip:port/live & echo $! > $PID &
fi
sleep 10
$SCRIPTPATH/ice_status.sh

stop_stream.sh

#!/bin/sh
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
PID=$(cat $SCRIPTPATH/pid)
kill -9 $PID
rm pid
sleep 5
$SCRIPTPATH/ice_status.sh

ice_status.sh

SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
DATA=$(curl -s --user admin:password http://icecast_server_ip:port/admin/stats.xsl)
#echo $DATA
listeners=$(echo $DATA | tr -d \\r | sed  's/.*>listeners<\/td> <td>\([[:digit:]]\).*/\1/')
sources=$(echo $DATA | tr -d \\r | sed  's/.*sources<\/td> <td>\([[:digit:]]\).*/\1/')
echo "{\"listeners\":\"$listeners\",\"sources\":\"$sources\"}" > $SCRIPTPATH/icecast_status.json

I defined those scripts as shell_commands in HA:

shell_command:
  start_icestream: '/config/custom_components/ice/start_stream.sh {{states.input_text.streaming_url.state}}'
  stop_icestream: '/config/custom_components/ice/stop_stream.sh'
  status_icestream: '/config/custom_components/ice/ice_status.sh'

I defined a input_text called streaming_url which means I can use any URL in the HA dashboard. This could be hardcoded if you wanted, but I wanted to be able to change the URL.

Then used this example here (Chromecast Radio with station and player selection) to cast to radio. I have a hard coded URL for the icecast server, so the final part of the data_template has:

    media_content_id: 'http://icecast_server_ip:port/live'
    media_content_type: 'audio/mpeg'

It is working well for me.