Coder Social home page Coder Social logo

Comments (4)

borine avatar borine commented on June 9, 2024

The "multi" alsa plugin that makes this happen seems to be the cause

The multi plugin was originally designed to be used with just one soundcard. That card provides a single clock for all the devices of the multi, so they naturally all run at exactly the same rate. When you use devices from different sound cards within a multi plugin, then they each have their own clock and so inevitably there is some very small rate drift between them. This causes one device to run down its buffer more quickly than the other.

The ALSA device seen by MPD is the multi plugin itself, and this runs at the rate set by the clock of its "master" child device. If the other child is faster than the master then it will eventually underrun because MPD is supplying samples at the rate set by the master child. There is nothing that MPD can do to work around this, it is a (design) feature of the ALSA multi plugin.

One thing you could try is to use the "speakermixer" device as the master child (you do not give the definition of "pcm.speakermixer"). The easiest way to do this is to add the key "master" to you multi definition:

pcm.mpdquader {
	type multi
		master 1
		slaves.a.pcm "mpdmixer"
		slaves.a.channels 2
# slaves.b.pcm "mpdfifo"
		slaves.b.pcm "mpdsoftvol"
		slaves.b.channels 2
		bindings.0 { slave a; channel 0; }
	bindings.1 { slave a; channel 1; }
	bindings.2 { slave b; channel 0; }
	bindings.3 { slave b; channel 1; }
}

That will make "mpdsoftvol" the master. (by default the master child is the first one given in the multi definition). Change to master 0 to make "mpdmixer" the master again.

This is not guaranteed to work. The master child not only supplies the clock, but also takes precedence when setting the hardware parameters so you may find other effects as well as the relative timing of the two devices.

Note also that the ALSA "rate" plugin can have an even greater effect on relative timing than the hardware device clock. PCM frame transfers happen at time intervals determined by the period time; but a transfer can only move a whole number of frames. If a rate conversion results in a fractional number of frames for the period size, then the rate plugin will round the period size down to the nearest whole number. This makes the child prone to underruns. The solution is to always choose a period time that is a whole number of frames at both the parent device rate and the child device rate. For example, if converting from 48000 to 44100, then choose a period time that is a multiple of 10ms: 10ms is 480 frames at 48000 and 441 frames at 44100.

output: Failed to play on "desktop (alsa)" (alsa): snd_pcm_writei() failed: Broken pipe

ALSA PCM functions return error code EPIPE to indicate underrun or overrun. Within the function AlsaOutput::DrainInternal() MPD does not attempt to recover from ALSA errors, so if an underrun occurs when MPD is draining its internal buffer then MPD stops the player. @MaxKellermann perhaps MPD should use AlsaInputStream::Recover() here to prevent recoverable errors from stopping playback?

from mpd.

peesock avatar peesock commented on June 9, 2024

"speakermixer" is the dmix plugin to my speakers:

pcm.speakermixer {
	type dmix
		ipc_key 1112
		slave {
			pcm "hw:PCH,0"
			rate 48000
			format S16_LE
			channels 2
			period_size 1024
# buffer_size 2048
			buffer_size 4096
		}
}

Setting that to the master child seems to work perfectly from short tests on both my MPD alsa device and my normal alsa device, which makes sense in hindsight (setting a loopback as the master doesn't make sense). This might also fix my long-running audio/video sync issues when recording with ffmpeg.

Thanks for the help. Should this be closed, or is mpd's stopped playback issue still an issue?

from mpd.

peesock avatar peesock commented on June 9, 2024

Update: I played around a lot and noticed that sometimes when opening pcm.mpd (and also my normal alsa device, which has the same config), it explodes and gives the same broken pipe error. On clients that don't immediately give up on errors, it seems to cause worse and worse xruns over time. But if it doesn't error at first, it seems to play forever. Edit: it does not play forever. It also constantly fails with aplay, but my normal alsa device is fine with aplay, so there must be some difference...

Increasing the number of periods from 2 to 3 or 4 eliminates the error when opening the device, but the pipe will eventually break over time. Setting lower period sizes (256) with a period of 3 or 4 shows mpd clearly increasing cpu usage over time to 100% of a core, before dropping back down and repeating.

I also tried combining alsaloop from alsa-utils with the loopback device and dmix to avoid using the multi plugin completely, but always resulted in a hundred xruns and failure. Audio is very hard.

from mpd.

borine avatar borine commented on June 9, 2024

Audio is very hard

Using low-level tools such as alsa-lib and alsaloop to achieve complex systems is hard. You need a deep understanding of what each ALSA plugin and utility does, and what their limitations are. This is not the proper place to get into such discussions.

Audio is much easier if you used audio tools that are designed to solve the 2 main problems that you are struggling with: synchronizing 2 soundcards and mixing audio streams from 2 or more applications into both those devices. Pipewire/Wireplumber and Pulseaudio do these things for free. You may have reached the point where your time is better spent learning to use use one of those rather than (the rather sparsely documented) ALSA.

from mpd.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.