diff options
Diffstat (limited to 'ccast/cctest.c')
-rw-r--r-- | ccast/cctest.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/ccast/cctest.c b/ccast/cctest.c new file mode 100644 index 0000000..2c95ae1 --- /dev/null +++ b/ccast/cctest.c @@ -0,0 +1,329 @@ + +/* + * Argyll Color Correction System + * ChromCast test harness + * + * Author: Graeme W. Gill + * Date: 28/8/2014 + * + * Copyright 2014 Graeme W. Gill + * All rights reserved. + * + * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :- + * see the License2.txt file for licencing details. + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <sys/types.h> +#include <time.h> +#include "copyright.h" +#include "aconfig.h" +#ifndef SALONEINSTLIB +#include "numlib.h" +#else +#include "numsup.h" +#endif +#include "ccmdns.h" +#include "ccpacket.h" +#include "ccmes.h" +#include "yajl.h" + +/* Check if JSON is invalid */ +/* Exits if invalid */ +static void check_json(char *mesbuf) { + yajl_val node; + char errbuf[1024]; + + if ((node = yajl_tree_parse(mesbuf, errbuf, sizeof(errbuf))) == NULL) { + printf("yajl_tree_parse of send message failed with '%s'\n",errbuf); + printf("JSON = '%s'\n",mesbuf); + exit(1); + } + yajl_tree_free(node); +} + +/* Return nz on error */ +static int get_a_reply(ccmessv *mes, ORD8 **pdata) { + ccmessv_err merr; + char *source_id; + char *destination_id; + char *namespace; + int binary; /* Flag */ + ORD8 *data; /* String or binary */ + ORD32 bin_len; /* Binary data length */ + + if ((merr = mes->receive(mes, &source_id, &destination_id, &namespace, + &binary, &data, &bin_len)) != ccmessv_OK) { + printf("mes->receive failed with '%s'\n",ccmessv_emes(merr)); + return -1; + } else { + printf("Got message:\n"); + printf(" source_id = '%s'\n",source_id); + printf(" destination_id = '%s'\n",destination_id); + printf(" namespace = '%s'\n",namespace); + printf(" binary = %d\n",binary); + if (binary) { + printf(" payload =\n"); + cc_dump_bytes(stdout, " ", data, bin_len); + } else { + printf(" payload = '%s'\n",data); + } + if (pdata != NULL) + *pdata = data; + else + free(data); + } + return 0; +} + +/* Get replies until we get one with the matching Id, then return */ +static int get_a_reply_id(ccmessv *mes, int tid, ORD8 **pdata) { + ORD8 *data; + int id, rv; + yajl_val node, v; + char errbuf[1024]; + +//printf("~~~ looking for id %d\n",tid); + for (;;) { + int id = -1; + + if ((rv = get_a_reply(mes, &data)) != 0) + return rv; + +// printf("\nGot JSON data to parse: '%s'\n",data); + if ((node = yajl_tree_parse(data, errbuf, sizeof(errbuf))) == NULL) + error("yajl_tree_parse failed with '%s'",errbuf); + + if ((v = yajl_tree_get_first(node, "requestId", yajl_t_number)) != NULL) { + printf("~~~~ Got id %d\n",id); + id = YAJL_GET_INTEGER(v); + } + yajl_tree_free(node); + + if (id == tid) { +//printf("~~~ got our message\n"); + break; + } + free(data); +//printf("~~~ round we go again\n"); + } + if (pdata != NULL) + *pdata = data; + else + free(data); + return 0; +} + +/* Do the authentication sequence */ +static void authenticate(ccmessv *mes) { + + /* (Not needed) */ +} + +int +main( + int argc, + char *argv[] +) { + ccast_id **ids; + int i; + ccpacket *pk; + ccpacket_err perr; + ccmessv *mes; + ccmessv_err merr; + char *sessionId = NULL; + char *transportId = NULL; + char mesbuf[1024]; + + if ((ids = get_ccids()) == NULL) { + error("get_ccids() failed"); + } + + if (ids[0] == NULL) { + error("Found no ChromCasts"); + } + + for (i = 0; ids[i] != NULL; i++) { + printf("Entry %d:\n",i); + printf(" Name: %s\n",ids[i]->name); + printf(" IP: %s\n",ids[i]->ip); + } + + if ((pk = new_ccpacket()) == NULL) { + error("new_ccpacket() failed"); + } + + if ((perr = pk->connect(pk, ids[0]->ip, 8009)) != ccpacket_OK) { + error("ccpacket connect failed with '%s",ccpacket_emes(perr)); + } + printf("Got TLS connection to '%s\n'",ids[0]->name); + + if ((mes = new_ccmessv(pk)) == NULL) { + error("new_ccmessv() failed"); + } + + /* Attempt a connection */ + if ((merr = mes->send(mes, "sender-0", "receiver-0", + "urn:x-cast:com.google.cast.tp.connection", 0, + "{ \"type\": \"CONNECT\" }", 0)) != ccmessv_OK) { + error("mes->send CONNECT failed with '%s'",ccmessv_emes(merr)); + } + + /* Send a ping */ + if ((merr = mes->send(mes, "sender-0", "receiver-0", + "urn:x-cast:com.google.cast.tp.heartbeat", 0, + "{ \"type\": \"PING\" }", 0)) != ccmessv_OK) { + error("mes->send PING failed with '%s'",ccmessv_emes(merr)); + } + + /* Wait for a PONG */ + get_a_reply(mes, NULL); + + authenticate(mes); + + /* Launch the default application */ + /* (Presumably we would use the com.google.cast.receiver channel */ + /* for monitoring and controlling the reciever) */ + if ((merr = mes->send(mes, "sender-0", "receiver-0", + "urn:x-cast:com.google.cast.receiver", 0, + "{ \"requestId\": 1, \"type\": \"LAUNCH\", \"appId\": \"CC1AD845\" }", 0)) != ccmessv_OK) { + error("mes->send LAUNCH failed with '%s'",ccmessv_emes(merr)); + } + + /* Receive the RECEIVER_STATUS status messages until it is ready to cast */ + /* and get the sessionId and transportId */ + /* We get periodic notification messages (requestId=0) as well as */ + /* a response messages (requestId=1) */ + for (;sessionId == NULL || transportId == NULL;) { + ORD8 *data; + yajl_val node, v; + char errbuf[1024]; + + get_a_reply(mes, &data); + +// printf("\nGot JSON data to parse: '%s'\n",data); + if ((node = yajl_tree_parse(data, errbuf, sizeof(errbuf))) == NULL) + error("yajl_tree_parse failed with '%s'",errbuf); + + if ((v = yajl_tree_get_first(node, "sessionId", yajl_t_string)) != NULL) { + sessionId = strdup(YAJL_GET_STRING(v)); +// printf("~1 got sessionId = '%s'\n",sessionId); + } + + if ((v = yajl_tree_get_first(node, "transportId", yajl_t_string)) != NULL) { + transportId = strdup(YAJL_GET_STRING(v)); +// printf("~1 got transportId = '%s'\n",transportId); + } + free(data); + yajl_tree_free(node); + } + + printf("\ngot sessionId = '%s', transportId = '%s'\n",sessionId, transportId); + + printf("\nAbout to send URL\n"); + + /* Connect up to the reciever media channels */ + if ((merr = mes->send(mes, "med_send", transportId, + "urn:x-cast:com.google.cast.tp.connection", 0, + "{ \"type\": \"CONNECT\" }", 0)) != ccmessv_OK) { + error("mes->send CONNECT failed with '%s'",ccmessv_emes(merr)); + } + + // "urn:x-cast:com.google.cast.player.message" + // "urn:x-cast:com.google.cast.media"} + + sprintf(mesbuf, "{ \"requestId\": 2, \"type\": \"LOAD\", \"media\": " + "{ \"contentId\": \"http://www.argyllcms.com/ArgyllCMSLogo.gif\",\"streamType\": \"LIVE\"," + "\"contentType\": \"image/gif\" } }"); + +// "\"contentType\": \"image/gif\", \"duration\" : 0.1 }, \"autplay\": \"true\" }"); + + check_json(mesbuf); + + /* Send the LOAD command */ + if ((merr = mes->send(mes, "med_send", transportId, + "urn:x-cast:com.google.cast.media", 0, + mesbuf, 0 + )) != ccmessv_OK) { + error("mes->send LOAD failed with '%s'",ccmessv_emes(merr)); + } + + if (get_a_reply_id(mes, 2, NULL) != 0) + exit(1); + + msec_sleep(2000); + +#ifdef NEVER + /* Check the media status */ + if ((merr = mes->send(mes, "med_send", transportId, + "urn:x-cast:com.google.cast.media", 0, + "{ \"requestId\": 3, \"type\": \"GET_STATUS\" }", 0)) != ccmessv_OK) { + error("mes->send GET_STATUS failed with '%s'",ccmessv_emes(merr)); + } + + if (get_a_reply_id(mes, 3, NULL) != 0) + exit(1); +#endif + + sprintf(mesbuf, "{ \"requestId\": 4, \"type\": \"LOAD\", \"media\": { \"contentId\": \"http://www.argyllcms.com/testing.png\",\"streamType\": \"LIVE\",\"contentType\": \"image/png\" } }"); + +// sprintf(mesbuf, "{ \"requestId\": 4, \"type\": \"LOAD\", \"media\": { \"contentId\": \"http://www.argyllcms.com/testing.tif\",\"streamType\": \"LIVE\",\"contentType\": \"image/tiff\" } }"); +// sprintf(mesbuf, "{ \"requestId\": 4, \"type\": \"LOAD\", \"media\": { \"contentId\": \"http://www.argyllcms.com/doc/sl.jpg\",\"streamType\": \"LIVE\",\"contentType\": \"image/jpeg\" } }"); + check_json(mesbuf); + + /* Send the LOAD command */ + if ((merr = mes->send(mes, "med_send", transportId, + "urn:x-cast:com.google.cast.media", 0, + mesbuf, 0 + )) != ccmessv_OK) { + error("mes->send LOAD failed with '%s'",ccmessv_emes(merr)); + } + + if (get_a_reply_id(mes, 4, NULL) != 0) + exit(1); + + msec_sleep(2000); + +#ifdef NEVER + /* Check the media status */ + if ((merr = mes->send(mes, "med_send", transportId, + "urn:x-cast:com.google.cast.media", 0, + "{ \"requestId\": 5, \"type\": \"GET_STATUS\" }", 0)) != ccmessv_OK) { + error("mes->send GET_STATUS failed with '%s'",ccmessv_emes(merr)); + } + + if (get_a_reply_id(mes, 5, NULL) != 0) + exit(1); +#endif + +#ifdef NEVER + /* Try and send it an image URL */ + if ((merr = mes->send(mes, "med_send", transportId, + "urn:x-cast:com.google.cast.media", 0, +// "{ \"imageUrl\": \"http://www.argyllcms.com/ArgyllCMSLogo.gif\", \"requestId\": 6 }", 0)) != ccmessv_OK) { + "{ \"url\": \"http://www.argyllcms.com/ArgyllCMSLogo.gif\", \"requestId\": 2 }", 0)) != ccmessv_OK) { + error("mes->send imageUrl failed with '%s'",ccmessv_emes(merr)); + } + +#endif + /* Wait for any reply */ + for (;;) { + if (get_a_reply(mes, NULL) != 0) + break; + } + + // ~~999 + + mes->del(mes); + pk->del(pk); + + printf("Disconnected from '%s'\n",ids[0]->name); + + free_ccids(ids); + + return 0; +} + |