Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PipeWire output plugin does not set sample rate #1283

Closed
jpalus opened this issue Oct 16, 2021 · 17 comments
Closed

PipeWire output plugin does not set sample rate #1283

jpalus opened this issue Oct 16, 2021 · 17 comments
Labels
waiting Waiting for more information from reporter

Comments

@jpalus
Copy link

jpalus commented Oct 16, 2021

Bug report

Describe the bug

With new pipewire output plugin in mpd 0.23 sample rate is no longer set dynamically based on input file. When using ALSA as well as PulseAudio plugins, both backed by pipewire, sample rate is changed correctly. pw-top shows as if mpd didn't set rate (value 0) hence device seems to always be set to default rate (48kHz) instead of matching rate from input file:
image

Expected Behavior

Sample rate of output device matches input file.

Actual Behavior

Sample rate of output device remains constant.

Version

Music Player Daemon 0.23 (0.23)
Copyright 2003-2007 Warren Dukes <warren.dukes@gmail.com>
Copyright 2008-2021 Max Kellermann <max.kellermann@gmail.com>
This is free software; see the source for copying conditions.  There is NO
warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Database plugins:
 simple proxy upnp

Storage plugins:
 local smbclient udisks nfs curl

Neighbor plugins:
 smbclient upnp udisks

Decoders plugins:
 [mad] mp3 mp2
 [mpg123] mp3
 [vorbis] ogg oga
 [oggflac] ogg oga
 [flac] flac
 [opus] opus ogg oga
 [sndfile] wav aiff aif au snd paf iff svx sf voc w64 pvf xi htk caf sd2
 [audiofile] wav au aiff aif
 [dsdiff] dff
 [dsf] dsf
 [hybrid_dsd] m4a
 [faad] aac
 [wavpack] wv
 [openmpt] mptm mod s3m xm it 669 amf ams c67 dbm digi dmf dsm dtm far imf ice j2b m15 mdl med mms mt2 mtm nst okt plm psm pt36 ptm sfx sfx2 st26 stk stm stp ult wow gdm mo3 oxm umx xpk ppm mmcmp
 [modplug] 669 amf ams dbm dfm dsm far it med mdl mod mtm mt2 okt s3m stm ult umx xm
 [mikmod] amf dsm far gdm imf it med mod mtm s3m stm stx ult uni xm
 [sidplay] sid mus str prg P00
 [wildmidi] mid
 [fluidsynth] mid
 [adplug] amd d00 hsc laa rad raw sa2
 [ffmpeg] 16sv 3g2 3gp 4xm 8svx aa3 aac ac3 adx afc aif aifc aiff al alaw amr anim apc ape asf atrac au aud avi avm2 avs bap bfi c93 cak cin cmv cpk daud dct divx dts dv dvd dxa eac3 film flac flc fli fll flx flv g726 gsm gxf iss m1v m2v m2t m2ts m4a m4b m4v mad mj2 mjpeg mjpg mka mkv mlp mm mmf mov mp+ mp1 mp2 mp3 mp4 mpc mpeg mpg mpga mpp mpu mve mvi mxf nc nsv nut nuv oga ogm ogv ogx oma ogg omg opus psp pva qcp qt r3d ra ram rl2 rm rmvb roq rpl rvc shn smk snd sol son spx str swf tak tgi tgq tgv thp ts tsp tta xa xvid uv uv2 vb vid vob voc vp6 vmd wav webm wma wmv wsaud wsvga wv wve rtp:// rtsp:// rtsps://
 [gme] ay gbs gym hes kss nsf nsfe rsn sap spc vgm vgz
 [pcm]

Filters:
 libsamplerate soxr

Tag plugins:
 id3tag

Output plugins:
 shout null fifo pipe alsa ao oss openal pipewire pulse jack httpd snapcast recorder

Encoder plugins:
 null vorbis opus lame twolame wave flac shine

Archive plugins:
 [bz2] bz2
 [zzip] zip
 [iso] iso

Input plugins:
 file io_uring archive alsa qobuz curl ffmpeg smbclient nfs mms cdio_paranoia

Playlist plugins:
 extm3u m3u pls xspf asx rss soundcloud flac cue embcue

Protocols:
 file:// alsa:// cdda:// ftp:// ftps:// gopher:// hls+http:// hls+https:// http:// https:// mms:// mmsh:// mmst:// mmsu:// nfs:// qobuz:// rtmp:// rtmpe:// rtmps:// rtmpt:// rtmpte:// rtp:// rtsp:// rtsps:// scp:// sftp:// smb:// srtp://

Other features:
 avahi dbus udisks epoll icu inotify ipv6 systemd tcp un
@jpalus jpalus changed the title PipeWire does not set sample rate PipeWire output plugin does not set sample rate Oct 16, 2021
@MaxKellermann
Copy link
Member

First of all, why did you refuse to post your log?

Second: can you explain how to do that, and what MPD is doing wrong?
MPD sets spa_audio_info_raw.rate here:

raw.rate = audio_format.sample_rate;

... which gets passed to pw_stream_connect() here:
params[0] = spa_format_audio_raw_build(&pod_builder,
SPA_PARAM_EnumFormat, &raw);
pw_stream_connect(stream,
PW_DIRECTION_OUTPUT,
target_id,
(enum pw_stream_flags)(PW_STREAM_FLAG_AUTOCONNECT |
PW_STREAM_FLAG_INACTIVE |
PW_STREAM_FLAG_MAP_BUFFERS |
PW_STREAM_FLAG_RT_PROCESS),
params, 1);

Had you pasted your log, as I asked you to (but you refused), you would have seen that MPD's resampling code is disabled, and MPD passes whatever sample rate is in your source file to libpipewire. It is then libpipewire's decision to resample, if that really happens, no idea, you didn't post any data backing this up.

My point is: MPD told libpipewire the audio format, and my idea is that's all that's needed to convince PipeWire to use that audio format. The decision to use another audio format is now outside of MPD.

@MaxKellermann MaxKellermann added the waiting Waiting for more information from reporter label Oct 17, 2021
@MaxKellermann
Copy link
Member

Is what you're asking even possible with PipeWire?
See https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#setting-sample-rates

PipeWire uses a global sample rate in the processing pipeline. All signals are converted to this sample rate and then converted to the sample rate of the device.

@jpalus
Copy link
Author

jpalus commented Oct 18, 2021

First of all, why did you refuse to post your log?

I didn't refuse anything, log did not contain anything that could be useful for the issue but contained lots of personal data I don't want to share and was not eager on filtering just to attach redundant log.

you would have seen that MPD's resampling code is disabled, and MPD passes whatever sample rate is in your source file to libpipewire

Where did I claim MPD resamples?

My point is: MPD told libpipewire the audio format

My point is: MPD didn't told libpipewire the audio format

Is what you're asking even possible with PipeWire?

It is, as mentioned in description both ALSA plugin provided by PipeWire, as well as PulseAudio server provided by PipeWire do it right.

Second: can you explain how to do that, and what MPD is doing wrong?

I don't really know, I'm merely MPD user which tried out new PipeWire output and didn't see his DAC changing frequency. But anyway after quick look into ALSA plugin code I guess the missing piece is:

pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", audio_format.sample_rate);

After adding this prop sample rate is dynamic, though pw-top still does not show any rate for MPD node, not sure why. Perhaps @wtay would be able to tell if there's anything wrong with

PipeWireOutput::Open(AudioFormat &audio_format)

@MaxKellermann
Copy link
Member

First of all, why did you refuse to post your log?

I didn't refuse anything, log did not contain anything that could be useful for the issue but contained lots of personal data I don't want to share and was not eager on filtering just to attach redundant log.

Yes, you did refuse. And you just explained the reason.

But let me judge what is useful and what is not.

you would have seen that MPD's resampling code is disabled, and MPD passes whatever sample rate is in your source file to libpipewire

Where did I claim MPD resamples?

You did not. But without implying that MPD resamples, your issue description doesn't make sense. If we had your log available, I could have explained to you.

My point is: MPD told libpipewire the audio format

My point is: MPD didn't told libpipewire the audio format

What the ... are you trying to troll me?
I showed you the very piece of code that does it. How can you claim that MPD didn't do what the MPD source code says? Gasp.

That makes no sense. And as long as we don't agree on certain very very basic facts, I can't help you.

Second: can you explain how to do that, and what MPD is doing wrong?

I don't really know, I'm merely MPD user which tried out new PipeWire output and didn't see his DAC changing frequency. But anyway after quick look into ALSA plugin code I guess the missing piece is:

pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", audio_format.sample_rate);

I didn't find PW_KEY_NODE_RATE anywhere, until I cloned the git repository - it is a new feature that was added to PipeWire recently, quite a while after MPD's PipeWire code was written. Unfortunately, it's undocumented (like most of PipeWire). But since you say that it doesn't solve your problem, it's probably something different. I have no idea.

@jpalus jpalus removed their assignment Oct 18, 2021
@wtay
Copy link

wtay commented Oct 18, 2021

pw_properties_setf(props, PW_KEY_NODE_RATE, "1/%u", audio_format.sample_rate);
After adding this prop sample rate is dynamic, though pw-top still does not show any rate for MPD node, not sure why. Perhaps > @wtay would be able to tell if there's anything wrong with

NODE_RATE is to suggest a new sample rate to the graph (ie, change the samplerate of everything, including the devices if that's possible).

pw-top only shows the latency requested by the application, you can't see the requested samplerate.

@wtay
Copy link

wtay commented Oct 18, 2021

Unfortunately, it's undocumented (like most of PipeWire).

What kind of documentation would you like? expand the comment in https://gitlab.freedesktop.org/pipewire/pipewire/-/blob/master/src/pipewire/keys.h#L160 ? Add examples? add a howto for these features?

@MaxKellermann
Copy link
Member

So... an application should always set both spa_audio_info_raw.rate and NODE_RATE to the same value?
What's the use of redundant information in NODE_RATE if PipeWire already knows the sample rate?

@MaxKellermann
Copy link
Member

What kind of documentation would you like?

An explanation of what "requested rate of the graph" means, why an application would want to request a rate, why/when setting this is useful/helpful/necessary, how it relates to spa_audio_info_raw.rate. And of course, how PipeWire uses it.

@wtay
Copy link

wtay commented Oct 18, 2021

So... an application should always set both spa_audio_info_raw.rate and NODE_RATE to the same value?
What's the use of redundant information in NODE_RATE if PipeWire already knows the sample rate?

The reason is that other nodes (mostly filters) in the graph don't use a format with a samplerate but always follow the graph rate, so they should be able to suggest one.

For pw-stream, I guess we could do this automatically based on the samplerate in the format (if any).

@wtay
Copy link

wtay commented Oct 18, 2021

An explanation of what "requested rate of the graph" means, why an application would want to request a rate, why/when
setting this is useful/helpful/necessary, how it relates to spa_audio_info_raw.rate. And of course, how PipeWire uses it.

It think I will make a chapter about pw-stream then with all this info.

@jpalus
Copy link
Author

jpalus commented Oct 18, 2021

pw-top only shows the latency requested by the application, you can't see the requested samplerate.

"RATE" column name got me confused. Indeed setting PW_KEY_NODE_LATENCY populates this column. Thanks.

@leigh123linux
Copy link
Contributor

@jpalus Hi, Can you post your pipewire settings in mpd.conf please?, I am having trouble getting it to work.

@jpalus
Copy link
Author

jpalus commented Oct 19, 2021

@leigh123linux I didn't do anything extraordinary with MPD configuration, just added:

audio_output { 
        type "pipewire"
        name "PipeWire"
}

Together with small modification of $XDG_CONFIG_HOME/pipewire/pipewire.conf (as per https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#setting-sample-rates):

context.properties = {
...
    default.clock.allowed-rates = [ 22050 44100 48000 88200 96000 192000 ]

it just works (after applying d5be8c7 linked to this issue of course).

@leigh123linux
Copy link
Contributor

@leigh123linux I didn't do anything extraordinary with MPD configuration, just added:

audio_output { 
        type "pipewire"
        name "PipeWire"
}

Together with small modification of $XDG_CONFIG_HOME/pipewire/pipewire.conf (as per https://gitlab.freedesktop.org/pipewire/pipewire/-/wikis/Config-PipeWire#setting-sample-rates):

context.properties = {
...
    default.clock.allowed-rates = [ 22050 44100 48000 88200 96000 192000 ]

it just works (after applying d5be8c7 linked to this issue of course).

Thanks.

I found the issue, mpd wasn't running as user.

@leigh123linux
Copy link
Contributor

leigh123linux commented Oct 19, 2021

@wtay Does pipewire support DSD?

Mpd has to convert it to PCM

Oct 19 12:57 : playlist: queue song 1:"Pink Floyd - Wish You Were Here/02 - Pink Floyd - Welcome To The Machine.dsf"
Oct 19 12:57 : decoder_thread: probing plugin dsf
Oct 19 12:57 : decoder: audio_format=dsd64:2, seekable=true
Oct 19 12:57 : output: opened "PipeWire" (pipewire) audio_format=352800:16:2
Oct 19 12:57 : output: converting in=dsd64:2 -> f=dsd64:2 -> out=352800:16:2
Oct 19 12:57 : client: [0] process command "status"

Alsa

Oct 19 12:54 : playlist: queue song 1:"Pink Floyd - Wish You Were Here/02 - Pink Floyd - Welcome To The Machine.dsf"
Oct 19 12:54 : decoder_thread: probing plugin dsf
Oct 19 12:54 : decoder: audio_format=dsd64:2, seekable=true
Oct 19 12:54 : alsa_output: opened iec958:CARD=D10,DEV=0 type=HW
Oct 19 12:54 : alsa_output: buffer: size=24..131072 time=272..1486078
Oct 19 12:54 : alsa_output: period: size=12..65536 time=136..743039
Oct 19 12:54 : alsa_output: default period_time = buffer_time/4 = 500000/4 = 125000
Oct 19 12:54 : alsa_output: format=DSD_U32_BE (Direct Stream Digital, 4-byte (x32), big endian, oldest bits in MSB)
Oct 19 12:54 : alsa_output: buffer_size=44100 period_size=11025
Oct 19 12:54 : output: opened "D10" (alsa) audio_format=dsd64:2
Oct 19 12:54 : client: [0] process command "status"

I added this to pipewire.conf

default.clock.allowed-rates = [ 44100 48000 88200 96000 176400 192000 352800 384000 ]
$ cat /proc/asound/card1/stream0
Topping D10 at usb-0000:00:15.0-2, high speed : USB Audio

Playback:
  Status: Running
    Interface = 1
    Altset = 1
    Packet Size = 392
    Momentary freq = 352796 Hz (0x2c.1978)
    Feedback Format = 16.16
  Interface 1
    Altset 1
    Format: S32_LE
    Channels: 2
    Endpoint: 0x01 (1 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
    Data packet interval: 125 us
    Bits: 32
    Channel map: FL FR
    Sync Endpoint: 0x81 (1 IN)
    Sync EP Interface: 1
    Sync EP Altset: 1
    Implicit Feedback Mode: No
  Interface 1
    Altset 2
    Format: S32_LE
    Channels: 2
    Endpoint: 0x01 (1 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
    Data packet interval: 125 us
    Bits: 24
    Channel map: FL FR
    Sync Endpoint: 0x81 (1 IN)
    Sync EP Interface: 1
    Sync EP Altset: 2
    Implicit Feedback Mode: No
  Interface 1
    Altset 3
    Format: SPECIAL DSD_U32_BE
    Channels: 2
    Endpoint: 0x01 (1 OUT) (ASYNC)
    Rates: 44100, 48000, 88200, 96000, 176400, 192000, 352800, 384000
    Data packet interval: 125 us
    Bits: 32
    DSD raw: DOP=0, bitrev=0
    Channel map: FL FR
    Sync Endpoint: 0x81 (1 IN)
    Sync EP Interface: 1
    Sync EP Altset: 3
    Implicit Feedback Mode: No

@MaxKellermann
Copy link
Member

PipeWire supports DSD since version 0.3.38, released a few weeks ago. MPD does not yet support that mode. I suggest opening a feature request issue here.

@leigh123linux
Copy link
Contributor

PipeWire supports DSD since version 0.3.38, released a few weeks ago. MPD does not yet support that mode. I suggest opening a feature request issue here.

Thanks.

$ rpm -q pipewire
pipewire-0.3.38-1.fc35.x86_64

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting Waiting for more information from reporter
Projects
None yet
Development

No branches or pull requests

4 participants