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

Setting UpdatePresenceWhenStopped is ignored and Presence shows impossible times #81

Closed
Svarr opened this issue Aug 25, 2021 · 7 comments · Fixed by #84
Closed

Setting UpdatePresenceWhenStopped is ignored and Presence shows impossible times #81

Svarr opened this issue Aug 25, 2021 · 7 comments · Fixed by #84
Assignees

Comments

@Svarr
Copy link
Contributor

Svarr commented Aug 25, 2021

Describe the bug
Under certain conditions the Rich Presence is displayed in Discord even though UpdatePresenceWhenStopped is turned off and nothing is currently played back. The presence shows information about the last track that was played.

To Reproduce
I'm not entirely certain about which conditions can cause this bug to appear. Here is one way to reproduce it (that is, how this bug happened to me today):

  1. Start MusicBee and play some music (don't run Discord yet, UpdatePresenceWhenStopped should be disabled)
  2. Do some housework or waste time in whatever way you prefer, and let the playlist run out (maybe a certain time of being afk is required)
  3. Eventually return to the PC (playback has already run out) and start Discord
  4. Admire the Rich Presence showing MusicBee and the last song that has been played, while still counting up the playtime (way above the track's duration)

Expected behavior
Nothing shown in Discord except my "About Me" text and other stuff that is usually shown when clicking on my name in the userlist.

Screenshots
discordbee
(In case you didn't know, that song is far shorter than 3h. 😉 )

Environment (please complete the following information):

  • MusicBee Version: 3.4.7805
  • Plugin Version: 1.4.2

Additional context
I think the key is to start Discord after MusicBee, while playback is halted but something had been played previously in the same MusicBee session (so that UpdateDiscordPresence had been called with PlayState.Playing at least once).

It may be worth to look into what DiscordRpcClient does on initialisation when no Discord client is currently running and then later, when Discord is run.

@Svarr
Copy link
Contributor Author

Svarr commented Aug 25, 2021

Ok, I did some digging and discord-rpc-csharp looks really sus to me now.

As it turns out, when DiscordRpcClient.Initialize() is called, the return value of RpcConnection.AttemptConnection() is assigned to DiscordRpcClient.IsInitialized. The problem is, that AttemptConnection() just starts a thread and immediately returns true. The only way a value of false is assigned, is when the Thread is already running, or when the RpcConnection is either aborting or not in Disconnected state. That means that DiscordRpcClient.IsInitialized == true does in no way guarantee that a connection to Discord is established.

The Method that runs in the thread started by AttemptConnection() keeps polling until a connection is established. Until then every command that is to be sent to Discord (like setting the presence) is stored in a queue while the oldest entry is dequeued if it has reached its maximum capacity (_maxRtQueueSize). This may have implications that I'm currently not aware of, but unless DiscordBee sends an old presence after the clearing triggered by MusicBee reaching the end of the playlist, the latest command (which should set the presence to null) should be received by Discord last. I don't know with which frequence the commands in the out queue are dispatched, maybe Discord drops some of them?

But even if that's the case, DiscordBee shouldn't try to send anything unless a connection to discord is established. So I guess the main goal should be to find out how the connection state can be retreived or at least deduced.

@sll552
Copy link
Owner

sll552 commented Aug 25, 2021

Thanks for your effort. Without having looked into it much I could think of using the Ready Event to check for initialization, provided the event is fired when the actual connection is established.

@sll552 sll552 self-assigned this Aug 25, 2021
@Svarr
Copy link
Contributor Author

Svarr commented Aug 26, 2021

That was my thought as well, but I couldn't find out where it's called.

@Svarr
Copy link
Contributor Author

Svarr commented Aug 26, 2021

The Ready Event works. It is called, once the connection is established. But to get notified when the connection is lost, I had to add a callback for the OnConnectionFailed Event. OnClose doesn't get dispatched ofc...

I pushed my changes to my fork here.

Since initialising a previously deinitialised instance of DiscordRpcClient doesn't seem to be supported currently, I dispose of the current instance and create a new one when required. This seems to work for the most part, except I keep getting a NRE when attempting to ClearPresence(). At some point RpcConnection.ProcessFrame(EventPayload) queues a new PresenceMessage instance which is processed by DiscordRpcClient.ProcessMessage(IMessage). Now, for some reason, CurrentPresence is null (which shouldn't be possible) and RichPresence.Merge(BaseRichPresence) is called with the uninitialised and therefore null presence of the fresh message object. Naturally Merge just assumes that the parameter is not null...

For the sake of completeness the exception details:

Unhandled Exception while processing event: System.NullReferenceException
Object reference not set to an instance of an object.
    at DiscordRPC.RichPresence.Merge(BaseRichPresence presence)
    at DiscordRPC.DiscordRpcClient.ProcessMessage(IMessage message)
    at DiscordRPC.DiscordRpcClient.<.ctor>b__103_0(Object sender, IMessage msg)
    at DiscordRPC.RPC.RpcConnection.EnqueueMessage(IMessage message)

This may be a bug in DiscordRPC or maybe I have screwed up. I don't know yet.

But ignoring this exception appears to have no negative effect. I haven't tested if this issue would be solved with my changes, however.

@Svarr
Copy link
Contributor Author

Svarr commented Aug 29, 2021

I found the cause for the exception and it's indeed a bug in DiscordRPC (see this issue).

But I forgot to make the crucial change of actually not sending the presence updates while not connected to Discord. This is fixed as of the latest commit to the branch feature/lifecycle-fix of my fork, linked in the post above.

I also tested whether the bug is still happening and it does seem to be fixed.

@sll552
Copy link
Owner

sll552 commented Aug 29, 2021

Nice work, would you like to open a pull request for it?

Also you might want to rebase because I pushed some changes today (which also include a cherry-pick from your master).

@Svarr
Copy link
Contributor Author

Svarr commented Aug 29, 2021

Pull Request is up.

Also you might want to rebase because I pushed some changes today (which also include a cherry-pick from your master).

Already done. 🙂

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 a pull request may close this issue.

2 participants