mk-fg / python-pulse-control

Python high-level interface and ctypes-based bindings for PulseAudio (libpulse)
https://pypi.org/project/pulsectl/
MIT License
170 stars 36 forks source link

Assertion 'c' failed at ../pulseaudio/src/pulse/subscribe.c:64, function pa_context_subscribe(). Aborting. #75

Closed kanehekili closed 1 year ago

kanehekili commented 1 year ago

Trying your "testEvents" example I get the error message mentioned. The code is copied form your example. Current version ist 22.3.2, tested on Manjaro.

mk-fg commented 1 year ago

Hi.

You mean this example code, right?

import pulsectl

with pulsectl.Pulse('event-printer') as pulse:
  # print('Event types:', pulsectl.PulseEventTypeEnum)
  # print('Event facilities:', pulsectl.PulseEventFacilityEnum)
  # print('Event masks:', pulsectl.PulseEventMaskEnum)

  def print_events(ev):
    print('Pulse event:', ev)
    ### Raise PulseLoopStop for event_listen() to return before timeout (if any)
    # raise pulsectl.PulseLoopStop

  pulse.event_mask_set('all')
  pulse.event_callback_set(print_events)
  pulse.event_listen(timeout=10)

It seem to work for me on current Arch, and looking at specific place that assertion mentions in pulseaudio code:

pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) {
    pa_operation *o;
    pa_tagstruct *t;
    uint32_t tag;

    pa_assert(c); // <--- line 64
    pa_assert(PA_REFCNT_VALUE(c) >= 1);
...

It looks like instead of pa_context "c" value, NULL pointer (python None) gets passed by pulse.event_mask_set() operation.

Which I can't seem to guess how can happen in example above normally, as it'd require setting pulse._ctx value there to None, which should normally only happen after pulse.close() or something like that is called, e.g.:

import pulsectl
pulse = pulsectl.Pulse('event-printer')
pulse.close()
pulse.event_mask_set('all')
kanehekili commented 1 year ago

Copied the code from your original answer and executed it - with the the aforementioned error. Went to local site packages/pulsectl/tests and startet the unit tests. No errors whatsoever , 16 tests were executed

This is a mystery, since my application using pulsectl runs without problems. Just getting events seems to be a problem in my environment.

Tried the test both from IDE and console - same result.

..An afterthought: both pipewire and pulseaudio are running:

789 ? S<sl 0:00 /usr/bin/pulseaudio --daemonize=no --log-target=journal 944 ? Sl 0:03 /usr/lib/xfce4/panel/wrapper-2.0 /usr/lib/xfce4/panel/plugins/libpulseaudio-plugin.so 8 14680082 pulseaudio PulseAudio Plugin Adjust the audio volume of the PulseAudio sound system 1334 ? Sl 0:00 /usr/lib/pulse/gsettings-helper 1295 ? S<sl 0:00 /usr/bin/pipewire

mk-fg commented 1 year ago

Can you try this code instead:

import pulsectl, pulsectl._pulsectl as c

with pulsectl.Pulse('event-printer') as pulse:

  print('Pulse context:', pulse._ctx)
  print('Pulse API:', pulse._api)
  print('Pulse new context:', c.pa.context_new(pulse._api, 'test'))
  print()

  with pulse._pulse_op_cb() as cb:
    c.pa.context_subscribe(pulse._ctx, 0x2ff, cb, None)

  def print_events(ev): print('Pulse event:', ev)
  pulse.event_callback_set(print_events)
  pulse.event_listen(timeout=10)

It should print something like this (with "Pulse event" lines only happening on playback/volume/etc changes):

Pulse context: <pulsectl._pulsectl.LP_PA_CONTEXT object at 0x7fb2f68db840>
Pulse API: <pulsectl._pulsectl.LP_PA_MAINLOOP_API object at 0x7fb2f68db6c0>
Pulse new context: <pulsectl._pulsectl.LP_PA_CONTEXT object at 0x7fb2f68db8c0>

Pulse event: facility=<EnumValue event-facility=sink_input>, index=62, t=<EnumValue event-type=change>
Pulse event: facility=<EnumValue event-facility=sink>, index=1, t=<EnumValue event-type=change>
...

Mostly wondering if "Pulse context:" line will print None for you, which would be surprising.

I think it's technically possible that pipewire has a compatibility wrapper for libpulse that doesn't use context and returns NULL for it. And then replaces most calls with ones that run pipewire stuff, but maybe doesn't replace that one pa_context_subscribe call and proxy it instead (not sure why it would though), which causes such issue.

But this does not add up with "No errors whatsoever , 16 tests were executed", as one of the tests is this: https://github.com/mk-fg/python-pulse-control/blob/caabb24/pulsectl/tests/test_with_dummy_instance.py#L347-L362 Not sure why similar code might work there then, but there's usually a perfectly reasonable explaination :)

kanehekili commented 1 year ago

Tested your code and it worked:

Pulse context: <pulsectl._pulsectl.LP_PA_CONTEXT object at 0x7fa6ed3d2340> Pulse API: <pulsectl._pulsectl.LP_PA_MAINLOOP_API object at 0x7fa6ed3d21c0> Pulse new context: <pulsectl._pulsectl.LP_PA_CONTEXT object at 0x7fa6ed3d23c0>

Pulse event: facility=<EnumValue event-facility=sink_input>, index=16, t=<EnumValue event-type=remove> Pulse event: facility=<EnumValue event-facility=sink>, index=3, t=<EnumValue event-type=change> Pulse event: facility=<EnumValue event-facility=source>, index=3, t=<EnumValue event-type=change> Pulse event: facility=<EnumValue event-facility=sink_input>, index=17, t=<EnumValue event-type=new> ...

The assertion error in the first example occurs when calling pulse.event_mask_set('all')

Update: completly my mistake. Despite copying the code, I've borked the tabs. So the "setMask" was not in the Pulse context. I' m closing this issue. I'm sorry for the hassle and thanks for your time!

kanehekili commented 1 year ago

Wrong indents. Closing