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

add basic pulseaudio support #221

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

lrusak
Copy link
Member

@lrusak lrusak commented Mar 11, 2021

This is a resurrection of some work I did 4 years ago. I always wanted to implement some sort of pavucontrol in Kodi and this is an initial implementation of that.

Features:

  • allows changing a card profile
  • allows changing the default audio device

Pretty awesome that this can be done with 0 deletions 😮

Some screenshots:
screenshot00000
screenshot00001
screenshot00002
screenshot00003
screenshot00004
screenshot00005

@lrusak
Copy link
Member Author

lrusak commented Mar 12, 2021

I've adjusted this a little bit so we now list sinks instead of cards, this will be more useful in the future.

I've also changed the layout a little bit which looks nicer (IMO)

screenshot00007

@flubshi
Copy link
Contributor

flubshi commented Mar 13, 2021

Works on pi 4 with BT headphones :)

image

image

But sound is delayed and has dropouts. Maybe this is addressed in your realtime PR for LE?

@lrusak
Copy link
Member Author

lrusak commented Mar 13, 2021

Works on pi 4 with BT headphones :)

But sound is delayed and has dropouts. Maybe this is addressed in your realtime PR for LE?

pulseaudio may have to resample depending on the content and the default resample method may be too heavy. It might be worth testing different resample methods.

EDIT:
you can check by running pulseaudio with -vvv (use systemctl edit --full pulseaudio to adjust)

Mar 13 12:21:52 LibreELEC pulseaudio[904]: D: [pulseaudio] resampler.c: Resampler:
Mar 13 12:21:52 LibreELEC pulseaudio[904]: D: [pulseaudio] resampler.c:   rate 48000 -> 44100 (method speex-float-1)
Mar 13 12:21:52 LibreELEC pulseaudio[904]: D: [pulseaudio] resampler.c:   format float32le -> s16le (intermediate float32le)
Mar 13 12:21:52 LibreELEC pulseaudio[904]: D: [pulseaudio] resampler.c:   channels 2 -> 2 (resampling 2)
Mar 13 12:21:52 LibreELEC pulseaudio[904]: I: [pulseaudio] speex.c: Choosing speex quality setting 1.

You can choose different resample methods with the following:

# pulseaudio --dump-resample-methods
trivial
speex-float-0
speex-float-1
speex-float-2
speex-float-3
speex-float-4
speex-float-5
speex-float-6
speex-float-7
speex-float-8
speex-float-9
speex-float-10
speex-fixed-0
speex-fixed-1
speex-fixed-2
speex-fixed-3
speex-fixed-4
speex-fixed-5
speex-fixed-6
speex-fixed-7
speex-fixed-8
speex-fixed-9
speex-fixed-10
ffmpeg
auto
copy
peaks
soxr-mq
soxr-hq
soxr-vhq

and

echo "resample-method = soxr-vhq" > /storage/.config/pulse-daemon.conf.d/custom.conf

Then restart pulseaudio and restart kodi (kodi doesn't like when pulse is pulled out from under). Or just reboot.

Mar 13 12:27:24 LibreELEC pulseaudio[1017]: D: [pulseaudio] resampler.c: Resampler:
Mar 13 12:27:24 LibreELEC pulseaudio[1017]: D: [pulseaudio] resampler.c:   rate 48000 -> 44100 (method soxr-vhq)
Mar 13 12:27:24 LibreELEC pulseaudio[1017]: D: [pulseaudio] resampler.c:   format float32le -> s16le (intermediate float32le)
Mar 13 12:27:24 LibreELEC pulseaudio[1017]: D: [pulseaudio] resampler.c:   channels 2 -> 2 (resampling 2)

It looks like the default is speex-float-1 which shouldn't be very heavy so you can also try using the option avoid-resampling = true instead but it's likely resampling will be needed.

You should also check in kodi the option for settings -> system -> audio -> output configuration, it should be set to best match or optimized and kodi will check the format of the sink.

Mar 13 12:36:19 LibreELEC pulseaudio[1106]: I: [pulseaudio] resampler.c: Forcing resampler 'copy', because of fixed, identical sample rates.
Mar 13 12:36:19 LibreELEC pulseaudio[1106]: D: [pulseaudio] resampler.c: Resampler:
Mar 13 12:36:19 LibreELEC pulseaudio[1106]: D: [pulseaudio] resampler.c:   rate 44100 -> 44100 (method copy)
Mar 13 12:36:19 LibreELEC pulseaudio[1106]: D: [pulseaudio] resampler.c:   format float32le -> s16le (intermediate s16le)
Mar 13 12:36:19 LibreELEC pulseaudio[1106]: D: [pulseaudio] resampler.c:   channels 2 -> 2 (resampling 2)

and lastly you can also try setting the following options

default-sample-format = float32le

but it's likely you may be limited by what your bluetooth device is able to use

Sink #1
        State: RUNNING
        Name: bluez_sink.A8_BE_27_19_C3_F5.a2dp_sink
        Description: Lukas's BeatsX
        Driver: module-bluez5-device.c
        Sample Specification: s16le 2ch 44100Hz

@flubshi
Copy link
Contributor

flubshi commented Mar 27, 2021

Sorry for the late reply. Works pretty good now!

Thanks a lot for your awesome explanation for my slightly off-topic problem! The following did solve my dropout issue:

You should also check in kodi the option for settings -> system -> audio -> output configuration, it should be set to best match or optimized and kodi will check the format of the sink.


rebuildList = 0
self.dbusDevices = self.get_sinks()
for dbusDevice in self.dbusDevices:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose if this loop? From the looks of it this block is executed once if self.dbusDevices is not empty so it can be replaced with if self.dbusDevices: condition. Or there is something I'm missing? I saw the same code in bluetooth module and wonder why it's implemented this way.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure what the question is. The loop iterates over a list of items returned from get_sinks. Then each item can be processed and added to the gui.

Is there a better way?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The thing is that this specific loop does not iterate as such. It breaks unconditionally after the first iteration. So I'm just curious if this has any specific meaning.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't look at the rest of the code, yes an if is probably fine here.

ysard added a commit to ysard/service.libreelec.settings that referenced this pull request Nov 10, 2021
ysard added a commit to ysard/service.libreelec.settings that referenced this pull request Nov 13, 2021
@ysard ysard mentioned this pull request Nov 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants