google / ExoPlayer

This project is deprecated and stale. The latest ExoPlayer code is available in https://github.com/androidx/media
https://developer.android.com/media/media3/exoplayer
Apache License 2.0
21.71k stars 6.02k forks source link

Improve speed/responsiveness of adaptive switches for audio only playback #3342

Open 0c6a183d opened 7 years ago

0c6a183d commented 7 years ago

Issue description

Hello. When playing DASH M4a AAC Audio, I have having two issues;

  1. The bandwidth meter takes on average 1:30 to generate its initial estimate. I have set (DEFAULT_MAX_INITIAL_BITRATE = 64_000) so that users get a quick start regardless of their current bandwidth. This selects the low bandwidth stream of ~40Kbps as expected. However it is not until 1-2 Minutes of play that bandwidth_meter estimates appear and the player starts downloading a higher bit rate stream.

  2. When throttling the available bandwidth (via a firewall) mid playback, the bandwidth meter does not appear to react to bandwidth changes until the buffer is drained empty, even with a large (20 Second) buffer. When I change a 512Kbps throttle to a 64Kbps throttle, the buffer starts draining and the player continues to perform GET requests on 320Kbps chunks which are far too large for the 64Kbps of bandwidth. The audio stops, the state changes to buffering and the player attempts to buffer a few more 320Kbps chunks before the bandwidth meter estimate drops to 64Kbps then the player starts performing GET requests on the lower 40Kbps stream. I have tested the audio/DASH media on the web based DASH reference player and it switches to the lower quality within a few seconds of the throttle being applied.

Thank you for your time , in advance.

Please Note: All audio tracks are the same sample rate and same codec for testing purposes. I have tried many variations of the below settings, plus the defaults to no avail....

DEFAULT_MAX_INITIAL_BITRATE = 64_000; DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS = 16_000; DEFAULT_MAX_DURATION_FOR_QUALITY_DECREASE_MS = 8_000; DEFAULT_MIN_DURATION_TO_RETAIN_AFTER_DISCARD_MS = 0_000; DEFAULT_BANDWIDTH_FRACTION = 0.75f;

DEFAULT_MIN_BUFFER_MS = 10_000; DEFAULT_MAX_BUFFER_MS = 20_000; DEFAULT_BUFFER_FOR_PLAYBACK_MS = 2_000; DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = 4_000;

Reproduction steps

Not required yet as it may be due to my code / settings.

Link to test content

Not required yet as it may be due to my code / settings.

Version of ExoPlayer being used

2.5.3

Device(s) and version(s) of Android being used

Same issue on all below Sony XA (F3111) Nougat 7.1 Samsung S4 (GT-I9505) Lollipop 5.0.1 LG G3 (D-855) Lollipop 5.0.0

A full bug report captured from the device

Not required yet as it may be due to my code / settings.

tonihei commented 7 years ago

That's actually a known issue and something we want to improve on. I'll mark this as an enhancement to track this.

Some background for explanation: Our current bandwidth meter keeps a window of recent bandwidth measurements and uses a weighted median of these measurements as final bandwidth estimate. The reason for this is to remove outliers and noise over time. However, it also means that sudden changes (including the initial correction to the actual bandwidth) won't be recognized very fast.

One quick workaround to let your bandwidth meter adapt much faster to new measurements is to decrease the "maxWeight" parameter of the DefaulBandwidthMeter which can be passed as a constructor parameter. Our default value is 2000. Note that you can't set this value to zero without rewriting the class because it has to be larger than sqrt(downloadedSampleSizeInBytes).

0c6a183d commented 7 years ago

Thank you for your reply and explanation. As you advised, changing the "maxWeight" parameter of the DefaultBandwidthMeter, made a huge difference and the audio tracks switch up and down within a within a few seconds to match the current bandwidth conditions. I can see the requirement for the "maxWeight" parameter, as if set too low, it estimates a very erratic bandwidth reading and caused a few undesired track changes within quick succession of each other. Setting it to a higher value seems to smooth out the bandwidth reading into a more average reading.

With issue 2. now resolved/controllable, I still have a small problem still with issue 1.

As I advised in my first post (1.), the bandwidth meter "sometimes" takes up to 2 minutes to start estimating an initial reading. I have completed some further testing on this, and have found the more the bandwidth is throttled on the firewall/router, the quicker the bandwidth-meter takes to produce the initial reading.

I am trying to get an initial quick start so I have set DEFAULT_MAX_INITIAL_BITRATE = 64_000; This works and starts playing my 40Kbps stream quickly. As the below results display, starving the phone of bandwidth appears to help the Bandwidth-meter estimate the initial reading. To rule out my firewall etc I tried it on 3G (6-9Mbps) and it took over a minute also. I also stopped and started the entire debugging session in between each of the below results to give the bandwidth-meter a fresh start. If you are able to shed any light on these results, and or provide an explanation / workaround, it would be much appreciated. Thanks.

(Router limiting bandwidth to 1Mbps. Bandwidth-meter takes 2m23s to produce initial estimate) 1Mbps=2:23 768Kbps=1:28 512Kbps=0:33 384Kbps=0:23 128Kbps=0:02 64Kbps=0:02 (Router limiting bandwidth to 64Kbps. Bandwidth-meter takes only 2 seconds to produce initial estimate)

tonihei commented 7 years ago

Thank you for the detailed testing. We noticed that our algorithm was tuned to work well with video data but has its limitations when to comes to audio (That's why @ojw28 changed the title of this issue).

The reason why you are seeing this behaviour is because we wait for either 2 seconds of total data transfer time or at 512 KB of total data transferred before making our first estimate. This ensures that we do not accidentally jump to the wrong conclusion due to noisy data. However, for audio data, it means that it takes a long time to reach 512 KB of data. So the timing you're seeing is most likely entirely based on the first threshold (2 seconds of total data transfer time). A slow connection uses the whole time to load data - leading to the 2 seconds real time you measured for 128 kbps and below. For the higher network speeds, the time spend tranferring data gets less and less, leading to this incredibly slow initial estimate.

That said - to fix your problem, you can copy our DefaultBandwidthMeter and replace ELAPSED_MILLIS_FOR_ESTIMATE and/or BYTES_TRANSFERRED_FOR_ESTIMATE to better suit your needs. Especially reducing the bytes needed should help for the higher network speeds. Note that for values working well with audio, it might cause problems when used for video data as it would reach an estimate very quickly and if that estimate is too high, it will cause unnecessary buffering. But as long as you use it for audio only, this workaround should help until we provide a better all purpose default solution.

0c6a183d commented 7 years ago

Hello. By editing the values you advised, I have now been able to achieve a quick start at low quality, with a rapid jump to the appropriate med/high quality, bandwidth permitting.

Thank you for all your help and quick responses on both issues, much appreciated!

alessandrojp commented 6 years ago

Hi,

I had the same issue and by changing the ELAPSED_MILLIS_FOR_ESTIMATE and BYTES_TRANSFERRED_FOR_ESTIMATE I also have been able to make it work during the playback.

But I have another issue in the beginning when it loads the EXT-X-KEY:METHOD=AES-128, URI . This file contains the key to decrypt the segment files, and even if the internet is set to 56kbps, the file has only 10 bytes so it loads very fast.

It seems because of that it's using the highest bitrate when it loads the first segments.

Anyone could advice me how I could improve this?

Thank you.

0c6a183d commented 6 years ago

Hi Alessandro.

I used DEFAULT_MAX_INITIAL_BITRATE = 64_000;

It provides (forces) the BandwidthMeter with an estimate of available bandwidth when no estimate is available. This is usually the case during in the first few seconds of playback when the BandwidthMeter has not downloaded enough data to get an accurate reading.

I have set mine to 64Kbps (as above) so it will always select a track from my mpd that is 64Kbps or lower. (48Kbps in my case)

I have then set DEFAULT_MIN_DURATION_FOR_QUALITY_INCREASE_MS = 4_000

So it always starts with 48Kbps, then after 4 Seconds, as long as the bandwidth meter has had enough time able to get an estimate (Based on your ELAPSED_MILLIS_FOR_ESTIMATE and BYTES_TRANSFERRED_FOR_ESTIMATE), it switches up to the best quality track available given the current bandwidth.

I did this to make Exoplayer start playing as quickly as possible.

Try those settings. I only started Developing 5 months ago so it make not be correct, but it works OK for my dash audio...

alessandrojp commented 6 years ago

Thank you for your reply.

Actually I have already tried to set DEFAULT_MAX_INITIAL_BITRATE to 64kbps. The first file loaded is the decryption key that has 10 bytes as I explained. I checked the bitrate of this on AdaptiveMediaSourceEventListener#onLoadCompleted and it was 64kbps as expected.

But since this file is very small, it seems the logic thinks that the internet is not slow and decide to use the highest bitrate available, in my case 320 kbps.

Do you encrypt your segments files?

0c6a183d commented 6 years ago

Hi. No my media is not encrypted.

If the CustomBandwithMeter with your new settings is behaving correctly with non-encrypted segments, but incorrectly with encrypted segments then I guess you would need the Exoplayer team to verify that it is expected behavior or not.

As a temporary workaround as DEFAULT_MAX_INITIAL_BITRATE is not helping.... I think I read that tracks can be blacklisted. If that is the case during playback, you could blacklist all the higher bit-rate streams for the first few seconds until an accurate estimate has been generated. Not sure if that is how they are meant to be used, just remember reading about it.... Might help...

Either way, probably best if you create a new issue stating its a potential issue with bandwidthMeter estimates when working with encrypted media. You will probably get a Exoplayer Team response then within 24 hours as they are pretty good.

Good Luck!

alessandrojp commented 6 years ago

Hi again,

Just to let you know, I tried to use a non-encrypted segment and it worked as expected.

Few seconds after it played in DEFAULT_MAX_INITIAL_BITRATE it switched to the highest bitrate in my case 320kbps.

One think that I didn't know is that once it switches, it will not switch again. Even if the internet connection becomes slow.

Anyway, thank you for your comments!

pals-ric commented 6 years ago

hi i am getting bitrate estimate value = -1 can anyone tell the the reason? default bandwidthmeter is not generating its initial bitrate.