Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

AE: Revisit Period Size, Period and Buffersize #2320

Merged
merged 1 commit into from

9 participants

@fritsch
Collaborator

First Part:
The triangle of this linear correlation was fixed to a constant Period of 16 and the Buffersize was limited to 8192. Therefore Period Size could be as low as 512. This is too small some specific hardware and results in stutter. We now use the 1024 as Period Size and use what we get as Buffersize after setting Period Size. We let the hw decide on the needed Period time.

Second part:
The initialization is now done with _near methods, so this should make sure, that we get the Sink initialized with one try.

Testing on other hardware would be a good idea.

@davilla

+1, works great on both AMLogic M1/M3 based SoCs under Pivos/Linux.

@elupus
Collaborator
@fritsch
Collaborator

@elupus:
I think I cannot follow here directly. Basically we choose what the Sink wants to give us and have an upper maximum of 256K in order to not get too far away. Basically, we can change the line as follows:

bufferSize  = std::min(bufferSize, (snd_pcm_uframes_t) 64 * 1024);

Did I miss the point?

@fritsch
Collaborator

I missed the point. You are right, it is a good idea to buffer 1 second, which corresponds to the sample rate value. Will add a patch tonight.

bufferSize  = std::min(bufferSize, (snd_pcm_uframes_t) sampleRate * channelCount );`
@fritsch
Collaborator

Now I think, if we don't need to calc at all, cause our sink is ready set up at this position, so we just could use:

snd_pcm_hw_params_set_buffer_time((m_pcm, hw_params, 1000 * 1000, NULL);

Will test it at home

@fritsch
Collaborator

@elupus:
I recalced the values and came to similar results as you did above. Though setting it to buffer a whole second cannot be done by all hw I think. I set it to double the period Size.

@elupus
Collaborator

double period size is too small I think. We want to have some time in dvdplayer to fill up new data. one second or half a second should be good enough. But don't make it much smaller.

@fritsch
Collaborator

Oki 2 is 200ms, 4 is 400 ms, 5 looks ugly, so let's try 8?

Btw. if you calc that values by hand on think of a 192khz source. that is a whole lot of data we are getting here...

@elupus
Collaborator

fine be me.

@fritsch
Collaborator

Squashed and rebased.

@gnif
Collaborator

The messy buffer size logic is REQUIRED due to issues with ALSA driver implementations, you are re-introducing a bug where the buffer size never gets set on some hardware. For confirmation please check the pulse audio ALSA driver where they have had to do the same thing.

@fritsch
Collaborator

@gnif: Thx for jumping in. So back to the roots or can we change something here, that increases period size to at least 1024 (fixes @davilla issue) e.g. the original patch, that started with period_size = 1024 and let the hw decide to use a buffer? Also see, that all hw access functions use snd_pcm_hw_params_set_buffer_size_near so I expected that at least something gets set.

@fritsch
Collaborator

I think I found a way, that does what the old logic does, but a bit more transparent, as we know which one failed and have to try only once for buffer_size.

@gnif
Collaborator

@fritsch: No worries, there is a bit of black magic and voodoo with a pinch of salt in here, I would get this tested by the community before assuming it is correct. You also need to work with a copy of the hwparams as each attempt modifies values in the structure in ALSA which can cause the next attempt to fail.

@fritsch
Collaborator

The last commit was done with the kind help of @anssih - highly appreciated. Thx.

@fritsch
Collaborator

@elupus @davilla @gnif
Okay for you all so far?

@davilla

seems ok on pivos m/1/m3, inject ?

@fritsch
Collaborator

Let's wait on @elupus as it is also important for his dvdplayer, so we don't have to change stuff afterwards, is this okay for you?

@gnif
Collaborator

@fritsch - Code looks good, but unable to test for the moment

@elupus
Collaborator
@fritsch
Collaborator

@elupus: We want to get 8 times period size, which is (the period size) always 100ms. If we see we can only get 8192 frames buffer, we reduce the period size to half the buffer in order not to run into underruns, to have enough data whenever a period ends.

@davilla davilla merged commit 3644e98 into xbmc:master
@ronie
Collaborator

meh...this is causing major audio borkage on my end.

paplayer + pulseaudio = underrun x many
http://xbmclogs.com/show.php?id=3069

all other combinations (dvdplayer + pulseaudio / paplayer + alsa) are fine.

@fritsch
Collaborator

@ronie:
Please try that one on top: #2382 You have USB soundcard, right? Same issue I have seen with some OE testers.

@fritsch
Collaborator

Yeah - no usb soundcard, but everything done in userspace via the pulseaudio default device.

@vicbitter

This PR breaks playback of DTS-HD and Dolby TrueHD on nVidia platforms...

@sjongele

Fritsch, 2320 causes big underruns with DTS-HD MA and TrueHD passthrough on my system: Intel, Ubuntu 12.04 64-bit, NVidia GT540M, ALSA, no Pulse.

@fritsch
Collaborator

@sjongele: Please retry with 2382 (just got merged) - this should fix that stuff. Buffer was way too large.

@vicbitter

@fritsch, on OpenELEC builds with PR 2382 still causes problems when playing DTS-HD and Dolby TrueHD.

@sjongele

Hello Fritsch; sorry, still lots of underruns. 2382 does not solve the issue.

@fritsch
Collaborator

Oki - so I need logfiles. Best is before and after those patches.

@fritsch fritsch deleted the fritsch:ae-period-size branch
@fritsch
Collaborator

@sjongele:
fritsch@4c8fe02

Please try this one on top of everything - let's discuss it further on my github, to not bomb too much people. I have underestimated the calculation of "sane" values. It rather looks, that we have to go back to what we had before.

@anssih
Collaborator

I'd rather not go back just yet.

Please try if either of these fixes the issue:
https://github.com/anssih/xbmc/tree/fix/AE-buffersize
https://github.com/anssih/xbmc/tree/fix/AE-periodsize

If neither helps, before/after logs would be nice.

@fritsch
Collaborator

@sjongele:
Yes, please check the patches made by @anssih - it is too early to give up yet - and as xbmc currently is in dev phase - it is okay to break and work on better dynamic defaults. When you start testing with anssih@95ea48d you can just cherry-pick the other anssih@39f2487 on top.

Thanks for your help.

@vicbitter

@fritsch , after applying both of @anssih's patches, I can confirm that DTS-HD and Dolby TrueHD are working again :)

Thanks for the quick turn around on a fix...

@Giftie

I needed to add both to fix the problem on my side.

@fritsch
Collaborator

@Giftie: Thx for your answer. This is also my experience: #2421 @anssih has PRd both and we need both. The important part is here that the bufferSize must be 4 times the periodSize -> so perhaps the second patch is enough alone - but applying a potential bufferSize without the influence of a first periodSize makes it more fail proof.

Both of those patches are in OpenELEC rc5 and for now - it looks good.

@sjongele

@fritsch
Not sure where my response ended up, but thought I had posted success with this solution as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Mar 3, 2013
  1. @fritsch

    AE: Revisit Device Opening. Try to set periodSize of 100 ms and Buffe…

    fritsch authored fritsch committed
    …rSize of 800 ms
This page is out of date. Refresh to see the latest.
Showing with 59 additions and 39 deletions.
  1. +59 −39 xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
View
98 xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
@@ -38,7 +38,6 @@
#endif
#define ALSA_OPTIONS (SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_FORMAT | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_RESAMPLE)
-#define ALSA_PERIODS 16
#define ALSA_MAX_CHANNELS 16
static enum AEChannel ALSAChannelMap[ALSA_MAX_CHANNELS + 1] = {
@@ -328,59 +327,80 @@ bool CAESinkALSA::InitializeHW(AEAudioFormat &format)
}
}
- unsigned int periods;
-
snd_pcm_uframes_t periodSize, bufferSize;
snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufferSize);
+ snd_pcm_hw_params_get_period_size_max(hw_params, &periodSize, NULL);
+
+ /*
+ We want to make sure, that we have approx 500 to 800 ms Buffer with
+ a periodSize of approx 100 ms.
+ It is calced:
+ periodSize = sampleRate / 10
+ buffersize = periodSize * 1 frame * 8.
+ */
+ periodSize = std::min(periodSize, (snd_pcm_uframes_t) sampleRate / 10);
+ bufferSize = std::min(bufferSize, (snd_pcm_uframes_t) periodSize * 8);
+
+ /*
+ According to upstream we should set buffer size first - so make sure it is always at least
+ double of period size to not get underruns
+ */
+ periodSize = std::min(periodSize, bufferSize / 2);
- bufferSize = std::min(bufferSize, (snd_pcm_uframes_t)8192);
- periodSize = bufferSize / ALSA_PERIODS;
- periods = ALSA_PERIODS;
-
- CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);
+ CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Request: periodSize %lu, bufferSize %lu", periodSize, bufferSize);
- /* work on a copy of the hw params */
snd_pcm_hw_params_t *hw_params_copy;
snd_pcm_hw_params_alloca(&hw_params_copy);
-
- /* try to set the buffer size then the period size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
- snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
+ snd_pcm_hw_params_copy(hw_params_copy, hw_params); // copy what we have and is already working
+
+ // first trying bufferSize, PeriodSize
+ // for more info see here:
+ // http://mailman.alsa-project.org/pipermail/alsa-devel/2009-September/021069.html
+ // the last three tries are done as within pulseaudio
+
+ // backup periodSize and bufferSize first. Restore them after every failed try
+ snd_pcm_uframes_t periodSizeTemp, bufferSizeTemp;
+ periodSizeTemp = periodSize;
+ bufferSizeTemp = bufferSize;
+ if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
+ || snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
+ || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
{
- /* try to set the period size then the buffer size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
+ bufferSize = bufferSizeTemp;
+ periodSize = periodSizeTemp;
+ // retry with PeriodSize, bufferSize
+ snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
+ if (snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
+ || snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
+ || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
{
- /* try to just set the buffer size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
+ // try only periodSize
+ periodSize = periodSizeTemp;
+ snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restore working copy
+ if(snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL) != 0
+ || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
{
- /* try to just set the period size */
- snd_pcm_hw_params_copy(hw_params_copy, hw_params);
- snd_pcm_hw_params_set_period_size_near(m_pcm, hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_set_periods_near (m_pcm, hw_params_copy, &periods , NULL);
- if (snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
+ // try only BufferSize
+ bufferSize = bufferSizeTemp;
+ snd_pcm_hw_params_copy(hw_params_copy, hw_params); // restory working copy
+ if (snd_pcm_hw_params_set_buffer_size_near(m_pcm, hw_params_copy, &bufferSize) != 0
+ || snd_pcm_hw_params(m_pcm, hw_params_copy) != 0)
{
- CLog::Log(LOGERROR, "CAESinkALSA::InitializeHW - Failed to set the parameters");
- return false;
+ // set default that Alsa would choose
+ CLog::Log(LOGWARNING, "CAESinkAlsa::IntializeHW - Using default alsa values - set failed");
+ if (snd_pcm_hw_params(m_pcm, hw_params) != 0)
+ {
+ CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Could not init a valid sink");
+ return false;
+ }
}
}
+ // reread values when alsa default was kept
+ snd_pcm_get_params(m_pcm, &bufferSize, &periodSize);
}
}
-
- snd_pcm_hw_params_get_period_size(hw_params_copy, &periodSize, NULL);
- snd_pcm_hw_params_get_buffer_size(hw_params_copy, &bufferSize);
-
- CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, periods %u, bufferSize %lu", periodSize, periods, bufferSize);
+ CLog::Log(LOGDEBUG, "CAESinkALSA::InitializeHW - Got: periodSize %lu, bufferSize %lu", periodSize, bufferSize);
/* set the format parameters */
format.m_sampleRate = sampleRate;
Something went wrong with that request. Please try again.