[Jack-Devel] Cannot callback the server in notification thread!

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[Jack-Devel] Cannot callback the server in notification thread!

Ethan Funk
In an application I am writing, I am getting an error message out stderr (see email subject), and a connection failure return result, when I try to use jack_connect() from inside a jack_set_port_registration_callback function, using Jack2. My goal is to have the application remember and re-connect to a disconnected port if/when it "comes back." Am I going to need to create a mostly sleeping thread just for port re-connections attempts, or is there something obvious I am missing?

Thanks,
Ethan...

_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Cannot callback the server in notification thread!

Tim-2
On 8/8/19 10:20 PM, Ethan Funk wrote:

> In an application I am writing, I am getting an error message out stderr
> (see email subject), and a connection failure return result, when I try
> to use jack_connect() from inside a jack_set_port_registration_callback
> function, using Jack2. My goal is to have the application remember and
> re-connect to a disconnected port if/when it "comes back." Am I going to
> need to create a mostly sleeping thread just for port re-connections
> attempts, or is there something obvious I am missing?
>
> Thanks,
> Ethan...

If I understand your goal, I did this in MusE.
I called it 'persistent connections', or 'persistent ports'.

For example you can unplug a USB midi device currently
  in use by MusE as a 'Jack device', then re-plug it,
  and MusE will automatically reconnect to its ports
  as if nothing happened and you may continue playing.
(I made our 'ALSA devices' do the same thing!)
It should also work with other Jack clients.

Look in our driver/jack.cpp, at:
   static void registration_callback(...),
   static void port_connect_callback(...),
  and
   static int graph_callback(...),
   // This is called in the gui context,
   //  triggered by graph_callback()
   void JackAudioDevice::graphChanged().

It was complicated. Very. I needed to support Jack 1 and 2.
So there are a few sequences of calls and resulting
  sequences of callbacks for example that are different
  in Jack 1 and 2. Several tricks and traps. See comments.

My system relies HEAVILY on the jack port 'alias names',
  because it was pretty much the ONLY thing you can rely on,
  because the regular port names and port numbers change
  upon re-plugging. It automatically chooses which alias is
  best or falls back to the not so good canonical port name.

So, that's what it 'remembers' between device plug ins -
  simply the port alias or name text.

HTH.
Tim.
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Cannot callback the server in notification thread!

Ethan Funk
Yes, what you describe is what I am implementing. I have also called it "persistence" in my application. Normally, when all audio ports are disconnected, my application quits. But I have an command line option to keep it running and have it "persist," not quit, try to reconnect.

I just implemented a simple queue of jack_port_ids. Callbacks add their relevant port_ids into the queue, with my main thread checking the queue periodically, to further check the queued ports for re-connection. This was not as hard as I though it would be, and works well so far. Just queueing the port id is a lot simpler that what you are doing in MusE, but it is sufficient for my application.

One remaining question: Am I safe assuming that jack2 will call my callbacks one at a time from a single thread, or do I need to make my port id queue writing function thread safe, just in case jack2 calls my callbacks concurrently?

Ethan...

On Fri, 2019-08-09 at 01:52 -0400, Tim wrote:
On 8/8/19 10:20 PM, Ethan Funk wrote:
In an application I am writing, I am getting an error message out stderr 
(see email subject), and a connection failure return result, when I try 
to use jack_connect() from inside a jack_set_port_registration_callback 
function, using Jack2. My goal is to have the application remember and 
re-connect to a disconnected port if/when it "comes back." Am I going to 
need to create a mostly sleeping thread just for port re-connections 
attempts, or is there something obvious I am missing?

Thanks,
Ethan...

If I understand your goal, I did this in MusE.
I called it 'persistent connections', or 'persistent ports'.

For example you can unplug a USB midi device currently
  in use by MusE as a 'Jack device', then re-plug it,
  and MusE will automatically reconnect to its ports
  as if nothing happened and you may continue playing.
(I made our 'ALSA devices' do the same thing!)
It should also work with other Jack clients.

Look in our driver/jack.cpp, at:
   static void registration_callback(...),
   static void port_connect_callback(...),
  and
   static int graph_callback(...),
   // This is called in the gui context,
   //  triggered by graph_callback()
   void JackAudioDevice::graphChanged().

It was complicated. Very. I needed to support Jack 1 and 2.
So there are a few sequences of calls and resulting
  sequences of callbacks for example that are different
  in Jack 1 and 2. Several tricks and traps. See comments.

My system relies HEAVILY on the jack port 'alias names',
  because it was pretty much the ONLY thing you can rely on,
  because the regular port names and port numbers change
  upon re-plugging. It automatically chooses which alias is
  best or falls back to the not so good canonical port name.

So, that's what it 'remembers' between device plug ins -
  simply the port alias or name text.

HTH.
Tim.
_______________________________________________
Jack-Devel mailing list
[hidden email]

http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org


_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org

signature.asc (849 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Cannot callback the server in notification thread!

Tim-2
On 8/9/19 12:01 PM, Ethan Funk wrote:
> Yes, what you describe is what I am implementing. I have also called it
> "persistence" in my application. Normally, when all audio ports are
> disconnected, my application quits. But I have an command line option to
> keep it running and have it "persist," not quit, try to reconnect.

I took it one step further and the 'persistence' is stored in the
  song file so that the next time the song is loaded, MusE does not
  complain that this or that is missing and will be removed, instead
  it simply chugs along happily and when the device reappears,
  everything works as before.

I have slowly adopted a policy of "nothing is removed from a song
  behind the user's back unless they specifically say so, even if it
  is ultimately missing some component, such as a port is missing
  or a plugin is missing on the system".
Thus, persistent... everything! across sessions is the goal.

> I just implemented a simple queue of jack_port_ids. Callbacks add their
> relevant port_ids into the queue, with my main thread checking the queue
> periodically, to further check the queued ports for re-connection. This
> was not as hard as I though it would be, and works well so far. Just
> queueing the port id is a lot simpler that what you are doing in MusE,
> but it is sufficient for my application.

Yes, as you might see, I actually store a few callback types in our
  callback queue and I must 'review' the queue when something happens
  to carefully determine what exactly took place, for example
  did a port disconnection happen before an unregistration or
  was it an unregistration alone, etc.
It was tricky. Those port ID functions sure help though.

> One remaining question: Am I safe assuming that jack2 will call my
> callbacks one at a time from a single thread, or do I need to make my
> port id queue writing function thread safe, just in case jack2 calls my
> callbacks concurrently?

Don't quote me, I might be getting this wrong, if I recall correctly ;-)
Jack 1 issues all callbacks in the realtime audio thread.
Jack 2 issues some important callbacks, such as the Sync callback,
  in the realtime audio thread, but most other callbacks are
  issued in ONE separate thread.
Therefore I don't think it could call them concurrently,
  but I'm not an expert here...
I think our queue is multi-writer anyway so I probably might not
  have noticed if they were concurrent, but I don't think I
  noticed anything unusual.

Tim.

>
> Ethan...
>
> On Fri, 2019-08-09 at 01:52 -0400, Tim wrote:
>> On 8/8/19 10:20 PM, Ethan Funk wrote:
>>> In an application I am writing, I am getting an error message out stderr
>>> (see email subject), and a connection failure return result, when I try
>>> to use jack_connect() from inside a jack_set_port_registration_callback
>>> function, using Jack2. My goal is to have the application remember and
>>> re-connect to a disconnected port if/when it "comes back." Am I going to
>>> need to create a mostly sleeping thread just for port re-connections
>>> attempts, or is there something obvious I am missing?
>>>
>>> Thanks,
>>> Ethan...
>>
>> If I understand your goal, I did this in MusE.
>> I called it 'persistent connections', or 'persistent ports'.
>>
>> For example you can unplug a USB midi device currently
>>    in use by MusE as a 'Jack device', then re-plug it,
>>    and MusE will automatically reconnect to its ports
>>    as if nothing happened and you may continue playing.
>> (I made our 'ALSA devices' do the same thing!)
>> It should also work with other Jack clients.
>>
>> Look in our driver/jack.cpp, at:
>>     static void registration_callback(...),
>>     static void port_connect_callback(...),
>>    and
>>     static int graph_callback(...),
>>     // This is called in the gui context,
>>     //  triggered by graph_callback()
>>     void JackAudioDevice::graphChanged().
>>
>> It was complicated. Very. I needed to support Jack 1 and 2.
>> So there are a few sequences of calls and resulting
>>    sequences of callbacks for example that are different
>>    in Jack 1 and 2. Several tricks and traps. See comments.
>>
>> My system relies HEAVILY on the jack port 'alias names',
>>    because it was pretty much the ONLY thing you can rely on,
>>    because the regular port names and port numbers change
>>    upon re-plugging. It automatically chooses which alias is
>>    best or falls back to the not so good canonical port name.
>>
>> So, that's what it 'remembers' between device plug ins -
>>    simply the port alias or name text.
>>
>> HTH.
>> Tim.
>> _______________________________________________
>> Jack-Devel mailing list
>> [hidden email]
>>  <mailto:[hidden email]>
>>
>> http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
>>
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Cannot callback the server in notification thread!

Robin Gareus
In reply to this post by Ethan Funk
On 8/9/19 4:20 AM, Ethan Funk wrote:
> In an application I am writing, I am getting an error message out
> stderr (see email subject), and a connection failure return result,
> when I try to use jack_connect() from inside a
> jack_set_port_registration_callback function, using Jack2.

sadly, jack thread semantics are not very well documented, but the
subject says it all. You can't send a request from a callback.

> My goal is
> to have the application remember and re-connect to a disconnected port
> if/when it "comes back."  Am I going to need to create a mostly
> sleeping thread just for port re-connections attempts, or is there
> something obvious I am missing?

Nope, you're not missing anything. That's what qjackctl's Patchbay does
for auto-connections, and jack.plumbing in deamon mode, etc..

Check out http://rohandrape.net/?t=rju&e=md/jack-plumbing.md it's
packaged part of "jack-tools" on most GNU/Linux distros and probably the
smallest codebase for the task at hand.

ciao,
robin
_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org
Reply | Threaded
Open this post in threaded view
|

Re: Cannot callback the server in notification thread!

Ethan Funk
In reply to this post by Tim-2
I am only writing for Jack2: I absolutely need to be able to "plug and unplug" jack clients while audio is running.
However, I decided to use spin-locks to make sure my jack_port_id queue is write concurrent safe. That seemed like a good compromise, considering how little time the locks are held, and that the hold time is deterministic.

I am porting a radio automation system I originally wrote of OS X/Core Audio. I made design decision to make all the media players and recorders/encoders there own processes that connect to the mixer-core via jack. So jack connections are being made to the mixer and then removed periodically, and that needs to happen without audio drop-out. So far, working well.

The recorder/encoder process, which I am working on right now, needs to be optionally able to reconnect to the mixer, or a processing chain connected to the mixer if it goes away and is restarted. That is what this was all about.

I will likely give the core mixer/control program similar persistent functionality next.

Thanks,
Ethan...



On Fri, 2019-08-09 at 14:50 -0400, Tim wrote:
On 8/9/19 12:01 PM, Ethan Funk wrote:
Yes, what you describe is what I am implementing. I have also called it 
"persistence" in my application. Normally, when all audio ports are 
disconnected, my application quits. But I have an command line option to 
keep it running and have it "persist," not quit, try to reconnect.

I took it one step further and the 'persistence' is stored in the
  song file so that the next time the song is loaded, MusE does not
  complain that this or that is missing and will be removed, instead
  it simply chugs along happily and when the device reappears,
  everything works as before.

I have slowly adopted a policy of "nothing is removed from a song
  behind the user's back unless they specifically say so, even if it
  is ultimately missing some component, such as a port is missing
  or a plugin is missing on the system".
Thus, persistent... everything! across sessions is the goal.

I just implemented a simple queue of jack_port_ids. Callbacks add their 
relevant port_ids into the queue, with my main thread checking the queue 
periodically, to further check the queued ports for re-connection. This 
was not as hard as I though it would be, and works well so far. Just 
queueing the port id is a lot simpler that what you are doing in MusE, 
but it is sufficient for my application.

Yes, as you might see, I actually store a few callback types in our
  callback queue and I must 'review' the queue when something happens
  to carefully determine what exactly took place, for example
  did a port disconnection happen before an unregistration or
  was it an unregistration alone, etc.
It was tricky. Those port ID functions sure help though.

One remaining question: Am I safe assuming that jack2 will call my 
callbacks one at a time from a single thread, or do I need to make my 
port id queue writing function thread safe, just in case jack2 calls my 
callbacks concurrently?

Don't quote me, I might be getting this wrong, if I recall correctly ;-)
Jack 1 issues all callbacks in the realtime audio thread.
Jack 2 issues some important callbacks, such as the Sync callback,
  in the realtime audio thread, but most other callbacks are
  issued in ONE separate thread.
Therefore I don't think it could call them concurrently,
  but I'm not an expert here...
I think our queue is multi-writer anyway so I probably might not
  have noticed if they were concurrent, but I don't think I
  noticed anything unusual.

Tim.


Ethan...

On Fri, 2019-08-09 at 01:52 -0400, Tim wrote:
On 8/8/19 10:20 PM, Ethan Funk wrote:
In an application I am writing, I am getting an error message out stderr
(see email subject), and a connection failure return result, when I try
to use jack_connect() from inside a jack_set_port_registration_callback
function, using Jack2. My goal is to have the application remember and
re-connect to a disconnected port if/when it "comes back." Am I going to
need to create a mostly sleeping thread just for port re-connections
attempts, or is there something obvious I am missing?

Thanks,
Ethan...

If I understand your goal, I did this in MusE.
I called it 'persistent connections', or 'persistent ports'.

For example you can unplug a USB midi device currently
   in use by MusE as a 'Jack device', then re-plug it,
   and MusE will automatically reconnect to its ports
   as if nothing happened and you may continue playing.
(I made our 'ALSA devices' do the same thing!)
It should also work with other Jack clients.

Look in our driver/jack.cpp, at:
    static void registration_callback(...),
    static void port_connect_callback(...),
   and
    static int graph_callback(...),
    // This is called in the gui context,
    //  triggered by graph_callback()
    void JackAudioDevice::graphChanged().

It was complicated. Very. I needed to support Jack 1 and 2.
So there are a few sequences of calls and resulting
   sequences of callbacks for example that are different
   in Jack 1 and 2. Several tricks and traps. See comments.

My system relies HEAVILY on the jack port 'alias names',
   because it was pretty much the ONLY thing you can rely on,
   because the regular port names and port numbers change
   upon re-plugging. It automatically chooses which alias is
   best or falls back to the not so good canonical port name.

So, that's what it 'remembers' between device plug ins -
   simply the port alias or name text.

HTH.
Tim.
_______________________________________________
Jack-Devel mailing list
[hidden email]

 <mailto:
[hidden email]
>

http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org



_______________________________________________
Jack-Devel mailing list
[hidden email]
http://lists.jackaudio.org/listinfo.cgi/jack-devel-jackaudio.org

signature.asc (849 bytes) Download Attachment