Jump to content

Auto quality issues in web app


unmovable

Recommended Posts

unmovable

In a web app, Emby utilizes the navigator.connection.downlink property to measure the client's download speed. This measurement helps determine the bandwidth for the "Auto" quality setting. This approach differs from the Playback/bitratetest endpoint used in Emby applications, and it presents several issues.

  1. The NetworkInformation API estimates the downlink based on recently observed application throughput across active connections. This includes any non-local connections. Therefore, if a user has recently connected to slow applications, the downlink property might return a conservative, lower-than-actual value. For example, after browsing a few websites in chrome, I the result I get from navigator.connection.downlink is 1.45, while my actual, measured downlink is 300 mbps.

  2. The downlink property is capped at 10 megabits for privacy reasons. This cap further diminishes its reliability as a measure of actual bandwidth.

  3. Additionally, the usage of the downlink property for bandwidth estimation assumes that users connect to servers sharing similar characteristics with the Emby server. This assumption is often incorrect. For instance, consider an Emby server located in a country that is not a major internet hub, with all its users in the same country. In this scenario, most other connections would perform slower than the Emby server. The Emby server might have sub 1 ms latency and very high speeds, which is not reflected in the downlink property measurement.

Consequently, this approach leads to several problems:

  • If the user recently connected to underperforming servers, this would adversely affect the Emby server's perceived performance, even if the actual connection to the Emby server is much faster.

  • In a web app, any bitrate above 10 megabits is always transcoded, due to the cap on the downlink property.

  • Since the NetworkInformation downlink estimation is conservative and Emby does not support adaptive bitrate streaming (i.e., this property is only accessed once before playback starts), a conservative estimate based on factors unrelated to the Emby server connection will impact the streaming quality for the entire duration.

And I've observed this in my server deployment - sessions from web apps are almost always transcoded on "Auto" setting, even though I know for a fact that the speed between me and clients is much higher than what emby chooses. This never happens on native apps as they use Playback/bitratetest endpoint and when it does happen, the reasoning is actually valid.

I propose that we discontinue the use of the NetworkInformation downlink property in web applications and instead adopt the Playback/bitrate test, as is used in other Emby applications. This would likely provide a more accurate and consistent measure of a user's actual bandwidth.

Edited by unmovable
  • Agree 2
Link to comment
Share on other sites

unmovable

One more thing, if navigator.connection is not available in the browser, Emby falls back to js hardcoded value of 4e6 - 4000000 - 4 Mbps. Which is a strange magic value that will undoubtedly result in a lot of transcodes:

 

function detectBitrateWithEndpointInfo(instance, _ref) {
        return _ref.IsInNetwork ? 16e7 : function() {
            if ("undefined" != typeof navigator) {
                var connection = navigator.connection;
                if (connection) {
                    var downlink = connection.downlink;
                    if (downlink && 0 < downlink && downlink < Number.POSITIVE_INFINITY)
                        return downlink = downlink * 1e6 * .7,
                        downlink = parseInt(downlink);
                    if ((downlink = connection.downlinkMax) && 0 < downlink && downlink < Number.POSITIVE_INFINITY)
                        return downlink = downlink * 1e6 * .7,
                        downlink = parseInt(downlink)
                }
            }
            return null
        }() || 4e6
    }

At the very least, this has to be configurable server-side. Media with bitrate of 4 Mbps is a tiny minority of my library.

  • Agree 1
Link to comment
Share on other sites

Hi, yes we are constantly working on improving this. Thanks for the feedback.

  • Agree 1
Link to comment
Share on other sites

  • 1 month later...
cochize1

@unmovablehey, by any chance do you know what code in what files needs to be modified so that (for web app connections) the default setting would be set to i.e. 1080p 20 Mbps instead of Auto (so that I wouldn't have to tell all my users to change that every time)?

My library is mostly 1080p hevc movies and series (no 4k content) and my users are mostly withing very good internet connection so in my use case that could limit much of unnecessary transcoding. Rhanks in advance.

Link to comment
Share on other sites

Happy2Play
6 hours ago, cochize1 said:

@unmovablehey, by any chance do you know what code in what files needs to be modified so that (for web app connections) the default setting would be set to i.e. 1080p 20 Mbps instead of Auto (so that I wouldn't have to tell all my users to change that every time)?

My library is mostly 1080p hevc movies and series (no 4k content) and my users are mostly withing very good internet connection so in my use case that could limit much of unnecessary transcoding. Rhanks in advance.

The code above is in the apiclient.js

Link to comment
Share on other sites

cochize1
8 minutes ago, Happy2Play said:

The code above is in the apiclient.js

Before I start to dig around, do you @Happy2Playthink it is somehow possible to modify apiclient.js file that way that remote web app connections will default to 1080p 20 Mbps in stead of Auto. Of course if a user want he can change it back but I want to just adjust the starting point for remote access.

Link to comment
Share on other sites

Happy2Play
2 minutes ago, cochize1 said:

Before I start to dig around, do you @Happy2Playthink it is somehow possible to modify apiclient.js file that way that remote web app connections will default to 1080p 20 Mbps in stead of Auto. Of course if a user want he can change it back but I want to just adjust the starting point for remote access.

I know nothing about scripts but if the 4mbps above is the fallback then changing it to a higher value would change Emby webclient fallback value for Auto.

Link to comment
Share on other sites

Happy2Play

Well the OP obviously did as they broke it down on exactly where the code is.

Link to comment
Share on other sites

cochize1

one more thing, if Chrome caps the value to 10 Mbps can I still set it to fall back to my desired 20 Mbps?

Link to comment
Share on other sites

Happy2Play
36 minutes ago, cochize1 said:

one more thing, if Chrome caps the value to 10 Mbps can I still set it to fall back to my desired 20 Mbps?

Not sure I follow but client specific set bitrates have no fallback.

Link to comment
Share on other sites

visproduction

So the * .7 allows 30% overhead from whatever the detected bitrate is found for a user.  If you narrow that, then you might run into buffering, whenever the throughput drops for a period of time, for whatever reason.  The suggestion is that this detected bitrate may be slower, than what the user can receive for several possible reasons.

Two possible optimizations:

  1. OK, so first test to see if multiple bitrate speed readings over several minutes vary a lot for many enduser connection tests.  If those results show that additional testing puts the bitrate speed up, then updating the function to do multiple test and take the average, might optimize the media delivery. 
  2. But if there is no significant change from multiple testing of the bitrate, then the only other option would be to increase the *.7 upward until the overhead is so small that fluctuations in bandwidth keeps causing playback buffering.  Maybe .8 or .85 can work fine.

    I would assume someone may have already done test #2 to arrive at the .7 in the first place.

Another possible optimization would be to look closely on how accurate using IsInNetwork, as a speed test.  Is there a better way to test?  Can a segment of either, a test media file or the actual media requested, be sent and then monitor if the end user hardware overruns it's allowed 'out of order' number of packets and requests packets be resent?  Obviously, if that happens the delivery rate is a little too fast for that user and needs to be reduced.  Can this testing be run while streaming is in progress and then the delivery rate adjusted, as needed?  That sounds pretty tricky.

This type of function is built in to many delivery services and discussed, usually without code examples in reports like this:
https://techdocs.akamai.com/download-delivery/docs/add-bit-rate-limiting

Of course, running any extra tests should be done in someway, to never slow first pageload and initial playback.  Even a delay of just a one second is not acceptable for performance and people will lose interest pretty fast.  I think the stats are that 50% people leave a page with a 2 second delay.  So, no delay is allowed with this extra speed test.

Hope that is of some interest.

Edited by visproduction
Link to comment
Share on other sites

unmovable
Posted (edited)

@cochize1I'm using linuxserver docker container and I've added a custom script (/custom-cont-init.d) that patches the file and sets minimum bitrate to 10mbps when container is started:

#!/usr/bin/with-contenv bash
set -e

manager_path="/app/emby/system/dashboard-ui/modules/common/playback/playbackmanager.js"

# Wait for manager file to exist
while [ ! -f "$manager_path" ]; do
    echo "Waiting for playbackmanager.js to exist..."
    sleep 5
done

# Patch the file
error=$(sed -i 's/function playAfterBitrateDetect(maxBitrate,item,playOptions,onPlaybackStartedFn,signal){/&maxBitrate=Math.max(maxBitrate, 10000001);/' "$manager_path" 2>&1)

# Check if sed command was successful
if [ $? -ne 0 ]; then
    echo "Failed to apply streaming patch. Error: $error"
    exit 1
fi

echo "Streaming patch applied successfully."

 

One odd thing that I noticed is that emby predefined bitrates end with either 1 or 2, which I'm guessing is some sort of special value that is used for some other reasons (maybe resolution?), hence the 10000001 usage in this patch.

 

Edited by unmovable
  • Thanks 2
Link to comment
Share on other sites

cochize1

@visproductionthank you for the detailed explanation and some suggestions on how to optimize a stream. As it was fairly easy to do I changed the .7 to .85 right now and observe my users behavior. From my testing on IPTV stream which was streaming at15 Mbps my auto picked it up from 6 Mbps with .7 setting to 8Mbps with .85. Of course I can still easily manually set 1080p 20 Mbps and the same stream will play smoothly without any buffering.

@unmovablewell this looks interesting as I understand your script does what I want to do - no matter what emby's internet testings are it still sets playback to 10 Mbps? I also have my server on linux (Synology) but with regular package not docker. Do you know a way I can run your script with maybe Scheduled Tasks? Or I could modify playbackmanager.js myself manually but couldn't exactly find a piece of code to replace and wouldn't want to break anything, maybe you could help with that?

Thank you both and I really do believe that this is somehow a question many people would like to know an answer for.

Link to comment
Share on other sites

unmovable

@cochize1correct, that's exactly what it does. However, it only works for browser sessions, not for the apps.

I'm not sure how it would work in Synology, and besides, every update would break it, so you'd have to adapt the script yourself per your requirements. Or you could just switch to using docker version as I believe Synology does support running docker containers.

Link to comment
Share on other sites

cochize1

@unmovableI fully understand that it works only for browser sessions and that's what I want to control as browsers cause most of transcoding in my case.

Synology of course supports containers but Emby is the only package I use as a standalone app in Synology. I know that any changes made to the files would be erased with an update but I would like to know how to control it anyway. 

So, since I am not using Emby in docker, could you tell me how can I manually modify a file (with every update) to set the desired playback value?

Link to comment
Share on other sites

unmovable
Posted (edited)

@cochize1sure. Find the playbackmanager.js file, find the following string (the file is minified, so it's all going to be on single line):

playAfterBitrateDetect(maxBitrate,item,playOptions,onPlaybackStartedFn,signal){

And right after the { at the end, insert this:

maxBitrate=Math.max(maxBitrate, 10000001);

This will effectively force all browser streams to be at least 10mbps. Which means that even if user manually selects quality lower than 10mbps, it will be forced back to 10, so it's not just for auto quality setting. The reason being - none of my users have internet quality that bad and quality lower than 10 is almost always done in error, either by emby or by user, so I think this works better than only forcing the auto quality one.

Edited by unmovable
Link to comment
Share on other sites

hthgihwaymonk

@unmovableI gave your docker custom startup script a try. 
Which looks to be a great way to manage browser users.

I get the exit 0 code showing it was applied.
But if I set playback to something like 480p-1Mbps, that is what gets played.
At least that is what is shown in "stats for nerds", and at that low of a resolution, it's obvious it is transcoding down to that.

I'm using lscr.io/linuxserver/emby:version-4.8.3.0 and chrome

lscr.io/linuxserver/emby:version-4.8.3.0
Link to comment
Share on other sites

Happy2Play
3 minutes ago, hthgihwaymonk said:

@unmovableI gave your docker custom startup script a try. 
Which looks to be a great way to manage browser users.

I get the exit 0 code showing it was applied.
But if I set playback to something like 480p-1Mbps, that is what gets played.
At least that is what is shown in "stats for nerds", and at that low of a resolution, it's obvious it is transcoding down to that.

I'm using lscr.io/linuxserver/emby:version-4.8.3.0 and chrome

lscr.io/linuxserver/emby:version-4.8.3.0

Yes as this edit should only affect Auto not falling back to its low 4Mbps.  It should not override client set options.  Or server applied streaming limits.

Link to comment
Share on other sites

hthgihwaymonk
2 minutes ago, Happy2Play said:

Yes as this edit should only affect Auto not falling back to its low 4Mbps.  It should not override client set options.  Or server applied streaming limits.

well, for me, AUTO did not work either.
a 12Mbps show was transcoded down to 7Mbps when AUTO was selected
and the OP stated -
 

Quote

This will effectively force all browser streams to be at least 10mbps. Which means that even if user manually selects quality lower than 10mbps, it will be forced back to 10

 

Link to comment
Share on other sites

Happy2Play
1 minute ago, hthgihwaymonk said:

a 12Mbps show was transcoded down to 7Mbps when AUTO was selected

Requires context as Auto does not have a fallback of 7Mbps to other factor must be present.

Link to comment
Share on other sites

hthgihwaymonk

what other context are you looking for?
Besides the version of emby, that script was applied, and AUTO was select as playback?
 

Link to comment
Share on other sites

Happy2Play
4 minutes ago, hthgihwaymonk said:

what other context are you looking for?
Besides the version of emby, that script was applied, and AUTO was select as playback?
 

This topic is about circumventing the 4Mbps default fallback rate for Auto on a Web Browser.

So server and ffmpeg log is needed for anything different but probably needs its own topic.

 

Link to comment
Share on other sites

unmovable
On 3/17/2024 at 4:20 AM, hthgihwaymonk said:

well, for me, AUTO did not work either.
a 12Mbps show was transcoded down to 7Mbps when AUTO was selected
and the OP stated -
 

 

Sorry, I was mistaken, I had another version of the script which I since abandoned and forgot that. It will only influence "Auto" setting, not manual, as Happy2Play correctly pointed out.

Link to comment
Share on other sites

  • 1 month later...
hoonlight

The script from @unmovable works very well.

Now my family and friends can leave it on Auto on all their devices without having to change the bitrate manually. Thank you.

 

I use the default emby image, not the emby image from linuxserver, and followed the steps below to apply the patch.

1. Modify the script file (apply_patch.sh)

#!/usr/bin/with-contenv bash

manager_path="/app/emby/system/dashboard-ui/modules/common/playback/playbackmanager.js"

Modify this part as shown below.

#!/usr/bin/with-contenv sh

manager_path="/system/dashboard-ui/modules/common/playback/playbackmanager.js"

 

2. Create a Dockerfile

FROM emby/embyserver:beta

COPY apply_patch.sh /etc/cont-init.d/apply_patch.sh

RUN chmod +x /etc/cont-init.d/apply_patch.sh

 

3. Build
Now build with docker-compose and run it, and the patch will be successfully applied at container startup.

Also, to make sure this works, in my case, I needed to initialize the browser cache. 

Edited by hoonlight
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...