masmu / pulseaudio-dlna

A lightweight streaming server which brings DLNA / UPNP and Chromecast support to PulseAudio and Linux
GNU General Public License v3.0
1.25k stars 162 forks source link

pycastv2: read Chromecast status #308

Open klaernie opened 7 years ago

klaernie commented 7 years ago

Skimming over the code I did not see anything in the library, that would provide an answer: Is it possible to query the Chromecasts on the network, to find out if they are currently playing media, and if so which application?

On the protocol level it must be possible, as the Google Home app is already doing just this.

This would also make a nice addition, to show in the pulseaudio virtual device name, that a particular device is currently playing something, maybe even that it is casting Spotify right now.

masmu commented 7 years ago

Apps on the Chromecast are identified by IDs, but Chromecasts also provide their displayed name with a displayName var in every RECEIVER_STATUS response.

 {
  "status": {
    "volume": {
      "muted": false, 
      "stepInterval": 0.05000000074505806, 
      "controlType": "attenuation", 
      "level": 1.0
    }, 
    "applications": [
      {
        "displayName": "Default Media Receiver", 
        "statusText": "Now Casting", 
        "transportId": "9e83a6bf-5c1c-417d-953f-6p6102d404fa", 
        "isIdleScreen": false, 
        "sessionId": "9e83a6bf-5c1c-417d-953f-6p6102d404fa", 
        "namespaces": [
          {
            "name": "urn:x-cast:com.google.cast.broadcast"
          }, 
          {
            "name": "urn:x-cast:com.google.cast.media"
          }
        ], 
        "appId": "CC1AD845"
      }
    ]
  }, 
  "type": "RECEIVER_STATUS", 
  "requestId": 1
}

There is also being sent a MEDIA_STATUS response.

 {
  "status": [
    {
      "mediaSessionId": 1, 
      "supportedMediaCommands": 15, 
      "currentTime": 0, 
      "media": {
        "duration": null, 
        "contentId": "http://192.168.1.2:8082/BigBuckBunny.mp4", 
        "streamType": "LIVE", 
        "contentType": "video/x-matroska"
      }, 
      "playbackRate": 1, 
      "volume": {
        "muted": false, 
        "level": 1
      }, 
      "currentItemId": 1, 
      "idleReason": "INTERRUPTED", 
      "playerState": "IDLE", 
      "extendedStatus": {
        "playerState": "LOADING", 
        "media": {
          "contentId": "http://192.168.1.2:8080/stream.mp3",
          "streamType": "LIVE", 
          "contentType": "audio/mp3", 
          "metadata": {
            "images": [
              {
                "url": "http://192.168.1.2:8080/stream.mp3",
              }
            ], 
            "metadataType": 3, 
            "artist": "Liveaudio on raketomat", 
            "title": "Spotify"
          }
        }
      }
    }
  ], 
  "type": "MEDIA_STATUS", 
  "requestId": 0
}

The real problem is that I implemented the castv2 protocol stateless. So there is just a connection to a Chromecast established when you are actually instructing the device to play or stop. And after that the connection is being closed again, basically like HTTP works. The reason for implementing this stateless was to avoid threads and therefore to be able to share pickled data between subprocesses easily.

So you would need to actually poll for the required information constantly or change the stateless approach.