[cast] Fallback if new mirroring app not present + metadata (not working)

This commit is contained in:
ejurgensen 2019-03-26 23:13:09 +01:00
parent 6930fdb28d
commit 9773d9b840

View File

@ -70,10 +70,9 @@
#define REPLY_TIMEOUT 5 #define REPLY_TIMEOUT 5
// ID of the audio mirroring app used by Chrome (Google Home) // ID of the audio mirroring app used by Chrome (Google Home)
//#define CAST_APP_ID "85CDB22F" #define CAST_APP_ID "85CDB22F"
// Old mirroring app (Chromecast) // Old mirroring app (Chromecast)
#define CAST_APP_ID "0F5096E8" #define CAST_APP_ID_OLD "0F5096E8"
// Namespaces // Namespaces
#define NS_CONNECTION "urn:x-cast:com.google.cast.tp.connection" #define NS_CONNECTION "urn:x-cast:com.google.cast.tp.connection"
@ -250,6 +249,8 @@ enum cast_msg_types
GET_STATUS, GET_STATUS,
RECEIVER_STATUS, RECEIVER_STATUS,
LAUNCH, LAUNCH,
LAUNCH_OLD,
LAUNCH_ERROR,
STOP, STOP,
MEDIA_CONNECT, MEDIA_CONNECT,
MEDIA_CLOSE, MEDIA_CLOSE,
@ -264,6 +265,7 @@ enum cast_msg_types
MEDIA_LOAD_FAILED, MEDIA_LOAD_FAILED,
MEDIA_LOAD_CANCELLED, MEDIA_LOAD_CANCELLED,
SET_VOLUME, SET_VOLUME,
PRESENTATION,
}; };
struct cast_msg_basic struct cast_msg_basic
@ -337,6 +339,16 @@ struct cast_msg_basic cast_msg[] =
.payload = "{'type':'LAUNCH','requestId':%d,'appId':'" CAST_APP_ID "'}", .payload = "{'type':'LAUNCH','requestId':%d,'appId':'" CAST_APP_ID "'}",
.flags = USE_REQUEST_ID_ONLY, .flags = USE_REQUEST_ID_ONLY,
}, },
{
.type = LAUNCH_OLD,
.namespace = NS_RECEIVER,
.payload = "{'type':'LAUNCH','requestId':%d,'appId':'" CAST_APP_ID_OLD "'}",
.flags = USE_REQUEST_ID_ONLY,
},
{
.type = LAUNCH_ERROR,
.tag = "LAUNCH_ERROR",
},
{ {
.type = STOP, .type = STOP,
.namespace = NS_RECEIVER, .namespace = NS_RECEIVER,
@ -418,6 +430,12 @@ struct cast_msg_basic cast_msg[] =
.payload = "{'type':'SET_VOLUME','volume':{'level':%.2f,'muted':0},'requestId':%d}", .payload = "{'type':'SET_VOLUME','volume':{'level':%.2f,'muted':0},'requestId':%d}",
.flags = USE_REQUEST_ID, .flags = USE_REQUEST_ID,
}, },
{
.type = PRESENTATION,
.namespace = NS_WEBRTC,
.payload = "{'type':'PRESENTATION','sessionId':'%s',seqnum:%d,'title':'forked-daapd','icons':[{'url':'http://www.gyfgafguf.dk/images/fugl.jpg'}] }",
.flags = USE_TRANSPORT_ID | USE_REQUEST_ID,
},
{ {
.type = 0, .type = 0,
}, },
@ -731,6 +749,8 @@ cast_msg_send(struct cast_session *cs, enum cast_msg_types type, cast_reply_cb r
snprintf(msg_buf, sizeof(msg_buf), cast_msg[type].payload, cs->session_id, cs->request_id); snprintf(msg_buf, sizeof(msg_buf), cast_msg[type].payload, cs->session_id, cs->request_id);
else if (type == OFFER) else if (type == OFFER)
snprintf(msg_buf, sizeof(msg_buf), cast_msg[type].payload, cs->request_id, cs->ssrc_id); snprintf(msg_buf, sizeof(msg_buf), cast_msg[type].payload, cs->request_id, cs->ssrc_id);
else if (type == PRESENTATION)
snprintf(msg_buf, sizeof(msg_buf), cast_msg[type].payload, cs->session_id, cs->request_id);
else if (type == MEDIA_LOAD) else if (type == MEDIA_LOAD)
snprintf(msg_buf, sizeof(msg_buf), cast_msg[type].payload, cs->stream_url, cs->session_id, cs->request_id); snprintf(msg_buf, sizeof(msg_buf), cast_msg[type].payload, cs->stream_url, cs->session_id, cs->request_id);
else if ((type == MEDIA_PLAY) || (type == MEDIA_PAUSE) || (type == MEDIA_STOP)) else if ((type == MEDIA_PLAY) || (type == MEDIA_PAUSE) || (type == MEDIA_STOP))
@ -1157,6 +1177,17 @@ cast_cb_startup_launch(struct cast_session *cs, struct cast_msg_payload *payload
goto error; goto error;
} }
if (payload->type == LAUNCH_ERROR && !cs->retry)
{
DPRINTF(E_WARN, L_CAST, "Device '%s' does not support app id '%s', trying '%s' instead\n", cs->devname, CAST_APP_ID, CAST_APP_ID_OLD);
cs->retry++;
ret = cast_msg_send(cs, LAUNCH_OLD, cast_cb_startup_launch);
if (ret < 0)
goto error;
return;
}
if (payload->type != RECEIVER_STATUS) if (payload->type != RECEIVER_STATUS)
{ {
DPRINTF(E_LOG, L_CAST, "No RECEIVER_STATUS reply to our LAUNCH (got type: %d) - aborting\n", payload->type); DPRINTF(E_LOG, L_CAST, "No RECEIVER_STATUS reply to our LAUNCH (got type: %d) - aborting\n", payload->type);
@ -1305,6 +1336,15 @@ cast_cb_flush(struct cast_session *cs, struct cast_msg_payload *payload)
cast_status(cs); cast_status(cs);
} }
static void
cast_cb_presentation(struct cast_session *cs, struct cast_msg_payload *payload)
{
if (!payload)
DPRINTF(E_LOG, L_CAST, "No reply to PRESENTATION request from '%s' - will continue\n", cs->devname);
else if (payload->type != MEDIA_STATUS)
DPRINTF(E_LOG, L_CAST, "Unexpected reply to PRESENTATION request from '%s' - will continue\n", cs->devname);
}
/* The core of this module. Libevent makes a callback to this function whenever /* The core of this module. Libevent makes a callback to this function whenever
* there is new data to be read on the fd from the ChromeCast. If everything is * there is new data to be read on the fd from the ChromeCast. If everything is
* good then the data will be passed to cast_msg_process() that will then * good then the data will be passed to cast_msg_process() that will then
@ -1492,6 +1532,15 @@ cast_device_cb(const char *name, const char *type, const char *domain, const cha
} }
/* --------------------------------- METADATA ------------------------------- */
static void
metadata_send(struct cast_session *cs)
{
cast_msg_send(cs, PRESENTATION, cast_cb_presentation);
}
/* --------------------- SESSION CONSTRUCTION AND SHUTDOWN ------------------ */ /* --------------------- SESSION CONSTRUCTION AND SHUTDOWN ------------------ */
static struct cast_master_session * static struct cast_master_session *
@ -2108,6 +2157,25 @@ cast_write(struct output_buffer *obuf)
} }
} }
static void
cast_metadata_send(struct output_metadata *metadata)
{
struct cast_session *cs;
struct cast_session *next;
for (cs = cast_sessions; cs; cs = next)
{
next = cs->next;
if (cs->state != CAST_STATE_MEDIA_CONNECTED)
continue;
metadata_send(cs);
}
// TODO free the metadata
}
static int static int
cast_init(void) cast_init(void)
{ {
@ -2200,6 +2268,8 @@ struct output_definition output_cast =
.type = OUTPUT_TYPE_CAST, .type = OUTPUT_TYPE_CAST,
.priority = 2, .priority = 2,
.disabled = 0, .disabled = 0,
.init = cast_init,
.deinit = cast_deinit,
.device_start = cast_device_start, .device_start = cast_device_start,
.device_probe = cast_device_probe, .device_probe = cast_device_probe,
.device_stop = cast_device_stop, .device_stop = cast_device_stop,
@ -2207,12 +2277,7 @@ struct output_definition output_cast =
.device_cb_set = cast_device_cb_set, .device_cb_set = cast_device_cb_set,
.device_volume_set = cast_device_volume_set, .device_volume_set = cast_device_volume_set,
.write = cast_write, .write = cast_write,
.init = cast_init, // .metadata_prepare = cast_metadata_prepare,
.deinit = cast_deinit,
/* TODO metadata support
.metadata_prepare = cast_metadata_prepare,
.metadata_send = cast_metadata_send, .metadata_send = cast_metadata_send,
.metadata_purge = cast_metadata_purge, // .metadata_purge = cast_metadata_purge,
.metadata_prune = cast_metadata_prune,
*/
}; };