Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chromecast Player Crashes / Chomecast Reboots #3285

Closed
1 task done
ijc opened this issue Dec 9, 2024 · 13 comments · Fixed by music-assistant/server#1806
Closed
1 task done

Chromecast Player Crashes / Chomecast Reboots #3285

ijc opened this issue Dec 9, 2024 · 13 comments · Fixed by music-assistant/server#1806
Labels
bug Something isn't working Fix to be Confirmed

Comments

@ijc
Copy link

ijc commented Dec 9, 2024

What version of Music Assistant has the issue?

2.3.3

What version of the Home Assistant Integration have you got installed?

Builtin to HA core 2024.12.1

Have you tried everything in the Troubleshooting FAQ and reviewed the Open and Closed Issues and Discussions to resolve this yourself?

  • Yes

The problem

When playing back a subset of my albums on a Chromecast Ultra I see a spinning wheel where the artwork would appear and then either the app exits or the chromecast reboots -- I get the "Something went wrong" screen from the Chromecast OS and then it restarts

While the spinning is ongoing music plays ok.

The crashes appear to correlate with higher DPI/larger cover art files. All artwork was scanned locally by me from the physical CD.

Causes the problem (files are 9.6M and 14M respectively):

Holy Moses - World Chaos/cover.jpeg:                JPEG image data, JFIF standard 1.01, resolution (DPI), density 1200x1200, segment length 16, baseline, precision 8, 5664x5669, components 3
Winterfylleth - The Dark Hereafter/cover.jpeg:      JPEG image data, JFIF standard 1.01, resolution (DPI), density 1200x1200, segment length 16, baseline, precision 8, 5668x5668, components 3

Do not cause the problem (files are 381K, 156K and 475K respectively):

The Haunted - The Haunted Made Me Do It/cover.jpeg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 300x300, segment length 16, baseline, precision 8, 1405x1405, components 3
Anathema - Eternity/cover.jpeg:                     JPEG image data, JFIF standard 1.01, resolution (DPI), density 150x150, segment length 16, baseline, precision 8, 826x738, components 3
Winterfylleth - The Threnody of Triumph/cover.jpeg: JPEG image data, JFIF standard 1.01, resolution (DPI), density 300x300, segment length 16, baseline, precision 8, 1417x1417, components 3

The music files are all flac files with the same sample rate:

Holy Moses - World Chaos/01-World Chaos.flac:                       FLAC audio bitstream data, 16 bit, stereo, 44.1 kHz, 8008560 samples
Winterfylleth - The Dark Hereafter/01-The Dark Hereafter.flac:      FLAC audio bitstream data, 16 bit, stereo, 44.1 kHz, 10829784 samples
The Haunted - The Haunted Made Me Do It/01-Dark Intentions.flac:    FLAC audio bitstream data, 16 bit, stereo, 44.1 kHz, 3993696 samples
Anathema - Eternity/01-Sentient.flac:                               FLAC audio bitstream data, 16 bit, stereo, 44.1 kHz, 7969164 samples
Winterfylleth - The Threnody of Triumph/01-A Thousand Winters.flac: FLAC audio bitstream data, 16 bit, stereo, 44.1 kHz, 20097252 samples

How to reproduce

It appears to deterministically occur with specific artwork for specific albums.

Here are the various good/bad files discussed above: ma.zip

Music Providers

All music from the local provider. Album artwork is a cover.jpeg in each folder. Artwork scanned locally by me from CD cover art.

Player Providers

All my providers are chromecast.

On a Chromecast Ultra I see the issue as described above

On a JBL speaker (no screen => no artwork) I do not see the issue.

Chromecast to an nVidia shield I do not see the issue, the artwork appears ~immediately.

Full log output

music-assistant.log

Additional information

I'm queuing albums via the web UI (from the "Random album" playlist).

I'm running HA and MA in Docker compose stacks on the same machine. Network mode is "host" for both containers. Music content is bind mounted ro into the MA container at /media.

Music is all musicbrainz tagged using picard.

Nothing in the troubleshooting guide seems relevant to a chromecast device crash.

What version of Home Assistant Core are your running

2024.12.1

What type of installation are you running?

Home Assistant Container

On what type of hardware are you running?

Generic x86-64 (e.g. Intel NUC)

@ijc ijc added the triage label Dec 9, 2024
@OzGav
Copy link
Contributor

OzGav commented Dec 9, 2024

This doesn’t sound like a MA problem as the Nvidia shield works? You say the physical device is crashing so seems like a device problem. Why don’t you just reduce the file size of the images?

@ijc
Copy link
Author

ijc commented Dec 9, 2024

Isn't there some sort of "MA applet" which runs on the chromecast while MA is casting to it? I assumed there was and that the bug would be in there somewhere (and is taking out the whole device due to lack of memory protection on the device or something).

It smells like either OOM or some sort of buffer overflow to me. Since the shield likely has a lot more RAM it isn't effected. According to some searches, Chromecast ultras have 1GB and Shields start at 8GB but can have lots more, I didn't check what mine actually has, I suspect that a shiled also has a full MMU capable process so an applet cannot crash the whole device in the same way as it appears it can on an Ultra.

I'd prefer not to downscale the images, if anything I'd want to rescanning the lower res ones at higher resolution (but I doubt I'll ever bother). I don't think the high res images are especially unusual.

@OzGav
Copy link
Contributor

OzGav commented Dec 9, 2024

No MA just streams to the device.

@ijc
Copy link
Author

ijc commented Dec 9, 2024

It seems to activate MASS_APP_ID = "C35B0678" and stream to that, but I can't figure out where that "app" is defined or where the UI (album cover, title of the track etc) are defined. I'd be happy to report this again to wherever that code lives but I haven't been able to find it.

@OzGav
Copy link
Contributor

OzGav commented Dec 9, 2024

@ijc
Copy link
Author

ijc commented Dec 9, 2024

That is sending a message to the chromecast device to tell it to launch that app. It is not (AFAICT) defining the app. It appears that the app is hosted at https://music-assistant.io/cast-receiver/, referred to by "https://clients3.google.com/cast/chromecast/device/app?a=C35B0678", and the source for that appears to be https://github.com/music-assistant/cast-receiver which I hadn't found until now.

Looks like most of the functionality comes from https://www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js.

@OzGav
Copy link
Contributor

OzGav commented Dec 9, 2024

You will have to be patient until Marcel can comment then.

@ijc
Copy link
Author

ijc commented Dec 11, 2024

I hot patched my container image with the following and it seems to have worked around the issue.

Just the patch to chromecast didn't work, so I think the core player_queues one might be the one which matters, which is a shame since it seems like a too generic place to deal with a chromecast issue. Neither is the hardcoding a good solution IMHO

diff --git a/music_assistant/controllers/player_queues.py b/music_assistant/controllers/player_queues.py
index eb52f897..351a0498 100644
--- a/music_assistant/controllers/player_queues.py
+++ b/music_assistant/controllers/player_queues.py
@@ -1261,7 +1261,7 @@ class PlayerQueuesController(CoreController):
                 album.name if (album := getattr(queue_item.media_item, "album", None)) else ""
             )
             if queue_item.image:
-                media.image_url = self.mass.metadata.get_image_url(queue_item.image)
+                media.image_url = self.mass.metadata.get_image_url(queue_item.image, size = 1024)
         return media
 
     async def get_artist_tracks(self, artist: Artist) -> list[Track]:
diff --git a/music_assistant/providers/chromecast/__init__.py b/music_assistant/providers/chromecast/__init__.py
index fdd5ff54..cc1a2b38 100644
--- a/music_assistant/providers/chromecast/__init__.py
+++ b/music_assistant/providers/chromecast/__init__.py
@@ -675,7 +675,7 @@ class ChromecastProvider(PlayerProvider):
         # update metadata of current item chromecast
         if media_controller.status.media_custom_data["queue_item_id"] != current_item.queue_item_id:
             image_url = (
-                self.mass.metadata.get_image_url(current_item.image)
+                self.mass.metadata.get_image_url(current_item.image, size=1024)
                 if current_item.image
                 else MASS_LOGO_ONLINE
             )

@OzGav
Copy link
Contributor

OzGav commented Dec 11, 2024

If you think you have a solution then feel free to submit a pr so it can be properly reviewed.

@ijc
Copy link
Author

ijc commented Dec 11, 2024

As I said, it's a work around, I don't think this is appropriate as a committed solution. I'll have to dig in a bit more to figure out a path forward.

@ijc
Copy link
Author

ijc commented Dec 15, 2024

@marcelveldt may I have your advice on how best to fix this since it's a bit non-obvious what the right fix is. I'll have a some spare cycles of the holiday period to implement something.

If I understand the code correctly the items in a PlayerQueuesController are not aware of the type player they are "for" and due to things like the ability to transfer queues between players I don't think such a relationship can exist.

Given that constraint I can see a few options:

  1. Enforce a maximum resolution for all PlayerMedia.image_url (either in player_media_from_queue_item or in get_image_url)
  2. Add a second field like PlayerMedia.image_url_lowres which sets a hard coded "small enough for all uses" size field in the URL.
  3. Push the call to get_image_url in player_media_from_queue_item down into the individual player providers somehow, perhaps by propagating QueueItem.image directly.

I think 3 is the most technically correct thing to do (out of that list at least) since it pushes the URL generation down to the place which is most aware of the capabilities of the device. OTOH it would involve touching every player...

Both 1 and 2 have the issue of having to decide what res to hardcode (and also deal with the possibility that the source image might be smaller than it).

I suppose there is a half-way-to-3 solution which is to add the image field to allow players to generate their own URL but also to keep the existing image_url for cases which just want the base resolution.

Or maybe you have a better idea or other preference?

@ijc
Copy link
Author

ijc commented Dec 15, 2024

If I understand the code correctly the items in a PlayerQueuesController are not aware of the type player they are "for" and due to things like the ability to transfer queues between players I don't think such a relationship can exist.

Actually, I'm having second thoughts about this. Maybe player_media_from_queue_item can actually safely know the target player since the result is always passed directly to an actual concrete player (self.mass.players.play_media or self.mass.players.enqueue_next_media)?

Not sure how that would work with groups though...

@OzGav
Copy link
Contributor

OzGav commented Dec 15, 2024

The other option is not to send such large images in the first place. A resolution for the cover of 1000x1000 is typically regarded as sufficient?

ijc referenced this issue in ijc/music-assistant-server Dec 16, 2024
…tadata

My Chromecast Ultra crashes when presented with cover images on the order of
5000x5000 pixels (I've not determined the actual limit, 2048x2048 is ok
though).

Address this by providing an advanced option per player which downscales the
image to a specified size.

Fixes: https://github.com/music-assistant/hass-music-assistant/issues/3285
ijc referenced this issue in ijc/music-assistant-server Dec 20, 2024
…tadata

My Chromecast Ultra crashes when presented with cover images on the order of
5000x5000 pixels (I've not determined the actual limit, 2048x2048 is ok
though).

Allow users to avoid this problem by providing an advanced option per player
which downscales the image to a specified size.

Fixes: https://github.com/music-assistant/hass-music-assistant/issues/3285
ijc referenced this issue in ijc/music-assistant-server Dec 20, 2024
My Chromecast Ultra crashes when presented with cover images on the order of
5000x5000 pixels (I've not determined the actual limit, 2048x2048 is ok
though).

Fixes: https://github.com/music-assistant/hass-music-assistant/issues/3285
@OzGav OzGav added bug Something isn't working Fix to be Confirmed and removed triage labels Dec 20, 2024
ijc referenced this issue in ijc/music-assistant-server Dec 21, 2024
My Chromecast Ultra crashes when presented with cover images on the order of
5000x5000 pixels (I've not determined the actual limit, 2048x2048 is ok
though).

This sets the default size in the player queue to 512x512 which affects all
players, as well as a chromecast specific codepath. Of the other callers of
`get_image_url` airplay already sets a size of 500x500 while the slimproto and
sonos players do not set any limit.

Fixes: https://github.com/music-assistant/hass-music-assistant/issues/3285
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Fix to be Confirmed
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants