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

[pulseaudio] Apply real disconnection when needed #13338

Merged
merged 3 commits into from
Sep 25, 2022

Conversation

dalgwen
Copy link
Contributor

@dalgwen dalgwen commented Aug 31, 2022

Bug description:
When the pulseaudio server is shutdown and relaunched, the socket is dead. But the audiosink connection doesn't properly reset the next time it is needed. The isIdle boolean prevents this disconnection/reconnection by checking if it's in use before effectively disconnecting (and of course it's in use, because we are trying to use it when we see that the connection is broken...)
Additionnally, isIdle is not in a try catch block for the pulseaudio sink : so exception within an operation doesn't free the boolean.

Actually, isIdle seems not even relevant : we should always honnor the disconnection request, even if an operation is running (disconnection requests occur when we get I/O exception, or when shutting down the bridge/thing).

This PR remove the isIdle boolean.

+Little bug fix on volume parsing: in some case (audio source), a volume request doesn't respond with a space after the comma separating left/right channel, so I change the volume pattern.

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
@dalgwen dalgwen added the bug An unexpected problem or unintended behavior of an add-on label Aug 31, 2022
@dalgwen dalgwen requested a review from peuter as a code owner August 31, 2022 11:03
@dalgwen dalgwen requested a review from GiviMAD August 31, 2022 11:03
@GiviMAD
Copy link
Member

GiviMAD commented Aug 31, 2022

The "isidle" logic attempts to prevent closing the connection for a while to speed up the response time when you are using it frequently (for example when using it with the dialog processor implementation), it was not implemented by me but doesn't seems like something we want to remove.
I think it will affect the performance of the binding for people which is already using it, as you will be tearing up and down the pulseaudio "Simple TCP Stream" protocol port on each use.

@GiviMAD
Copy link
Member

GiviMAD commented Aug 31, 2022

The "isidle" logic attempts to prevent closing the connection for a while to speed up the response time when you are using it frequently (for example when using it with the dialog processor implementation), it was not implemented by me but doesn't seems like something we want to remove.
I think it will affect the performance of the binding for people which is already using it, as you will be tearing up and down the pulseaudio "Simple TCP Stream" protocol port on each use.

Have reviewed the code and I was wrong, the disconnect method just closes the socket, do not instruct the pulseaudio server to close the "Simple TCP Stream" protocol port, but still the next usage will require to check if this port is available plus reopening the connection so I don't think is a bad idea to keep the "isidle" logic if we can fix the issue in another way.

@dalgwen
Copy link
Contributor Author

dalgwen commented Aug 31, 2022

Thank you for checking this PR !
You point me to something I forgot (case 3 below)

So, if I want to sum up, as far as I understand it, the isIdle boolean is :

  • set to false when we want to use the socket
  • set to true when it is finished
  • Its only purpose is to be checked against, when something tries to disconnect (false --> do not close, true --> ok to close)

So it prevents the socket from being disconnect, when we are playing or recording a sound.

The situations, when we want to disconnect, are :
1- getting an IO exception --> we should force close it now, even if isIdle is false. Currently the boolean prevents the closure and the socket is in a broken state until the scheduled time out closure (which in some case could never happen, if the timeout is set to -1)
2- disabling the sink / source / bridge / bundle / whatever --> we should force close it, even if isIdle is false. Currently it is not closed: if we try to disable the thing when a sound is playing, the socket is kept open (possibly forever if the timeout is set to -1)
3- the idle timeout is expired --> Indeed, if isIdle in false, we should NOT close it. In fact we should NOT even try to. The idle timeout and the associated scheduledDisconnection should be canceled/postponed the exact moment we start to use the socket.

I think we should implement it this way: canceling the scheduledDisconnection when the socket is opened/used, instead of not closing it at the scheduledDisconnection timeout expiration if the socket is in use.
If we do it like this, we don't need the isIdle boolean, and its side effect bug with the other close cases are gone.

I will add a commit to this PR to take the third point in consideration.

@lolodomo
Copy link
Contributor

lolodomo commented Sep 3, 2022

I will add a commit to this PR to take the third point in consideration.

So, PR is not yet ready for review & merge ?

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
@dalgwen
Copy link
Contributor Author

dalgwen commented Sep 3, 2022

This PR is now ready for a second review.

After the judicious comment from @GiviMAD , I complete my initial proposal with a rewrited system for the idle -> disconnection functionnality.

Instead of simply deleting the isIdle variable (which as I said in the OP was faulty and prevented in some case a needed healing disconnection) I now propose using a count of the clients using the connection, and giving it the responsibility of scheduling optional disconnection.
The isIdle variable was not thread safe, and a thread safe count seams a better logic system. It works like this :

  • When the count is down to 0 (i.e. when the last client finish its operation), a future disconnection is scheduled.
  • When the count is up (a client initiate an operation), then the future disconnection is canceled.
    AFAIK, it ensures that :
  • no disconnection can happen if the source/sink is still in use
  • a disconnection is always scheduled after all operations are done.

Alternatively, the connectIfNeeded method can also schedule a disconnection. Indeed, using solely the end of an operation to schedule a disconnection is not sufficient because the handler also initiate a dumb connection at startup, without operation, with the goal to check connectivity.

I tested this solution with a sink (with a TTS) and with a source (using rustpotter KS and volk STT) and it works.

Additionnaly, I made a little enhancement to avoid using a synchronized method for a method called very often.

@GiviMAD
Copy link
Member

GiviMAD commented Sep 17, 2022

Hey @dalgwen, I let you a couple of comments, but it seems like a great improvement, thank you!

Copy link
Member

@GiviMAD GiviMAD left a comment

Choose a reason for hiding this comment

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

LGTM!
Thanks for the changes. I'm using this binding on a daily basis to connect to a speaker at my living room for using the voice assistant capabilities and I think I have faced the issue couple of times, so really appreciated!

Copy link
Contributor

@lolodomo lolodomo left a comment

Choose a reason for hiding this comment

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

Code LGTM, I have not tried to understand the detailed stuff with "idle" but as @GiviMAD already approved the changes, that is fine for me.

@lolodomo lolodomo merged commit b7cbf2b into openhab:main Sep 25, 2022
@lolodomo lolodomo added this to the 3.4 milestone Sep 25, 2022
leifbladt pushed a commit to leifbladt/openhab-addons that referenced this pull request Oct 15, 2022
* [pulseaudio] Removing isIdle test

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

* [pulseaudio] Enhancement to the idle detection for disconnection

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

* [pulseaudio] Small performance enhancement

Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
seime pushed a commit to seime/openhab2-addons that referenced this pull request Oct 16, 2022
* [pulseaudio] Removing isIdle test

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

* [pulseaudio] Enhancement to the idle detection for disconnection

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

* [pulseaudio] Small performance enhancement

Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
andan67 pushed a commit to andan67/openhab-addons that referenced this pull request Nov 6, 2022
* [pulseaudio] Removing isIdle test

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

* [pulseaudio] Enhancement to the idle detection for disconnection

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

* [pulseaudio] Small performance enhancement

Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
andrasU pushed a commit to andrasU/openhab-addons that referenced this pull request Nov 12, 2022
* [pulseaudio] Removing isIdle test

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

* [pulseaudio] Enhancement to the idle detection for disconnection

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

* [pulseaudio] Small performance enhancement

Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
Signed-off-by: Andras Uhrin <andras.uhrin@gmail.com>
@dalgwen dalgwen deleted the pulseaudio_network_error_retries branch December 29, 2022 22:59
borazslo pushed a commit to borazslo/openhab-mideaac-addon that referenced this pull request Jan 8, 2023
* [pulseaudio] Removing isIdle test

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

* [pulseaudio] Enhancement to the idle detection for disconnection

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

* [pulseaudio] Small performance enhancement

Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
psmedley pushed a commit to psmedley/openhab-addons that referenced this pull request Feb 23, 2023
* [pulseaudio] Removing isIdle test

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

* [pulseaudio] Enhancement to the idle detection for disconnection

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

* [pulseaudio] Small performance enhancement

Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
nemerdaud pushed a commit to nemerdaud/openhab-addons that referenced this pull request Feb 28, 2023
* [pulseaudio] Removing isIdle test

The isIdle boolean was not properly handled.
When disconnection is called, isIdle is not relevant : we should always honnor the disconnection request.
In fact, isIdle prevented disconnection when it is necessary (example : when a IOException occurs when sending audio to sink)

+Little bug fix on volume parsing: some volume request doesn't respond with a space after the comma separating left/right channel.

* [pulseaudio] Enhancement to the idle detection for disconnection

Using a counter to count client instead of a isIdle variable, which was not thread safe.
The PulseaudioSimpleProtocolStream parent class is now the sole responsible for closing source or sink stream.

* [pulseaudio] Small performance enhancement

Avoid a costly synchronized operation for a method called very often.

Signed-off-by: Gwendal Roulleau <gwendal.roulleau@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug An unexpected problem or unintended behavior of an add-on
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants