thibauts / node-castv2-client

A Chromecast client based on the new (CASTV2) protocol
MIT License
648 stars 95 forks source link

requesting playerState #82

Open untitledlt opened 6 years ago

untitledlt commented 6 years ago

I know I can get playerState on various player events like play, pause or track change. How can i get playerState (f.e. PLAYING) without waiting for such event?

client.getStatus() returns active app but there is no playerState.

pedromsilvapt commented 6 years ago

When you join (client.join()) or launch (client.launch()) an app, it returns the player reference (the same you can use to pause, resume and overall control the player). You can call player.getStatus(), and the callback will have the object with (among many others) the playerState property.

untitledlt commented 6 years ago

Hey @pedromsilvapt, thanks for answer! I can get playerState now but encountered another issue. After joining existing client i'm starting setInterval and i'm requesting .getStatus() every few seconds. The problem is that after some time i get this error:

(node:5925) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 message listeners added. Use emitter.setMaxListeners() to increase limit

Can I call .getStatus() multiple times? Looks like it's creating listener with every call but each call returns only once. What i'm doing wrong here?

pedromsilvapt commented 6 years ago

Although I am not super familiar with the module's inner workings, a quick look through the code does indeed reveal that every request creates a new listener here: https://github.com/thibauts/node-castv2-client/blob/master/lib/controllers/request-response.js#L31

But I gotta say, I've used it before like that (calling .getStatus() on an interval) and haven't run into this issue.

One possible solution that I see is: it creates a event listener for every request, and removes it when the response comes. However, let's say that for whatever reason it is taking a long time to respond (it happens sometimes on my chromecasts). `setInterval has a fixed interval, which means, it does not wait for it's code to finish before triggering again. Let's say your interval is of 2 seconds, and the requests are taking a long time, every two seconds will add another listener, without removing the ones before.

Obviously this is just a theory, and I can't know for sure without seeing your code, but if the case above applies to you, maybe try increasing the setInterval, or use a setTimeout instead, and recreate it only once the last one finishes.

untitledlt commented 6 years ago

Just realized that I'm getting this error when Backdrop is active on Chromecast. It never happens when Spotify is an active app.

pedromsilvapt commented 6 years ago

Well, probably the backdrop app does not answer to the status request, hence the memory leak on the event emitter.

You can listen to the client.on( 'status' ) to be aware when the app changes, or use the client.getStatus() manually and disable/enable the interval accordingly.

FrancescoCioria commented 3 years ago

player.getStatus tries to send a message to the urn:x-cast:com.google.cast.media namespace, but this namespace does not necessarily always exist, the main example is the Backdrop app.

What I did in my application is to call player.getStatus only if the current client session (you can get it with client.getSessions() includes urn:x-cast:com.google.cast.media in its namespaces:

example:

if (session.namespaces.find(n => n.name === "urn:x-cast:com.google.cast.media")) {
  player.getStatus();
} else {
  throw new Error("There is no active media session");
}