Stream component: add customer header support

A bit of background. I’m the developer responsible for the custom Arlo integration.

Recently Arlo changed their back end and changed the user agent we use to get rtsp streams. In this case we were lucky and another user was able to dig into the iPhone app and find a new user_agent to get this working.

By default Arlo returns mpeg-dash streams which I believe I can feed into the stream component. The only problem is I need to add some custom headers to the request. I need to provide the an egressToken, some referer information and a user agent otherwise the request fails with INVALIDDATA.

To give you an idea, this is how I can run the ffmpeg (from a Python test project) to connect to the stream. It’s the -headers piece I need.

    os.system(f"ffmpeg -v debug "
              f"-headers 'Egress-Token: {egress_token}\r\n"
              "Origin: https://my.arlo.com\r\n"
              "Referer: https://my.arlo.com/\r\n"
              "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 14_7_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3 Safari/605.1.15\r\n' "
              f"-i '{stream_url}' "
              "-c copy out.mp4")

Is this possible to do with the stream component? I tried adding headers to the STREAM_OPTIONS_SCHEMA but it didn’t help.

Thanks.

This is the diff I need, I’ll look to create a PR for this.

diff --git a/homeassistant/components/stream/__init__.py b/homeassistant/components/stream/__init__.py
index 8fa4c69ac5a..51758f0ede8 100644
--- a/homeassistant/components/stream/__init__.py
+++ b/homeassistant/components/stream/__init__.py
@@ -44,6 +44,7 @@ from .const import (
     ATTR_SETTINGS,
     ATTR_STREAMS,
     CONF_EXTRA_PART_WAIT_TIME,
+    CONF_HTTP_HEADERS,
     CONF_LL_HLS,
     CONF_PART_DURATION,
     CONF_RTSP_TRANSPORT,
@@ -166,6 +167,8 @@ def _convert_stream_options(
         pyav_options["rtsp_transport"] = rtsp_transport
     if stream_options.get(CONF_USE_WALLCLOCK_AS_TIMESTAMPS):
         pyav_options["use_wallclock_as_timestamps"] = "1"
+    if headers := stream_options.get(CONF_HTTP_HEADERS):
+        pyav_options[CONF_HTTP_HEADERS] = headers
 
     # For RTSP streams, prefer TCP
     if isinstance(stream_source, str) and stream_source[:7] == "rtsp://":
@@ -624,5 +627,6 @@ STREAM_OPTIONS_SCHEMA: Final = vol.Schema(
         vol.Optional(CONF_RTSP_TRANSPORT): vol.In(RTSP_TRANSPORTS),
         vol.Optional(CONF_USE_WALLCLOCK_AS_TIMESTAMPS): bool,
         vol.Optional(CONF_EXTRA_PART_WAIT_TIME): cv.positive_float,
+        vol.Optional(CONF_HTTP_HEADERS): cv.string,
     }
 )
diff --git a/homeassistant/components/stream/const.py b/homeassistant/components/stream/const.py
index c81d2f6cb18..d6b96deef5c 100644
--- a/homeassistant/components/stream/const.py
+++ b/homeassistant/components/stream/const.py
@@ -60,6 +60,7 @@ RTSP_TRANSPORTS = {
 }
 CONF_USE_WALLCLOCK_AS_TIMESTAMPS = "use_wallclock_as_timestamps"
 CONF_EXTRA_PART_WAIT_TIME = "extra_part_wait_time"
+CONF_HTTP_HEADERS = "headers"
 
 
 class StreamClientError(IntEnum):