[gnome-network-displays/cc-tmp: 26/80] cc: json functions
- From: Benjamin Berg <bberg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-network-displays/cc-tmp: 26/80] cc: json functions
- Date: Fri, 9 Sep 2022 12:03:50 +0000 (UTC)
commit 4c5bf6e5c01e08281953f2445fbb3f3106ad9176
Author: Anupam Kumar <kyteinsky gmail com>
Date: Wed Aug 31 13:16:06 2022 +0530
cc: json functions
src/cc/cc-comm.c | 15 +--
src/cc/cc-common.h | 53 ++++++++
src/cc/cc-ctrl.c | 342 ++++++++++++++++++++++++++++++++++++++----------
src/cc/cc-ctrl.h | 3 +-
src/cc/cc-json-helper.c | 342 +++++++++++++++++++++++++-----------------------
src/cc/cc-json-helper.h | 11 +-
src/nd-cc-sink.c | 7 +-
7 files changed, 524 insertions(+), 249 deletions(-)
---
diff --git a/src/cc/cc-comm.c b/src/cc/cc-comm.c
index 65a5b3e..0e3b9e2 100644
--- a/src/cc/cc-comm.c
+++ b/src/cc/cc-comm.c
@@ -144,15 +144,6 @@ cc_comm_parse_received_data (CcComm *comm, uint8_t * input_buffer, gssize input_
// go for another round while we process this one
cc_comm_listen (comm);
- CcReceivedMessageType type = cc_json_helper_get_message_type (message, NULL);
-
- if (type == CC_RWAIT_TYPE_PING || type == CC_RWAIT_TYPE_PONG || type == -1)
- return;
-
- g_debug ("CcComm: Received message:");
- cc_json_helper_dump_message (message);
-
- // actual message handling
comm->closure->message_received_cb (comm->closure, message);
cast__channel__cast_message__free_unpacked (message, NULL);
@@ -595,10 +586,12 @@ cc_comm_send_request (CcComm *comm,
memcpy (sock_buffer, &packed_size_be, 4);
cast__channel__cast_message__pack (&message, 4 + sock_buffer);
- if (message_type != CC_MESSAGE_TYPE_PING && message_type != CC_MESSAGE_TYPE_PONG)
+ if (message_type != CC_MESSAGE_TYPE_PING
+ && message_type != CC_MESSAGE_TYPE_PONG
+ && message_type != CC_MESSAGE_TYPE_AUTH)
{
g_debug ("CcComm: Sending message:");
- cc_json_helper_dump_message (&message);
+ cc_json_helper_dump_message (&message, FALSE);
}
return cc_comm_tls_send (comm,
diff --git a/src/cc/cc-common.h b/src/cc/cc-common.h
index 2a68fe9..f49cabc 100644
--- a/src/cc/cc-common.h
+++ b/src/cc/cc-common.h
@@ -61,4 +61,57 @@ typedef enum {
typedef CcReceivedMessageType CcWaitingFor;
+typedef struct _Stream {
+ gint index;
+
+ // Default channel count is 1, e.g. for video.
+ gint channels;
+ gint rtp_payload_type;
+ gint ssrc;
+ gint target_delay;
+
+ // AES Key and IV mask format is very strict: a 32 digit hex string that
+ // must be converted to a 16 digit byte array.
+ // uint8_t aes_key[16];
+ // uint8_t aes_iv_mask[16];
+ gchar *aes_iv_mask;
+ gchar *aes_key;
+ gboolean receiver_rtcp_event_log;
+ gchar *receiver_rtcp_dscp;
+ // gint rtp_timebase;
+ gchar *rtp_timebase;
+
+ // The codec parameter field honors the format laid out in RFC 6381:
+ // https://datatracker.ietf.org/doc/html/rfc6381.
+ gchar *codec_parameter;
+} Stream;
+
+typedef struct _AudioStream {
+ Stream stream;
+ gchar *codec;
+ gint bit_rate;
+ gint sample_rate;
+ gchar *profile;
+} AudioStream;
+
+typedef struct _VideoStream {
+ Stream stream;
+ gchar *codec;
+ gchar *max_frame_rate;
+ gint max_bit_rate;
+ gchar *protection;
+ gchar *profile;
+ gchar *level;
+ gint **resolutions;
+ gchar *error_recovery_mode;
+} VideoStream;
+
+typedef struct _Offer {
+ gchar *cast_mode;
+ guint seq_num;
+ gboolean receiver_get_status;
+ AudioStream audio_stream;
+ VideoStream video_stream;
+} Offer;
+
G_END_DECLS
diff --git a/src/cc/cc-ctrl.c b/src/cc/cc-ctrl.c
index 229c1b7..7b14193 100644
--- a/src/cc/cc-ctrl.c
+++ b/src/cc/cc-ctrl.c
@@ -19,6 +19,26 @@
#include "cc-ctrl.h"
#include "cc-comm.h"
+// WAITING FOR
+
+static void
+cc_ctrl_set_waiting_for (CcCtrl *ctrl, CcWaitingFor waiting_for)
+{
+ ctrl->waiting_for |= waiting_for;
+}
+
+static void
+cc_ctrl_unset_waiting_for (CcCtrl *ctrl, CcWaitingFor waiting_for)
+{
+ ctrl->waiting_for &= ~waiting_for;
+}
+
+static gboolean
+cc_ctrl_is_waiting_for (CcCtrl *ctrl, CcWaitingFor waiting_for)
+{
+ return (ctrl->waiting_for & waiting_for) > CC_RWAIT_TYPE_NONE;
+}
+
// SEND HELPER FUNCTIONS
static gboolean
@@ -38,10 +58,30 @@ cc_ctrl_send_connect (CcCtrl *ctrl, gchar *destination_id, GError **error)
{
g_debug ("CcCtrl: Sending CONNECT");
+ JsonNode *senderInfo;
+ JsonNode *origin;
+ cc_json_helper_build_node (&origin, NULL);
+ cc_json_helper_build_node (&senderInfo,
+ "sdkType", CC_JSON_TYPE_INT, 2,
+ "version", CC_JSON_TYPE_STRING, "X11; Linux x86_64",
+ "browserVersion", CC_JSON_TYPE_STRING, "X11; Linux x86_64",
+ "platform", CC_JSON_TYPE_INT, 6,
+ "connectionType", CC_JSON_TYPE_INT, 1,
+ NULL);
+
+ gchar *json;
+ cc_json_helper_build_string (&json,
+ "type", CC_JSON_TYPE_STRING, "CONNECT",
+ "userAgent", CC_JSON_TYPE_STRING, "GND/0.90.5 (X11; Linux x86_64)",
+ "connType", CC_JSON_TYPE_INT, 0,
+ "origin", CC_JSON_TYPE_OBJECT, origin,
+ "senderInfo", CC_JSON_TYPE_OBJECT, senderInfo,
+ NULL);
+
return cc_comm_send_request (&ctrl->comm,
destination_id,
CC_MESSAGE_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 } }",
+ json,
error);
}
@@ -50,10 +90,15 @@ cc_ctrl_send_disconnect (CcCtrl *ctrl, gchar *destination_id, GError **error)
{
g_debug ("CcCtrl: Sending CLOSE");
+ gchar *json;
+ cc_json_helper_build_string (&json,
+ "type", CC_JSON_TYPE_STRING, "CLOSE",
+ NULL);
+
return cc_comm_send_request (&ctrl->comm,
destination_id,
CC_MESSAGE_TYPE_DISCONNECT,
- "{ \"type\": \"CLOSE\" }",
+ json,
error);
}
@@ -62,13 +107,21 @@ cc_ctrl_send_get_status (CcCtrl *ctrl, gchar *destination_id, GError **error)
{
g_debug ("CcCtrl: Sending GET_STATUS");
- g_autoptr (GString) json = g_string_new ("{ \"type\": \"GET_STATUS\", ");
- g_string_append_printf (json, "\"requestId\": %d }", ctrl->request_id++);
- return cc_comm_send_request (&ctrl->comm,
+ gchar *json;
+ cc_json_helper_build_string (&json,
+ "type", CC_JSON_TYPE_STRING, "GET_STATUS",
+ "requestId", CC_JSON_TYPE_INT, ctrl->request_id++,
+ NULL);
+
+ gboolean send_ok = cc_comm_send_request (&ctrl->comm,
destination_id,
CC_MESSAGE_TYPE_RECEIVER,
- json->str,
+ json,
error);
+ if (send_ok)
+ cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_RECEIVER_STATUS);
+
+ return send_ok;
}
static gboolean
@@ -76,13 +129,25 @@ cc_ctrl_send_get_app_availability (CcCtrl *ctrl, gchar *destination_id, gchar *a
{
g_debug ("CcCtrl: Sending GET_APP_AVAILABILITY");
- g_autoptr (GString) json = g_string_new ("{ \"type\": \"GET_APP_AVAILABILITY\", ");
- g_string_append_printf (json, "\"appId\": [\"%s\"], \"requestId\": %d }", appId, ctrl->request_id++);
- return cc_comm_send_request (&ctrl->comm,
+ g_autoptr (GArray) appIds = g_array_new (FALSE, FALSE, sizeof (gchar *));
+ g_array_append_val (appIds, CC_MIRRORING_APP_ID);
+
+ gchar *json;
+ cc_json_helper_build_string (&json,
+ "type", CC_JSON_TYPE_STRING, "GET_APP_AVAILABILITY",
+ "appId", CC_JSON_TYPE_ARRAY_STRING, appIds,
+ "requestId", CC_JSON_TYPE_INT, ctrl->request_id++,
+ NULL);
+
+ gboolean send_ok = cc_comm_send_request (&ctrl->comm,
destination_id,
CC_MESSAGE_TYPE_RECEIVER,
- json->str,
+ json,
error);
+
+ if (send_ok)
+ cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_GET_APP_AVAILABILITY);
+ return send_ok;
}
static gboolean
@@ -90,13 +155,23 @@ cc_ctrl_send_launch_app (CcCtrl *ctrl, gchar *destination_id, gchar *appId, GErr
{
g_debug ("CcCtrl: Sending LAUNCH");
- g_autoptr (GString) json = g_string_new ("{ \"type\": \"LAUNCH\", \"language\": \"en-US\", ");
- g_string_append_printf (json, "\"appId\": \"%s\", \"requestId\": %d }", appId, ctrl->request_id++);
- return cc_comm_send_request (&ctrl->comm,
+ gchar *json;
+ cc_json_helper_build_string (&json,
+ "type", CC_JSON_TYPE_STRING, "LAUNCH",
+ "launguage", CC_JSON_TYPE_STRING, "en-US",
+ "appId", CC_JSON_TYPE_STRING, appId,
+ "requestId", CC_JSON_TYPE_INT, ctrl->request_id++,
+ NULL);
+
+ gboolean send_ok = cc_comm_send_request (&ctrl->comm,
destination_id,
CC_MESSAGE_TYPE_RECEIVER,
- json->str,
+ json,
error);
+
+ if (send_ok)
+ cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_RECEIVER_STATUS);
+ return send_ok;
}
static gboolean
@@ -104,46 +179,127 @@ cc_ctrl_send_close_app (CcCtrl *ctrl, gchar *sessionId, GError **error)
{
g_debug ("CcCtrl: Sending STOP");
- g_autoptr (GString) json = g_string_new ("{ \"type\": \"STOP\", ");
- g_string_append_printf (json, "\"sessionId\": \"%s\", \"requestId\": %d }", sessionId, ctrl->request_id++);
- return cc_comm_send_request (&ctrl->comm,
+ gchar *json;
+ cc_json_helper_build_string (&json,
+ "type", CC_JSON_TYPE_STRING, "STOP",
+ "sessionId", CC_JSON_TYPE_STRING, sessionId,
+ "requestId", CC_JSON_TYPE_INT, ctrl->request_id++,
+ NULL);
+
+ gboolean send_ok = cc_comm_send_request (&ctrl->comm,
sessionId,
CC_MESSAGE_TYPE_RECEIVER,
- json->str,
+ json,
error);
-}
-
-static gboolean
-cc_ctrl_send_offer (CcCtrl *ctrl, gchar *destination_id, GError **error)
-{
- g_debug ("CcCtrl: Sending OFFER");
- /* look into [ adaptive_playout_delay, rtpExtensions, rtpPayloadType, rtpProfile, aes stuff, ssrc
increment in received msg ] */
- return cc_comm_send_request (&ctrl->comm,
- destination_id,
- CC_MESSAGE_TYPE_WEBRTC,
- "{ \"offer\": { \"castMode\": \"mirroring\", \"receiverGetStatus\": true,
\"supportedStreams\": [ { \"aesIvMask\": \"1D20EA1C710E5598ECF80FB26ABC57B0\", \"aesKey\":
\"BB0CAE24F76EA1CAC9A383CFB1CFD54E\", \"bitRate\": 102000, \"channels\": 2, \"codecName\": \"aac\",
\"index\": 0, \"receiverRtcpEventLog\": true, \"rtpExtensions\": \"adaptive_playout_delay\",
\"rtpPayloadType\": 127, \"rtpProfile\": \"cast\", \"sampleRate\": 48000, \"ssrc\": 144842, \"targetDelay\":
400, \"timeBase\": \"1/48000\", \"type\": \"audio_source\" }, { \"aesIvMask\":
\"1D20EA1C710E5598ECF80FB26ABC57B0\", \"aesKey\": \"BB0CAE24F76EA1CAC9A383CFB1CFD54E\", \"codecName\":
\"h264\", \"index\": 1, \"maxBitRate\": 5000000, \"maxFrameRate\": \"30000/1000\", \"receiverRtcpEventLog\":
true, \"renderMode\": \"video\", \"resolutions\": [{ \"height\": 1080, \"width\": 1920 }], \"rtpExtensions\":
\"adaptive_playout_delay\", \"rtpPayloadType\": 96, \"rtpProfile\": \"cast\", \"ssrc\": 545579, \"
targetDelay\": 400, \"timeBase\": \"1/90000\", \"type\": \"video_source\" } ] }, \"seqNum\": 730137397,
\"type\": \"OFFER\" }",
- error);
+ if (send_ok)
+ cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_RECEIVER_STATUS);
+ return send_ok;
}
-// WAITING FOR
+// OFFER MESSAGE
-static void
-cc_ctrl_set_waiting_for (CcCtrl *ctrl, CcWaitingFor waiting_for)
+JsonNode *
+build_audio_source (AudioStream *audio_stream)
{
- ctrl->waiting_for |= waiting_for;
+ JsonNode *node;
+
+ cc_json_helper_build_node (&node,
+ "aesIvMask", CC_JSON_TYPE_STRING, audio_stream->stream.aes_iv_mask,
+ "aesKey", CC_JSON_TYPE_STRING, audio_stream->stream.aes_key,
+ "bitRate", CC_JSON_TYPE_INT, audio_stream->bit_rate,
+ "codecName", CC_JSON_TYPE_STRING, audio_stream->codec,
+ "index", CC_JSON_TYPE_INT, audio_stream->stream.index,
+ "receiverRtcpEventLog", CC_JSON_TYPE_BOOLEAN, audio_stream->stream.receiver_rtcp_event_log,
+ "rtpExtensions", CC_JSON_TYPE_STRING, "adaptive_playout_delay",
+ "rtpPayloadType", CC_JSON_TYPE_INT, audio_stream->stream.rtp_payload_type,
+ "rtpProfile", CC_JSON_TYPE_STRING, audio_stream->profile,
+ "sampleRate", CC_JSON_TYPE_INT, audio_stream->sample_rate,
+ "ssrc", CC_JSON_TYPE_INT, audio_stream->stream.ssrc,
+ "targetDelay", CC_JSON_TYPE_INT, audio_stream->stream.target_delay,
+ "timeBase", CC_JSON_TYPE_STRING, audio_stream->stream.rtp_timebase,
+ "type", CC_JSON_TYPE_STRING, "audio_source",
+ NULL);
+
+ return g_steal_pointer (&node);
}
-static void
-cc_ctrl_unset_waiting_for (CcCtrl *ctrl, CcWaitingFor waiting_for)
+JsonNode *
+build_video_source (VideoStream *video_stream)
{
- ctrl->waiting_for &= ~waiting_for;
+ JsonNode *node;
+ JsonNode *resolution;
+ g_autoptr (GArray) resolutions = g_array_new (FALSE, FALSE, sizeof (JsonNode *));
+
+ cc_json_helper_build_node (&resolution,
+ "height", CC_JSON_TYPE_INT, 1080,
+ "width", CC_JSON_TYPE_INT, 1920,
+ NULL);
+ g_array_append_val (resolutions, resolution);
+
+ cc_json_helper_build_node (&node,
+ "aesIvMask", CC_JSON_TYPE_STRING, video_stream->stream.aes_iv_mask,
+ "aesKey", CC_JSON_TYPE_STRING, video_stream->stream.aes_key,
+ "codecName", CC_JSON_TYPE_STRING, video_stream->codec,
+ "index", CC_JSON_TYPE_INT, video_stream->stream.index,
+ "maxBitRate", CC_JSON_TYPE_INT, video_stream->max_bit_rate,
+ "maxFrameRate", CC_JSON_TYPE_STRING, video_stream->max_frame_rate,
+ "receiverRtcpEventLog", CC_JSON_TYPE_BOOLEAN, video_stream->stream.receiver_rtcp_event_log,
+ "renderMode", CC_JSON_TYPE_STRING, "video",
+ "resolutions", CC_JSON_TYPE_ARRAY_OBJECT, resolutions,
+ "rtpExtensions", CC_JSON_TYPE_STRING, "adaptive_playout_delay",
+ "rtpPayloadType", CC_JSON_TYPE_INT, video_stream->stream.rtp_payload_type,
+ "rtpProfile", CC_JSON_TYPE_STRING, video_stream->profile,
+ "ssrc", CC_JSON_TYPE_INT, video_stream->stream.ssrc,
+ "targetDelay", CC_JSON_TYPE_INT, video_stream->stream.target_delay,
+ "timeBase", CC_JSON_TYPE_STRING, video_stream->stream.rtp_timebase,
+ "type", CC_JSON_TYPE_STRING, "video_source",
+ NULL);
+
+ return g_steal_pointer (&node);
}
static gboolean
-cc_ctrl_is_waiting_for (CcCtrl *ctrl, CcWaitingFor waiting_for)
+cc_ctrl_send_offer (CcCtrl *ctrl, gchar *destination_id, GError **error)
{
- return (ctrl->waiting_for & waiting_for) > CC_RWAIT_TYPE_NONE;
+ g_debug ("CcCtrl: Sending OFFER");
+
+ /* look into [ adaptive_playout_delay, rtpExtensions, rtpPayloadType, rtpProfile, aes stuff, ssrc
increment in received msg ] */
+
+ Offer *offer = ctrl->closure->get_offer_message (ctrl->closure);
+ JsonNode *audio_source_node = build_audio_source (&offer->audio_stream);
+ JsonNode *video_source_node = build_video_source (&offer->video_stream);
+
+ g_autoptr (GArray) streams = g_array_new (FALSE, FALSE, sizeof (JsonNode *));
+ g_array_append_val (streams, audio_source_node);
+ g_array_append_val (streams, video_source_node);
+
+ JsonNode *offer_key;
+ cc_json_helper_build_node (&offer_key,
+ "castMode", CC_JSON_TYPE_STRING, offer->cast_mode,
+ "receiverGetStatus", CC_JSON_TYPE_BOOLEAN, offer->receiver_get_status,
+ "supportedStreams", CC_JSON_TYPE_ARRAY_OBJECT, streams,
+ NULL);
+
+ JsonNode *root;
+ cc_json_helper_build_node (&root,
+ "offer", CC_JSON_TYPE_OBJECT, offer_key,
+ "seqNum", CC_JSON_TYPE_INT, offer->seq_num,
+ "type", CC_JSON_TYPE_STRING, "OFFER",
+ NULL);
+
+ gchar *json;
+ cc_json_helper_node_to_string (&json, root);
+
+ gboolean send_ok = cc_comm_send_request (&ctrl->comm,
+ destination_id,
+ CC_MESSAGE_TYPE_WEBRTC,
+ json,
+ error);
+
+ if (send_ok)
+ cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_ANSWER);
+ return send_ok;
}
// INTERVAL FUNCTIONS
@@ -189,12 +345,12 @@ cc_ctrl_send_ping (CcCtrl *ctrl)
}
static gboolean
-cc_ctrl_send_gaa_cb (CcCtrl *ctrl)
+cc_ctrl_send_offer_cb (CcCtrl *ctrl)
{
g_autoptr (GError) error = NULL;
- if (!cc_ctrl_send_get_app_availability (ctrl, CC_DEFAULT_RECEIVER_ID, CC_MIRRORING_APP_ID, &error))
- g_warning ("CcCtrl: Failed to send GET_APP_AVAILABILITY to the mirroring app: %s", error->message);
- return FALSE;
+ if (!cc_ctrl_send_offer (ctrl, ctrl->session_id, &error))
+ g_warning ("CcCtrl: Failed to send OFFER to the mirroring app: %s", error->message);
+ return G_SOURCE_REMOVE;
}
static void
@@ -206,23 +362,36 @@ cc_ctrl_mirroring_app_init (CcCtrl *ctrl, GError **error)
return;
}
- // send get_app_availability message after 2 seconds
- g_timeout_add_seconds (2, G_SOURCE_FUNC (cc_ctrl_send_gaa_cb), ctrl);
+ // send offer message after 1 second
+ g_timeout_add_seconds (1, G_SOURCE_FUNC (cc_ctrl_send_offer_cb), ctrl);
}
// HANDLE MESSAGE
-// should be status received callback
static void
cc_ctrl_handle_get_app_availability (CcCtrl *ctrl, JsonReader *reader)
{
g_autoptr (GError) error = NULL;
- // TODO: reader
- if (!cc_ctrl_send_offer (ctrl, ctrl->session_id, &error))
+ if (json_reader_read_member (reader, "availability"))
{
- g_warning ("CcCtrl: Failed to send offer: %s", error->message);
- return;
+ if (json_reader_read_member (reader, CC_MIRRORING_APP_ID))
+ {
+ const gchar *available = json_reader_get_string_value (reader);
+ if (g_strcmp0 (available, "APP_AVAILABLE"))
+ {
+ // launch the app now
+ if (!cc_ctrl_send_launch_app (ctrl, CC_DEFAULT_RECEIVER_ID, CC_MIRRORING_APP_ID, &error))
+ {
+ g_warning ("CcCtrl: Failed to launch the app: %s", error->message);
+ return;
+ }
+ }
+
+ // since the app is not available, stop attempts
+ g_warning ("CcCtrl: %s app is not available, quiting", CC_MIRRORING_APP_ID);
+ ctrl->closure->end_stream (ctrl->closure);
+ }
}
}
@@ -231,8 +400,8 @@ static void
cc_ctrl_handle_receiver_status (CcCtrl *ctrl, JsonParser *parser)
{
// reports all the open apps (the relevant stuff)
- // if the app is open, it has a sessionId: hijack the session
- // connect to it, send a stop, and then propose an offer
+ // if the app is open, it has a sessionId: opened by this app or not, it is hijackable
+ // connect to it, and then propose an offer
g_autoptr (GError) error = NULL;
g_autoptr (JsonNode) app_status = NULL;
@@ -260,7 +429,6 @@ cc_ctrl_handle_receiver_status (CcCtrl *ctrl, JsonParser *parser)
return;
}
- cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_RECEIVER_STATUS);
ctrl->state = CC_CTRL_STATE_LAUNCH_SENT;
return;
}
@@ -284,30 +452,56 @@ cc_ctrl_handle_receiver_status (CcCtrl *ctrl, JsonParser *parser)
if (g_strcmp0 (appId, CC_MIRRORING_APP_ID) == 0)
{
// takeover the session, doesn't matter which sender opened it
- g_debug ("CcCtrl: Mirroring app is open,");
+ g_debug ("CcCtrl: Mirroring app is open");
ctrl->state = CC_CTRL_STATE_APP_OPEN;
- /* is this freed automatically? */
+ g_clear_pointer (&ctrl->session_id, g_free);
ctrl->session_id = g_strdup (sessionId);
cc_ctrl_mirroring_app_init (ctrl, &error);
- cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_GET_APP_AVAILABILITY);
-
return;
}
- if (!cc_ctrl_send_launch_app (ctrl, CC_DEFAULT_RECEIVER_ID, CC_MIRRORING_APP_ID, &error))
+ // some other app is open, check if `CC_MIRRORING_APP_ID` is available
+ if (!cc_ctrl_send_get_app_availability (ctrl, CC_MIRRORING_APP_ID, CC_DEFAULT_RECEIVER_ID,
&error))
{
- g_warning ("CcCtrl: Failed to launch the app: %s", error->message);
+ g_warning ("CcCtrl: Failed to send GET_APP_AVAILABILITY: %s", error->message);
return;
}
-
- cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_RECEIVER_STATUS);
- ctrl->state = CC_CTRL_STATE_LAUNCH_SENT;
}
}
}
}
+static void
+cc_ctrl_handle_media_status (CcCtrl *ctrl, Cast__Channel__CastMessage *message, JsonReader *reader)
+{
+ // since answer and media_status are received one after another, we discard this
+ // for the mirroring app
+ // and since this stream is LIVE, we won't need any of it
+ // if (g_strcmp0 (message->source_id, ctrl->session_id))
+ // return;
+}
+
+static void
+cc_ctrl_handle_close (CcCtrl *ctrl, Cast__Channel__CastMessage *message)
+{
+ g_autoptr (GError) error = NULL;
+
+ if (g_strcmp0 (message->source_id, CC_DEFAULT_RECEIVER_ID) == 0)
+ {
+ g_warning ("CcCtrl: Receiver closed the connection");
+ ctrl->closure->end_stream (ctrl->closure);
+ return;
+ }
+
+ // the app closed
+ g_debug ("CcCtrl: App sent a close message, launching again");
+ if (!cc_ctrl_send_launch_app (ctrl, CC_DEFAULT_RECEIVER_ID, CC_MIRRORING_APP_ID, &error))
+ {
+ g_warning ("CcCtrl: Failed to launch app");
+ }
+}
+
void
cc_ctrl_handle_received_msg (CcCommClosure *closure,
Cast__Channel__CastMessage *message)
@@ -320,8 +514,8 @@ cc_ctrl_handle_received_msg (CcCommClosure *closure,
parser = json_parser_new ();
if (!json_parser_load_from_data (parser, message->payload_utf8, -1, &error))
{
- cc_json_helper_dump_message (message);
g_warning ("CcCtrl: Error parsing received messaage JSON: %s", error->message);
+ cc_json_helper_dump_message (message, TRUE);
return;
}
@@ -329,6 +523,12 @@ cc_ctrl_handle_received_msg (CcCommClosure *closure,
CcReceivedMessageType type = cc_json_helper_get_message_type (message, reader);
+ if (!(type == CC_RWAIT_TYPE_PING || type == CC_RWAIT_TYPE_PONG || type == -1))
+ {
+ g_debug ("CcComm: Received message:");
+ cc_json_helper_dump_message (message, FALSE);
+ }
+
switch (type)
{
case CC_RWAIT_TYPE_RECEIVER_STATUS:
@@ -340,7 +540,8 @@ cc_ctrl_handle_received_msg (CcCommClosure *closure,
cc_ctrl_handle_get_app_availability (ctrl, reader);
break;
case CC_RWAIT_TYPE_LAUNCH_ERROR:
- // cc_ctrl_handle_launch_error (ctrl, reader);
+ g_warning ("CcCtrl: Failed to launch app");
+ ctrl->closure->end_stream (ctrl->closure);
break;
case CC_RWAIT_TYPE_ANSWER:
cc_ctrl_unset_waiting_for (ctrl, CC_RWAIT_TYPE_ANSWER);
@@ -348,7 +549,7 @@ cc_ctrl_handle_received_msg (CcCommClosure *closure,
break;
case CC_RWAIT_TYPE_MEDIA_STATUS:
cc_ctrl_unset_waiting_for (ctrl, CC_RWAIT_TYPE_MEDIA_STATUS);
- // cc_ctrl_handle_media_status (ctrl, reader);
+ cc_ctrl_handle_media_status (ctrl, message, reader);
break;
case CC_RWAIT_TYPE_PING:
cc_ctrl_unset_waiting_for (ctrl, CC_RWAIT_TYPE_PING);
@@ -357,11 +558,12 @@ cc_ctrl_handle_received_msg (CcCommClosure *closure,
cc_ctrl_unset_waiting_for (ctrl, CC_RWAIT_TYPE_PONG);
break;
case CC_RWAIT_TYPE_CLOSE:
- // cc_ctrl_handle_close (ctrl, reader);
+ cc_ctrl_handle_close (ctrl, message);
break;
case CC_RWAIT_TYPE_UNKNOWN:
default:
g_warning ("CcCtrl: Unknown message type");
+ ctrl->closure->end_stream (ctrl->closure);
break;
}
}
@@ -369,7 +571,7 @@ cc_ctrl_handle_received_msg (CcCommClosure *closure,
void
cc_ctrl_fatal_error (CcCommClosure *closure, GError **error)
{
- // XXX
+ // XXX: add error arg in end_stream and display an error message to user
CcCtrl *ctrl = (CcCtrl *) closure->userdata;
ctrl->closure->end_stream (ctrl->closure);
}
@@ -387,8 +589,6 @@ cc_ctrl_get_callback_closure (CcCtrl *ctrl)
gboolean
cc_ctrl_connection_init (CcCtrl *ctrl, gchar *remote_address)
{
- // pay attn to the receiver ids sent before the messages
-
g_autoptr (GError) error = NULL;
ctrl->state = CC_CTRL_STATE_DISCONNECTED;
@@ -430,7 +630,6 @@ cc_ctrl_connection_init (CcCtrl *ctrl, gchar *remote_address)
g_warning ("CcCtrl: Failed to send get status: %s", error->message);
return FALSE;
}
- cc_ctrl_set_waiting_for (ctrl, CC_RWAIT_TYPE_RECEIVER_STATUS);
return TRUE;
}
@@ -474,3 +673,6 @@ cc_ctrl_finish (CcCtrl *ctrl, GError **r_error)
// close the socket connection
cc_comm_close_connection (&ctrl->comm);
}
+
+// TODO: make the code less coupled with the mirroring app
+// TODO: use waiting_for for error messages
diff --git a/src/cc/cc-ctrl.h b/src/cc/cc-ctrl.h
index 4633978..9e5adc5 100644
--- a/src/cc/cc-ctrl.h
+++ b/src/cc/cc-ctrl.h
@@ -40,8 +40,9 @@ struct _CcCtrlClosure
{
gpointer userdata;
// TODO
- void (*end_stream) (struct _CcCtrlClosure *closure);
+ Offer * (*get_offer_message) (struct _CcCtrlClosure *closure);
void (*start_stream) (struct _CcCtrlClosure *closure);
+ void (*end_stream) (struct _CcCtrlClosure *closure);
};
typedef struct _CcCtrlClosure CcCtrlClosure;
diff --git a/src/cc/cc-json-helper.c b/src/cc/cc-json-helper.c
index cbf33d8..16c3738 100644
--- a/src/cc/cc-json-helper.c
+++ b/src/cc/cc-json-helper.c
@@ -18,149 +18,147 @@
#include "cc-json-helper.h"
-// static void
-// cc_json_helper_add_type_value (JsonBuilder *builder,
-// CcJsonType type,
-// gpointer value)
-// {
-// switch (type)
-// {
-// case CC_JSON_TYPE_STRING:
-// json_builder_add_string_value (builder, (gchar *) *value);
-// break;
-// case CC_JSON_TYPE_INT:
-// json_builder_add_int_value (builder, (gint) *value);
-// break;
-// case CC_JSON_TYPE_DOUBLE:
-// json_builder_add_double_value (builder, (gdouble) *value);
-// break;
-// case CC_JSON_TYPE_BOOLEAN:
-// json_builder_add_boolean_value (builder, (gboolean) *value);
-// break;
-// case CC_JSON_TYPE_NULL: /* no additional arg is required here */
-// json_builder_add_null_value (builder);
-// break;
-// case CC_JSON_TYPE_OBJECT:
-// json_builder_begin_object (builder);
-// json_builder_add_value (builder, (JsonNode *) value);
-// json_builder_end_object (builder);
-// break;
-// /* only 1D arrays supported */
-// }
-// }
-
-// void
-// cc_json_helper_build_root (JsonBuilder *builder,
-// const gchar *first_key,
-// va_list var_args)
-// {
-// gchar *key = first_key;
-
-// while (key)
-// {
-// json_builder_set_member_name (builder, key);
-// CcJsonType type = va_arg (var_args, CcJsonType);
-
-// if (type == CC_JSON_TYPE_ARRAY)
-// {
-// json_builder_begin_array (builder);
-// gint length = va_arg (var_args, gint);
-// for (gint i = 0; i < length; i++)
-// {
-// cc_json_helper_add_type_value (builder, type, va_arg (var_args, gpointer));
-// }
-// json_builder_end_array (builder);
-// }
-// switch (type)
-// {
-// case CC_JSON_TYPE_STRING:
-// json_builder_add_string_value (builder, va_arg (var_args, gchar *));
-// break;
-// case CC_JSON_TYPE_INT:
-// json_builder_add_int_value (builder, va_arg (var_args, gint));
-// break;
-// case CC_JSON_TYPE_DOUBLE:
-// json_builder_add_double_value (builder, va_arg (var_args, gdouble));
-// break;
-// case CC_JSON_TYPE_BOOLEAN:
-// json_builder_add_boolean_value (builder, va_arg (var_args, gboolean));
-// break;
-// case CC_JSON_TYPE_NULL: /* no additional arg is required here */
-// json_builder_add_null_value (builder);
-// break;
-// case CC_JSON_TYPE_OBJECT:
-// json_builder_begin_object (builder);
-// json_builder_add_value (builder, va_arg (var_args, JsonNode *));
-// json_builder_end_object (builder);
-// break;
-// case CC_JSON_TYPE_ARRAY: /* type for array elements is also required here */
-// json_builder_begin_array (builder);
-// CcJsonType array_type = va_arg (var_args, CcJsonType);
-// /* GArray */
-// json_builder_end_array (builder);
-// break;
-// default:
-// output = NULL;
-// return;
-// }
-
-// key = va_arg (var_args, gchar *);
-// }
-// }
-
-// void
-// cc_json_helper_build_string (gchar *output,
-// const gchar *first_key,
-// ...)
-// {
-// va_list var_args;
-// va_start (var_args, first_key);
-
-// JsonBuilder *builder = json_builder_new ();
-
-// json_builder_begin_object (builder);
-// cc_json_helper_build_root (builder, first_key, var_args);
-// json_builder_end_object (builder);
-
-// JsonGenerator *gen = json_generator_new ();
-// JsonNode *root = json_builder_get_root (builder);
-// json_generator_set_root (gen, root);
-
-// output = json_generator_to_data (gen, NULL);
-
-// va_end (var_args);
-// json_node_free (root);
-// g_object_unref (gen);
-// g_object_unref (builder);
-// }
-
-// void
-// cc_json_helper_build_string (gchar *output,
-// const gchar *first_key,
-// ...)
-// {
-// va_list var_args;
-// va_start (var_args, first_key);
-
-// JsonBuilder *builder = json_builder_new ();
-
-// json_builder_begin_object (builder);
-// cc_json_helper_build_root (builder, first_key, var_args);
-// json_builder_end_object (builder);
-
-// JsonGenerator *gen = json_generator_new ();
-// JsonNode *root = json_builder_get_root (builder);
-// json_generator_set_root (gen, root);
-
-// output = json_generator_to_data (gen, NULL);
-
-// va_end (var_args);
-// json_node_free (root);
-// g_object_unref (gen);
-// g_object_unref (builder);
-// }
+static void
+cc_json_helper_build_internal (JsonBuilder *builder,
+ gchar *first_key,
+ va_list var_args)
+{
+ gchar *key = first_key;
+ while (key)
+ {
+ json_builder_set_member_name (builder, key);
+ CcJsonType type = va_arg (var_args, CcJsonType);
+ if (type < CC_JSON_TYPE_STRING || type > CC_JSON_TYPE_ARRAY_OBJECT)
+ {
+ g_warning ("CcJsonHelper: Incorrect type passed in json contructor: %d", type);
+ return;
+ }
+
+ switch (type)
+ {
+ case CC_JSON_TYPE_STRING:
+ json_builder_add_string_value (builder, va_arg (var_args, gchar *));
+ break;
+ case CC_JSON_TYPE_INT:
+ json_builder_add_int_value (builder, va_arg (var_args, gint));
+ break;
+ case CC_JSON_TYPE_DOUBLE:
+ json_builder_add_double_value (builder, va_arg (var_args, gdouble));
+ break;
+ case CC_JSON_TYPE_BOOLEAN:
+ json_builder_add_boolean_value (builder, va_arg (var_args, gboolean));
+ break;
+ case CC_JSON_TYPE_NULL: /* no additional arg is required here */
+ json_builder_add_null_value (builder);
+ break;
+ case CC_JSON_TYPE_OBJECT:
+ json_builder_add_value (builder, va_arg (var_args, JsonNode *));
+ break;
+ default:
+ break;
+ }
+
+ if (type < CC_JSON_TYPE_ARRAY_STRING)
+ {
+ key = va_arg (var_args, gchar *);
+ continue;
+ }
+
+ json_builder_begin_array (builder);
+ GArray *arr = va_arg (var_args, GArray *);
+ guint i;
+
+ for (i=0; i<arr->len; i++)
+ {
+ switch (type)
+ {
+ case CC_JSON_TYPE_ARRAY_STRING:
+ json_builder_add_string_value (builder, g_array_index (arr, gchar *, i));
+ break;
+ case CC_JSON_TYPE_ARRAY_INT:
+ json_builder_add_int_value (builder, g_array_index (arr, gint, i));
+ break;
+ case CC_JSON_TYPE_ARRAY_DOUBLE:
+ json_builder_add_double_value (builder, g_array_index (arr, gdouble, i));
+ break;
+ case CC_JSON_TYPE_ARRAY_BOOLEAN:
+ json_builder_add_boolean_value (builder, g_array_index (arr, gboolean, i));
+ break;
+ case CC_JSON_TYPE_ARRAY_NULL:
+ json_builder_add_null_value (builder);
+ break;
+ case CC_JSON_TYPE_ARRAY_OBJECT:
+ json_builder_add_value (builder, g_array_index (arr, JsonNode *, i));
+ break;
+ default:
+ break;
+ }
+ }
+
+ json_builder_end_array (builder);
+
+ key = va_arg (var_args, gchar *);
+ }
+}
+
+void
+cc_json_helper_build_node (JsonNode **output,
+ gchar *first_key,
+ ...)
+{
+ va_list var_args;
+ va_start (var_args, first_key);
+
+ JsonBuilder *builder = json_builder_new ();
+
+ json_builder_begin_object (builder);
+ cc_json_helper_build_internal (builder, first_key, var_args);
+ json_builder_end_object (builder);
+
+ *output = json_builder_get_root (builder);
+
+ va_end (var_args);
+ g_object_unref (builder);
+}
+
+void
+cc_json_helper_build_string (gchar **output,
+ // gboolean pretty_print,
+ gchar *first_key,
+ ...)
+{
+ va_list var_args;
+ va_start (var_args, first_key);
+
+ JsonBuilder *builder = json_builder_new ();
+
+ json_builder_begin_object (builder);
+ cc_json_helper_build_internal (builder, first_key, var_args);
+ json_builder_end_object (builder);
+
+ JsonNode *root = json_builder_get_root (builder);
+ JsonGenerator *gen = json_generator_new ();
+
+ // json_generator_set_pretty (gen, pretty_print);
+ json_generator_set_root (gen, root);
+ *output = json_generator_to_data (gen, NULL);
+
+ va_end (var_args);
+ json_node_free (root);
+ g_object_unref (gen);
+ g_object_unref (builder);
+}
+
+void
+cc_json_helper_node_to_string (gchar **output, JsonNode *node)
+{
+ JsonGenerator *gen = json_generator_new ();
+ json_generator_set_root (gen, node);
+ *output = json_generator_to_data (gen, NULL);
+ g_object_unref (gen);
+}
CcReceivedMessageType
cc_json_helper_get_message_type (Cast__Channel__CastMessage *message,
@@ -169,20 +167,20 @@ cc_json_helper_get_message_type (Cast__Channel__CastMessage *message,
const gchar *message_type;
g_autoptr (GError) error = NULL;
- if (reader == NULL)
- {
- g_autoptr(JsonParser) parser = NULL;
+ // if (reader == NULL)
+ // {
+ // g_autoptr(JsonParser) parser = NULL;
- parser = json_parser_new ();
- if (!json_parser_load_from_data (parser, message->payload_utf8, -1, &error))
- {
- cc_json_helper_dump_message (message);
- g_warning ("CcJsonHelper: Error parsing received message JSON: %s", error->message);
- return -1;
- }
+ // parser = json_parser_new ();
+ // if (!json_parser_load_from_data (parser, message->payload_utf8, -1, &error))
+ // {
+ // cc_json_helper_dump_message (message);
+ // g_warning ("CcJsonHelper: Error parsing received message JSON: %s", error->message);
+ // return -1;
+ // }
- reader = json_reader_new (json_parser_get_root (parser));
- }
+ // reader = json_reader_new (json_parser_get_root (parser));
+ // }
gboolean typeExists = json_reader_read_member (reader, "type");
if (typeExists)
@@ -194,8 +192,8 @@ cc_json_helper_get_message_type (Cast__Channel__CastMessage *message,
message_type = json_reader_get_string_value (reader);
else
{
- cc_json_helper_dump_message (message);
g_warning ("CcJsonHelper: Error parsing received message JSON: no type or responseType keys");
+ cc_json_helper_dump_message (message, TRUE);
return -1;
}
}
@@ -224,14 +222,34 @@ cc_json_helper_get_message_type (Cast__Channel__CastMessage *message,
} cc_end
}
+/* borked var reduces extra computation */
void
-cc_json_helper_dump_message (Cast__Channel__CastMessage *message)
+cc_json_helper_dump_message (Cast__Channel__CastMessage *message, gboolean borked)
{
- // TODO: pretty print json object
- g_debug ("{ source_id: %s, destination_id: %s, namespace_: %s, payload_type: %d, payload_utf8: %s }",
- message->source_id,
- message->destination_id,
- message->namespace_,
- message->payload_type,
- message->payload_utf8);
+ JsonNode *payload_utf8_node;
+ JsonParser *parser = json_parser_new ();
+ g_autoptr (GError) error = NULL;
+
+ if (borked || !json_parser_load_from_data (parser, message->payload_utf8, -1, &error))
+ {
+ g_warning ("CcJsonHelper: Error parsing received JSON payload: %s", error->message);
+ g_debug ("{ source_id: %s, destination_id: %s, namespace_: %s, payload_utf8: %s }",
+ message->source_id,
+ message->destination_id,
+ message->namespace_,
+ message->payload_utf8);
+ return;
+ }
+
+ payload_utf8_node = json_parser_get_root (parser);
+
+ gchar *output;
+ cc_json_helper_build_string (&output, //TRUE,
+ "source_id", CC_JSON_TYPE_STRING, message->source_id,
+ "destination_id", CC_JSON_TYPE_STRING, message->destination_id,
+ "namespace", CC_JSON_TYPE_STRING, message->namespace_,
+ "payload_utf8", CC_JSON_TYPE_OBJECT, payload_utf8_node,
+ NULL);
+
+ g_debug ("%s", output);
}
diff --git a/src/cc/cc-json-helper.h b/src/cc/cc-json-helper.h
index 0f22124..02bcd80 100644
--- a/src/cc/cc-json-helper.h
+++ b/src/cc/cc-json-helper.h
@@ -25,7 +25,8 @@
G_BEGIN_DECLS
-typedef enum {
+typedef enum
+{
CC_JSON_TYPE_STRING,
CC_JSON_TYPE_INT,
CC_JSON_TYPE_DOUBLE,
@@ -41,8 +42,14 @@ typedef enum {
CC_JSON_TYPE_ARRAY_OBJECT,
} CcJsonType;
+
+// void cc_json_helper_build_node (JsonNode **output, gchar *first_key, ...) G_GNUC_NULL_TERMINATED;
+void cc_json_helper_build_node (JsonNode **output, gchar *first_key, ...);
+void cc_json_helper_build_string (gchar **output, gchar *first_key, ...);
+// void cc_json_helper_build_string (gchar **output, gboolean pretty_print, gchar *first_key, ...);
+void cc_json_helper_node_to_string (gchar **output, JsonNode *node);
CcReceivedMessageType cc_json_helper_get_message_type (Cast__Channel__CastMessage *message,
JsonReader *json_reader);
-void cc_json_helper_dump_message (Cast__Channel__CastMessage *message);
+void cc_json_helper_dump_message (Cast__Channel__CastMessage *message, gboolean borked);
G_END_DECLS
diff --git a/src/nd-cc-sink.c b/src/nd-cc-sink.c
index ff83e9a..6ec5e73 100644
--- a/src/nd-cc-sink.c
+++ b/src/nd-cc-sink.c
@@ -24,6 +24,7 @@
#include "wfd/wfd-media-factory.h"
#include "wfd/wfd-server.h"
#include "cc/cc-ctrl.h"
+#include "cc/cc-common.h"
// TODO: add cancellable everywhere
@@ -327,8 +328,8 @@ nd_cc_sink_get_callback_closure (NdCCSink *sink)
{
CcCtrlClosure *closure = (CcCtrlClosure *) g_malloc (sizeof (CcCtrlClosure));
closure->userdata = sink;
- closure->end_stream = nd_cc_sink_error_in_ctrl;
closure->start_stream = nd_cc_sink_start_webrtc_stream;
+ closure->end_stream = nd_cc_sink_error_in_ctrl;
return closure;
}
@@ -413,8 +414,8 @@ nd_cc_sink_sink_stop_stream_int (NdCCSink *self)
{
cc_ctrl_finish (&self->ctrl, NULL);
- g_cancellable_cancel (self->cancellable);
- g_clear_object (&self->cancellable);
+ // g_cancellable_cancel (self->cancellable);
+ // g_clear_object (&self->cancellable);
self->cancellable = g_cancellable_new ();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]