home-assistant-libs / pychromecast

Library for Python 3 to communicate with the Google Chromecast.
MIT License
2.53k stars 377 forks source link

Unable to get media_controller status when run script multiple times #225

Open erinarbleizez opened 6 years ago

erinarbleizez commented 6 years ago

Hi,

I try to make a cron task that send video when the chromecast is not used. I tried this code that work to send video

#!/usr/bin/python3

import pychromecast,os,random

chromecasts = pychromecast.get_chromecasts()
pychromecast.IGNORE_CEC.append('*')
for chromecast in chromecasts:
    mc = chromecast.media_controller
    print (mc.status)
    if chromecast.status is not None and ( chromecast.status.display_name == "Backdrop" or chromecast.status.display_name == "Default Media Receiver" ) and mc.status.player_state != 'PLAYING':
        chromecast.set_volume(0)
        choice = random.choice(os.listdir("/home/erin/Nextcloud/Video"))
        mc.play_media('http://10.42.42.18:8100/' + choice, 'video/mp4')
        mc.block_until_active()
        print (mc.status)

I receive the right status right after starting the video:

<MediaStatus {'metadata_type': None, 'title': None, 'series_title': None, 'season': None, 'episode': None, 'artist': None, 'album_name': None, 'album_artist': None, 'track': None, 'subtitle_tracks': {}, 'images': [], 'supports_pause': True, 'supports_seek': True, 'supports_stream_volume': True, 'supports_stream_mute': True, 'supports_skip_forward': False, 'supports_skip_backward': False, 'current_time': 340.501219, 'content_id': 'http://10.42.42.18:8100/playing.mp4', 'content_type': 'video/mp4', 'duration': 674.144, 'stream_type': 'BUFFERED', 'idle_reason': None, 'media_session_id': 1, 'playback_rate': 1, 'player_state': 'PLAYING', 'supported_media_commands': 15, 'volume_level': 1, 'volume_muted': False, 'media_custom_data': {}, 'media_metadata': {}, 'current_subtitle_tracks': [], 'last_updated': datetime.datetime(2018, 3, 24, 16, 15, 59, 956082)}>

but when I restart the script while the videos are playing to check the status I get this:

<MediaStatus {'metadata_type': None, 'title': None, 'series_title': None, 'season': None, 'episode': None, 'artist': None, 'album_name': None, 'album_artist': None, 'track': None, 'subtitle_tracks': {}, 'images': [], 'supports_pause': False, 'supports_seek': False, 'supports_stream_volume': False, 'supports_stream_mute': False, 'supports_skip_forward': False, 'supports_skip_backward': False, 'current_time': 0, 'content_id': None, 'content_type': None, 'duration': None, 'stream_type': 'UNKNOWN', 'idle_reason': None, 'media_session_id': None, 'playback_rate': 1, 'player_state': 'UNKNOWN', 'supported_media_commands': 0, 'volume_level': 1, 'volume_muted': False, 'media_custom_data': {}, 'media_metadata': {}, 'current_subtitle_tracks': [], 'last_updated': None}>

I tried with 1 chromecast v1, 1 chromecast v2 and 2 chromecast ultra, same result

did I missed something?

hjmsw commented 6 years ago

@erinarbleizez I'm having this issue too. I tested in a python shell and I can get back a proper status from media_controller.status, track info and all. When I run a script I'm writing in PyCharm CE, I get back what you have shown above.

Python 3.6.5 running in a virtualenv on MacOS, ChromeCast audio.

I can see this was a while ago now but did you get to the bottom of this issue?

hjmsw commented 6 years ago

If anyone else comes across this issue, try adding time.sleep(1) before your call to media_controller.status - This ended up solving this issue for me.

ygmarchi commented 6 years ago

Hello, I think I'm experiencing similar problems. I'm using the first (and only?) Chromecast Audio device.

In my case I'm playing a sequence of songs. My intention is to play the next song when I receive the media status update that the previous song is finished.

When the previous song finishes, by enabling logging, this message is received from the Chromecast

DEBUG:pychromecast.socket_client:Received: Message urn:x-cast:com.google.cast.media from 46e5ee83-49f8-4a1a-b3d7-178af713f74f to *: {'type': 'MEDIA_STATUS', 'status': [{'mediaSessionId': 7, 'playbackRate': 1, 'playerState': 'IDLE', 'currentTime': 0, 'supportedMediaCommands': 274447, 'volume': {'level': 1, 'muted': False}, 'currentItemId': 7, 'idleReason': 'FINISHED'}], 'requestId': 0}

This causes the internal media_controller status object to be updated to playerState = IDLE idleReason = FINISHED contentId = previous track

Then I submit the next track

[ Wed Sep 5 00:49:05 2018 ] Playing http://192.168.1.90:8000/Clip%204.ogg.flac

INFO:pychromecast.controllers:Not launching app CC1AD845 - already running DEBUG:pychromecast.socket_client:Sending: Message urn:x-cast:com.google.cast.media from sender-0 to 46e5ee83-49f8-4a1a-b3d7-178af713f74f: {'media': {'contentId': 'http://192.168.1.90:8000/Clip%204.ogg.flac', 'streamType': 'BUFFERED', 'contentType': 'audio/flac', 'metadata': {}}, 'type': 'LOAD', 'currentTime': 0, 'autoplay': True, 'customData': {}, 'requestId': 6, 'sessionId': '46e5ee83-49f8-4a1a-b3d7-178af713f74f'}

and the following message is received immediately

DEBUG:pychromecast.socket_client:Received: Message urn:x-cast:com.google.cast.media from 46e5ee83-49f8-4a1a-b3d7-178af713f74f to *: {'type': 'MEDIA_STATUS', 'status': [{'mediaSessionId': 8, 'playbackRate': 1, 'playerState': 'IDLE', 'currentTime': 0, 'supportedMediaCommands': 274447, 'volume': {'level': 1, 'muted': False}, 'media': {'contentId': 'http://192.168.1.90:8000/Clip%204.ogg.flac', 'streamType': 'BUFFERED', 'contentType': 'audio/flac', 'metadata': {}}, 'currentItemId': 8, 'extendedStatus': {'playerState': 'LOADING', 'media': {'contentId': 'http://192.168.1.90:8000/Clip%204.ogg.flac', 'streamType': 'BUFFERED', 'contentType': 'audio/flac', 'metadata': {}}}, 'repeatMode': 'REPEAT_OFF'}], 'requestId': 0}

note that the playerState is still IDLE but there's an extendedStatus structure that is completely ignored by the library containg an playerState LOADING update. This way the internal status is updated this way

playerState = IDLE idleReason = FINISHED contentId = next track

and this new status is delivered to the registered listeners, which of course is totally misleading.

Best Regards, Carlo.

ygmarchi commented 6 years ago

Naively, by inserting the following code in the update method in media.py things get much better:

extended_status_data = status_data.get('extendedStatus')
if extended_status_data:
    data ['status'] = [extended_status_data]
    self.update (data)
rf-tsukasa-dewa commented 3 years ago

Hello, I also had this issue. I use Pychromecast v7.5.1 https://github.com/home-assistant-libs/pychromecast/commit/7c2bec4af3eedd236c4295a750ea60d3798e1313

DEBUG : 2020-10-22 09:59:51,328 : [(xxx.xxx.xxx.xxx):8009] Received: Message urn:x-cast:com.google.cast.media from c3f10024-d44e-418a-9cbc-e989533a19dd to *: {'type': 'MEDIA_STATUS', 'status': [{'mediaSessionId': 2, 'playbackRate': 1, 'playerState': 'IDLE', 'currentTime': 0, 'supportedMediaCommands': 274447, 'volume': {'level': 1, 'muted': False}, 'media': {'contentId': 'http://xxx.xxx.xxx.xxx/media/sample_media.mp4', 'streamType': 'BUFFERED', 'contentType': 'video/mp4', 'metadata': {}, 'mediaCategory': 'VIDEO'}, 'currentItemId': 1, 'extendedStatus': {'playerState': 'LOADING', 'media': {'contentId': 'http://xxx.xxx.xxx.xxx/media/sample_media.mp4', 'streamType': 'BUFFERED', 'contentType': 'video/mp4', 'metadata': {}, 'mediaCategory': 'VIDEO'}, 'mediaSessionId': 2}, 'repeatMode': 'REPEAT_OFF'}], 'requestId': 0}
DEBUG : 2020-10-22 09:59:51,328 : Media:Received status {'type': 'MEDIA_STATUS', 'status': [{'mediaSessionId': 2, 'playbackRate': 1, 'playerState': 'IDLE', 'currentTime': 0, 'supportedMediaCommands': 274447, 'volume': {'level': 1, 'muted': False}, 'media': {'contentId': 'http://xxx.xxx.xxx.xxx/media/sample_media.mp4', 'streamType': 'BUFFERED', 'contentType': 'video/mp4', 'metadata': {}, 'mediaCategory': 'VIDEO'}, 'currentItemId': 1, 'extendedStatus': {'playerState': 'LOADING', 'media': {'contentId': 'http://xxx.xxx.xxx.xxx/media/sample_media.mp4', 'streamType': 'BUFFERED', 'contentType': 'video/mp4', 'metadata': {}, 'mediaCategory': 'VIDEO'}, 'mediaSessionId': 2}, 'repeatMode': 'REPEAT_OFF'}], 'requestId': 0}

I did the following code in the update method in media.py. L. 287

        extended_status = status_data.get("extendedStatus", {})
        self.player_state = extended_status.get("playerState", self.player_state)
        media_data = extended_status.get("media") or {}
        self.media_session_id = extended_status.get("mediaSessionId", self.media_session_id)
        self.content_id = media_data.get("contentId", self.content_id)
        self.content_type = media_data.get("contentType", self.content_type)
        self.duration = media_data.get("duration", self.duration)
        self.stream_type = media_data.get("streamType", self.stream_type)
        self.media_custom_data = media_data.get("customData", self.media_custom_data)
        self.media_metadata = media_data.get("metadata", self.media_metadata)
        self.subtitle_tracks = media_data.get("tracks", self.subtitle_tracks)

And I also added the following property.

    @property
    def player_is_loading(self):
        """ Return True if player is LOADING. """
        return self.player_state == MEDIA_PLAYER_STATE_LOADING

I thought about the extendedStatus parameter based on the following URI, but I'm not sure if this is correct. https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.messages.ExtendedMediaStatus