[gnome-network-displays/cc-tmp: 20/80] cc: fix crash on cancel cast




commit ecf89d285b8c437ed85083217c24287220f92f05
Author: Anupam Kumar <kyteinsky gmail com>
Date:   Sat Aug 6 17:43:14 2022 +0530

    cc: fix crash on cancel cast

 src/cc/cc-comm.c | 495 +++++++++++++++++++++++++++----------------------------
 src/cc/cc-comm.h |  19 ++-
 src/nd-cc-sink.c | 124 +++++++-------
 3 files changed, 322 insertions(+), 316 deletions(-)
---
diff --git a/src/cc/cc-comm.c b/src/cc/cc-comm.c
index 03d45bd..d02b141 100644
--- a/src/cc/cc-comm.c
+++ b/src/cc/cc-comm.c
@@ -23,16 +23,16 @@
 
 // function decl
 static void cc_comm_listen (CcComm *comm);
-static void cc_comm_read (CcComm *comm, gsize io_bytes, gboolean read_header);
+static void cc_comm_read (CcComm  *comm,
+                          gsize    io_bytes,
+                          gboolean read_header);
 
 
 static gboolean
 cc_comm_load_media_cb (CcComm *comm)
 {
   if (!cc_comm_send_request (comm, MESSAGE_TYPE_MEDIA, "{ \"type\": \"LOAD\", \"media\": { \"contentId\": 
\"https://commondatastorage.googleapis.com/gtv-videos-bucket/CastVideos/mp4/BigBuckBunny.mp4\";, 
\"streamType\": \"BUFFERED\", \"contentType\": \"video/mp4\" }, \"requestId\": 4 }", NULL))
-  {
     g_warning ("NdCCSink: something went wrong with load media");
-  }
 
   return FALSE;
 }
@@ -75,15 +75,15 @@ static gboolean
 cc_comm_parse_json_data (CcComm *comm, char *payload)
 {
   g_autoptr(GError) error = NULL;
-  g_autoptr(JsonParser) parser;
-  g_autoptr(JsonReader) reader;
+  g_autoptr(JsonParser) parser = NULL;
+  g_autoptr(JsonReader) reader = NULL;
 
   parser = json_parser_new ();
   if (!json_parser_load_from_data (parser, payload, -1, &error))
-  {
-    g_warning ("NdCCSink: Error parsing received messaage JSON: %s", error->message);
-    return TRUE;
-  }
+    {
+      g_warning ("NdCCSink: Error parsing received messaage JSON: %s", error->message);
+      return TRUE;
+    }
 
   reader = json_reader_new (json_parser_get_root (parser));
 
@@ -92,66 +92,69 @@ cc_comm_parse_json_data (CcComm *comm, char *payload)
   json_reader_end_member (reader);
 
   if (g_strcmp0 (message_type, "PONG") == 0)
-  {
     return FALSE;
-  }
 
   if (g_strcmp0 (message_type, "RECEIVER_STATUS") == 0)
-  {
-    if (!json_reader_read_member (reader, "status")) goto exit_parse;
-      if (!json_reader_read_member (reader, "applications")) goto exit_parse;
-        if (!json_reader_read_element (reader, 0)) goto exit_parse;
-          if (!json_reader_read_member (reader, "appId")) goto exit_parse;
-          const char *app_id = json_reader_get_string_value (reader);
-          if (g_strcmp0 (app_id, "CC1AD845") == 0)
+    {
+      if (json_reader_read_member (reader, "status"))
+        {
+          if (json_reader_read_member (reader, "applications"))
             {
+              if (json_reader_read_element (reader, 0))
+                {
+                  if (json_reader_read_member (reader, "appId"))
+                    {
+                      const char *app_id = json_reader_get_string_value (reader);
+                      if (g_strcmp0 (app_id, "CC1AD845") == 0)
+                        {
+                          json_reader_end_member (reader);
+                          json_reader_read_member (reader, "transportId");
+                          const char *transport_id = json_reader_get_string_value (reader);
+                          g_debug ("CcComm: Transport Id: %s!", transport_id);
+
+                          // start a new virtual connection
+                          comm->destination_id = g_strdup (transport_id);
+                          g_debug ("CcComm: Sending second connect request");
+                          if (!cc_comm_send_request (comm, MESSAGE_TYPE_CONNECT, NULL, NULL))
+                            {
+                              g_warning ("CcComm: Something went wrong with VC request for media");
+                              return TRUE;
+                            }
+                          // call the LOAD media request after 2 seconds
+                          g_timeout_add_seconds (2, G_SOURCE_FUNC (cc_comm_load_media_cb), comm);
+                        }
+                      json_reader_end_member (reader);
+                    }
+                  json_reader_end_element (reader);
+                }
               json_reader_end_member (reader);
-              json_reader_read_member (reader, "transportId");
-              const char *transport_id = json_reader_get_string_value (reader);
-              g_debug ("CcComm: Transport Id: %s!", transport_id);
-
-              // start a new virtual connection
-              comm->destination_id = g_strdup (transport_id);
-              // g_clear_pointer (&comm->sender_id, g_free);
-              // comm->sender_id = g_strdup ("sender-gnd");
-              g_debug ("CcComm: Sending second connect request");
-              if (!cc_comm_send_request(comm, MESSAGE_TYPE_CONNECT, NULL, NULL))
-              {
-                g_warning ("CcComm: Something went wrong with VC request for media");
-                return TRUE;
-              }
-              // call the LOAD media request after 4 seconds
-              g_timeout_add_seconds (4, G_SOURCE_FUNC (cc_comm_load_media_cb), comm);
             }
           json_reader_end_member (reader);
-        json_reader_end_element (reader);
-      json_reader_end_member (reader);
-    json_reader_end_member (reader);
-  }
+        }
+    }
 
-exit_parse:
   return TRUE;
 }
 
 static void
-cc_comm_parse_received_data(CcComm *comm, uint8_t * input_buffer, gssize input_size)
+cc_comm_parse_received_data (CcComm *comm, uint8_t * input_buffer, gssize input_size)
 {
   Castchannel__CastMessage *message;
 
-  message = castchannel__cast_message__unpack(NULL, input_size, input_buffer);
+  message = castchannel__cast_message__unpack (NULL, input_size, input_buffer);
   if (message == NULL)
-  {
-    g_warning ("CcComm: Failed to unpack received data");
-    return;
-  }
+    {
+      g_warning ("CcComm: Failed to unpack received data");
+      return;
+    }
 
   if (cc_comm_parse_json_data (comm, message->payload_utf8))
-  {
-    g_debug("CcComm: Received data:");
-    cc_comm_dump_json_message (message);
-  }
+    {
+      g_debug ("CcComm: Received message:");
+      cc_comm_dump_json_message (message);
+    }
 
-  castchannel__cast_message__free_unpacked(message, NULL);
+  castchannel__cast_message__free_unpacked (message, NULL);
 }
 
 static gboolean
@@ -183,19 +186,17 @@ cc_comm_accept_certificate (GTlsClientConnection *conn,
 static guint32
 cc_comm_to_message_size (CcComm *comm)
 {
-  return (guint32) (comm->header_buffer[0] * pow(256, 3) +
-                    comm->header_buffer[1] * pow(256, 2) +
-                    comm->header_buffer[2] * pow(256, 1) +
-                    comm->header_buffer[3] * pow(256, 0));
+  return GINT32_FROM_BE (*(guint32 *) comm->header_buffer);
 }
 
 // async callback for message read
 static void
-cc_comm_message_read_cb (GObject *source_object,
-                        GAsyncResult *res,
-                        gpointer user_data) 
+cc_comm_message_read_cb (GObject      *source_object,
+                         GAsyncResult *res,
+                         gpointer      user_data)
 {
-  CcComm * comm = (CcComm*) user_data;
+  CcComm * comm = (CcComm *) user_data;
+
   g_autoptr(GError) error = NULL;
   gboolean success;
   gsize io_bytes;
@@ -212,25 +213,25 @@ cc_comm_message_read_cb (GObject *source_object,
    * then just give up immediately with a CLOSED error.
    */
   if (comm->con &&
-    g_io_stream_get_input_stream (G_IO_STREAM (comm->con)) != G_INPUT_STREAM (source_object))
-  {
-    g_error ("CcComm: Error on old read connection, ignoring.");
-    cc_comm_listen (comm);
-    return;
-  }
+      g_io_stream_get_input_stream (G_IO_STREAM (comm->con)) != G_INPUT_STREAM (source_object))
+    {
+      g_error ("CcComm: Error on old read connection, ignoring.");
+      // cc_comm_listen (comm);
+      return;
+    }
 
   if (!success || io_bytes == 0)
-  {
-    if (error)
     {
-      g_error ("CcComm: Error reading message from stream: %s", error->message);
+      if (error)
+        {
+          g_error ("CcComm: Error reading message from stream: %s", error->message);
+          cc_comm_listen (comm);
+          return;
+        }
+      g_error ("CcComm: Error reading message from stream.");
       cc_comm_listen (comm);
       return;
     }
-    g_error ("CcComm: Error reading message from stream.");
-    cc_comm_listen (comm);
-    return;
-  }
 
   // dump the received message and try to parse it
   // cc_comm_dump_message (comm->message_buffer, io_bytes);
@@ -239,16 +240,17 @@ cc_comm_message_read_cb (GObject *source_object,
   g_clear_pointer (&comm->message_buffer, g_free);
 
   // go for another round
-  cc_comm_listen(comm);
+  cc_comm_listen (comm);
 }
 
 // async callback for header read
 static void
-cc_comm_header_read_cb (GObject *source_object,
+cc_comm_header_read_cb (GObject      *source_object,
                         GAsyncResult *res,
-                        gpointer user_data) 
+                        gpointer      user_data)
 {
-  CcComm * comm = (CcComm*) user_data;
+  CcComm * comm = (CcComm *) user_data;
+
   g_autoptr(GError) error = NULL;
   gboolean success;
   gsize io_bytes;
@@ -266,25 +268,25 @@ cc_comm_header_read_cb (GObject *source_object,
    * then just give up immediately with a CLOSED error.
    */
   if (comm->con &&
-    g_io_stream_get_input_stream (G_IO_STREAM (comm->con)) != G_INPUT_STREAM (source_object))
-  {
-    g_error ("CcComm: Error on old read connection, ignoring.");
-    cc_comm_listen (comm);
-    return;
-  }
+      g_io_stream_get_input_stream (G_IO_STREAM (comm->con)) != G_INPUT_STREAM (source_object))
+    {
+      g_error ("CcComm: Error on old read connection, ignoring.");
+      cc_comm_listen (comm);
+      return;
+    }
 
   if (!success || io_bytes != 4)
-  {
-    if (error)
     {
-      g_error ("CcComm: Error reading header from stream: %s", error->message);
+      if (error)
+        {
+          g_error ("CcComm: Error reading header from stream: %s", error->message);
+          cc_comm_listen (comm);
+          return;
+        }
+      g_error ("CcComm: Error reading header from stream.");
       cc_comm_listen (comm);
       return;
     }
-    g_error ("CcComm: Error reading header from stream.");
-    cc_comm_listen (comm);
-    return;
-  }
 
   // if everything is well, read all `io_bytes`
   g_debug ("CcComm: Raw header dump:");
@@ -309,21 +311,21 @@ cc_comm_read (CcComm *comm, gsize io_bytes, gboolean read_header)
   if (read_header)
     {
       g_input_stream_read_all_async (istream,
-                                    comm->header_buffer,
-                                    io_bytes,
-                                    G_PRIORITY_DEFAULT,
-                                    NULL,
-                                    cc_comm_header_read_cb,
-                                    comm);
+                                     comm->header_buffer,
+                                     io_bytes,
+                                     G_PRIORITY_DEFAULT,
+                                     comm->cancellable,
+                                     cc_comm_header_read_cb,
+                                     comm);
       return;
     }
   g_input_stream_read_all_async (istream,
-                                comm->message_buffer,
-                                io_bytes,
-                                G_PRIORITY_DEFAULT,
-                                NULL,
-                                cc_comm_message_read_cb,
-                                comm);
+                                 comm->message_buffer,
+                                 io_bytes,
+                                 G_PRIORITY_DEFAULT,
+                                 comm->cancellable,
+                                 cc_comm_message_read_cb,
+                                 comm);
 }
 
 // listen to all incoming messages from Chromecast
@@ -355,49 +357,49 @@ cc_comm_make_connection (CcComm *comm, gchar *remote_address, GError **error)
   socket_family = G_SOCKET_FAMILY_IPV4;
   socket = g_socket_new (socket_family, socket_type, G_SOCKET_PROTOCOL_DEFAULT, error);
   if (socket == NULL)
-  {
-    g_warning ("CcComm: Failed to create socket: %s", (*error)->message);
-    return FALSE;
-  }
+    {
+      g_warning ("CcComm: Failed to create socket: %s", (*error)->message);
+      return FALSE;
+    }
 
   // XXX
   // g_socket_set_timeout (socket, 10);
 
   connectable = g_network_address_parse (remote_address, 8009, error);
   if (connectable == NULL)
-  {
-    g_warning ("CcComm: Failed to create connectable: %s", (*error)->message);
-    return FALSE;
-  }
+    {
+      g_warning ("CcComm: Failed to create connectable: %s", (*error)->message);
+      return FALSE;
+    }
 
   enumerator = g_socket_connectable_enumerate (connectable);
   while (TRUE)
-  {
-    address = g_socket_address_enumerator_next (enumerator, NULL, error);
-    if (address == NULL)
     {
-      g_warning ("CcComm: Failed to create address: %s", (*error)->message);
-      return FALSE;
-    }
+      address = g_socket_address_enumerator_next (enumerator, comm->cancellable, error);
+      if (address == NULL)
+        {
+          g_warning ("CcComm: Failed to create address: %s", (*error)->message);
+          return FALSE;
+        }
 
-    if (g_socket_connect (socket, address, NULL, &err))
-      break;
+      if (g_socket_connect (socket, address, comm->cancellable, &err))
+        break;
 
-    // g_message ("Connection to %s failed: %s, trying next", socket_address_to_string (address), 
err->message);
-    g_clear_error (&err);
+      // g_message ("Connection to %s failed: %s, trying next", socket_address_to_string (address), 
err->message);
+      g_clear_error (&err);
 
-    g_object_unref (address);
-  }
+      g_object_unref (address);
+    }
   g_object_unref (enumerator);
 
   comm->con = G_IO_STREAM (g_socket_connection_factory_create_connection (socket));
 
   tls_conn = g_tls_client_connection_new (comm->con, connectable, error);
   if (tls_conn == NULL)
-  {
-    g_warning ("CcComm: Failed to create TLS connection: %s", (*error)->message);
-    return FALSE;
-  }
+    {
+      g_warning ("CcComm: Failed to create TLS connection: %s", (*error)->message);
+      return FALSE;
+    }
 
   g_signal_connect (tls_conn, "accept-certificate", G_CALLBACK (cc_comm_accept_certificate), NULL);
   g_object_unref (comm->con);
@@ -405,11 +407,11 @@ cc_comm_make_connection (CcComm *comm, gchar *remote_address, GError **error)
   comm->con = G_IO_STREAM (tls_conn);
 
   // see what should be done about cancellable
-  if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn), NULL, error))
-  {
-    g_warning ("CcComm: Failed to handshake: %s", (*error)->message);
-    return FALSE;
-  }
+  if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn), comm->cancellable, error))
+    {
+      g_warning ("CcComm: Failed to handshake: %s", (*error)->message);
+      return FALSE;
+    }
 
   g_debug ("CcComm: Connected to %s", remote_address);
 
@@ -420,10 +422,10 @@ cc_comm_make_connection (CcComm *comm, gchar *remote_address, GError **error)
 }
 
 static gboolean
-cc_comm_tls_send (CcComm        * comm,
-                  uint8_t       * message,
-                  gssize          size,
-                  GError        **error)
+cc_comm_tls_send (CcComm  * comm,
+                  uint8_t * message,
+                  gssize    size,
+                  GError  **error)
 {
   GOutputStream *ostream;
   gssize io_bytes;
@@ -442,53 +444,54 @@ cc_comm_tls_send (CcComm        * comm,
 
   // start sending data synchronously
   while (size > 0)
-  {
-    io_bytes = g_output_stream_write (ostream, message, size, NULL, error);
-
-    if (io_bytes <= 0)
     {
-      g_warning ("CcComm: Failed to write: %s", (*error)->message);
-      g_clear_error (error);
-      return FALSE;
-    }
+      io_bytes = g_output_stream_write (ostream, message, size, comm->cancellable, error);
 
-    g_debug ("CcComm: Sent %" G_GSSIZE_FORMAT " bytes", io_bytes);
+      if (io_bytes <= 0)
+        {
+          g_warning ("CcComm: Failed to write: %s", (*error)->message);
+          g_clear_error (error);
+          return FALSE;
+        }
+
+      // g_debug ("CcComm: Sent %" G_GSSIZE_FORMAT " bytes", io_bytes);
 
-    size -= io_bytes;
-  }
+      size -= io_bytes;
+    }
 
   return TRUE;
 }
 
 // builds message based on available types
 static Castchannel__CastMessage
-cc_comm_build_message (gchar *source_id,
-                       gchar *namespace_,
+cc_comm_build_message (gchar                                *namespace_,
                        Castchannel__CastMessage__PayloadType payload_type,
-                       ProtobufCBinaryData * binary_payload,
-                       gchar *utf8_payload)
+                       ProtobufCBinaryData                 * binary_payload,
+                       gchar                                *utf8_payload)
 {
   Castchannel__CastMessage message;
-  castchannel__cast_message__init(&message);
+
+  castchannel__cast_message__init (&message);
 
   message.protocol_version = CASTCHANNEL__CAST_MESSAGE__PROTOCOL_VERSION__CASTV2_1_0;
-  message.source_id = source_id;
+  message.source_id = "sender-gnd";
   message.destination_id = "receiver-0";
   message.namespace_ = namespace_;
   message.payload_type = payload_type;
 
   switch (payload_type)
-  {
-  case CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__BINARY:
-    message.payload_binary = *binary_payload;
-    message.has_payload_binary = 1;
-    break;
-  case CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING:
-  default:
-    message.payload_utf8 = utf8_payload;
-    message.has_payload_binary = 0;
-    break;
-  }
+    {
+    case CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__BINARY:
+      message.payload_binary = *binary_payload;
+      message.has_payload_binary = 1;
+      break;
+
+    case CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING:
+    default:
+      message.payload_utf8 = utf8_payload;
+      message.has_payload_binary = 0;
+      break;
+    }
 
   return message;
 }
@@ -501,97 +504,91 @@ cc_comm_send_request (CcComm * comm, enum MessageType message_type, char *utf8_p
   g_autofree uint8_t *sock_buffer = NULL;
 
   switch (message_type)
-  {
-  case MESSAGE_TYPE_AUTH:
-    ProtobufCBinaryData binary_payload;
-    binary_payload.data = NULL;
-    binary_payload.len = 0;
-
-    message = cc_comm_build_message(
-      comm->sender_id,
-      "urn:x-cast:com.google.cast.tp.deviceauth",
-      CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__BINARY,
-      &binary_payload,
-      NULL);
-    break;
-
-  case MESSAGE_TYPE_CONNECT:
-    message = cc_comm_build_message(
-      comm->sender_id,
-      "urn:x-cast:com.google.cast.tp.connection",
-      CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
-      NULL,
-      // "{ \"type\": \"CONNECT\" }");
-      "{ \"type\": \"CONNECT\", \"userAgent\": \"GND/0.90.5  (X11; Linux x86_64)\", \"connType\": 0, 
\"origin\": {}, \"senderInfo\": { \"sdkType\": 2, \"version\": \"X11; Linux x86_64\", \"browserVersion\": 
\"X11; Linux x86_64\", \"platform\": 6, \"connectionType\": 1 } }");
+    {
+    case MESSAGE_TYPE_AUTH:
+      ProtobufCBinaryData binary_payload;
+      binary_payload.data = NULL;
+      binary_payload.len = 0;
+
+      message = cc_comm_build_message (
+        "urn:x-cast:com.google.cast.tp.deviceauth",
+        CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__BINARY,
+        &binary_payload,
+        NULL);
+      break;
+
+    case MESSAGE_TYPE_CONNECT:
+      message = cc_comm_build_message (
+        "urn:x-cast:com.google.cast.tp.connection",
+        CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
+        NULL,
+        // "{ \"type\": \"CONNECT\" }");
+        "{ \"type\": \"CONNECT\", \"userAgent\": \"GND/0.90.5  (X11; Linux x86_64)\", \"connType\": 0, 
\"origin\": {}, \"senderInfo\": { \"sdkType\": 2, \"version\": \"X11; Linux x86_64\", \"browserVersion\": 
\"X11; Linux x86_64\", \"platform\": 6, \"connectionType\": 1 } }");
       message.destination_id = comm->destination_id;
-    break;
-
-  case MESSAGE_TYPE_DISCONNECT:
-    message = cc_comm_build_message(
-      comm->sender_id,
-      "urn:x-cast:com.google.cast.tp.connection",
-      CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
-      NULL,
-      "{ \"type\": \"CLOSE\" }");
-    break;
-
-  case MESSAGE_TYPE_PING:
-    message = cc_comm_build_message(
-      comm->sender_id,
-      "urn:x-cast:com.google.cast.tp.heartbeat",
-      CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
-      NULL,
-      "{ \"type\": \"PING\" }");
-    break;
-
-  case MESSAGE_TYPE_PONG:
-    message = cc_comm_build_message(
-      comm->sender_id,
-      "urn:x-cast:com.google.cast.tp.heartbeat",
-      CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
-      NULL,
-      "{ \"type\": \"PONG\" }");
-    break;
-
-  case MESSAGE_TYPE_RECEIVER:
-    message = cc_comm_build_message(
-      comm->sender_id,
-      "urn:x-cast:com.google.cast.receiver",
-      CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
-      NULL,
-      utf8_payload);
-    break;
-
-  case MESSAGE_TYPE_MEDIA:
-    message = cc_comm_build_message(
-      comm->sender_id,
-      "urn:x-cast:com.google.cast.media",
-      CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
-      NULL,
-      utf8_payload);
-    message.destination_id = comm->destination_id;
-    break;
-
-  default:
-    return FALSE;
-  }
+      break;
+
+    case MESSAGE_TYPE_DISCONNECT:
+      message = cc_comm_build_message (
+        "urn:x-cast:com.google.cast.tp.connection",
+        CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
+        NULL,
+        "{ \"type\": \"CLOSE\" }");
+      break;
 
-  packed_size = castchannel__cast_message__get_packed_size(&message);
-  sock_buffer = malloc(4 + packed_size);
+    case MESSAGE_TYPE_PING:
+      message = cc_comm_build_message (
+        "urn:x-cast:com.google.cast.tp.heartbeat",
+        CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
+        NULL,
+        "{ \"type\": \"PING\" }");
+      break;
+
+    case MESSAGE_TYPE_PONG:
+      message = cc_comm_build_message (
+        "urn:x-cast:com.google.cast.tp.heartbeat",
+        CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
+        NULL,
+        "{ \"type\": \"PONG\" }");
+      break;
 
-  guint32 packed_size_be = GUINT32_TO_BE(packed_size);
-  memcpy(sock_buffer, &packed_size_be, 4);
-  castchannel__cast_message__pack(&message, 4 + sock_buffer);
+    case MESSAGE_TYPE_RECEIVER:
+      message = cc_comm_build_message (
+        "urn:x-cast:com.google.cast.receiver",
+        CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
+        NULL,
+        utf8_payload);
+      break;
+
+    case MESSAGE_TYPE_MEDIA:
+      message = cc_comm_build_message (
+        "urn:x-cast:com.google.cast.media",
+        CASTCHANNEL__CAST_MESSAGE__PAYLOAD_TYPE__STRING,
+        NULL,
+        utf8_payload);
+      message.destination_id = comm->destination_id;
+      break;
+
+    default:
+      return FALSE;
+    }
+
+  packed_size = castchannel__cast_message__get_packed_size (&message);
+  sock_buffer = malloc (4 + packed_size);
+
+  guint32 packed_size_be = GUINT32_TO_BE (packed_size);
+
+  memcpy (sock_buffer, &packed_size_be, 4);
+  castchannel__cast_message__pack (&message, 4 + sock_buffer);
 
   if (message_type != MESSAGE_TYPE_PING && message_type != MESSAGE_TYPE_PONG)
-  {
-    g_debug ("CcComm: Sending message:");
-    cc_comm_dump_json_message (&message);
-  }
+    {
+      g_debug ("CcComm: Sending message:");
+      cc_comm_dump_json_message (&message);
+    }
 
   return cc_comm_tls_send (comm,
                            sock_buffer,
-                           packed_size+4,
+                           packed_size + 4,
                            error);
 }
 
@@ -601,16 +598,16 @@ cc_comm_send_ping (CcComm * comm)
   g_autoptr(GError) error = NULL;
 
   // if this errors out, we cancel the periodic ping by returning FALSE
-  if (!cc_comm_send_request(comm, MESSAGE_TYPE_PING, NULL, &error))
+  if (!cc_comm_send_request (comm, MESSAGE_TYPE_PING, NULL, &error))
     {
       if (error != NULL)
         {
           g_warning ("CcComm: Failed to send ping message: %s", error->message);
-          return FALSE;
+          return G_SOURCE_REMOVE;
         }
-        g_warning ("CcComm: Failed to send ping message");
-        return FALSE;
+      g_warning ("CcComm: Failed to send ping message");
+      return G_SOURCE_REMOVE;
     }
 
-  return TRUE;
+  return G_SOURCE_CONTINUE;
 }
diff --git a/src/cc/cc-comm.h b/src/cc/cc-comm.h
index d958469..fd82b89 100644
--- a/src/cc/cc-comm.h
+++ b/src/cc/cc-comm.h
@@ -28,13 +28,13 @@ G_BEGIN_DECLS
 struct _CcComm
 {
   /*< public >*/
-  GIOStream *con;
+  GIOStream    *con;
 
-  gchar     *sender_id;
-  gchar     *destination_id;
+  gchar        *destination_id;
+  guint8       *header_buffer;
+  guint8       *message_buffer;
 
-  guint8    *header_buffer;
-  guint8    *message_buffer;
+  GCancellable *cancellable;
 };
 
 typedef struct _CcComm CcComm;
@@ -49,8 +49,13 @@ enum MessageType {
   MESSAGE_TYPE_MEDIA,
 };
 
-gboolean cc_comm_make_connection (CcComm *comm, gchar *remote_address, GError **error);
-gboolean cc_comm_send_request (CcComm *sink, enum MessageType message_type, char *utf8_payload, GError 
**error);
+gboolean cc_comm_make_connection (CcComm  *comm,
+                                  gchar   *remote_address,
+                                  GError **error);
+gboolean cc_comm_send_request (CcComm          *sink,
+                               enum MessageType message_type,
+                               char            *utf8_payload,
+                               GError         **error);
 gboolean cc_comm_send_ping (CcComm *sink);
 
 G_END_DECLS
diff --git a/src/nd-cc-sink.c b/src/nd-cc-sink.c
index 2021b2c..49b7c91 100644
--- a/src/nd-cc-sink.c
+++ b/src/nd-cc-sink.c
@@ -29,25 +29,25 @@
 
 struct _NdCCSink
 {
-  GObject            parent_instance;
+  GObject        parent_instance;
 
-  NdSinkState        state;
+  NdSinkState    state;
 
-  GCancellable      *cancellable;
+  GCancellable  *cancellable;
 
-  GStrv              missing_video_codec;
-  GStrv              missing_audio_codec;
-  char              *missing_firewall_zone;
+  GStrv          missing_video_codec;
+  GStrv          missing_audio_codec;
+  char          *missing_firewall_zone;
 
-  gchar             *remote_address;
-  gchar             *remote_name;
+  gchar         *remote_address;
+  gchar         *remote_name;
 
-  GSocketClient     *comm_client;
-  CcComm             comm;
-  guint              ping_timeout_handle;
+  GSocketClient *comm_client;
+  CcComm         comm;
+  guint          ping_timeout_handle;
 
-  WfdServer         *server;
-  guint              server_source_id;
+  WfdServer     *server;
+  guint          server_source_id;
 };
 
 enum {
@@ -81,9 +81,9 @@ G_DEFINE_TYPE_EXTENDED (NdCCSink, nd_cc_sink, G_TYPE_OBJECT, 0,
 static GParamSpec * props[PROP_LAST] = { NULL, };
 
 static void
-nd_cc_sink_get_property (GObject *    object,
+nd_cc_sink_get_property (GObject    * object,
                          guint        prop_id,
-                         GValue *     value,
+                         GValue     * value,
                          GParamSpec * pspec)
 {
   NdCCSink *sink = ND_CC_SINK (object);
@@ -263,7 +263,7 @@ static void
 closed_cb (NdCCSink *sink, CCClient *client)
 {
   /* Connection was closed, do a clean shutdown */
-  cc_comm_send_request(&sink->comm, MESSAGE_TYPE_DISCONNECT, NULL, NULL);
+  cc_comm_send_request (&sink->comm, MESSAGE_TYPE_DISCONNECT, NULL, NULL);
 
   nd_cc_sink_sink_stop_stream (ND_SINK (sink));
 }
@@ -312,33 +312,19 @@ server_create_audio_source_cb (NdCCSink *sink, WfdServer *server)
   return res;
 }
 
-static gboolean
-nd_cc_sink_close_conn_cb (NdCCSink *sink)
-{
-  if (!cc_comm_send_request(&sink->comm, MESSAGE_TYPE_DISCONNECT, NULL, NULL))
-  {
-    g_warning ("NdCCSink: something went wrong with closing connection");
-  }
-  return FALSE;
-}
-
 static gboolean
 nd_cc_sink_launch_default_app_cb (NdCCSink *sink)
 {
-  if (!cc_comm_send_request(&sink->comm, MESSAGE_TYPE_RECEIVER, "{ \"type\": \"LAUNCH\", \"appId\": 
\"CC1AD845\", \"requestId\": 3 }", NULL))
-  {
+  if (!cc_comm_send_request (&sink->comm, MESSAGE_TYPE_RECEIVER, "{ \"type\": \"LAUNCH\", \"appId\": 
\"CC1AD845\", \"requestId\": 3 }", NULL))
     g_warning ("NdCCSink: something went wrong with default app launch");
-  }
   return FALSE;
 }
 
 static gboolean
 nd_cc_sink_get_status_cb (NdCCSink *sink)
 {
-  if (!cc_comm_send_request(&sink->comm, MESSAGE_TYPE_RECEIVER, "{ \"type\": \"GET_STATUS\", \"requestId\": 
2 }", NULL))
-  {
+  if (!cc_comm_send_request (&sink->comm, MESSAGE_TYPE_RECEIVER, "{ \"type\": \"GET_STATUS\", \"requestId\": 
2 }", NULL))
     g_warning ("NdCCSink: something went wrong with get status");
-  }
   return FALSE;
 }
 
@@ -346,6 +332,7 @@ static NdSink *
 nd_cc_sink_sink_start_stream (NdSink *sink)
 {
   NdCCSink *self = ND_CC_SINK (sink);
+
   g_autoptr(GError) error = NULL;
   // gchar six_digits[6];
 
@@ -361,11 +348,11 @@ nd_cc_sink_sink_start_stream (NdSink *sink)
 
   g_debug ("NdCCSink: Attempting connection to Chromecast: %s", self->remote_name);
 
-  self->comm.sender_id = g_strdup ("sender-gnd");
-  self->comm.destination_id = g_strdup ("receiver-0");
+  self->comm.destination_id = "receiver-0";
+  self->comm.cancellable = self->cancellable;
 
   // open a TLS connection to the CC device
-  if (!cc_comm_make_connection(&self->comm, self->remote_address, &error))
+  if (!cc_comm_make_connection (&self->comm, self->remote_address, &error))
     {
       self->state = ND_SINK_STATE_ERROR;
       g_object_notify (G_OBJECT (self), "state");
@@ -375,7 +362,7 @@ nd_cc_sink_sink_start_stream (NdSink *sink)
     }
 
   // authenticate with the CC device
-  if (!cc_comm_send_request(&self->comm, MESSAGE_TYPE_AUTH, NULL, NULL))
+  if (!cc_comm_send_request (&self->comm, MESSAGE_TYPE_AUTH, NULL, NULL))
     {
       self->state = ND_SINK_STATE_ERROR;
       g_object_notify (G_OBJECT (self), "state");
@@ -385,7 +372,7 @@ nd_cc_sink_sink_start_stream (NdSink *sink)
     }
 
   // open up a virtual connection to the device
-  if (!cc_comm_send_request(&self->comm, MESSAGE_TYPE_CONNECT, NULL, NULL))
+  if (!cc_comm_send_request (&self->comm, MESSAGE_TYPE_CONNECT, NULL, NULL))
     {
       self->state = ND_SINK_STATE_ERROR;
       g_object_notify (G_OBJECT (self), "state");
@@ -394,27 +381,18 @@ nd_cc_sink_sink_start_stream (NdSink *sink)
       return NULL;
     }
 
-  // sprintf (six_digits, "%ld", time (NULL) % 1000000);
-  // self->comm.sender_id = "sender-";
-  // strncat (self->comm.sender_id, six_digits, 6);
-
-  // set sender_id after connection (sender-xxxxxx)
-
   // send pings to device every 5 seconds
-  self->ping_timeout_handle = g_timeout_add_seconds(5, G_SOURCE_FUNC (cc_comm_send_ping), &self->comm);
+  self->ping_timeout_handle = g_timeout_add_seconds (5, G_SOURCE_FUNC (cc_comm_send_ping), &self->comm);
 
   // send req to get status
-  g_debug("NdCCSink: Get Status");
+  g_debug ("NdCCSink: Get Status");
   g_timeout_add_seconds (2, G_SOURCE_FUNC (nd_cc_sink_get_status_cb), self);
 
-  g_debug("NdCCSink: Launching Default Media App");
+  g_debug ("NdCCSink: Launching Default Media App");
   g_timeout_add_seconds (6, G_SOURCE_FUNC (nd_cc_sink_launch_default_app_cb), self);
 
-  g_debug("NdCCSink: Closing Connection");
-  g_timeout_add_seconds (60, G_SOURCE_FUNC (nd_cc_sink_close_conn_cb), self);
-
-  // g_debug ("NdCCSink: Mute the Chromecast");
-  // cc_comm_send_request(&self->comm, MESSAGE_TYPE_RECEIVER, "{ \"type\": \"SET_VOLUME\", \"volume\": { 
\"muted\": true } }", NULL);
+  self->state = ND_SINK_STATE_STREAMING;
+  g_object_notify (G_OBJECT (self), "state");
 
   self->server = wfd_server_new ();
   self->server_source_id = gst_rtsp_server_attach (GST_RTSP_SERVER (self->server), NULL);
@@ -446,8 +424,8 @@ nd_cc_sink_sink_start_stream (NdSink *sink)
                            self,
                            G_CONNECT_SWAPPED);
 
-  self->state = ND_SINK_STATE_WAIT_SOCKET;
-  g_object_notify (G_OBJECT (self), "state");
+  // self->state = ND_SINK_STATE_WAIT_SOCKET;
+  // g_object_notify (G_OBJECT (self), "state");
 
   // these were originally here
   // 1. send connect request
@@ -459,27 +437,53 @@ nd_cc_sink_sink_start_stream (NdSink *sink)
 static void
 nd_cc_sink_sink_stop_stream_int (NdCCSink *self)
 {
-  g_autoptr(GError) error;
+  g_autoptr(GError) error = NULL;
   gboolean close_ok;
 
+  // Close the app before closing the connection
+  // hack to know if the app is already up
+  if (g_strcmp0 (self->comm.destination_id, "receiver-0") != 0)
+    {
+      g_autoptr(GString) close_app_message = NULL;
+      close_app_message = g_string_new ("{ \"type\": \"STOP\", \"requestId\": 5, \"sessionId\": \"");
+      g_string_append (close_app_message, self->comm.destination_id);
+      g_string_append (close_app_message, "\" }");
+
+      if (!cc_comm_send_request (&self->comm, MESSAGE_TYPE_RECEIVER, close_app_message->str, &error))
+        {
+          if (error != NULL)
+            g_warning ("NdCCSink: Error closing the cast app: %s", error->message);
+          else
+            g_warning ("NdCCSink: Error closing the cast app");
+        }
+
+      g_clear_error (&error);
+      g_clear_pointer (&self->comm.destination_id, g_free);
+      self->comm.destination_id = g_strdup ("receiver-0");
+    }
+
+  if (!cc_comm_send_request (&self->comm, MESSAGE_TYPE_DISCONNECT, NULL, NULL))
+    g_warning ("NdCCSink: Error closing virtual connection");
+
   g_cancellable_cancel (self->cancellable);
   g_clear_object (&self->cancellable);
 
   self->cancellable = g_cancellable_new ();
 
+  // cancel ping timeout
+  g_clear_handle_id (&self->ping_timeout_handle, g_source_remove);
+
   /* Close the client connection
-   * FIX: this does not close the connection
    * TODO: This should be moved into cc-comm.c */
   if (self->comm.con != NULL)
     {
       close_ok = g_io_stream_close (G_IO_STREAM (self->comm.con), NULL, &error);
-      if (error != NULL)
-        {
-          g_warning ("NdCCSink: Error closing communication client connection: %s", error->message);
-        }
       if (!close_ok)
         {
-          g_warning ("NdCCSink: Communication client connection not closed");
+          if (error != NULL)
+            g_warning ("NdCCSink: Error closing communication client connection: %s", error->message);
+          else
+            g_warning ("NdCCSink: Communication client connection not closed");
         }
 
       g_clear_object (&self->comm.con);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]