[P8P/Gonic] Bitrate Configuration Ignored

TL;DR:

It doesn’t matter what bitrate I choose on Symfonium, I need to override it server-side - which made me waste a bunch of data in the process.

Wanna try it yourself on my server? I made an account just for you:

[removed]

Issue description:

Hello. I have recently moved from an iPhone to Android and I’m loving Symfonium’s UX and experience. However, my data usage has significantly gone up since I switched, and this app is the reason why.

For context, I am using Gonic v0.16.0 because it was recommended on Symfonium’s website. The device I am using to run Symfonium is a Google Pixel 8 Pro.

I got curious about this data issue (in only the past three days I’ve used over 1.5GB of mobile data just on Symfonium), so I’ve been tinkering with the settings. The bitrate I have configured in the Symfonium settings is the lowest, at 64kbit/s. However, it doesn’t seem to matter, because my data usage is still very high - and I can see 1-2MiB go up for every minute of my playback (I’m using android’s native data meter for this metric).

To confirm this further, I made a little test bench. I chose a favorite song of mine from Dream Theater and converted it to Opus. Here you can see the size of the original file && the “mock transcoded” one:

As such, I expect my data usage after playing the whole song to increase by about 12MiB, + any overheads from the pings/scrobbles. However, after listening to half of the track, I found that nearly 30MiB had been consumed.

The Symfonium logs (attached below) confirm that. This is line 168 from the code below:

2023-11-04 12:16:14.359 Verbose/TranscoderManager: FFProbe [996ms]: {"streams":[{"index":0,"codec_name":"mp3","codec_long_name":"unknown","codec_type":"audio","codec_tag_string":"[0][0][0][0]","codec_tag":"0x0000","sample_fmt":"s16p","sample_rate":"44100","channels":2,"channel_layout":"stereo","bits_per_sample":0,"initial_padding":0,"r_frame_rate":"0\/0","avg_frame_rate":"0\/0","time_base":"1\/14112000","start_pts":353600,"start_time":"0.025057","duration_ts":20322385920,"duration":"1440.078367","bit_rate":"320000","disposition":{"default":0,"dub":0,"original":0,"comment":0,"lyrics":0,"karaoke":0,"forced":0,"hearing_impaired":0,"visual_impaired":0,"clean_effects":0,"attached_pic":0,"timed_thumbnails":0,"captions":0,"descriptions":0,"metadata":0,"dependent":0,"still_image":0},"tags":{"encoder":"LAME3.97 "}},{"index":1,"codec_name":"mjpeg","codec_long_name":"unknown","profile":"192","codec_type":"video","codec_tag_string":"[0][0][0][0]","codec_tag":"0x0000","width":432,"height":432,"coded_width":432,"coded_height":432,"closed_captions":0,"film_grain":0,"has_b_frames":0,"sample_aspect_ratio":"1:1","display_aspect_ratio":"1:1","pix_fmt":"yuvj420p","level":-99,"color_range":"pc","color_space":"bt470bg","chroma_location":"center","refs":1,"r_frame_rate":"90000\/1","avg_frame_rate":"0\/0","time_base":"1\/90000","start_pts":2255,"start_time":"0.025056","duration_ts":129607053,"duration":"1440.078367","bits_per_raw_sample":"8","disposition":{"default":0,"dub":0,"original":0,"comment":0,"lyrics":0,"karaoke":0,"forced":0,"hearing_impaired":0,"visual_impaired":0,"clean_effects":0,"attached_pic":1,"timed_thumbnails":0,"captions":0,"descriptions":0,"metadata":0,"dependent":0,"still_image":0},"tags":{"comment":"Cover (front)"}}],"format":{"filename":"https:\/\/music.danielstefani.online:443\/gonic\/rest\/stream.view?id=tr-15290&u=REDACTED&t=REDACTED&s=REDACTED&v=1.13.0&c=Symfonium&f=json&maxBitRate=64&format=opus","nb_streams":2,"nb_programs":0,"format_name":"mp3","start_time":"0.025056","duration":"1440.078367","size":"57631505","bit_rate":"320157","probe_score":51,"tags":{"album":"Octavarium","artist":"Dream Theater","genre":"Progressive Metal","title":"Octavarium","track":"8\/8","date":"2005"}}}

From this single log line we can extract a lot of information: The original HTTP call included the query params maxBitRate=64&format=opus, which were clearly not respected. We can also observe that no transcoding occurred, from the codec_name and size, which match with the original mp3 file.


I was gonna end the post with just the information above, but I found out about Gonic’s transcoding override feature. Thus, also repeated the experiment with a Gonic “transcoding device profiles” rule, forcing the transcoder to work at Opus@96kbit/s:

[I had an image here but the forum won’t let me post over 1 screenshot, so just imagine that it’s an image of the Gonic control panel with the configuration for opus].

And this worked! My client is now receiving transcoded data. I can’t see the actual size from this log, but I assume that it’s 96kbit/s:

2023-11-04 13:03:55.059 Verbose/TranscoderManager: FFProbe [27641ms]: {"streams":[{"index":0,"codec_name":"opus","codec_long_name":"unknown","codec_type":"audio","codec_tag_string":"[0][0][0][0]","codec_tag":"0x0000","sample_fmt":"fltp","sample_rate":"48000","channels":2,"channel_layout":"stereo","bits_per_sample":0,"initial_padding":312,"r_frame_rate":"0\/0","avg_frame_rate":"0\/0","time_base":"1\/48000","start_pts":0,"start_time":"0.000000","extradata_size":19,"disposition":{"default":0,"dub":0,"original":0,"comment":0,"lyrics":0,"karaoke":0,"forced":0,"hearing_impaired":0,"visual_impaired":0,"clean_effects":0,"attached_pic":0,"timed_thumbnails":0,"captions":0,"descriptions":0,"metadata":0,"dependent":0,"still_image":0},"tags":{"encoder":"Lavc60.3.100 libopus","album":"Octavarium","artist":"Dream Theater","genre":"Progressive Metal","title":"Octavarium","track":"8\/8","date":"2005"}}],"format":{"filename":"https:\/\/music.danielstefani.online:443\/gonic\/rest\/stream.view?id=tr-15290&u=REDACTED&t=REDACTED&s=REDACTED&v=1.13.0&c=Symfonium&f=json&maxBitRate=64&format=opus","nb_streams":1,"nb_programs":0,"format_name":"ogg","start_time":"0.000000","probe_score":100}}

As such, for this server/client combo, the settings for bitrate selection seem to do nothing. My hunch is that there’s a misunderstanding in the API contract between you guys, or Gonic is just ignoring your settings and an issue has to be opened there. Anyway I thought I’d make this post here first.

Logs:

  1. debug.log (82.0 KB) → Playback with no transcoding device profile.
  2. debug-override.log (74.5 KB) → Playback WITH transcoding device profile.

Yes we discussed that recently with @sentriz and I could not change he’s mind about respecting the param or failing to avoid this precisely :frowning:

Will add a note in the doc for now.

So for the moment you need to set server side or use another server like LMS from @itm .

1 Like

Thanks for the blazing quick reply.

That is definitely disappointing because I think Gonic is pretty good software because its resource usage is SUPER LOW (I’m running my server on an old Core 2 Duo with 2GB RAM) but I need this feature as I want separate bitrates for WiFi & Cellular - high quality at home, good enough on the go.

I’ll give LMS a try, ty for the recommend! I’ll delete the user I provided on my server as it doesn’t seem that it’s needed.

You can open a feature request on Gonic github, maybe he’ll change his mind.

LMS is also pretty lightweight (that’s the L in the name :stuck_out_tongue: )and have no problem handling my 300k songs on docker on a Synology nas.

Nice to hear! Sadly LMS doesn’t seem to have last.fm support yet, but they’ve started working on it like, a few days ago lol. So probably I’ll stick to Gonic with a lower bitrate for now because I’d rather have the scrobbling.

Anyway just to keep things aligned, I opened up a new issue regarding Gonic here.

@itm is here too so can say if / when it’s planned to support that :slight_smile:

Hello! Yes last.fm support is planned indeed, already started working on this

1 Like

Sounds great, I wish you good luck and looking forward to seeing this feature! For now I’ve already created a LMS container to try it out and it’s seems to run perfectly.

1 Like

@sentriz’s reply on the matter. Apparently the values you set on Gonic’s transcoding settings are treated like a maximum; only bitrates requested beyond that will not be transcoded, but for bitrates below that maximum, maxBitRate will be respected.

Seems it’s a max always applied and if you do not enable transcoding on server without knowing you end up with large phone bills , but well ;). And clients can’t detect properly either.
And you can’t request more and if you want no transcoding on Wifi you can’t as it will enforce server side.

This is not really how it works on many servers and I’ve discovered that lately but not sure he’ll ever agree.

Anyway if you are happy that’s the most important.

But yes in this case there’s not really a need for an extension to respect the params.

I agree with you. It doesn’t make sense to configure these settings on the server and it is a little frustrating for me as well, but personally until ITM finishes the last.fm integration, Gonic seems like the best bet. After that’s done I’ll make the switch, since LMS also has much better cover art handling (Gonic only looks for separate cover images, LMS reads the embedded album art too).

I hope that sentriz can also understand at some point that this isn’t the best UX.

The thing is that

I need this feature as I want separate bitrates for WiFi & Cellular - high quality at home

Is not possible with Gonic. If you enable server side transcoding Symfonium can’t get the full bitrate on wifi so you will always transcode for no reason.

That’s the main issue with your need. Even if you set opus 320, flac files would be transcoded on Wifi for no reason and lower quality.

That’s the main issue with your need. Even if you set opus 320, flac files would be transcoded on Wifi for no reason and lower quality.

Yup, I understand that, and that’s why I’m putting my hopes on ITM. Practically speaking though, it’s not that big of a deal for me because at home I’m using Airsonic-Advanced to play stuff (I love the web interface, nothing beats it for me).

I mostly use Symfonium when I’m commuting or playing stuff on my speaker - and transcoding is great for that purpose, so this combo works for me atm.

May I ask details about what makes the web interface better for home? In case there’s things to improve in Symfonium?

I don’t think that there’s anything on the app’s end that draws me back from using it at home per se. Your app is very beautiful and probably the best UX I’ve had in a music player, and I know how hard it is to make one - I started developing an Android music app too at some point.

It all falls down to my usage patterns. I don’t use my phone at home at all, and I’m mostly on my browser. So what happens is that I hook up my headphones with a wire instead of Bluetooth and just listen from my laptop whilst working.

The only improvement that could make my experience like 10% better would be adding a letter index when it comes to your List Views. That would make Symfonium practically perfect for my usage. And I think it’s a natural thing to have, cause every time you go to a music store to pick out records or CDs, you can find all artists organized by letters.

On Airsonic’s web UI for example I have a list of artists to my left organized by letter, so it’s easy to browse without using the search.

Thanks.

The thing about A-Z is that it’s English only :wink: Does not work for most of the other languages that have different characters, accents, …

And when not in file mode Symfonium can handle lists with 800 000 songs without issues because I don’t load all in memory so I can’t know where the letter is without slowing down everything a lot.

And of course this also only works when sorting by title ascending (or eventually descending and inverting the list) not all the many many other provided sorts.

So TL;DR; this only solve a very very limited part of the problem and it’s the reason it’s not here.

Great point, i8n is a very important thing to take care of.

Here’s some food for thought though: You don’t actually have to specify an index by English letters only. You are already incorporating a sorting step in your display pipeline, so that means you’re running some sort of comparator. In that comparator, you are probably already sorting the songs by their order on the ASCII table, or something similar - which we already know is sorted alphabetically.

My proposal is this: Why don’t you make another step in your sorting pipeline that just “groups” artists/songs/whatever that start with the same character? Then, you can populate the index with the given groups.

If you have mixed artists, let’s say with Cyrillic characters and some with Latin characters, then your index would look something like [0-9, A-Z, A-Я], because the ASCII code is in that order for said characters.

I’m not sure of the performance impact as it depends on your implementation but in the worst case scenario, you will notice a linear impact.

This is not that simple, the sort is done at database level and the app only get small parts of the data, it never have the 800 000 songs in memory or anywhere to group it would require another very slow query. So the app have no idea of the index of the first item for a given letter.

And as a reminder the app support [Wiki] Smart filters so infinite complexity on the queries so the worst case is very far from linear.

Everything is relatively simple at little scale on a computer, but at large scale on a low end mobile device this is a completely different story.

I hadn’t explored the smart filters feature before, that seems like a very powerful tool.

I understand your situation regarding the processing difficulty, so let’s forget about client-side processing as it will probably be too time consuming to find a solution without degrading performance noticeably.

How about:

  1. Utilizing Subsonic’s getIndexes in the sync process. That way you don’t do processing on your own (question here is, do the other APIs have support for a similar call?)
  2. Constraining the letter index to just the artist & folder browser - so you don’t have to deal with 800,000 songs.

For artists, you can get the index groups from the <index> elements and have it stored ready in the database (so no complex queries).
For folders, well - I think you fetch these on-demand from the server, so it shouldn’t be too expensive to get the letters in that specific context.

Anyway I don’t know the roadmap or anything internal about your app, I just love it and will keep using it for the forseeable future, so it’s really fun to talk about its technical details! I hope this conversation can be somewhat inspiring for you to just think about this in another perspective.

As I said smart filters and library filters are the issue, it is not possible to pre compute.

There’s no need for a call I could save the results of the query, but as soon as you apply any filter, the data is wrong. Since the data is dynamic the positions are dynamic there’s nothing to do about it.

The app is all about consistency and learnable UI/UX, features that only work in some screens or in some cases are not good, users will complain about the thing missing in the other places.

Most things in the app are thought and many things are based on the millions users feedback from my other app Yatse.

1 Like