diff --git a/conf/janus.plugin.audiobridge.jcfg.sample b/conf/janus.plugin.audiobridge.jcfg.sample index 58b073f4b0..ee78db1eb9 100644 --- a/conf/janus.plugin.audiobridge.jcfg.sample +++ b/conf/janus.plugin.audiobridge.jcfg.sample @@ -37,6 +37,10 @@ general: { # .wav --> .wav.tmp until the file is closed #events = false # Whether events should be sent to event # handlers (default=true) + + # By default, integers are used as a unique ID for both rooms and participants. + # In case you want to use strings instead (e.g., a UUID), set string_ids to true. + #string_ids = true } room-1234: { diff --git a/conf/janus.plugin.textroom.jcfg.sample b/conf/janus.plugin.textroom.jcfg.sample index 3d4b837846..6e1fc61f5e 100644 --- a/conf/janus.plugin.textroom.jcfg.sample +++ b/conf/janus.plugin.textroom.jcfg.sample @@ -13,6 +13,10 @@ general: { # plain (no indentation) or compact (no indentation and no spaces) #events = false # Whether events should be sent to event # handlers (default=true) + + # By default, integers are used as a unique ID for rooms. In case you + # want to use strings instead (e.g., a UUID), set string_ids to true. + #string_ids = true } room-1234: { diff --git a/conf/janus.plugin.videoroom.jcfg.sample b/conf/janus.plugin.videoroom.jcfg.sample index 72999525a5..866caa6db4 100644 --- a/conf/janus.plugin.videoroom.jcfg.sample +++ b/conf/janus.plugin.videoroom.jcfg.sample @@ -44,6 +44,10 @@ general: { # enforced for RTP forwarding requests too #events = false # Whether events should be sent to event # handlers (default=true) + + # By default, integers are used as a unique ID for both rooms and participants. + # In case you want to use strings instead (e.g., a UUID), set string_ids to true. + #string_ids = true } room-1234: { diff --git a/plugins/janus_audiobridge.c b/plugins/janus_audiobridge.c index 4b480456e4..105e942d37 100644 --- a/plugins/janus_audiobridge.c +++ b/plugins/janus_audiobridge.c @@ -737,6 +737,30 @@ static struct janus_json_parameter request_parameters[] = { static struct janus_json_parameter adminkey_parameters[] = { {"admin_key", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} }; +static struct janus_json_parameter room_parameters[] = { + {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter roomopt_parameters[] = { + {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter roomstr_parameters[] = { + {"room", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} +}; +static struct janus_json_parameter roomstropt_parameters[] = { + {"room", JSON_STRING, 0} +}; +static struct janus_json_parameter id_parameters[] = { + {"id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter idopt_parameters[] = { + {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter idstr_parameters[] = { + {"id", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} +}; +static struct janus_json_parameter idstropt_parameters[] = { + {"id", JSON_STRING, 0} +}; static struct janus_json_parameter create_parameters[] = { {"description", JSON_STRING, 0}, {"secret", JSON_STRING, 0}, @@ -751,11 +775,9 @@ static struct janus_json_parameter create_parameters[] = { {"audiolevel_ext", JANUS_JSON_BOOL, 0}, {"audiolevel_event", JANUS_JSON_BOOL, 0}, {"audio_active_packets", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, - {"audio_level_average", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, - {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} + {"audio_level_average", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} }; static struct janus_json_parameter edit_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"secret", JSON_STRING, 0}, {"new_description", JSON_STRING, 0}, {"new_secret", JSON_STRING, 0}, @@ -764,36 +786,22 @@ static struct janus_json_parameter edit_parameters[] = { {"permanent", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter destroy_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"permanent", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter allowed_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"secret", JSON_STRING, 0}, {"action", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, {"allowed", JSON_ARRAY, 0} }; -static struct janus_json_parameter kick_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, - {"secret", JSON_STRING, 0}, - {"id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} -}; -static struct janus_json_parameter mute_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, - {"secret", JSON_STRING, 0}, - {"id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, -}; -static struct janus_json_parameter room_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} +static struct janus_json_parameter secret_parameters[] = { + {"secret", JSON_STRING, 0} }; static struct janus_json_parameter join_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"display", JSON_STRING, 0}, {"token", JSON_STRING, 0}, {"muted", JANUS_JSON_BOOL, 0}, {"quality", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, - {"volume", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, - {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} + {"volume", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} }; static struct janus_json_parameter configure_parameters[] = { {"muted", JANUS_JSON_BOOL, 0}, @@ -805,7 +813,6 @@ static struct janus_json_parameter configure_parameters[] = { {"update", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter rtp_forward_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"ssrc", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"ptype", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"port", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, @@ -816,7 +823,6 @@ static struct janus_json_parameter rtp_forward_parameters[] = { {"always_on", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter stop_rtp_forward_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"stream_id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} }; @@ -828,6 +834,7 @@ static janus_mutex config_mutex = JANUS_MUTEX_INITIALIZER; /* Useful stuff */ static volatile gint initialized = 0, stopping = 0; static gboolean notify_events = TRUE; +static gboolean string_ids = FALSE; static janus_callbacks *gateway = NULL; static GThread *handler_thread; static void *janus_audiobridge_handler(void *data); @@ -851,10 +858,12 @@ static janus_audiobridge_message exit_message; /* Structs */ typedef struct janus_audiobridge_room { - guint64 room_id; /* Unique room ID */ + guint64 room_id; /* Unique room ID (when using integers) */ + gchar *room_id_str; /* Unique room ID (when using strings) */ gchar *room_name; /* Room description */ gchar *room_secret; /* Secret needed to manipulate (e.g., destroy) this room */ gchar *room_pin; /* Password needed to join this room, if any */ + uint32_t room_ssrc; /* SSRC we'll use for packets generated by the mixer */ gboolean is_private; /* Whether this room is 'private' (as in hidden) or not */ uint32_t sampling_rate; /* Sampling rate of the mix (e.g., 16000 for wideband; can be 8, 12, 16, 24 or 48kHz) */ gboolean audiolevel_ext; /* Whether the ssrc-audio-level extension must be negotiated or not for new joins */ @@ -901,6 +910,7 @@ typedef struct janus_audiobridge_participant { janus_audiobridge_session *session; janus_audiobridge_room *room; /* Room */ guint64 user_id; /* Unique ID in the room */ + gchar *user_id_str; /* Unique ID in the room (when using strings) */ gchar *display; /* Display name (opaque value, only meaningful to application) */ gboolean prebuffering; /* Whether this participant needs pre-buffering of a few packets (just joined) */ volatile gint active; /* Whether this participant can receive media at all */ @@ -965,6 +975,7 @@ static void janus_audiobridge_participant_unref(janus_audiobridge_participant *p static void janus_audiobridge_participant_free(const janus_refcount *participant_ref) { janus_audiobridge_participant *participant = janus_refcount_containerof(participant_ref, janus_audiobridge_participant, ref); /* This participant can be destroyed, free all the resources */ + g_free(participant->user_id_str); g_free(participant->display); if(participant->encoder) opus_encoder_destroy(participant->encoder); @@ -1019,6 +1030,7 @@ static void janus_audiobridge_room_destroy(janus_audiobridge_room *audiobridge) static void janus_audiobridge_room_free(const janus_refcount *audiobridge_ref) { janus_audiobridge_room *audiobridge = janus_refcount_containerof(audiobridge_ref, janus_audiobridge_room, ref); /* This room can be destroyed, free all the resources */ + g_free(audiobridge->room_id_str); g_free(audiobridge->room_name); g_free(audiobridge->room_secret); g_free(audiobridge->room_pin); @@ -1143,8 +1155,8 @@ static guint32 janus_audiobridge_rtp_forwarder_add_helper(janus_audiobridge_room janus_mutex_unlock(&room->rtp_mutex); - JANUS_LOG(LOG_VERB, "Added RTP forwarder to room %"SCNu64": %s:%d (ID: %"SCNu32")\n", - room->room_id, host, port, actual_stream_id); + JANUS_LOG(LOG_VERB, "Added RTP forwarder to room %s: %s:%d (ID: %"SCNu32")\n", + room->room_id_str, host, port, actual_stream_id); return actual_stream_id; } @@ -1221,12 +1233,12 @@ static int janus_audiobridge_create_udp_socket_if_needed(janus_audiobridge_room audiobridge->rtp_udp_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if(audiobridge->rtp_udp_sock <= 0) { - JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP forwarder (room %"SCNu64")\n", audiobridge->room_id); + JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP forwarder (room %s)\n", audiobridge->room_id_str); return -1; } int v6only = 0; if(setsockopt(audiobridge->rtp_udp_sock, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)) != 0) { - JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP forwarder (room %"SCNu64")\n", audiobridge->room_id); + JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP forwarder (room %s)\n", audiobridge->room_id_str); return -1; } @@ -1241,7 +1253,7 @@ static int janus_audiobridge_create_opus_encoder_if_needed(janus_audiobridge_roo int error = 0; audiobridge->rtp_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error); if(error != OPUS_OK) { - JANUS_LOG(LOG_ERR, "Error creating Opus encoder for RTP forwarder (room %"SCNu64")\n", audiobridge->room_id); + JANUS_LOG(LOG_ERR, "Error creating Opus encoder for RTP forwarder (room %s)\n", audiobridge->room_id_str); return -1; } @@ -1357,7 +1369,7 @@ static int janus_audiobridge_create_static_rtp_forwarder(janus_config_category * if(s_suite && s_suite->value) { srtp_suite = atoi(s_suite->value); if(srtp_suite != 32 && srtp_suite != 80) { - JANUS_LOG(LOG_ERR, "Can't add static RTP forwarder for room %"SCNu64", invalid SRTP suite...\n", audiobridge->room_id); + JANUS_LOG(LOG_ERR, "Can't add static RTP forwarder for room %s, invalid SRTP suite...\n", audiobridge->room_id_str); return 0; } if(s_crypto && s_crypto->value) @@ -1422,7 +1434,6 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { if(config != NULL) janus_config_print(config); - rooms = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)janus_audiobridge_room_destroy); sessions = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)janus_audiobridge_session_destroy); messages = g_async_queue_new_full((GDestroyNotify) janus_audiobridge_message_free); /* This is the callback we'll need to invoke to contact the Janus core */ @@ -1447,7 +1458,17 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { if(!notify_events && callback->events_is_enabled()) { JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_AUDIOBRIDGE_NAME); } - /* Iterate on all rooms */ + janus_config_item *ids = janus_config_get(config, config_general, janus_config_type_item, "string_ids"); + if(ids != NULL && ids->value != NULL) + string_ids = janus_is_true(ids->value); + if(string_ids) { + JANUS_LOG(LOG_INFO, "AudioBridge will use alphanumeric IDs, not numeric\n"); + } + } + /* Iterate on all rooms */ + rooms = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)janus_audiobridge_room_destroy); + if(config != NULL) { GList *clist = janus_config_get_categories(config, NULL), *cl = clist; while(cl != NULL) { janus_config_category *cat = (janus_config_category *)cl->data; @@ -1455,7 +1476,7 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { cl = cl->next; continue; } - JANUS_LOG(LOG_VERB, "Adding audio room '%s'\n", cat->name); + JANUS_LOG(LOG_VERB, "Adding AudioBridge room '%s'\n", cat->name); janus_config_item *desc = janus_config_get(config, cat, janus_config_type_item, "description"); janus_config_item *priv = janus_config_get(config, cat, janus_config_type_item, "is_private"); janus_config_item *sampling = janus_config_get(config, cat, janus_config_type_item, "sampling_rate"); @@ -1468,16 +1489,45 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { janus_config_item *record = janus_config_get(config, cat, janus_config_type_item, "record"); janus_config_item *recfile = janus_config_get(config, cat, janus_config_type_item, "record_file"); if(sampling == NULL || sampling->value == NULL) { - JANUS_LOG(LOG_ERR, "Can't add the audio room, missing mandatory information...\n"); + JANUS_LOG(LOG_ERR, "Can't add the AudioBridge room, missing mandatory information...\n"); cl = cl->next; continue; } - /* Create the audio bridge room */ + /* Create the AudioBridge room */ janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room)); const char *room_num = cat->name; if(strstr(room_num, "room-") == room_num) room_num += 5; - audiobridge->room_id = g_ascii_strtoull(room_num, NULL, 0); + if(!string_ids) { + audiobridge->room_id = g_ascii_strtoull(room_num, NULL, 0); + if(audiobridge->room_id == 0) { + JANUS_LOG(LOG_ERR, "Can't add the AudioBridge room, invalid ID 0...\n"); + g_free(audiobridge); + cl = cl->next; + continue; + } + /* Make sure the ID is completely numeric */ + char room_id_str[30]; + g_snprintf(room_id_str, sizeof(room_id_str), "%"SCNu64, audiobridge->room_id); + if(strcmp(room_num, room_id_str)) { + JANUS_LOG(LOG_ERR, "Can't add the AudioBridge room, ID '%s' is not numeric...\n", room_num); + g_free(audiobridge); + cl = cl->next; + continue; + } + } + /* Let's make sure the room doesn't exist already */ + janus_mutex_lock(&rooms_mutex); + if(g_hash_table_lookup(rooms, string_ids ? (gpointer)room_num : (gpointer)&audiobridge->room_id) != NULL) { + /* It does... */ + janus_mutex_unlock(&rooms_mutex); + JANUS_LOG(LOG_ERR, "Can't add the AudioBridge room, room %s already exists...\n", room_num); + g_free(audiobridge); + cl = cl->next; + continue; + } + janus_mutex_unlock(&rooms_mutex); + audiobridge->room_id_str = g_strdup(room_num); char *description = NULL; if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0) description = g_strdup(desc->value); @@ -1523,7 +1573,7 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { } } } - + audiobridge->room_ssrc = janus_random_uint32(); if(secret != NULL && secret->value != NULL) { audiobridge->room_secret = g_strdup(secret->value); } @@ -1537,7 +1587,8 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { audiobridge->record_file = g_strdup(recfile->value); audiobridge->recording = NULL; audiobridge->destroy = 0; - audiobridge->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, + audiobridge->participants = g_hash_table_new_full( + string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)janus_audiobridge_participant_unref); audiobridge->check_tokens = FALSE; /* Static rooms can't have an "allowed" list yet, no hooks to the configuration file */ audiobridge->allowed = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); @@ -1548,20 +1599,20 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { audiobridge->rtp_udp_sock = -1; janus_mutex_init(&audiobridge->rtp_mutex); janus_refcount_init(&audiobridge->ref, janus_audiobridge_room_free); - JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n", - audiobridge->room_id, audiobridge->room_name, + JANUS_LOG(LOG_VERB, "Created AudioBridge room: %s (%s, %s, secret: %s, pin: %s)\n", + audiobridge->room_id_str, audiobridge->room_name, audiobridge->is_private ? "private" : "public", audiobridge->room_secret ? audiobridge->room_secret : "no secret", audiobridge->room_pin ? audiobridge->room_pin : "no pin"); if(janus_audiobridge_create_static_rtp_forwarder(cat, audiobridge)) { - JANUS_LOG(LOG_ERR, "Error creating static RTP forwarder (room %"SCNu64")\n", audiobridge->room_id); + JANUS_LOG(LOG_ERR, "Error creating static RTP forwarder (room %s)\n", audiobridge->room_id_str); } /* We need a thread for the mix */ GError *error = NULL; char tname[16]; - g_snprintf(tname, sizeof(tname), "mixer %"SCNu64, audiobridge->room_id); + g_snprintf(tname, sizeof(tname), "mixer %s", audiobridge->room_id_str); janus_refcount_increase(&audiobridge->ref); audiobridge->thread = g_thread_try_new(tname, &janus_audiobridge_mixer_thread, audiobridge, &error); if(error != NULL) { @@ -1570,7 +1621,9 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the mixer thread...\n", error->code, error->message ? error->message : "??"); } else { janus_mutex_lock(&rooms_mutex); - g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge); + g_hash_table_insert(rooms, + string_ids ? (gpointer)g_strdup(audiobridge->room_id_str) : (gpointer)janus_uint64_dup(audiobridge->room_id), + audiobridge); janus_mutex_unlock(&rooms_mutex); } cl = cl->next; @@ -1586,8 +1639,8 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { g_hash_table_iter_init(&iter, rooms); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_audiobridge_room *ar = value; - JANUS_LOG(LOG_VERB, " ::: [%"SCNu64"][%s] %"SCNu32" (%s be recorded)\n", - ar->room_id, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT"); + JANUS_LOG(LOG_VERB, " ::: [%s][%s] %"SCNu32" (%s be recorded)\n", + ar->room_id_str, ar->room_name, ar->sampling_rate, ar->record ? "will" : "will NOT"); } janus_mutex_unlock(&rooms_mutex); @@ -1598,7 +1651,8 @@ int janus_audiobridge_init(janus_callbacks *callback, const char *config_path) { handler_thread = g_thread_try_new("audiobridge handler", janus_audiobridge_handler, NULL, &error); if(error != NULL) { g_atomic_int_set(&initialized, 0); - JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", error->code, error->message ? error->message : "??"); + JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the AudioBridge handler thread...\n", + error->code, error->message ? error->message : "??"); janus_config_destroy(config); return -1; } @@ -1723,7 +1777,7 @@ static void janus_audiobridge_notify_participants(janus_audiobridge_participant while (!participant->room->destroyed && g_hash_table_iter_next(&iter, NULL, &value)) { janus_audiobridge_participant *p = value; if(p && p->session && p != participant) { - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, msg, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -1751,9 +1805,9 @@ json_t *janus_audiobridge_query_session(janus_plugin_session *handle) { janus_mutex_lock(&rooms_mutex); janus_audiobridge_room *room = participant->room; if(room != NULL) - json_object_set_new(info, "room", json_integer(room->room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room->room_id_str) : json_integer(room->room_id)); janus_mutex_unlock(&rooms_mutex); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); if(participant->display) json_object_set_new(info, "display", json_string(participant->display)); json_object_set_new(info, "muted", participant->muted ? json_true() : json_false()); @@ -1795,11 +1849,22 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s json_t *response = NULL; if(!strcasecmp(request_text, "create")) { - /* Create a new audiobridge */ - JANUS_LOG(LOG_VERB, "Creating a new audiobridge\n"); + /* Create a new AudioBridge */ + JANUS_LOG(LOG_VERB, "Creating a new AudioBridge room\n"); JANUS_VALIDATE_JSON_OBJECT(root, create_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, roomopt_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstropt_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; if(admin_key != NULL) { @@ -1857,27 +1922,35 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s goto prepare_response; } guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; json_t *room = json_object_get(root, "room"); - room_id = json_integer_value(room); - if(room_id == 0) { - JANUS_LOG(LOG_WARN, "Desired room ID is 0, which is not allowed... picking random ID instead\n"); + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } + if(room_id == 0 && room_id_str == NULL) { + JANUS_LOG(LOG_WARN, "Desired room ID is empty, which is not allowed... picking random ID instead\n"); } janus_mutex_lock(&rooms_mutex); - if(room_id > 0) { + if(room_id > 0 || room_id_str != NULL) { /* Let's make sure the room doesn't exist already */ - if(g_hash_table_lookup(rooms, &room_id) != NULL) { + if(g_hash_table_lookup(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id) != NULL) { /* It does... */ janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "Room %"SCNu64" already exists!\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_ROOM_EXISTS; - g_snprintf(error_cause, 512, "Room %"SCNu64" already exists", room_id); + JANUS_LOG(LOG_ERR, "Room %s already exists!\n", room_id_str); + g_snprintf(error_cause, 512, "Room %s already exists", room_id_str); goto prepare_response; } } - /* Create the audio bridge room */ + /* Create the AudioBridge room */ janus_audiobridge_room *audiobridge = g_malloc0(sizeof(janus_audiobridge_room)); - /* Generate a random ID */ - if(room_id == 0) { + /* Generate a random ID, if needed */ + gboolean room_id_allocated = FALSE; + if(!string_ids && room_id == 0) { while(room_id == 0) { room_id = janus_random_uint64(); if(g_hash_table_lookup(rooms, &room_id) != NULL) { @@ -1885,14 +1958,26 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s room_id = 0; } } + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else if(string_ids && room_id_str == NULL) { + while(room_id_str == NULL) { + room_id_str = janus_random_uuid(); + if(g_hash_table_lookup(rooms, room_id_str) != NULL) { + /* Room ID already taken, try another one */ + g_clear_pointer(&room_id_str, g_free); + } + } + room_id_allocated = TRUE; } audiobridge->room_id = room_id; + audiobridge->room_id_str = room_id_str ? g_strdup(room_id_str) : NULL; char *description = NULL; if(desc != NULL && strlen(json_string_value(desc)) > 0) { description = g_strdup(json_string_value(desc)); } else { char roomname[255]; - g_snprintf(roomname, 255, "Room %"SCNu64"", audiobridge->room_id); + g_snprintf(roomname, 255, "Room %s", audiobridge->room_id_str); description = g_strdup(roomname); } audiobridge->room_name = description; @@ -1930,12 +2015,15 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s JANUS_LOG(LOG_VERB, "Sampling rate for mixing: %"SCNu32"\n", audiobridge->sampling_rate); break; default: + if(room_id_allocated) + g_free(room_id_str); janus_mutex_unlock(&rooms_mutex); JANUS_LOG(LOG_ERR, "Unsupported sampling rate %"SCNu32"...\n", audiobridge->sampling_rate); error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR; g_snprintf(error_cause, 512, "We currently only support 16kHz (wideband) as a sampling rate for audio rooms, %"SCNu32" TBD...", audiobridge->sampling_rate); goto prepare_response; } + audiobridge->room_ssrc = janus_random_uint32(); audiobridge->record = FALSE; if(record && json_is_true(record)) audiobridge->record = TRUE; @@ -1965,16 +2053,18 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s audiobridge->rtp_udp_sock = -1; janus_mutex_init(&audiobridge->rtp_mutex); janus_refcount_init(&audiobridge->ref, janus_audiobridge_room_free); - g_hash_table_insert(rooms, janus_uint64_dup(audiobridge->room_id), audiobridge); - JANUS_LOG(LOG_VERB, "Created audiobridge: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n", - audiobridge->room_id, audiobridge->room_name, + g_hash_table_insert(rooms, + string_ids ? (gpointer)g_strdup(audiobridge->room_id_str) : (gpointer)janus_uint64_dup(audiobridge->room_id), + audiobridge); + JANUS_LOG(LOG_VERB, "Created AudioBridge: %s (%s, %s, secret: %s, pin: %s)\n", + audiobridge->room_id_str, audiobridge->room_name, audiobridge->is_private ? "private" : "public", audiobridge->room_secret ? audiobridge->room_secret : "no secret", audiobridge->room_pin ? audiobridge->room_pin : "no pin"); /* We need a thread for the mix */ GError *error = NULL; char tname[16]; - g_snprintf(tname, sizeof(tname), "mixer %"SCNu64, audiobridge->room_id); + g_snprintf(tname, sizeof(tname), "mixer %s", audiobridge->room_id_str); janus_refcount_increase(&audiobridge->ref); audiobridge->thread = g_thread_try_new(tname, &janus_audiobridge_mixer_thread, audiobridge, &error); if(error != NULL) { @@ -1982,18 +2072,20 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s error_code = JANUS_AUDIOBRIDGE_ERROR_UNKNOWN_ERROR; g_snprintf(error_cause, 512, "Got error %d (%s) trying to launch the mixer thread", error->code, error->message ? error->message : "??"); janus_refcount_decrease(&audiobridge->ref); - g_hash_table_remove(rooms, &audiobridge->room_id); + g_hash_table_remove(rooms, string_ids ? (gpointer)audiobridge->room_id_str : (gpointer)&audiobridge->room_id); janus_mutex_unlock(&rooms_mutex); + if(room_id_allocated) + g_free(room_id_str); goto prepare_response; } if(save) { /* This room is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Saving room %"SCNu64" permanently in config file\n", audiobridge->room_id); + JANUS_LOG(LOG_VERB, "Saving room %s permanently in config file\n", audiobridge->room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ], value[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, audiobridge->room_id); + g_snprintf(cat, BUFSIZ, "room-%s", audiobridge->room_id_str); janus_config_category *c = janus_config_get_create(config, NULL, janus_config_type_category, cat); /* Now for the values */ janus_config_add(config, c, janus_config_item_create("description", audiobridge->room_name)); @@ -2030,22 +2122,37 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s /* Send info back */ response = json_object(); json_object_set_new(response, "audiobridge", json_string("created")); - json_object_set_new(response, "room", json_integer(audiobridge->room_id)); + json_object_set_new(response, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); json_object_set_new(response, "permanent", save ? json_true() : json_false()); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("created")); - json_object_set_new(info, "room", json_integer(audiobridge->room_id)); + json_object_set_new(info, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); gateway->notify_event(&janus_audiobridge_plugin, session ? session->handle : NULL, info); } + if(room_id_allocated) + g_free(room_id_str); janus_mutex_unlock(&rooms_mutex); goto prepare_response; } else if(!strcasecmp(request_text, "edit")) { - JANUS_LOG(LOG_VERB, "Attempt to edit an existing audiobridge room\n"); + JANUS_LOG(LOG_VERB, "Attempt to edit an existing AudioBridge room\n"); JANUS_VALIDATE_JSON_OBJECT(root, edit_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; /* We only allow for a limited set of properties to be edited */ @@ -2062,14 +2169,23 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s g_snprintf(error_cause, 512, "No configuration file, can't edit room permanently"); goto prepare_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } janus_mutex_lock(&audiobridge->mutex); @@ -2105,11 +2221,11 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s if(save) { /* This change is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Modifying room %"SCNu64" permanently in config file\n", room_id); + JANUS_LOG(LOG_VERB, "Modifying room %s permanently in config file\n", room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ], value[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, room_id); + g_snprintf(cat, BUFSIZ, "room-%s", room_id_str); /* Remove the old category first */ janus_config_remove(config, NULL, cat); /* Now write the room details again */ @@ -2148,13 +2264,14 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s /* Prepare response/notification */ response = json_object(); json_object_set_new(response, "audiobridge", json_string("edited")); - json_object_set_new(response, "room", json_integer(audiobridge->room_id)); + json_object_set_new(response, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); json_object_set_new(response, "permanent", save ? json_true() : json_false()); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("edited")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); gateway->notify_event(&janus_audiobridge_plugin, session ? session->handle : NULL, info); } janus_mutex_unlock(&audiobridge->mutex); @@ -2163,10 +2280,21 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s JANUS_LOG(LOG_VERB, "Audiobridge room edited\n"); goto prepare_response; } else if(!strcasecmp(request_text, "destroy")) { - JANUS_LOG(LOG_VERB, "Attempt to destroy an existing audiobridge room\n"); + JANUS_LOG(LOG_VERB, "Attempt to destroy an existing AudioBridge room\n"); JANUS_VALIDATE_JSON_OBJECT(root, destroy_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); @@ -2178,14 +2306,23 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s g_snprintf(error_cause, 512, "No configuration file, can't destroy room permanently"); goto prepare_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } janus_mutex_lock(&audiobridge->mutex); @@ -2199,15 +2336,15 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s } /* Remove room */ janus_refcount_increase(&audiobridge->ref); - g_hash_table_remove(rooms, &room_id); + g_hash_table_remove(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(save) { /* This change is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Destroying room %"SCNu64" permanently in config file\n", room_id); + JANUS_LOG(LOG_VERB, "Destroying room %s permanently in config file\n", room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, room_id); + g_snprintf(cat, BUFSIZ, "room-%s", room_id_str); janus_config_remove(config, NULL, cat); /* Save modified configuration */ if(janus_config_save(config, config_folder, JANUS_AUDIOBRIDGE_PACKAGE) < 0) @@ -2217,7 +2354,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s /* Prepare response/notification */ json_t *destroyed = json_object(); json_object_set_new(destroyed, "audiobridge", json_string("destroyed")); - json_object_set_new(destroyed, "room", json_integer(room_id)); + json_object_set_new(destroyed, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); /* Notify all participants that the fun is over, and that they'll be kicked */ JANUS_LOG(LOG_VERB, "Notifying all participants\n"); GHashTableIter iter; @@ -2257,7 +2394,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("destroyed")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); gateway->notify_event(&janus_audiobridge_plugin, session ? session->handle : NULL, info); } janus_mutex_unlock(&audiobridge->mutex); @@ -2266,7 +2403,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s /* Done */ response = json_object(); json_object_set_new(response, "audiobridge", json_string("destroyed")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "permanent", save ? json_true() : json_false()); JANUS_LOG(LOG_VERB, "Audiobridge room destroyed\n"); goto prepare_response; @@ -2291,7 +2428,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s continue; } json_t *rl = json_object(); - json_object_set_new(rl, "room", json_integer(room->room_id)); + json_object_set_new(rl, "room", string_ids ? json_string(room->room_id_str) : json_integer(room->room_id)); json_object_set_new(rl, "description", json_string(room->room_name)); json_object_set_new(rl, "sampling_rate", json_integer(room->sampling_rate)); json_object_set_new(rl, "pin_required", room->room_pin ? json_true() : json_false()); @@ -2307,26 +2444,51 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s goto prepare_response; } else if(!strcasecmp(request_text, "exists")) { /* Check whether a given room exists or not, returns true/false */ - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - gboolean room_exists = g_hash_table_contains(rooms, &room_id); + gboolean room_exists = g_hash_table_contains(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); janus_mutex_unlock(&rooms_mutex); response = json_object(); json_object_set_new(response, "audiobridge", json_string("success")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "exists", room_exists ? json_true() : json_false()); goto prepare_response; } else if(!strcasecmp(request_text, "allowed")) { - JANUS_LOG(LOG_VERB, "Attempt to edit the list of allowed participants in an existing audiobridge room\n"); + JANUS_LOG(LOG_VERB, "Attempt to edit the list of allowed participants in an existing AudioBridge room\n"); JANUS_VALIDATE_JSON_OBJECT(root, allowed_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *action = json_object_get(root, "action"); @@ -2340,14 +2502,23 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s g_snprintf(error_cause, 512, "Unsupported action '%s' (allowed)", action_text); goto prepare_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } janus_mutex_lock(&audiobridge->mutex); @@ -2360,10 +2531,10 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s goto prepare_response; } if(!strcasecmp(action_text, "enable")) { - JANUS_LOG(LOG_VERB, "Enabling the check on allowed authorization tokens for room %"SCNu64"\n", room_id); + JANUS_LOG(LOG_VERB, "Enabling the check on allowed authorization tokens for room %s\n", room_id_str); audiobridge->check_tokens = TRUE; } else if(!strcasecmp(action_text, "disable")) { - JANUS_LOG(LOG_VERB, "Disabling the check on allowed authorization tokens for room %"SCNu64" (free entry)\n", room_id); + JANUS_LOG(LOG_VERB, "Disabling the check on allowed authorization tokens for room %s (free entry)\n", room_id_str); audiobridge->check_tokens = FALSE; } else { gboolean add = !strcasecmp(action_text, "add"); @@ -2403,7 +2574,8 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s /* Prepare response */ response = json_object(); json_object_set_new(response, "audiobridge", json_string("success")); - json_object_set_new(response, "room", json_integer(audiobridge->room_id)); + json_object_set_new(response, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); json_t *list = json_array(); if(strcasecmp(action_text, "disable")) { if(g_hash_table_size(audiobridge->allowed) > 0) { @@ -2423,27 +2595,56 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s JANUS_LOG(LOG_VERB, "Audiobridge room allowed list updated\n"); goto prepare_response; } else if(!strcasecmp(request_text, "mute") || !strcasecmp(request_text, "unmute")) { - JANUS_LOG(LOG_VERB, "Attempt to mute a participant from an existing audiobridge room\n"); - JANUS_VALIDATE_JSON_OBJECT(root, mute_parameters, + JANUS_LOG(LOG_VERB, "Attempt to mute a participant from an existing AudioBridge room\n"); + JANUS_VALIDATE_JSON_OBJECT(root, secret_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, id_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); json_t *id = json_object_get(root, "id"); gboolean muted = (!strcasecmp(request_text, "mute")) ? TRUE : FALSE; - guint64 room_id = json_integer_value(room); - + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } - janus_refcount_increase(&audiobridge->ref); janus_mutex_lock(&audiobridge->mutex); janus_mutex_unlock(&rooms_mutex); @@ -2457,14 +2658,23 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s goto prepare_response; } - guint64 user_id = json_integer_value(id); - janus_audiobridge_participant *participant = g_hash_table_lookup(audiobridge->participants, &user_id); + guint64 user_id = 0; + char user_id_num[30], *user_id_str = NULL; + if(!string_ids) { + user_id = json_integer_value(id); + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; + } else { + user_id_str = (char *)json_string_value(id); + } + janus_audiobridge_participant *participant = g_hash_table_lookup(audiobridge->participants, + string_ids ? (gpointer)user_id_str : (gpointer)&user_id); if(participant == NULL) { janus_mutex_unlock(&audiobridge->mutex); janus_refcount_decrease(&audiobridge->ref); - JANUS_LOG(LOG_ERR, "No such user %"SCNu64" in room %"SCNu64"\n", user_id, room_id); + JANUS_LOG(LOG_ERR, "No such user %s in room %s\n", user_id_str, room_id_str); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_USER; - g_snprintf(error_cause, 512, "No such user %"SCNu64" in room %"SCNu64, user_id, room_id); + g_snprintf(error_cause, 512, "No such user %s in room %s", user_id_str, room_id_str); goto prepare_response; } @@ -2484,7 +2694,8 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s participant->muted = muted; if(participant->muted) { - JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %"SCNu64", user %"SCNu64")\n", participant->muted ? "true" : "false", participant->room->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %s, user %s)\n", + participant->muted ? "true" : "false", participant->room->room_id_str, participant->user_id_str); /* Clear the queued packets waiting to be handled */ janus_mutex_lock(&participant->qmutex); while(participant->inbuf) { @@ -2494,8 +2705,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s first = NULL; if(pkt == NULL) continue; - if(pkt->data) - g_free(pkt->data); + g_free(pkt->data); pkt->data = NULL; g_free(pkt); pkt = NULL; @@ -2506,7 +2716,8 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s if(audiobridge != NULL) { json_t *list = json_array(); json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(participant->user_id)); + json_object_set_new(pl, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); if(participant->display) json_object_set_new(pl, "display", json_string(participant->display)); json_object_set_new(pl, "setup", g_atomic_int_get(&participant->session->started) ? json_true() : json_false()); @@ -2514,14 +2725,15 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s json_array_append_new(list, pl); json_t *pub = json_object(); json_object_set_new(pub, "audiobridge", json_string("event")); - json_object_set_new(pub, "room", json_integer(participant->room->room_id)); + json_object_set_new(pub, "room", + string_ids ? json_string(participant->room->room_id_str) : json_integer(participant->room->room_id)); json_object_set_new(pub, "participants", list); GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, audiobridge->participants); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_audiobridge_participant *p = value; - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -2532,12 +2744,12 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string(request_text)); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "id", json_integer(user_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "id", string_ids ? json_string(user_id_str) : json_integer(user_id)); gateway->notify_event(&janus_audiobridge_plugin, session ? session->handle : NULL, info); } - JANUS_LOG(LOG_VERB, "Muted user %"SCNu64" from room %"SCNu64"\n", user_id, room_id); + JANUS_LOG(LOG_VERB, "Muted user %s from room %s\n", user_id_str, room_id_str); /* Prepare response */ response = json_object(); @@ -2548,22 +2760,53 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s janus_refcount_decrease(&audiobridge->ref); goto prepare_response; } else if(!strcasecmp(request_text, "kick")) { - JANUS_LOG(LOG_VERB, "Attempt to kick a participant from an existing audiobridge room\n"); - JANUS_VALIDATE_JSON_OBJECT(root, kick_parameters, + JANUS_LOG(LOG_VERB, "Attempt to kick a participant from an existing AudioBridge room\n"); + JANUS_VALIDATE_JSON_OBJECT(root, secret_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, id_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); json_t *id = json_object_get(root, "id"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } janus_refcount_increase(&audiobridge->ref); @@ -2577,27 +2820,36 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s janus_refcount_decrease(&audiobridge->ref); goto prepare_response; } - guint64 user_id = json_integer_value(id); - janus_audiobridge_participant *participant = g_hash_table_lookup(audiobridge->participants, &user_id); + guint64 user_id = 0; + char user_id_num[30], *user_id_str = NULL; + if(!string_ids) { + user_id = json_integer_value(id); + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; + } else { + user_id_str = (char *)json_string_value(id); + } + janus_audiobridge_participant *participant = g_hash_table_lookup(audiobridge->participants, + string_ids ? (gpointer)user_id_str : (gpointer)&user_id); if(participant == NULL) { janus_mutex_unlock(&audiobridge->mutex); janus_refcount_decrease(&audiobridge->ref); - JANUS_LOG(LOG_ERR, "No such user %"SCNu64" in room %"SCNu64"\n", user_id, room_id); + JANUS_LOG(LOG_ERR, "No such user %s in room %s\n", user_id_str, room_id_str); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_USER; - g_snprintf(error_cause, 512, "No such user %"SCNu64" in room %"SCNu64, user_id, room_id); + g_snprintf(error_cause, 512, "No such user %s in room %s", user_id_str, room_id_str); goto prepare_response; } /* Notify all participants about the kick */ json_t *event = json_object(); json_object_set_new(event, "audiobridge", json_string("event")); - json_object_set_new(event, "room", json_integer(room_id)); - json_object_set_new(event, "kicked", json_integer(user_id)); + json_object_set_new(event, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(event, "kicked", string_ids ? json_string(user_id_str) : json_integer(user_id)); GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, audiobridge->participants); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_audiobridge_participant *p = value; - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -2606,14 +2858,14 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("kicked")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "id", json_integer(user_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "id", string_ids ? json_string(user_id_str) : json_integer(user_id)); gateway->notify_event(&janus_audiobridge_plugin, session ? session->handle : NULL, info); } /* Tell the core to tear down the PeerConnection, hangup_media will do the rest */ if(participant && participant->session) gateway->close_pc(participant->session->handle); - JANUS_LOG(LOG_VERB, "Kicked user %"SCNu64" from room %"SCNu64"\n", user_id, room_id); + JANUS_LOG(LOG_VERB, "Kicked user %s from room %s\n", user_id_str, room_id_str); /* Prepare response */ response = json_object(); json_object_set_new(response, "audiobridge", json_string("success")); @@ -2623,20 +2875,35 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s goto prepare_response; } else if(!strcasecmp(request_text, "listparticipants")) { /* List all participants in a room */ - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); - if(audiobridge == NULL || g_atomic_int_get(&audiobridge->destroyed)) { + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); + if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } janus_refcount_increase(&audiobridge->ref); @@ -2648,7 +2915,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s while (!g_atomic_int_get(&audiobridge->destroyed) && g_hash_table_iter_next(&iter, NULL, &value)) { janus_audiobridge_participant *p = value; json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(p->user_id)); + json_object_set_new(pl, "id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if(p->display) json_object_set_new(pl, "display", json_string(p->display)); json_object_set_new(pl, "setup", g_atomic_int_get(&p->session->started) ? json_true() : json_false()); @@ -2661,7 +2928,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s janus_mutex_unlock(&rooms_mutex); response = json_object(); json_object_set_new(response, "audiobridge", json_string("participants")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "participants", list); goto prepare_response; } else if(!strcasecmp(request_text, "resetdecoder")) { @@ -2681,6 +2948,17 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s JANUS_VALIDATE_JSON_OBJECT(root, rtp_forward_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; if(lock_rtpfwd && admin_key != NULL) { @@ -2696,7 +2974,16 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s goto prepare_response; } /* Parse arguments */ - guint64 room_id = json_integer_value(json_object_get(root, "room")); + json_t *room = json_object_get(root, "room"); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } guint32 ssrc_value = 0; json_t *ssrc = json_object_get(root, "ssrc"); if(ssrc) @@ -2779,12 +3066,13 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s } /* Update room */ janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s", room_id_str); goto prepare_response; } /* A secret may be required for this action */ @@ -2798,9 +3086,9 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s if(audiobridge->destroyed) { janus_mutex_unlock(&audiobridge->mutex); janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } @@ -2828,7 +3116,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s /* Done, prepare response */ response = json_object(); json_object_set_new(response, "audiobridge", json_string("success")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "stream_id", json_integer(stream_id)); json_object_set_new(response, "host", json_string(host)); json_object_set_new(response, "port", json_integer(port)); @@ -2837,6 +3125,17 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s JANUS_VALIDATE_JSON_OBJECT(root, stop_rtp_forward_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; if(lock_rtpfwd && admin_key != NULL) { @@ -2852,17 +3151,27 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s goto prepare_response; } /* Parse parameters */ - guint64 room_id = json_integer_value(json_object_get(root, "room")); + json_t *room = json_object_get(root, "room"); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } guint32 stream_id = json_integer_value(json_object_get(root, "stream_id")); /* Update room */ /* Update room */ janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } /* A secret may be required for this action */ @@ -2876,9 +3185,9 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s if(audiobridge->destroyed) { janus_mutex_unlock(&audiobridge->mutex); janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } janus_mutex_lock(&audiobridge->rtp_mutex); @@ -2888,31 +3197,46 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s janus_mutex_unlock(&rooms_mutex); response = json_object(); json_object_set_new(response, "audiobridge", json_string("success")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "stream_id", json_integer(stream_id)); goto prepare_response; } else if(!strcasecmp(request_text, "listforwarders")) { /* List all forwarders in a room */ - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(audiobridge == NULL) { - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); - error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); janus_mutex_unlock(&rooms_mutex); + error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto prepare_response; } if(audiobridge->destroyed) { - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); janus_mutex_unlock(&rooms_mutex); goto prepare_response; } @@ -2954,7 +3278,7 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s janus_mutex_unlock(&rooms_mutex); response = json_object(); json_object_set_new(response, "audiobridge", json_string("forwarders")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "rtp_forwarders", list); goto prepare_response; } else { @@ -3153,7 +3477,8 @@ void janus_audiobridge_setup_media(janus_plugin_session *handle) { janus_mutex_lock(&audiobridge->mutex); json_t *list = json_array(); json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(participant->user_id)); + json_object_set_new(pl, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); if(participant->display) json_object_set_new(pl, "display", json_string(participant->display)); json_object_set_new(pl, "setup", json_true()); @@ -3161,7 +3486,8 @@ void janus_audiobridge_setup_media(janus_plugin_session *handle) { json_array_append_new(list, pl); json_t *pub = json_object(); json_object_set_new(pub, "audiobridge", json_string("event")); - json_object_set_new(pub, "room", json_integer(participant->room->room_id)); + json_object_set_new(pub, "room", + string_ids ? json_string(participant->room->room_id_str) : json_integer(participant->room->room_id)); json_object_set_new(pub, "participants", list); GHashTableIter iter; gpointer value; @@ -3171,7 +3497,7 @@ void janus_audiobridge_setup_media(janus_plugin_session *handle) { if(p == participant) { continue; /* Skip the new participant itself */ } - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -3276,8 +3602,11 @@ void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, janus_plugin_r janus_mutex_lock(&participant->room->mutex); json_t *event = json_object(); json_object_set_new(event, "audiobridge", json_string(participant->talking ? "talking" : "stopped-talking")); - json_object_set_new(event, "room", json_integer(participant->room ? participant->room->room_id : 0)); - json_object_set_new(event, "id", json_integer(participant->user_id)); + json_object_set_new(event, "room", + string_ids ? json_string(participant->room ? participant->room->room_id_str : NULL) : + json_integer(participant->room ? participant->room->room_id : 0)); + json_object_set_new(event, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); janus_audiobridge_notify_participants(participant, event); json_decref(event); janus_mutex_unlock(&participant->room->mutex); @@ -3285,8 +3614,11 @@ void janus_audiobridge_incoming_rtp(janus_plugin_session *handle, janus_plugin_r if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "audiobridge", json_string(participant->talking ? "talking" : "stopped-talking")); - json_object_set_new(info, "room", json_integer(participant->room ? participant->room->room_id : 0)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", + string_ids ? json_string(participant->room ? participant->room->room_id_str : NULL) : + json_integer(participant->room ? participant->room->room_id : 0)); + json_object_set_new(info, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); gateway->notify_event(&janus_audiobridge_plugin, session->handle, info); } } @@ -3471,9 +3803,12 @@ static void janus_audiobridge_hangup_media_internal(janus_plugin_session *handle janus_mutex_lock(&audiobridge->mutex); json_t *event = json_object(); json_object_set_new(event, "audiobridge", json_string("event")); - json_object_set_new(event, "room", json_integer(audiobridge->room_id)); - json_object_set_new(event, "leaving", json_integer(participant->user_id)); - removed = g_hash_table_remove(audiobridge->participants, &participant->user_id); + json_object_set_new(event, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); + json_object_set_new(event, "leaving", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); + removed = g_hash_table_remove(audiobridge->participants, + string_ids ? (gpointer)participant->user_id_str : (gpointer)&participant->user_id); GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, audiobridge->participants); @@ -3482,7 +3817,7 @@ static void janus_audiobridge_hangup_media_internal(janus_plugin_session *handle if(p == participant) { continue; /* Skip the leaving participant itself */ } - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -3491,8 +3826,10 @@ static void janus_audiobridge_hangup_media_internal(janus_plugin_session *handle if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("left")); - json_object_set_new(info, "room", json_integer(audiobridge->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); + json_object_set_new(info, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(info, "display", json_string(participant->display)); gateway->notify_event(&janus_audiobridge_plugin, session->handle, info); } @@ -3613,17 +3950,48 @@ static void *janus_audiobridge_handler(void *data) { JANUS_VALIDATE_JSON_OBJECT(root, join_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto error; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto error; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, idopt_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, idstropt_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto error; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); - if(audiobridge == NULL || g_atomic_int_get(&audiobridge->destroyed)) { + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); + if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto error; } janus_refcount_increase(&audiobridge->ref); @@ -3666,30 +4034,56 @@ static void *janus_audiobridge_handler(void *data) { goto error; } guint64 user_id = 0; + char user_id_num[30], *user_id_str = NULL; + gboolean user_id_allocated = FALSE; json_t *id = json_object_get(root, "id"); if(id) { - user_id = json_integer_value(id); - if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) { + if(!string_ids) { + user_id = json_integer_value(id); + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; + } else { + user_id_str = (char *)json_string_value(id); + } + if(g_hash_table_lookup(audiobridge->participants, + string_ids ? (gpointer)user_id_str : (gpointer)&user_id) != NULL) { /* User ID already taken */ janus_mutex_unlock(&audiobridge->mutex); janus_refcount_decrease(&audiobridge->ref); - JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id); error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS; - g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id); + JANUS_LOG(LOG_ERR, "User ID %s already exists\n", user_id_str); + g_snprintf(error_cause, 512, "User ID %s already exists", user_id_str); goto error; } } - if(user_id == 0) { - /* Generate a random ID */ - while(user_id == 0) { - user_id = janus_random_uint64(); - if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) { - /* User ID already taken, try another one */ - user_id = 0; + if(!string_ids) { + if(user_id == 0) { + /* Generate a random ID */ + while(user_id == 0) { + user_id = janus_random_uint64(); + if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) { + /* User ID already taken, try another one */ + user_id = 0; + } } + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; } + JANUS_LOG(LOG_VERB, " -- Participant ID: %"SCNu64"\n", user_id); + } else { + if(user_id_str == NULL) { + /* Generate a random ID */ + while(user_id_str == NULL) { + user_id_str = janus_random_uuid(); + if(g_hash_table_lookup(audiobridge->participants, user_id_str) != NULL) { + /* User ID already taken, try another one */ + g_clear_pointer(&user_id_str, g_free); + } + } + user_id_allocated = TRUE; + } + JANUS_LOG(LOG_VERB, " -- Participant ID: %s\n", user_id_str); } - JANUS_LOG(LOG_VERB, " -- Participant ID: %"SCNu64"\n", user_id); if(participant == NULL) { participant = g_malloc0(sizeof(janus_audiobridge_participant)); janus_refcount_init(&participant->ref, janus_audiobridge_participant_free); @@ -3713,6 +4107,7 @@ static void *janus_audiobridge_handler(void *data) { participant->session = session; participant->room = audiobridge; participant->user_id = user_id; + participant->user_id_str = user_id_str ? g_strdup(user_id_str) : NULL; g_free(participant->display); participant->display = display_text ? g_strdup(display_text) : NULL; participant->muted = muted ? json_is_true(muted) : FALSE; /* By default, everyone's unmuted when joining */ @@ -3735,6 +4130,8 @@ static void *janus_audiobridge_handler(void *data) { if(participant->encoder == NULL) { participant->encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error); if(error != OPUS_OK) { + if(user_id_allocated) + g_free(user_id_str); janus_mutex_unlock(&audiobridge->mutex); janus_refcount_decrease(&audiobridge->ref); g_free(participant->display); @@ -3767,6 +4164,8 @@ static void *janus_audiobridge_handler(void *data) { error = 0; participant->decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error); if(error != OPUS_OK) { + if(user_id_allocated) + g_free(user_id_str); janus_mutex_unlock(&audiobridge->mutex); janus_refcount_decrease(&audiobridge->ref); g_free(participant->display); @@ -3788,8 +4187,8 @@ static void *janus_audiobridge_handler(void *data) { if(participant->thread == NULL) { GError *error = NULL; char roomtrunc[5], parttrunc[5]; - g_snprintf(roomtrunc, sizeof(roomtrunc), "%"SCNu64, audiobridge->room_id); - g_snprintf(parttrunc, sizeof(parttrunc), "%"SCNu64, participant->user_id); + g_snprintf(roomtrunc, sizeof(roomtrunc), "%s", audiobridge->room_id_str); + g_snprintf(parttrunc, sizeof(parttrunc), "%s", participant->user_id_str); char tname[16]; g_snprintf(tname, sizeof(tname), "mixer %s %s", roomtrunc, parttrunc); janus_refcount_increase(&session->ref); @@ -3806,14 +4205,17 @@ static void *janus_audiobridge_handler(void *data) { /* Done */ session->participant = participant; janus_refcount_increase(&participant->ref); - g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant); + g_hash_table_insert(audiobridge->participants, + string_ids ? (gpointer)g_strdup(participant->user_id_str) : (gpointer)janus_uint64_dup(participant->user_id), + participant); /* Notify the other participants */ json_t *newuser = json_object(); json_object_set_new(newuser, "audiobridge", json_string("joined")); - json_object_set_new(newuser, "room", json_integer(room_id)); + json_object_set_new(newuser, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_t *newuserlist = json_array(); json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(participant->user_id)); + json_object_set_new(pl, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); if(participant->display) json_object_set_new(pl, "display", json_string(participant->display)); /* Clarify we're still waiting for the user to negotiate a PeerConnection */ @@ -3829,7 +4231,7 @@ static void *janus_audiobridge_handler(void *data) { if(p == participant) { continue; } - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -3843,7 +4245,7 @@ static void *janus_audiobridge_handler(void *data) { continue; } json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(p->user_id)); + json_object_set_new(pl, "id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if(p->display) json_object_set_new(pl, "display", json_string(p->display)); json_object_set_new(pl, "setup", g_atomic_int_get(&p->session->started) ? json_true() : json_false()); @@ -3855,20 +4257,22 @@ static void *janus_audiobridge_handler(void *data) { janus_mutex_unlock(&audiobridge->mutex); event = json_object(); json_object_set_new(event, "audiobridge", json_string("joined")); - json_object_set_new(event, "room", json_integer(room_id)); - json_object_set_new(event, "id", json_integer(user_id)); + json_object_set_new(event, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(event, "id", string_ids ? json_string(user_id_str) : json_integer(user_id)); json_object_set_new(event, "participants", list); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("joined")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "id", json_integer(user_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "id", string_ids ? json_string(user_id_str) : json_integer(user_id)); json_object_set_new(info, "display", json_string(participant->display)); json_object_set_new(info, "setup", g_atomic_int_get(&participant->session->started) ? json_true() : json_false()); json_object_set_new(info, "muted", participant->muted ? json_true() : json_false()); gateway->notify_event(&janus_audiobridge_plugin, session->handle, info); } + if(user_id_allocated) + g_free(user_id_str); } else if(!strcasecmp(request_text, "configure")) { /* Handle this participant */ janus_audiobridge_participant *participant = (janus_audiobridge_participant *)session->participant; @@ -3908,7 +4312,8 @@ static void *janus_audiobridge_handler(void *data) { if(muted || display) { if(muted) { participant->muted = json_is_true(muted); - JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %"SCNu64", user %"SCNu64")\n", participant->muted ? "true" : "false", participant->room->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting muted property: %s (room %s, user %s)\n", + participant->muted ? "true" : "false", participant->room->room_id_str, participant->user_id_str); if(participant->muted) { /* Clear the queued packets waiting to be handled */ janus_mutex_lock(&participant->qmutex); @@ -3933,7 +4338,8 @@ static void *janus_audiobridge_handler(void *data) { char *new_display = g_strdup(json_string_value(display)); participant->display = new_display; g_free(old_display); - JANUS_LOG(LOG_VERB, "Setting display property: %s (room %"SCNu64", user %"SCNu64")\n", participant->display, participant->room->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting display property: %s (room %s, user %s)\n", + participant->display, participant->room->room_id_str, participant->user_id_str); } /* Notify all other participants about the mute/unmute */ janus_mutex_lock(&rooms_mutex); @@ -3942,7 +4348,8 @@ static void *janus_audiobridge_handler(void *data) { janus_mutex_lock(&audiobridge->mutex); json_t *list = json_array(); json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(participant->user_id)); + json_object_set_new(pl, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); if(participant->display) json_object_set_new(pl, "display", json_string(participant->display)); json_object_set_new(pl, "setup", g_atomic_int_get(&participant->session->started) ? json_true() : json_false()); @@ -3950,7 +4357,8 @@ static void *janus_audiobridge_handler(void *data) { json_array_append_new(list, pl); json_t *pub = json_object(); json_object_set_new(pub, "audiobridge", json_string("event")); - json_object_set_new(pub, "room", json_integer(participant->room->room_id)); + json_object_set_new(pub, "room", + string_ids ? json_string(participant->room->room_id_str) : json_integer(participant->room->room_id)); json_object_set_new(pub, "participants", list); GHashTableIter iter; gpointer value; @@ -3960,7 +4368,8 @@ static void *janus_audiobridge_handler(void *data) { if(p == participant) { continue; /* Skip the new participant itself */ } - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", + p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, pub, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -3974,11 +4383,11 @@ static void *janus_audiobridge_handler(void *data) { if(json_is_true(record)) { /* Start recording (ignore if recording already) */ if(participant->arc != NULL) { - JANUS_LOG(LOG_WARN, "Already recording participant's audio (room %"SCNu64", user %"SCNu64")\n", - participant->room->room_id, participant->user_id); + JANUS_LOG(LOG_WARN, "Already recording participant's audio (room %s, user %s)\n", + participant->room->room_id_str, participant->user_id_str); } else { - JANUS_LOG(LOG_INFO, "Starting recording of participant's audio (room %"SCNu64", user %"SCNu64")\n", - participant->room->room_id, participant->user_id); + JANUS_LOG(LOG_INFO, "Starting recording of participant's audio (room %s, user %s)\n", + participant->room->room_id_str, participant->user_id_str); char filename[255]; gint64 now = janus_get_real_time(); memset(filename, 0, 255); @@ -3993,8 +4402,8 @@ static void *janus_audiobridge_handler(void *data) { } } else { /* Build a filename */ - g_snprintf(filename, 255, "audiobridge-%"SCNu64"-%"SCNu64"-%"SCNi64"-audio", - participant->room->room_id, participant->user_id, now); + g_snprintf(filename, 255, "audiobridge-%s-%s-%"SCNi64"-audio", + participant->room->room_id_str, participant->user_id_str, now); participant->arc = janus_recorder_create(NULL, "opus", filename); if(participant->arc == NULL) { /* FIXME We should notify the fact the recorder could not be created */ @@ -4021,8 +4430,10 @@ static void *janus_audiobridge_handler(void *data) { janus_audiobridge_room *audiobridge = participant->room; json_t *info = json_object(); json_object_set_new(info, "event", json_string("configured")); - json_object_set_new(info, "room", json_integer(audiobridge->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); + json_object_set_new(info, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(info, "display", json_string(participant->display)); json_object_set_new(info, "muted", participant->muted ? json_true() : json_false()); json_object_set_new(info, "quality", json_integer(participant->opus_complexity)); @@ -4040,25 +4451,46 @@ static void *janus_audiobridge_handler(void *data) { JANUS_VALIDATE_JSON_OBJECT(root, join_parameters, error_code, error_cause, TRUE, JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto error; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto error; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); /* Is this the same room we're in? */ - if(participant->room && participant->room->room_id == room_id) { + if(participant->room && ((!string_ids && participant->room->room_id == room_id) || + (string_ids && participant->room->room_id_str && !strcmp(participant->room->room_id_str, room_id_str)))) { janus_mutex_unlock(&rooms_mutex); JANUS_LOG(LOG_ERR, "Already in this room\n"); error_code = JANUS_AUDIOBRIDGE_ERROR_ALREADY_JOINED; g_snprintf(error_cause, 512, "Already in this room"); goto error; } - janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, &room_id); - if(audiobridge == NULL || g_atomic_int_get(&audiobridge->destroyed)) { + janus_audiobridge_room *audiobridge = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); + if(audiobridge == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto error; } janus_refcount_increase(&audiobridge->ref); @@ -4103,31 +4535,56 @@ static void *janus_audiobridge_handler(void *data) { goto error; } guint64 user_id = 0; + char user_id_num[30], *user_id_str = NULL; + gboolean user_id_allocated = FALSE; json_t *id = json_object_get(root, "id"); if(id) { - user_id = json_integer_value(id); - if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) { + if(!string_ids) { + user_id = json_integer_value(id); + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; + } else { + user_id_str = (char *)json_string_value(id); + } + if(g_hash_table_lookup(audiobridge->participants, + string_ids ? (gpointer)user_id_str : (gpointer)&user_id) != NULL) { + /* User ID already taken */ janus_mutex_unlock(&audiobridge->mutex); janus_refcount_decrease(&audiobridge->ref); - /* User ID already taken */ - janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id); error_code = JANUS_AUDIOBRIDGE_ERROR_ID_EXISTS; - g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id); + JANUS_LOG(LOG_ERR, "User ID %s already exists\n", user_id_str); + g_snprintf(error_cause, 512, "User ID %s already exists", user_id_str); goto error; } } - if(user_id == 0) { - /* Generate a random ID */ - while(user_id == 0) { - user_id = janus_random_uint64(); - if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) { - /* User ID already taken, try another one */ - user_id = 0; + if(!string_ids) { + if(user_id == 0) { + /* Generate a random ID */ + while(user_id == 0) { + user_id = janus_random_uint64(); + if(g_hash_table_lookup(audiobridge->participants, &user_id) != NULL) { + /* User ID already taken, try another one */ + user_id = 0; + } + } + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; + } + JANUS_LOG(LOG_VERB, " -- Participant ID in new room %"SCNu64": %"SCNu64"\n", room_id, user_id); + } else { + if(user_id_str == NULL) { + /* Generate a random ID */ + while(user_id_str == NULL) { + user_id_str = janus_random_uuid(); + if(g_hash_table_lookup(audiobridge->participants, user_id_str) != NULL) { + /* User ID already taken, try another one */ + g_clear_pointer(&user_id_str, g_free); + } } + user_id_allocated = TRUE; } + JANUS_LOG(LOG_VERB, " -- Participant ID in new room %s: %s\n", room_id_str, user_id_str); } - JANUS_LOG(LOG_VERB, " -- Participant ID in new room %"SCNu64": %"SCNu64"\n", room_id, user_id); participant->prebuffering = TRUE; participant->audio_active_packets = 0; participant->audio_dBov_sum = 0; @@ -4137,12 +4594,15 @@ static void *janus_audiobridge_handler(void *data) { /* Leave the old room first... */ janus_refcount_increase(&participant->ref); janus_mutex_lock(&old_audiobridge->mutex); - g_hash_table_remove(old_audiobridge->participants, &participant->user_id); + g_hash_table_remove(old_audiobridge->participants, + string_ids ? (gpointer)participant->user_id_str : (gpointer)&participant->user_id); if(old_audiobridge->sampling_rate != audiobridge->sampling_rate) { /* Create a new one that takes into account the sampling rate we want now */ int error = 0; OpusEncoder *new_encoder = opus_encoder_create(audiobridge->sampling_rate, 1, OPUS_APPLICATION_VOIP, &error); if(error != OPUS_OK) { + if(user_id_allocated) + g_free(user_id_str); janus_refcount_decrease(&audiobridge->ref); if(new_encoder) opus_encoder_destroy(new_encoder); @@ -4151,7 +4611,9 @@ static void *janus_audiobridge_handler(void *data) { error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR; g_snprintf(error_cause, 512, "Error creating Opus decoder"); /* Join the old room again... */ - g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant); + g_hash_table_insert(audiobridge->participants, + string_ids ? (gpointer)g_strdup(participant->user_id_str) : (gpointer)janus_uint64_dup(participant->user_id), + participant); janus_mutex_unlock(&old_audiobridge->mutex); janus_mutex_unlock(&audiobridge->mutex); janus_mutex_unlock(&rooms_mutex); @@ -4178,6 +4640,8 @@ static void *janus_audiobridge_handler(void *data) { error = 0; OpusDecoder *new_decoder = opus_decoder_create(audiobridge->sampling_rate, 1, &error); if(error != OPUS_OK) { + if(user_id_allocated) + g_free(user_id_str); janus_refcount_decrease(&audiobridge->ref); if(new_encoder) opus_encoder_destroy(new_encoder); @@ -4189,7 +4653,9 @@ static void *janus_audiobridge_handler(void *data) { error_code = JANUS_AUDIOBRIDGE_ERROR_LIBOPUS_ERROR; g_snprintf(error_cause, 512, "Error creating Opus decoder"); /* Join the old room again... */ - g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant); + g_hash_table_insert(audiobridge->participants, + string_ids ? (gpointer)g_strdup(participant->user_id_str) : (gpointer)janus_uint64_dup(participant->user_id), + participant); janus_mutex_unlock(&old_audiobridge->mutex); janus_mutex_unlock(&audiobridge->mutex); janus_mutex_unlock(&rooms_mutex); @@ -4207,8 +4673,10 @@ static void *janus_audiobridge_handler(void *data) { /* Everything looks fine, start by telling the folks in the old room this participant is going away */ event = json_object(); json_object_set_new(event, "audiobridge", json_string("event")); - json_object_set_new(event, "room", json_integer(old_audiobridge->room_id)); - json_object_set_new(event, "leaving", json_integer(participant->user_id)); + json_object_set_new(event, "room", + string_ids ? json_string(old_audiobridge->room_id_str) : json_integer(old_audiobridge->room_id)); + json_object_set_new(event, "leaving", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, old_audiobridge->participants); @@ -4217,7 +4685,7 @@ static void *janus_audiobridge_handler(void *data) { if(p == participant) { continue; /* Skip the new participant itself */ } - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -4226,8 +4694,10 @@ static void *janus_audiobridge_handler(void *data) { if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("left")); - json_object_set_new(info, "room", json_integer(old_audiobridge->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", + string_ids ? json_string(old_audiobridge->room_id_str) : json_integer(old_audiobridge->room_id)); + json_object_set_new(info, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(info, "display", json_string(participant->display)); gateway->notify_event(&janus_audiobridge_plugin, session->handle, info); } @@ -4239,6 +4709,8 @@ static void *janus_audiobridge_handler(void *data) { janus_refcount_decrease(&old_audiobridge->ref); /* Done, join the new one */ participant->user_id = user_id; + g_free(participant->user_id_str); + participant->user_id_str = user_id_str ? g_strdup(user_id_str) : NULL; g_free(participant->display); participant->display = display_text ? g_strdup(display_text) : NULL; participant->room = audiobridge; @@ -4252,14 +4724,18 @@ static void *janus_audiobridge_handler(void *data) { if(participant->encoder) opus_encoder_ctl(participant->encoder, OPUS_SET_COMPLEXITY(participant->opus_complexity)); } - g_hash_table_insert(audiobridge->participants, janus_uint64_dup(participant->user_id), participant); + g_hash_table_insert(audiobridge->participants, + string_ids ? (gpointer)g_strdup(participant->user_id_str) : (gpointer)janus_uint64_dup(participant->user_id), + participant); /* Notify the other participants */ json_t *newuser = json_object(); json_object_set_new(newuser, "audiobridge", json_string("joined")); - json_object_set_new(newuser, "room", json_integer(audiobridge->room_id)); + json_object_set_new(newuser, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); json_t *newuserlist = json_array(); json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(participant->user_id)); + json_object_set_new(pl, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); if(participant->display) json_object_set_new(pl, "display", json_string(participant->display)); json_object_set_new(pl, "setup", g_atomic_int_get(&participant->session->started) ? json_true() : json_false()); @@ -4272,7 +4748,7 @@ static void *janus_audiobridge_handler(void *data) { if(p == participant) { continue; } - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, newuser, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -4286,7 +4762,7 @@ static void *janus_audiobridge_handler(void *data) { continue; } json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(p->user_id)); + json_object_set_new(pl, "id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if(p->display) json_object_set_new(pl, "display", json_string(p->display)); json_object_set_new(pl, "setup", g_atomic_int_get(&p->session->started) ? json_true() : json_false()); @@ -4297,19 +4773,24 @@ static void *janus_audiobridge_handler(void *data) { } event = json_object(); json_object_set_new(event, "audiobridge", json_string("roomchanged")); - json_object_set_new(event, "room", json_integer(audiobridge->room_id)); - json_object_set_new(event, "id", json_integer(user_id)); + json_object_set_new(event, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); + json_object_set_new(event, "id", string_ids ? json_string(user_id_str) : json_integer(user_id)); json_object_set_new(event, "participants", list); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("joined")); - json_object_set_new(info, "room", json_integer(audiobridge->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); + json_object_set_new(info, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(info, "display", json_string(participant->display)); json_object_set_new(info, "muted", participant->muted ? json_true() : json_false()); gateway->notify_event(&janus_audiobridge_plugin, session->handle, info); } + if(user_id_allocated) + g_free(user_id_str); janus_mutex_unlock(&audiobridge->mutex); janus_mutex_unlock(&rooms_mutex); } else if(!strcasecmp(request_text, "leave")) { @@ -4330,8 +4811,10 @@ static void *janus_audiobridge_handler(void *data) { janus_mutex_lock(&audiobridge->mutex); event = json_object(); json_object_set_new(event, "audiobridge", json_string("event")); - json_object_set_new(event, "room", json_integer(audiobridge->room_id)); - json_object_set_new(event, "leaving", json_integer(participant->user_id)); + json_object_set_new(event, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); + json_object_set_new(event, "leaving", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, audiobridge->participants); @@ -4340,13 +4823,14 @@ static void *janus_audiobridge_handler(void *data) { if(p == participant) { continue; /* Skip the new participant itself */ } - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_audiobridge_plugin, NULL, event, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } json_decref(event); /* Actually leave the room... */ - removed = g_hash_table_remove(audiobridge->participants, &participant->user_id); + removed = g_hash_table_remove(audiobridge->participants, + string_ids ? (gpointer)participant->user_id_str : (gpointer)&participant->user_id); participant->room = NULL; } /* Get rid of queued packets */ @@ -4374,8 +4858,10 @@ static void *janus_audiobridge_handler(void *data) { if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("left")); - json_object_set_new(info, "room", json_integer(audiobridge->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); + json_object_set_new(info, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(info, "display", json_string(participant->display)); gateway->notify_event(&janus_audiobridge_plugin, session->handle, info); } @@ -4383,11 +4869,13 @@ static void *janus_audiobridge_handler(void *data) { event = json_object(); json_object_set_new(event, "audiobridge", json_string("left")); if(audiobridge != NULL) { - json_object_set_new(event, "room", json_integer(audiobridge->room_id)); + json_object_set_new(event, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); janus_mutex_unlock(&audiobridge->mutex); janus_refcount_decrease(&audiobridge->ref); } - json_object_set_new(event, "id", json_integer(participant->user_id)); + json_object_set_new(event, "id", + string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); janus_mutex_unlock(&rooms_mutex); if(removed) { /* Only decrease the counter if we were still there */ @@ -4475,7 +4963,7 @@ static void *janus_audiobridge_handler(void *data) { /* Replace the session name */ g_free(answer->s_name); char s_name[100]; - g_snprintf(s_name, sizeof(s_name), "AudioBridge %"SCNu64, participant->room->room_id); + g_snprintf(s_name, sizeof(s_name), "AudioBridge %s", participant->room->room_id_str); answer->s_name = g_strdup(s_name); /* Add a fmtp attribute */ janus_sdp_attribute *a = janus_sdp_attribute_create("fmtp", @@ -4542,7 +5030,8 @@ static void *janus_audiobridge_mixer_thread(void *data) { JANUS_LOG(LOG_ERR, "Invalid room!\n"); return NULL; } - JANUS_LOG(LOG_VERB, "Thread is for mixing room %"SCNu64" (%s) at rate %"SCNu32"...\n", audiobridge->room_id, audiobridge->room_name, audiobridge->sampling_rate); + JANUS_LOG(LOG_VERB, "Thread is for mixing room %s (%s) at rate %"SCNu32"...\n", + audiobridge->room_id_str, audiobridge->room_name, audiobridge->sampling_rate); /* Do we need to record the mix? */ if(audiobridge->record) { @@ -4551,7 +5040,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { g_snprintf(filename, 255, "%s%s%s", audiobridge->record_file, rec_tempext ? "." : "", rec_tempext ? rec_tempext : ""); } else { - g_snprintf(filename, 255, "janus-audioroom-%"SCNu64".wav%s%s", audiobridge->room_id, + g_snprintf(filename, 255, "janus-audioroom-%s.wav%s%s", audiobridge->room_id_str, rec_tempext ? "." : "", rec_tempext ? rec_tempext : ""); } audiobridge->recording = fopen(filename, "wb"); @@ -4638,13 +5127,13 @@ static void *janus_audiobridge_mixer_thread(void *data) { janus_mutex_unlock_nodebug(&audiobridge->mutex); /* No participant and RTP forwarders, do nothing */ if(prev_count > 0) { - JANUS_LOG(LOG_VERB, "Last user/forwarder just left room %"SCNu64", going idle...\n", audiobridge->room_id); + JANUS_LOG(LOG_VERB, "Last user/forwarder just left room %s, going idle...\n", audiobridge->room_id_str); prev_count = 0; } continue; } if(prev_count == 0) { - JANUS_LOG(LOG_VERB, "First user/forwarder just joined room %"SCNu64", waking it up...\n", audiobridge->room_id); + JANUS_LOG(LOG_VERB, "First user/forwarder just joined room %s, waking it up...\n", audiobridge->room_id_str); } prev_count = count+rf_count; /* Update RTP header information */ @@ -4746,7 +5235,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { mixedpkt->length = samples; /* We set the number of samples here, not the data length */ mixedpkt->timestamp = ts; mixedpkt->seq_number = seq; - mixedpkt->ssrc = audiobridge->room_id; + mixedpkt->ssrc = audiobridge->room_ssrc; mixedpkt->silence = FALSE; g_async_queue_push(p->outbuf, mixedpkt); if(pkt) { @@ -4807,8 +5296,8 @@ static void *janus_audiobridge_mixer_thread(void *data) { (struct sockaddr *)&forwarder->serv_addr : (struct sockaddr *)&forwarder->serv_addr6); size_t addrlen = (forwarder->serv_addr.sin_family == AF_INET ? sizeof(forwarder->serv_addr) : sizeof(forwarder->serv_addr6)); if(sendto(audiobridge->rtp_udp_sock, rtpbuffer, length+12, 0, address, addrlen) < 0) { - JANUS_LOG(LOG_HUGE, "Error forwarding mixed RTP packet for room %"SCNu64"... %s (len=%d)...\n", - audiobridge->room_id, strerror(errno), length+12); + JANUS_LOG(LOG_HUGE, "Error forwarding mixed RTP packet for room %s... %s (len=%d)...\n", + audiobridge->room_id_str, strerror(errno), length+12); } } } @@ -4834,7 +5323,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { if(audiobridge->record_file) { g_snprintf(filename, 255, "%s", audiobridge->record_file); } else { - g_snprintf(filename, 255, "janus-audioroom-%"SCNu64".wav", audiobridge->room_id); + g_snprintf(filename, 255, "janus-audioroom-%s.wav", audiobridge->room_id_str); } if(rec_tempext) { /* We need to rename the file, to remove the temporary extension */ @@ -4842,7 +5331,7 @@ static void *janus_audiobridge_mixer_thread(void *data) { if(audiobridge->record_file) { g_snprintf(extfilename, 255, "%s.%s", audiobridge->record_file, rec_tempext); } else { - g_snprintf(extfilename, 255, "janus-audioroom-%"SCNu64".wav.%s", audiobridge->room_id, rec_tempext); + g_snprintf(extfilename, 255, "janus-audioroom-%s.wav.%s", audiobridge->room_id_str, rec_tempext); } if(rename(extfilename, filename) != 0) { JANUS_LOG(LOG_ERR, "Error renaming %s to %s...\n", extfilename, filename); @@ -4854,13 +5343,14 @@ static void *janus_audiobridge_mixer_thread(void *data) { if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("recordingdone")); - json_object_set_new(info, "room", json_integer(audiobridge->room_id)); + json_object_set_new(info, "room", + string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id)); json_object_set_new(info, "record_file", json_string(filename)); gateway->notify_event(&janus_audiobridge_plugin, NULL, info); } } g_free(rtpbuffer); - JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %"SCNu64" (%s)...\n", audiobridge->room_id, audiobridge->room_name); + JANUS_LOG(LOG_VERB, "Leaving mixer thread for room %s (%s)...\n", audiobridge->room_id_str, audiobridge->room_name); janus_refcount_decrease(&audiobridge->ref); @@ -4876,7 +5366,8 @@ static void *janus_audiobridge_participant_thread(void *data) { g_thread_unref(g_thread_self()); return NULL; } - JANUS_LOG(LOG_VERB, "Thread is for participant %"SCNu64" (%s)\n", participant->user_id, participant->display ? participant->display : "??"); + JANUS_LOG(LOG_VERB, "Thread is for participant %s (%s)\n", + participant->user_id_str, participant->display ? participant->display : "??"); janus_audiobridge_session *session = participant->session; /* Output buffer */ diff --git a/plugins/janus_textroom.c b/plugins/janus_textroom.c index 3a97ea6f34..3a16a2e7a4 100644 --- a/plugins/janus_textroom.c +++ b/plugins/janus_textroom.c @@ -585,11 +585,19 @@ static struct janus_json_parameter transaction_parameters[] = { static struct janus_json_parameter room_parameters[] = { {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} }; +static struct janus_json_parameter roomopt_parameters[] = { + {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter roomstr_parameters[] = { + {"room", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} +}; +static struct janus_json_parameter roomstropt_parameters[] = { + {"room", JSON_STRING, 0} +}; static struct janus_json_parameter adminkey_parameters[] = { {"admin_key", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} }; static struct janus_json_parameter create_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"description", JSON_STRING, 0}, {"secret", JSON_STRING, 0}, {"pin", JSON_STRING, 0}, @@ -599,11 +607,9 @@ static struct janus_json_parameter create_parameters[] = { {"permanent", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter destroy_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"permanent", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter edit_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"secret", JSON_STRING, 0}, {"new_description", JSON_STRING, 0}, {"new_secret", JSON_STRING, 0}, @@ -613,31 +619,26 @@ static struct janus_json_parameter edit_parameters[] = { {"permanent", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter allowed_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"secret", JSON_STRING, 0}, {"action", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, {"allowed", JSON_ARRAY, 0} }; static struct janus_json_parameter kick_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"secret", JSON_STRING, 0}, {"username", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} }; static struct janus_json_parameter join_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"username", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, {"pin", JSON_STRING, 0}, {"display", JSON_STRING, 0} }; static struct janus_json_parameter message_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"text", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, {"to", JSON_STRING, 0}, {"tos", JSON_ARRAY, 0}, {"ack", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter announcement_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"secret", JSON_STRING, 0}, {"text", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} }; @@ -650,6 +651,7 @@ static janus_mutex config_mutex = JANUS_MUTEX_INITIALIZER; /* Useful stuff */ static volatile gint initialized = 0, stopping = 0; static gboolean notify_events = TRUE; +static gboolean string_ids = FALSE; static janus_callbacks *gateway = NULL; static GThread *handler_thread; static void *janus_textroom_handler(void *data); @@ -660,7 +662,8 @@ static size_t json_format = JSON_INDENT(3) | JSON_PRESERVE_ORDER; typedef struct janus_textroom_room { - guint64 room_id; /* Unique room ID */ + guint64 room_id; /* Unique room ID (when using integers) */ + gchar *room_id_str; /* Unique room ID (when using strings) */ gchar *room_name; /* Room description */ gchar *room_secret; /* Secret needed to manipulate (e.g., destroy) this room */ gchar *room_pin; /* Password needed to join this room, if any */ @@ -673,7 +676,7 @@ typedef struct janus_textroom_room { janus_mutex mutex; /* Mutex to lock this room instance */ janus_refcount ref; } janus_textroom_room; -static GHashTable *rooms; +static GHashTable *rooms = NULL; static janus_mutex rooms_mutex = JANUS_MUTEX_INITIALIZER; static char *admin_key = NULL; @@ -708,6 +711,7 @@ static void janus_textroom_room_destroy(janus_textroom_room *textroom) { static void janus_textroom_room_free(const janus_refcount *textroom_ref) { janus_textroom_room *textroom = janus_refcount_containerof(textroom_ref, janus_textroom_room, ref); /* This room can be destroyed, free all the resources */ + g_free(textroom->room_id_str); g_free(textroom->room_name); g_free(textroom->room_secret); g_free(textroom->room_pin); @@ -856,7 +860,6 @@ int janus_textroom_init(janus_callbacks *callback, const char *config_path) { config_folder = config_path; if(config != NULL) janus_config_print(config); - rooms = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)janus_textroom_room_destroy); sessions = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)janus_textroom_session_destroy); messages = g_async_queue_new_full((GDestroyNotify) janus_textroom_message_free); /* This is the callback we'll need to invoke to contact the Janus core */ @@ -892,7 +895,17 @@ int janus_textroom_init(janus_callbacks *callback, const char *config_path) { if(!notify_events && callback->events_is_enabled()) { JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_TEXTROOM_NAME); } - /* Iterate on all rooms */ + janus_config_item *ids = janus_config_get(config, config_general, janus_config_type_item, "string_ids"); + if(ids != NULL && ids->value != NULL) + string_ids = janus_is_true(ids->value); + if(string_ids) { + JANUS_LOG(LOG_INFO, "TextRoom will use alphanumeric IDs, not numeric\n"); + } + } + /* Iterate on all rooms */ + rooms = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)janus_textroom_room_destroy); + if(config != NULL) { GList *clist = janus_config_get_categories(config, NULL), *cl = clist; while(cl != NULL) { janus_config_category *cat = (janus_config_category *)cl->data; @@ -900,7 +913,7 @@ int janus_textroom_init(janus_callbacks *callback, const char *config_path) { cl = cl->next; continue; } - JANUS_LOG(LOG_VERB, "Adding text room '%s'\n", cat->name); + JANUS_LOG(LOG_VERB, "Adding TextRoom room '%s'\n", cat->name); janus_config_item *desc = janus_config_get(config, cat, janus_config_type_item, "description"); janus_config_item *priv = janus_config_get(config, cat, janus_config_type_item, "is_private"); janus_config_item *secret = janus_config_get(config, cat, janus_config_type_item, "secret"); @@ -911,7 +924,36 @@ int janus_textroom_init(janus_callbacks *callback, const char *config_path) { const char *room_num = cat->name; if(strstr(room_num, "room-") == room_num) room_num += 5; - textroom->room_id = g_ascii_strtoull(room_num, NULL, 0); + if(!string_ids) { + textroom->room_id = g_ascii_strtoull(room_num, NULL, 0); + if(textroom->room_id == 0) { + JANUS_LOG(LOG_ERR, "Can't add the TextRoom room, invalid ID 0...\n"); + g_free(textroom); + cl = cl->next; + continue; + } + /* Make sure the ID is completely numeric */ + char room_id_str[30]; + g_snprintf(room_id_str, sizeof(room_id_str), "%"SCNu64, textroom->room_id); + if(strcmp(room_num, room_id_str)) { + JANUS_LOG(LOG_ERR, "Can't add the TextRoom room, ID '%s' is not numeric...\n", room_num); + g_free(textroom); + cl = cl->next; + continue; + } + } + /* Let's make sure the room doesn't exist already */ + janus_mutex_lock(&rooms_mutex); + if(g_hash_table_lookup(rooms, string_ids ? (gpointer)room_num : (gpointer)&textroom->room_id) != NULL) { + /* It does... */ + janus_mutex_unlock(&rooms_mutex); + JANUS_LOG(LOG_ERR, "Can't add the TextRoom room, room %s already exists...\n", room_num); + g_free(textroom); + cl = cl->next; + continue; + } + janus_mutex_unlock(&rooms_mutex); + textroom->room_id_str = g_strdup(room_num); char *description = NULL; if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0) description = g_strdup(desc->value); @@ -939,12 +981,14 @@ int janus_textroom_init(janus_callbacks *callback, const char *config_path) { textroom->destroyed = 0; janus_mutex_init(&textroom->mutex); janus_refcount_init(&textroom->ref, janus_textroom_room_free); - JANUS_LOG(LOG_VERB, "Created textroom: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n", - textroom->room_id, textroom->room_name, + JANUS_LOG(LOG_VERB, "Created TextRoom: %s (%s, %s, secret: %s, pin: %s)\n", + textroom->room_id_str, textroom->room_name, textroom->is_private ? "private" : "public", textroom->room_secret ? textroom->room_secret : "no secret", textroom->room_pin ? textroom->room_pin : "no pin"); - g_hash_table_insert(rooms, janus_uint64_dup(textroom->room_id), textroom); + g_hash_table_insert(rooms, + string_ids ? (gpointer)g_strdup(textroom->room_id_str) : (gpointer)janus_uint64_dup(textroom->room_id), + textroom); cl = cl->next; } g_list_free(clist); @@ -958,7 +1002,7 @@ int janus_textroom_init(janus_callbacks *callback, const char *config_path) { g_hash_table_iter_init(&iter, rooms); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_room *tr = value; - JANUS_LOG(LOG_VERB, " ::: [%"SCNu64"][%s]\n", tr->room_id, tr->room_name); + JANUS_LOG(LOG_VERB, " ::: [%s][%s]\n", tr->room_id_str, tr->room_name); } janus_mutex_unlock(&rooms_mutex); @@ -1059,7 +1103,8 @@ void janus_textroom_create_session(janus_plugin_session *handle, int *error) { } janus_textroom_session *session = g_malloc0(sizeof(janus_textroom_session)); session->handle = handle; - session->rooms = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)janus_textroom_participant_dereference); + session->rooms = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)janus_textroom_participant_dereference); session->destroyed = 0; janus_mutex_init(&session->mutex); janus_refcount_init(&session->ref, janus_textroom_session_free); @@ -1375,29 +1420,50 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session JANUS_VALIDATE_JSON_OBJECT(root, message_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_refcount_increase(&textroom->ref); janus_mutex_lock(&textroom->mutex); janus_mutex_unlock(&rooms_mutex); - janus_textroom_participant *participant = g_hash_table_lookup(session->rooms, &room_id); + janus_textroom_participant *participant = g_hash_table_lookup(session->rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(participant == NULL) { janus_mutex_unlock(&textroom->mutex); janus_refcount_decrease(&textroom->ref); - JANUS_LOG(LOG_ERR, "Not in room %"SCNu64"\n", room_id); + JANUS_LOG(LOG_ERR, "Not in room %s\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NOT_IN_ROOM; - g_snprintf(error_cause, 512, "Not in room %"SCNu64, room_id); + g_snprintf(error_cause, 512, "Not in room %s", room_id_str); goto msg_response; } janus_refcount_increase(&participant->ref); @@ -1416,7 +1482,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Prepare outgoing message */ json_t *msg = json_object(); json_object_set_new(msg, "textroom", json_string("message")); - json_object_set_new(msg, "room", json_integer(room_id)); + json_object_set_new(msg, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(msg, "from", json_string(participant->username)); time_t timer; time(&timer); @@ -1437,7 +1503,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* A single user */ json_t *sent = json_object(); const char *to = json_string_value(username); - JANUS_LOG(LOG_VERB, "To %s in %"SCNu64": %s\n", to, room_id, message); + JANUS_LOG(LOG_VERB, "To %s in %s: %s\n", to, room_id_str, message); janus_textroom_participant *top = g_hash_table_lookup(textroom->participants, to); if(top) { janus_refcount_increase(&top->ref); @@ -1446,7 +1512,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session janus_refcount_decrease(&top->ref); json_object_set_new(sent, to, json_true()); } else { - JANUS_LOG(LOG_WARN, "User %s is not in room %"SCNu64", failed to send message\n", to, room_id); + JANUS_LOG(LOG_WARN, "User %s is not in room %s, failed to send message\n", to, room_id_str); json_object_set_new(sent, to, json_false()); } json_object_set_new(reply, "sent", sent); @@ -1457,7 +1523,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session for(i=0; iparticipants, to); if(top) { janus_refcount_increase(&top->ref); @@ -1466,21 +1532,21 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session janus_refcount_decrease(&top->ref); json_object_set_new(sent, to, json_true()); } else { - JANUS_LOG(LOG_WARN, "User %s is not in room %"SCNu64", failed to send message\n", to, room_id); + JANUS_LOG(LOG_WARN, "User %s is not in room %s, failed to send message\n", to, room_id_str); json_object_set_new(sent, to, json_false()); } } json_object_set_new(reply, "sent", sent); } else { /* Everybody in the room */ - JANUS_LOG(LOG_VERB, "To everybody in %"SCNu64": %s\n", room_id, message); + JANUS_LOG(LOG_VERB, "To everybody in %s: %s\n", room_id_str, message); if(textroom->participants) { GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, textroom->participants); while(g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_participant *top = value; - JANUS_LOG(LOG_VERB, " >> To %s in %"SCNu64": %s\n", top->username, room_id, message); + JANUS_LOG(LOG_VERB, " >> To %s in %s: %s\n", top->username, room_id_str, message); janus_refcount_increase(&top->ref); janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; gateway->relay_data(top->session->handle, &data); @@ -1535,17 +1601,37 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session JANUS_VALIDATE_JSON_OBJECT(root, join_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_refcount_increase(&textroom->ref); @@ -1560,13 +1646,13 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session goto msg_response; } janus_mutex_lock(&session->mutex); - if(g_hash_table_lookup(session->rooms, &room_id) != NULL) { + if(g_hash_table_lookup(session->rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id) != NULL) { janus_mutex_unlock(&session->mutex); janus_mutex_unlock(&textroom->mutex); janus_refcount_decrease(&textroom->ref); - JANUS_LOG(LOG_ERR, "Already in room %"SCNu64"\n", room_id); + JANUS_LOG(LOG_ERR, "Already in room %s\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_ALREADY_IN_ROOM; - g_snprintf(error_cause, 512, "Already in room %"SCNu64, room_id); + g_snprintf(error_cause, 512, "Already in room %s", room_id_str); goto msg_response; } json_t *username = json_object_get(root, "username"); @@ -1593,7 +1679,9 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session janus_mutex_init(&participant->mutex); janus_refcount_init(&participant->ref, janus_textroom_participant_free); janus_refcount_increase(&participant->ref); - g_hash_table_insert(session->rooms, janus_uint64_dup(textroom->room_id), participant); + g_hash_table_insert(session->rooms, + string_ids ? (gpointer)g_strdup(textroom->room_id_str) : (gpointer)janus_uint64_dup(textroom->room_id), + participant); janus_refcount_increase(&participant->ref); g_hash_table_insert(textroom->participants, participant->username, participant); /* Notify all participants */ @@ -1603,7 +1691,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Prepare event */ json_t *event = json_object(); json_object_set_new(event, "textroom", json_string("join")); - json_object_set_new(event, "room", json_integer(textroom->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); json_object_set_new(event, "username", json_string(username_text)); if(display_text != NULL) json_object_set_new(event, "display", json_string(display_text)); @@ -1620,7 +1708,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(top == participant) continue; /* Skip us */ janus_refcount_increase(&top->ref); - JANUS_LOG(LOG_VERB, " >> To %s in %"SCNu64"\n", top->username, room_id); + JANUS_LOG(LOG_VERB, " >> To %s in %s\n", top->username, room_id_str); gateway->relay_data(top->session->handle, &data); /* Take note of this user */ json_t *p = json_object(); @@ -1645,45 +1733,61 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("join")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(info, "username", json_string(username_text)); if(display_text) json_object_set_new(info, "display", json_string(display_text)); gateway->notify_event(&janus_textroom_plugin, session->handle, info); } } else if(!strcasecmp(request_text, "leave")) { - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_refcount_increase(&textroom->ref); janus_mutex_lock(&textroom->mutex); janus_mutex_unlock(&rooms_mutex); janus_mutex_lock(&session->mutex); - janus_textroom_participant *participant = g_hash_table_lookup(session->rooms, &room_id); + janus_textroom_participant *participant = g_hash_table_lookup(session->rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(participant == NULL) { janus_mutex_unlock(&session->mutex); janus_mutex_unlock(&textroom->mutex); janus_refcount_decrease(&textroom->ref); - JANUS_LOG(LOG_ERR, "Not in room %"SCNu64"\n", room_id); + JANUS_LOG(LOG_ERR, "Not in room %s\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NOT_IN_ROOM; - g_snprintf(error_cause, 512, "Not in room %"SCNu64, room_id); + g_snprintf(error_cause, 512, "Not in room %s", room_id_str); goto msg_response; } janus_refcount_increase(&participant->ref); - g_hash_table_remove(session->rooms, &room_id); + g_hash_table_remove(session->rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); g_hash_table_remove(textroom->participants, participant->username); participant->session = NULL; participant->room = NULL; @@ -1693,7 +1797,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Prepare event */ json_t *event = json_object(); json_object_set_new(event, "textroom", json_string("leave")); - json_object_set_new(event, "room", json_integer(textroom->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); json_object_set_new(event, "username", json_string(participant->username)); char *event_text = json_dumps(event, json_format); json_decref(event); @@ -1708,7 +1812,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(top == participant) continue; /* Skip us */ janus_refcount_increase(&top->ref); - JANUS_LOG(LOG_VERB, " >> To %s in %"SCNu64"\n", top->username, room_id); + JANUS_LOG(LOG_VERB, " >> To %s in %s\n", top->username, room_id_str); gateway->relay_data(top->session->handle, &data); janus_refcount_decrease(&top->ref); } @@ -1718,7 +1822,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("leave")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(info, "username", json_string(participant->username)); gateway->notify_event(&janus_textroom_plugin, session->handle, info); } @@ -1754,7 +1858,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session continue; } json_t *rl = json_object(); - json_object_set_new(rl, "room", json_integer(room->room_id)); + json_object_set_new(rl, "room", string_ids ? json_string(room->room_id_str) : json_integer(room->room_id)); json_object_set_new(rl, "description", json_string(room->room_name)); json_object_set_new(rl, "pin_required", room->room_pin ? json_true() : json_false()); json_object_set_new(rl, "num_participants", json_integer(g_hash_table_size(room->participants))); @@ -1771,20 +1875,35 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session } } else if(!strcasecmp(request_text, "listparticipants")) { /* List all participants in a room */ - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL || g_atomic_int_get(&textroom->destroyed)) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_refcount_increase(&textroom->ref); @@ -1806,14 +1925,25 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(!internal) { /* Send response back */ reply = json_object(); - json_object_set_new(reply, "room", json_integer(room_id)); + json_object_set_new(reply, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(reply, "participants", list); } } else if(!strcasecmp(request_text, "allowed")) { - JANUS_LOG(LOG_VERB, "Attempt to edit the list of allowed participants in an existing textroom room\n"); + JANUS_LOG(LOG_VERB, "Attempt to edit the list of allowed participants in an existing TextRoom room\n"); JANUS_VALIDATE_JSON_OBJECT(root, allowed_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *action = json_object_get(root, "action"); @@ -1827,14 +1957,23 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session g_snprintf(error_cause, 512, "Unsupported action '%s' (allowed)", action_text); goto msg_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_mutex_lock(&textroom->mutex); @@ -1847,10 +1986,10 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session goto msg_response; } if(!strcasecmp(action_text, "enable")) { - JANUS_LOG(LOG_VERB, "Enabling the check on allowed authorization tokens for room %"SCNu64"\n", room_id); + JANUS_LOG(LOG_VERB, "Enabling the check on allowed authorization tokens for room %s\n", room_id_str); textroom->check_tokens = TRUE; } else if(!strcasecmp(action_text, "disable")) { - JANUS_LOG(LOG_VERB, "Disabling the check on allowed authorization tokens for room %"SCNu64" (free entry)\n", room_id); + JANUS_LOG(LOG_VERB, "Disabling the check on allowed authorization tokens for room %s (free entry)\n", room_id_str); textroom->check_tokens = FALSE; } else { gboolean add = !strcasecmp(action_text, "add"); @@ -1891,7 +2030,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Send response back */ reply = json_object(); json_object_set_new(reply, "textroom", json_string("success")); - json_object_set_new(reply, "room", json_integer(textroom->room_id)); + json_object_set_new(reply, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); json_t *list = json_array(); if(strcasecmp(action_text, "disable")) { if(g_hash_table_size(textroom->allowed) > 0) { @@ -1910,22 +2049,42 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session JANUS_LOG(LOG_VERB, "TextRoom room allowed list updated\n"); } } else if(!strcasecmp(request_text, "kick")) { - JANUS_LOG(LOG_VERB, "Attempt to kick a participant from an existing textroom room\n"); + JANUS_LOG(LOG_VERB, "Attempt to kick a participant from an existing TextRoom room\n"); JANUS_VALIDATE_JSON_OBJECT(root, kick_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); json_t *username = json_object_get(root, "username"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_mutex_lock(&textroom->mutex); @@ -1942,7 +2101,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(participant == NULL) { janus_mutex_unlock(&textroom->mutex); janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such participant %s in room %"SCNu64"\n", user_id, room_id); + JANUS_LOG(LOG_ERR, "No such participant %s in room %s\n", user_id, room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_USER; g_snprintf(error_cause, 512, "No such user %s in room %"SCNu64, user_id, room_id); goto msg_response; @@ -1953,7 +2112,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Prepare event */ json_t *event = json_object(); json_object_set_new(event, "textroom", json_string("kicked")); - json_object_set_new(event, "room", json_integer(textroom->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); json_object_set_new(event, "username", json_string(participant->username)); char *event_text = json_dumps(event, json_format); json_decref(event); @@ -1963,7 +2122,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session g_hash_table_iter_init(&iter, textroom->participants); while(g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_participant *top = value; - JANUS_LOG(LOG_VERB, " >> To %s in %"SCNu64"\n", top->username, room_id); + JANUS_LOG(LOG_VERB, " >> To %s in %s\n", top->username, room_id_str); janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; gateway->relay_data(top->session->handle, &data); } @@ -1973,12 +2132,12 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "textroom", json_string("kicked")); - json_object_set_new(info, "room", json_integer(textroom->room_id)); + json_object_set_new(info, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); json_object_set_new(info, "username", json_string(participant->username)); gateway->notify_event(&janus_textroom_plugin, session->handle, info); } /* Remove user from list */ - g_hash_table_remove(participant->session->rooms, &room_id); + g_hash_table_remove(participant->session->rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); g_hash_table_remove(textroom->participants, participant->username); participant->session = NULL; participant->room = NULL; @@ -1994,21 +2153,41 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session json_object_set_new(reply, "textbridge", json_string("success")); } } else if(!strcasecmp(request_text, "announcement")) { - JANUS_LOG(LOG_VERB, "Attempt to send a textroom announcement\n"); + JANUS_LOG(LOG_VERB, "Attempt to send a TextRoom announcement\n"); JANUS_VALIDATE_JSON_OBJECT(root, announcement_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_refcount_increase(&textroom->ref); @@ -2027,7 +2206,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Prepare outgoing message */ json_t *msg = json_object(); json_object_set_new(msg, "textroom", json_string("announcement")); - json_object_set_new(msg, "room", json_integer(room_id)); + json_object_set_new(msg, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); time_t timer; time(&timer); struct tm *tm_info = localtime(&timer); @@ -2044,7 +2223,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session g_hash_table_iter_init(&iter, textroom->participants); while(g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_participant *top = value; - JANUS_LOG(LOG_VERB, " >> To %s in %"SCNu64": %s\n", top->username, room_id, message); + JANUS_LOG(LOG_VERB, " >> To %s in %s: %s\n", top->username, room_id_str, message); janus_refcount_increase(&top->ref); janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = msg_text, .length = strlen(msg_text) }; gateway->relay_data(top->session->handle, &data); @@ -2092,6 +2271,17 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session JANUS_VALIDATE_JSON_OBJECT(root, create_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, roomopt_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstropt_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; if(admin_key != NULL) { @@ -2142,26 +2332,34 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session goto msg_response; } guint64 room_id = 0; - room_id = json_integer_value(room); - if(room_id == 0) { - JANUS_LOG(LOG_WARN, "Desired room ID is 0, which is not allowed... picking random ID instead\n"); + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } + if(room_id == 0 && room_id_str == NULL) { + JANUS_LOG(LOG_WARN, "Desired room ID is empty, which is not allowed... picking random ID instead\n"); } janus_mutex_lock(&rooms_mutex); - if(room_id > 0) { + if(room_id > 0 || room_id_str != NULL) { /* Let's make sure the room doesn't exist already */ - if(g_hash_table_lookup(rooms, &room_id) != NULL) { + if(g_hash_table_lookup(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id) != NULL) { /* It does... */ janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "Room %"SCNu64" already exists!\n", room_id); error_code = JANUS_TEXTROOM_ERROR_ROOM_EXISTS; - g_snprintf(error_cause, 512, "Room %"SCNu64" already exists", room_id); + JANUS_LOG(LOG_ERR, "Room %s already exists!\n", room_id_str); + g_snprintf(error_cause, 512, "Room %s already exists", room_id_str); goto msg_response; } } /* Create the text room */ janus_textroom_room *textroom = g_malloc0(sizeof(janus_textroom_room)); /* Generate a random ID */ - if(room_id == 0) { + gboolean room_id_allocated = FALSE; + if(!string_ids && room_id == 0) { while(room_id == 0) { room_id = janus_random_uint64(); if(g_hash_table_lookup(rooms, &room_id) != NULL) { @@ -2169,14 +2367,26 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session room_id = 0; } } + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else if(string_ids && room_id_str == NULL) { + while(room_id_str == NULL) { + room_id_str = janus_random_uuid(); + if(g_hash_table_lookup(rooms, room_id_str) != NULL) { + /* Room ID already taken, try another one */ + g_clear_pointer(&room_id_str, g_free); + } + } + room_id_allocated = TRUE; } textroom->room_id = room_id; + textroom->room_id_str = room_id_str ? g_strdup(room_id_str) : NULL; char *description = NULL; if(desc != NULL && strlen(json_string_value(desc)) > 0) { description = g_strdup(json_string_value(desc)); } else { char roomname[255]; - g_snprintf(roomname, 255, "Room %"SCNu64"", textroom->room_id); + g_snprintf(roomname, 255, "Room %s", textroom->room_id_str); description = g_strdup(roomname); } textroom->room_name = description; @@ -2210,20 +2420,22 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session textroom->destroyed = 0; janus_mutex_init(&textroom->mutex); janus_refcount_init(&textroom->ref, janus_textroom_room_free); - g_hash_table_insert(rooms, janus_uint64_dup(textroom->room_id), textroom); - JANUS_LOG(LOG_VERB, "Created textroom: %"SCNu64" (%s, %s, secret: %s, pin: %s)\n", - textroom->room_id, textroom->room_name, + g_hash_table_insert(rooms, + string_ids ? (gpointer)g_strdup(textroom->room_id_str) : (gpointer)janus_uint64_dup(textroom->room_id), + textroom); + JANUS_LOG(LOG_VERB, "Created TextRoom: %s (%s, %s, secret: %s, pin: %s)\n", + textroom->room_id_str, textroom->room_name, textroom->is_private ? "private" : "public", textroom->room_secret ? textroom->room_secret : "no secret", textroom->room_pin ? textroom->room_pin : "no pin"); if(save) { /* This room is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Saving room %"SCNu64" permanently in config file\n", textroom->room_id); + JANUS_LOG(LOG_VERB, "Saving room %s permanently in config file\n", textroom->room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, textroom->room_id); + g_snprintf(cat, BUFSIZ, "room-%s", textroom->room_id_str); janus_config_category *c = janus_config_get_create(config, NULL, janus_config_type_category, cat); /* Now for the values */ janus_config_add(config, c, janus_config_item_create("description", textroom->room_name)); @@ -2246,7 +2458,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session g_hash_table_iter_init(&iter, rooms); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_room *tr = value; - JANUS_LOG(LOG_VERB, " ::: [%"SCNu64"][%s]\n", tr->room_id, tr->room_name); + JANUS_LOG(LOG_VERB, " ::: [%s][%s]\n", tr->room_id_str, tr->room_name); } janus_mutex_unlock(&rooms_mutex); if(!internal) { @@ -2254,38 +2466,65 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session reply = json_object(); /* Notice that we reply differently if the request came via Janus API */ json_object_set_new(reply, "textroom", json_string(json == NULL ? "success" : "created")); - json_object_set_new(reply, "room", json_integer(textroom->room_id)); + json_object_set_new(reply, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); json_object_set_new(reply, "permanent", save ? json_true() : json_false()); } /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("created")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); gateway->notify_event(&janus_textroom_plugin, session ? session->handle : NULL, info); } + if(room_id_allocated) + g_free(room_id_str); } else if(!strcasecmp(request_text, "exists")) { - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - gboolean room_exists = g_hash_table_contains(rooms, &room_id); + gboolean room_exists = g_hash_table_contains(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); janus_mutex_unlock(&rooms_mutex); if(!internal) { /* Send response back */ reply = json_object(); json_object_set_new(reply, "textroom", json_string("success")); - json_object_set_new(reply, "room", json_integer(room_id)); + json_object_set_new(reply, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(reply, "exists", room_exists ? json_true() : json_false()); } } else if(!strcasecmp(request_text, "edit")) { JANUS_VALIDATE_JSON_OBJECT(root, edit_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; /* We only allow for a limited set of properties to be edited */ @@ -2303,14 +2542,23 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session g_snprintf(error_cause, 512, "No configuration file, can't edit room permanently"); goto msg_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_mutex_lock(&textroom->mutex); @@ -2352,7 +2600,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session if(save) { /* This change is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Modifying room %"SCNu64" permanently in config file\n", room_id); + JANUS_LOG(LOG_VERB, "Modifying room %s permanently in config file\n", room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ @@ -2382,20 +2630,31 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session reply = json_object(); /* Notice that we reply differently if the request came via Janus API */ json_object_set_new(reply, "textroom", json_string(json == NULL ? "success" : "edited")); - json_object_set_new(reply, "room", json_integer(room_id)); + json_object_set_new(reply, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(reply, "permanent", save ? json_true() : json_false()); } /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("edited")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); gateway->notify_event(&janus_textroom_plugin, session ? session->handle : NULL, info); } } else if(!strcasecmp(request_text, "destroy")) { JANUS_VALIDATE_JSON_OBJECT(root, destroy_parameters, error_code, error_cause, TRUE, JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto msg_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_TEXTROOM_ERROR_MISSING_ELEMENT, JANUS_TEXTROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto msg_response; json_t *room = json_object_get(root, "room"); @@ -2407,14 +2666,23 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session g_snprintf(error_cause, 512, "No configuration file, can't destroy room permanently"); goto msg_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - janus_textroom_room *textroom = g_hash_table_lookup(rooms, &room_id); + janus_textroom_room *textroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(textroom == NULL) { janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_TEXTROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); goto msg_response; } janus_refcount_increase(&textroom->ref); @@ -2429,15 +2697,15 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session goto msg_response; } /* Remove room */ - g_hash_table_remove(rooms, &room_id); + g_hash_table_remove(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(save) { /* This change is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Destroying room %"SCNu64" permanently in config file\n", room_id); + JANUS_LOG(LOG_VERB, "Destroying room %s permanently in config file\n", room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, room_id); + g_snprintf(cat, BUFSIZ, "room-%s", room_id_str); janus_config_remove(config, NULL, cat); /* Save modified configuration */ if(janus_config_save(config, config_folder, JANUS_TEXTROOM_PACKAGE) < 0) @@ -2450,7 +2718,7 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session /* Prepare event */ json_t *event = json_object(); json_object_set_new(event, "textroom", json_string("destroyed")); - json_object_set_new(event, "room", json_integer(textroom->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(textroom->room_id_str) : json_integer(textroom->room_id)); char *event_text = json_dumps(event, json_format); json_decref(event); janus_plugin_data data = { .label = NULL, .binary = FALSE, .buffer = event_text, .length = strlen(event_text) }; @@ -2462,10 +2730,10 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session while(g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_participant *top = value; janus_refcount_increase(&top->ref); - JANUS_LOG(LOG_VERB, " >> To %s in %"SCNu64"\n", top->username, room_id); + JANUS_LOG(LOG_VERB, " >> To %s in %s\n", top->username, room_id_str); gateway->relay_data(top->session->handle, &data); janus_mutex_lock(&top->session->mutex); - g_hash_table_remove(top->session->rooms, &room_id); + g_hash_table_remove(top->session->rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); janus_mutex_unlock(&top->session->mutex); janus_refcount_decrease(&top->ref); janus_textroom_participant_destroy(top); @@ -2480,14 +2748,14 @@ janus_plugin_result *janus_textroom_handle_incoming_request(janus_plugin_session reply = json_object(); /* Notice that we reply differently if the request came via Janus API */ json_object_set_new(reply, "textroom", json_string(json == NULL ? "success" : "destroyed")); - json_object_set_new(reply, "room", json_integer(room_id)); + json_object_set_new(reply, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(reply, "permanent", save ? json_true() : json_false()); } /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("destroyed")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); gateway->notify_event(&janus_textroom_plugin, session ? session->handle : NULL, info); } } else { @@ -2566,8 +2834,10 @@ static void janus_textroom_hangup_media_internal(janus_plugin_session *handle) { while(g_hash_table_iter_next(&iter, NULL, &value)) { janus_textroom_participant *p = value; janus_mutex_lock(&p->mutex); - if(p->room) - list = g_list_append(list, janus_uint64_dup(p->room->room_id)); + if(p->room) { + list = g_list_append(list, string_ids ? + (gpointer)g_strdup(p->room->room_id_str) : (gpointer)janus_uint64_dup(p->room->room_id)); + } janus_mutex_unlock(&p->mutex); } janus_mutex_unlock(&rooms_mutex); @@ -2577,8 +2847,13 @@ static void janus_textroom_hangup_media_internal(janus_plugin_session *handle) { char request[100]; GList *first = list; while(list) { - guint64 room_id = *((guint64 *)list->data); - g_snprintf(request, sizeof(request), "{\"textroom\":\"leave\",\"transaction\":\"internal\",\"room\":%"SCNu64"}", room_id); + char *room_id_str = (char *)list->data; + if(string_ids) { + g_snprintf(request, sizeof(request), "{\"textroom\":\"leave\",\"transaction\":\"internal\",\"room\":\"%s\"}", room_id_str); + } else { + guint64 room_id = *(guint64 *)room_id_str; + g_snprintf(request, sizeof(request), "{\"textroom\":\"leave\",\"transaction\":\"internal\",\"room\":%"SCNu64"}", room_id); + } janus_textroom_handle_incoming_request(handle, g_strdup(request), NULL, TRUE); list = list->next; } diff --git a/plugins/janus_videoroom.c b/plugins/janus_videoroom.c index 71f45277b5..e99c95e89c 100644 --- a/plugins/janus_videoroom.c +++ b/plugins/janus_videoroom.c @@ -1180,23 +1180,51 @@ static struct janus_json_parameter edit_parameters[] = { static struct janus_json_parameter room_parameters[] = { {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} }; +static struct janus_json_parameter roomopt_parameters[] = { + {"room", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter roomstr_parameters[] = { + {"room", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} +}; +static struct janus_json_parameter roomstropt_parameters[] = { + {"room", JSON_STRING, 0} +}; +static struct janus_json_parameter id_parameters[] = { + {"id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter idopt_parameters[] = { + {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter idstr_parameters[] = { + {"id", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} +}; +static struct janus_json_parameter idstropt_parameters[] = { + {"id", JSON_STRING, 0} +}; +static struct janus_json_parameter pid_parameters[] = { + {"publisher_id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter pidstr_parameters[] = { + {"publisher_id", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} +}; +static struct janus_json_parameter feed_parameters[] = { + {"feed", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} +}; +static struct janus_json_parameter feedstr_parameters[] = { + {"feed", JSON_STRING, JANUS_JSON_PARAM_REQUIRED} +}; static struct janus_json_parameter destroy_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"permanent", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter allowed_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"secret", JSON_STRING, 0}, {"action", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, {"allowed", JSON_ARRAY, 0} }; static struct janus_json_parameter kick_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, - {"secret", JSON_STRING, 0}, - {"id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} + {"secret", JSON_STRING, 0} }; static struct janus_json_parameter join_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"ptype", JSON_STRING, JANUS_JSON_PARAM_REQUIRED}, {"audio", JANUS_JSON_BOOL, 0}, {"video", JANUS_JSON_BOOL, 0}, @@ -1222,8 +1250,6 @@ static struct janus_json_parameter publish_parameters[] = { {"restart", JANUS_JSON_BOOL, 0} }; static struct janus_json_parameter rtp_forward_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, - {"publisher_id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"video_port", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"video_rtcp_port", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"video_ssrc", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, @@ -1246,12 +1272,9 @@ static struct janus_json_parameter rtp_forward_parameters[] = { {"srtp_crypto", JSON_STRING, 0} }; static struct janus_json_parameter stop_rtp_forward_parameters[] = { - {"room", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, - {"publisher_id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"stream_id", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE} }; static struct janus_json_parameter publisher_parameters[] = { - {"id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"display", JSON_STRING, 0} }; static struct janus_json_parameter configure_parameters[] = { @@ -1268,7 +1291,6 @@ static struct janus_json_parameter configure_parameters[] = { {"update", JANUS_JSON_BOOL, 0}, }; static struct janus_json_parameter subscriber_parameters[] = { - {"feed", JSON_INTEGER, JANUS_JSON_PARAM_REQUIRED | JANUS_JSON_PARAM_POSITIVE}, {"private_id", JSON_INTEGER, JANUS_JSON_PARAM_POSITIVE}, {"close_pc", JANUS_JSON_BOOL, 0}, {"audio", JANUS_JSON_BOOL, 0}, @@ -1293,6 +1315,7 @@ static janus_mutex config_mutex = JANUS_MUTEX_INITIALIZER; /* Useful stuff */ static volatile gint initialized = 0, stopping = 0; static gboolean notify_events = TRUE; +static gboolean string_ids = FALSE; static janus_callbacks *gateway = NULL; static GThread *handler_thread; static void *janus_videoroom_handler(void *data); @@ -1317,7 +1340,8 @@ static janus_videoroom_message exit_message; typedef struct janus_videoroom { - guint64 room_id; /* Unique room ID */ + guint64 room_id; /* Unique room ID (when using integers) */ + gchar *room_id_str; /* Unique room ID (when using strings) */ gchar *room_name; /* Room description */ gchar *room_secret; /* Secret needed to manipulate (e.g., destroy) this room */ gchar *room_pin; /* Password needed to join this room, if any */ @@ -1450,7 +1474,9 @@ typedef struct janus_videoroom_publisher { janus_videoroom_session *session; janus_videoroom *room; /* Room */ guint64 room_id; /* Unique room ID */ + gchar *room_id_str; /* Unique room ID (when using strings) */ guint64 user_id; /* Unique ID in the room */ + gchar *user_id_str; /* Unique ID in the room (when using strings) */ guint32 pvt_id; /* This is sent to the publisher for mapping purposes, but shouldn't be shared with others */ gchar *display; /* Display name (just for fun) */ gchar *sdp; /* The SDP this publisher negotiated, if any */ @@ -1510,6 +1536,7 @@ typedef struct janus_videoroom_subscriber { janus_videoroom_session *session; janus_videoroom *room; /* Room */ guint64 room_id; /* Unique room ID */ + gchar *room_id_str; /* Unique room ID (when using strings) */ janus_videoroom_publisher *feed; /* Participant this subscriber is subscribed to */ gboolean close_pc; /* Whether we should automatically close the PeerConnection when the publisher goes away */ guint32 pvt_id; /* Private ID of the participant that is subscribing (if available/provided) */ @@ -1558,6 +1585,7 @@ static void janus_videoroom_subscriber_destroy(janus_videoroom_subscriber *s) { static void janus_videoroom_subscriber_free(const janus_refcount *s_ref) { janus_videoroom_subscriber *s = janus_refcount_containerof(s_ref, janus_videoroom_subscriber, ref); /* This subscriber can be destroyed, free all the resources */ + g_free(s->room_id_str); janus_sdp_destroy(s->sdp); g_free(s); } @@ -1584,6 +1612,8 @@ static void janus_videoroom_publisher_destroy(janus_videoroom_publisher *p) { static void janus_videoroom_publisher_free(const janus_refcount *p_ref) { janus_videoroom_publisher *p = janus_refcount_containerof(p_ref, janus_videoroom_publisher, ref); + g_free(p->room_id_str); + g_free(p->user_id_str); g_free(p->display); p->display = NULL; g_free(p->sdp); @@ -1633,6 +1663,7 @@ static void janus_videoroom_room_destroy(janus_videoroom *room) { static void janus_videoroom_room_free(const janus_refcount *room_ref) { janus_videoroom *room = janus_refcount_containerof(room_ref, janus_videoroom, ref); /* This room can be destroyed, free all the resources */ + g_free(room->room_id_str); g_free(room->room_name); g_free(room->room_secret); g_free(room->room_pin); @@ -1694,7 +1725,8 @@ static void janus_videoroom_codecstr(janus_videoroom *videoroom, char *audio_cod static void janus_videoroom_reqpli(janus_videoroom_publisher *publisher, const char *reason) { /* Send a PLI */ - JANUS_LOG(LOG_VERB, "%s sending PLI to %"SCNu64" (%s)\n", reason, publisher->user_id, publisher->display ? publisher->display : "??"); + JANUS_LOG(LOG_VERB, "%s sending PLI to %s (%s)\n", reason, + publisher->user_id_str, publisher->display ? publisher->display : "??"); gateway->send_pli(publisher->session->handle); /* Update the time of when we last sent a keyframe request */ publisher->fir_latest = janus_get_monotonic_time(); @@ -1900,8 +1932,8 @@ static guint32 janus_videoroom_rtp_forwarder_add_helper(janus_videoroom_publishe (void)sendto(fd, &rtp, 12, 0, address, addrlen); } janus_mutex_unlock(&p->rtp_forwarders_mutex); - JANUS_LOG(LOG_VERB, "Added %s/%d rtp_forward to participant %"SCNu64" host: %s:%d stream_id: %"SCNu32"\n", - is_data ? "data" : (is_video ? "video" : "audio"), substream, p->user_id, host, port, stream_id); + JANUS_LOG(LOG_VERB, "Added %s/%d rtp_forward to participant %s host: %s:%d stream_id: %"SCNu32"\n", + is_data ? "data" : (is_video ? "video" : "audio"), substream, p->user_id_str, host, port, stream_id); return stream_id; } @@ -1967,10 +1999,7 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { if(config != NULL) janus_config_print(config); - rooms = g_hash_table_new_full(g_int64_hash, g_int64_equal, - (GDestroyNotify)g_free, (GDestroyNotify) janus_videoroom_room_destroy); sessions = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)janus_videoroom_session_destroy); - messages = g_async_queue_new_full((GDestroyNotify) janus_videoroom_message_free); /* This is the callback we'll need to invoke to contact the Janus core */ @@ -1992,7 +2021,17 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { if(!notify_events && callback->events_is_enabled()) { JANUS_LOG(LOG_WARN, "Notification of events to handlers disabled for %s\n", JANUS_VIDEOROOM_NAME); } - /* Iterate on all rooms */ + janus_config_item *ids = janus_config_get(config, config_general, janus_config_type_item, "string_ids"); + if(ids != NULL && ids->value != NULL) + string_ids = janus_is_true(ids->value); + if(string_ids) { + JANUS_LOG(LOG_INFO, "VideoRoom will use alphanumeric IDs, not numeric\n"); + } + } + rooms = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)janus_videoroom_room_destroy); + /* Iterate on all rooms */ + if(config != NULL) { GList *clist = janus_config_get_categories(config, NULL), *cl = clist; while(cl != NULL) { janus_config_category *cat = (janus_config_category *)cl->data; @@ -2000,7 +2039,7 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { cl = cl->next; continue; } - JANUS_LOG(LOG_VERB, "Adding video room '%s'\n", cat->name); + JANUS_LOG(LOG_VERB, "Adding VideoRoom room '%s'\n", cat->name); janus_config_item *desc = janus_config_get(config, cat, janus_config_type_item, "description"); janus_config_item *priv = janus_config_get(config, cat, janus_config_type_item, "is_private"); janus_config_item *secret = janus_config_get(config, cat, janus_config_type_item, "secret"); @@ -2029,7 +2068,36 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { const char *room_num = cat->name; if(strstr(room_num, "room-") == room_num) room_num += 5; - videoroom->room_id = g_ascii_strtoull(room_num, NULL, 0); + if(!string_ids) { + videoroom->room_id = g_ascii_strtoull(room_num, NULL, 0); + if(videoroom->room_id == 0) { + JANUS_LOG(LOG_ERR, "Can't add the VideoRoom room, invalid ID 0...\n"); + g_free(videoroom); + cl = cl->next; + continue; + } + /* Make sure the ID is completely numeric */ + char room_id_str[30]; + g_snprintf(room_id_str, sizeof(room_id_str), "%"SCNu64, videoroom->room_id); + if(strcmp(room_num, room_id_str)) { + JANUS_LOG(LOG_ERR, "Can't add the VideoRoom room, ID '%s' is not numeric...\n", room_num); + g_free(videoroom); + cl = cl->next; + continue; + } + } + /* Let's make sure the room doesn't exist already */ + janus_mutex_lock(&rooms_mutex); + if(g_hash_table_lookup(rooms, string_ids ? (gpointer)room_num : (gpointer)&videoroom->room_id) != NULL) { + /* It does... */ + janus_mutex_unlock(&rooms_mutex); + JANUS_LOG(LOG_ERR, "Can't add the VideoRoom room, room %s already exists...\n", room_num); + g_free(videoroom); + cl = cl->next; + continue; + } + janus_mutex_unlock(&rooms_mutex); + videoroom->room_id_str = g_strdup(room_num); char *description = NULL; if(desc != NULL && desc->value != NULL && strlen(desc->value) > 0) description = g_strdup(desc->value); @@ -2161,7 +2229,7 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { if(rec_dir && rec_dir->value) { videoroom->rec_dir = g_strdup(rec_dir->value); } - /* By default, the videoroom plugin does not notify about participants simply joining the room. + /* By default, the VideoRoom plugin does not notify about participants simply joining the room. It only notifies when the participant actually starts publishing media. */ videoroom->notify_joining = FALSE; if(notify_joining != NULL && notify_joining->value != NULL) @@ -2169,25 +2237,29 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { g_atomic_int_set(&videoroom->destroyed, 0); janus_mutex_init(&videoroom->mutex); janus_refcount_init(&videoroom->ref, janus_videoroom_room_free); - videoroom->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)janus_videoroom_publisher_dereference); + videoroom->participants = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)janus_videoroom_publisher_dereference); videoroom->private_ids = g_hash_table_new(NULL, NULL); videoroom->check_allowed = FALSE; /* Static rooms can't have an "allowed" list yet, no hooks to the configuration file */ videoroom->allowed = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); janus_mutex_lock(&rooms_mutex); - g_hash_table_insert(rooms, janus_uint64_dup(videoroom->room_id), videoroom); + g_hash_table_insert(rooms, + string_ids ? (gpointer)g_strdup(videoroom->room_id_str) : (gpointer)janus_uint64_dup(videoroom->room_id), + videoroom); janus_mutex_unlock(&rooms_mutex); /* Compute a list of the supported codecs for the summary */ char audio_codecs[100], video_codecs[100]; janus_videoroom_codecstr(videoroom, audio_codecs, video_codecs, sizeof(audio_codecs), "|"); - JANUS_LOG(LOG_VERB, "Created videoroom: %"SCNu64" (%s, %s, %s/%s codecs, secret: %s, pin: %s, pvtid: %s)\n", - videoroom->room_id, videoroom->room_name, + JANUS_LOG(LOG_VERB, "Created VideoRoom: %s (%s, %s, %s/%s codecs, secret: %s, pin: %s, pvtid: %s)\n", + videoroom->room_id_str, videoroom->room_name, videoroom->is_private ? "private" : "public", audio_codecs, video_codecs, videoroom->room_secret ? videoroom->room_secret : "no secret", videoroom->room_pin ? videoroom->room_pin : "no pin", videoroom->require_pvtid ? "required" : "optional"); if(videoroom->record) { - JANUS_LOG(LOG_VERB, " -- Room is going to be recorded in %s\n", videoroom->rec_dir ? videoroom->rec_dir : "the current folder"); + JANUS_LOG(LOG_VERB, " -- Room is going to be recorded in %s\n", + videoroom->rec_dir ? videoroom->rec_dir : "the current folder"); } cl = cl->next; } @@ -2204,8 +2276,8 @@ int janus_videoroom_init(janus_callbacks *callback, const char *config_path) { /* Compute a list of the supported codecs for the summary */ char audio_codecs[100], video_codecs[100]; janus_videoroom_codecstr(vr, audio_codecs, video_codecs, sizeof(audio_codecs), "|"); - JANUS_LOG(LOG_VERB, " ::: [%"SCNu64"][%s] %"SCNu32", max %d publishers, FIR frequency of %d seconds, %s audio codec(s), %s video codec(s)\n", - vr->room_id, vr->room_name, vr->bitrate, vr->max_publishers, vr->fir_freq, + JANUS_LOG(LOG_VERB, " ::: [%s][%s] %"SCNu32", max %d publishers, FIR frequency of %d seconds, %s audio codec(s), %s video codec(s)\n", + vr->room_id_str, vr->room_name, vr->bitrate, vr->max_publishers, vr->fir_freq, audio_codecs, video_codecs); } janus_mutex_unlock(&rooms_mutex); @@ -2365,7 +2437,7 @@ static void janus_videoroom_notify_participants(janus_videoroom_publisher *parti while (participant->room && !g_atomic_int_get(&participant->room->destroyed) && g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom_publisher *p = value; if(p && p->session && p != participant) { - JANUS_LOG(LOG_VERB, "Notifying participant %"SCNu64" (%s)\n", p->user_id, p->display ? p->display : "??"); + JANUS_LOG(LOG_VERB, "Notifying participant %s (%s)\n", p->user_id_str, p->display ? p->display : "??"); int ret = gateway->push_event(p->session->handle, &janus_videoroom_plugin, NULL, msg, NULL); JANUS_LOG(LOG_VERB, " >> %d (%s)\n", ret, janus_get_api_error(ret)); } @@ -2379,12 +2451,12 @@ static void janus_videoroom_participant_joining(janus_videoroom_publisher *p) { if(!g_atomic_int_get(&p->room->destroyed) && p->room->notify_joining) { json_t *event = json_object(); json_t *user = json_object(); - json_object_set_new(user, "id", json_integer(p->user_id)); + json_object_set_new(user, "id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if (p->display) { json_object_set_new(user, "display", json_string(p->display)); } json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(p->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(p->room_id_str) : json_integer(p->room_id)); json_object_set_new(event, "joining", user); janus_videoroom_notify_participants(p, event); /* user gets deref-ed by the owner event */ @@ -2397,8 +2469,8 @@ static void janus_videoroom_leave_or_unpublish(janus_videoroom_publisher *partic if(participant->room == NULL) return; janus_mutex_lock(&rooms_mutex); - if (!g_hash_table_lookup(rooms, &participant->room_id)) { - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", participant->room_id); + if(!g_hash_table_lookup(rooms, string_ids ? (gpointer)participant->room_id_str : (gpointer)&participant->room_id)) { + JANUS_LOG(LOG_ERR, "No such room (%s)\n", participant->room_id_str); janus_mutex_unlock(&rooms_mutex); return; } @@ -2415,7 +2487,7 @@ static void janus_videoroom_leave_or_unpublish(janus_videoroom_publisher *partic } json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(participant->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); json_object_set_new(event, is_leaving ? (kicked ? "kicked" : "leaving") : "unpublished", json_integer(participant->user_id)); janus_videoroom_notify_participants(participant, event); @@ -2423,12 +2495,13 @@ static void janus_videoroom_leave_or_unpublish(janus_videoroom_publisher *partic if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string(is_leaving ? (kicked ? "kicked" : "leaving") : "unpublished")); - json_object_set_new(info, "room", json_integer(participant->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); + json_object_set_new(info, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); gateway->notify_event(&janus_videoroom_plugin, NULL, info); } if(is_leaving) { - g_hash_table_remove(participant->room->participants, &participant->user_id); + g_hash_table_remove(participant->room->participants, + string_ids ? (gpointer)participant->user_id_str : (gpointer)&participant->user_id); g_hash_table_remove(participant->room->private_ids, GUINT_TO_POINTER(participant->pvt_id)); g_clear_pointer(&participant->room, janus_videoroom_room_dereference); } @@ -2512,7 +2585,7 @@ json_t *janus_videoroom_query_session(janus_plugin_session *handle) { if(participant && participant->room) { janus_videoroom *room = participant->room; json_object_set_new(info, "room", room ? json_integer(room->room_id) : NULL); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(info, "private_id", json_integer(participant->pvt_id)); if(participant->display) json_object_set_new(info, "display", json_string(participant->display)); @@ -2555,7 +2628,7 @@ json_t *janus_videoroom_query_session(janus_plugin_session *handle) { janus_videoroom *room = feed->room; json_object_set_new(info, "room", room ? json_integer(room->room_id) : NULL); json_object_set_new(info, "private_id", json_integer(participant->pvt_id)); - json_object_set_new(info, "feed_id", json_integer(feed->user_id)); + json_object_set_new(info, "feed_id", string_ids ? json_string(feed->user_id_str) : json_integer(feed->user_id)); if(feed->display) json_object_set_new(info, "feed_display", json_string(feed->display)); } @@ -2596,20 +2669,29 @@ static int janus_videoroom_access_room(json_t *root, gboolean check_modify, gboo /* rooms_mutex has to be locked */ int error_code = 0; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); - *videoroom = g_hash_table_lookup(rooms, &room_id); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } + *videoroom = g_hash_table_lookup(rooms, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); if(*videoroom == NULL) { - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_ROOM; if(error_cause) - g_snprintf(error_cause, error_cause_size, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, error_cause_size, "No such room (%s)", room_id_str); return error_code; } if(g_atomic_int_get(&((*videoroom)->destroyed))) { - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); + JANUS_LOG(LOG_ERR, "No such room (%s)\n", room_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_ROOM; if(error_cause) - g_snprintf(error_cause, error_cause_size, "No such room (%"SCNu64")", room_id); + g_snprintf(error_cause, error_cause_size, "No such room (%s)", room_id_str); return error_code; } if(check_modify) { @@ -2627,7 +2709,7 @@ static int janus_videoroom_access_room(json_t *root, gboolean check_modify, gboo json_t *token = json_object_get(root, "token"); if(token) { char room_descriptor[26]; - g_snprintf(room_descriptor, sizeof(room_descriptor), "room=%"SCNu64, room_id); + g_snprintf(room_descriptor, sizeof(room_descriptor), "room=%s", room_id_str); if(gateway->auth_signature_contains(&janus_videoroom_plugin, json_string_value(token), room_descriptor)) return 0; } @@ -2653,11 +2735,22 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi json_t *response = NULL; if(!strcasecmp(request_text, "create")) { - /* Create a new videoroom */ - JANUS_LOG(LOG_VERB, "Creating a new videoroom\n"); + /* Create a new VideoRoom */ + JANUS_LOG(LOG_VERB, "Creating a new VideoRoom room\n"); JANUS_VALIDATE_JSON_OBJECT(root, create_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, roomopt_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstropt_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; if(admin_key != NULL) { @@ -2769,29 +2862,35 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi goto prepare_response; } guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; json_t *room = json_object_get(root, "room"); - if(room) { + if(!string_ids) { room_id = json_integer_value(room); - if(room_id == 0) { - JANUS_LOG(LOG_WARN, "Desired room ID is 0, which is not allowed... picking random ID instead\n"); - } + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } + if(room_id == 0 && room_id_str == NULL) { + JANUS_LOG(LOG_WARN, "Desired room ID is empty, which is not allowed... picking random ID instead\n"); } janus_mutex_lock(&rooms_mutex); - if(room_id > 0) { + if(room_id > 0 || room_id_str != NULL) { /* Let's make sure the room doesn't exist already */ - if(g_hash_table_lookup(rooms, &room_id) != NULL) { + if(g_hash_table_lookup(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id) != NULL) { /* It does... */ janus_mutex_unlock(&rooms_mutex); - JANUS_LOG(LOG_ERR, "Room %"SCNu64" already exists!\n", room_id); error_code = JANUS_VIDEOROOM_ERROR_ROOM_EXISTS; - g_snprintf(error_cause, 512, "Room %"SCNu64" already exists", room_id); + JANUS_LOG(LOG_ERR, "Room %s already exists!\n", room_id_str); + g_snprintf(error_cause, 512, "Room %s already exists", room_id_str); goto prepare_response; } } /* Create the room */ janus_videoroom *videoroom = g_malloc0(sizeof(janus_videoroom)); /* Generate a random ID */ - if(room_id == 0) { + gboolean room_id_allocated = FALSE; + if(!string_ids && room_id == 0) { while(room_id == 0) { room_id = janus_random_uint64(); if(g_hash_table_lookup(rooms, &room_id) != NULL) { @@ -2799,14 +2898,28 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi room_id = 0; } } + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else if(string_ids && room_id_str == NULL) { + while(room_id_str == NULL) { + room_id_str = janus_random_uuid(); + if(g_hash_table_lookup(rooms, room_id_str) != NULL) { + /* Room ID already taken, try another one */ + g_clear_pointer(&room_id_str, g_free); + } + } + room_id_allocated = TRUE; } videoroom->room_id = room_id; + videoroom->room_id_str = room_id_str ? g_strdup(room_id_str) : NULL; + if(room_id_allocated) + g_free(room_id_str); char *description = NULL; if(desc != NULL && strlen(json_string_value(desc)) > 0) { description = g_strdup(json_string_value(desc)); } else { char roomname[255]; - g_snprintf(roomname, 255, "Room %"SCNu64"", videoroom->room_id); + g_snprintf(roomname, 255, "Room %s", videoroom->room_id_str); description = g_strdup(roomname); } videoroom->room_name = description; @@ -2915,7 +3028,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi videoroom->videoorient_ext = videoorient_ext ? json_is_true(videoorient_ext) : TRUE; videoroom->playoutdelay_ext = playoutdelay_ext ? json_is_true(playoutdelay_ext) : TRUE; videoroom->transport_wide_cc_ext = transport_wide_cc_ext ? json_is_true(transport_wide_cc_ext) : TRUE; - /* By default, the videoroom plugin does not notify about participants simply joining the room. + /* By default, the VideoRoom plugin does not notify about participants simply joining the room. It only notifies when the participant actually starts publishing media. */ videoroom->notify_joining = notify_joining ? json_is_true(notify_joining) : FALSE; if(record) { @@ -2927,7 +3040,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi g_atomic_int_set(&videoroom->destroyed, 0); janus_mutex_init(&videoroom->mutex); janus_refcount_init(&videoroom->ref, janus_videoroom_room_free); - videoroom->participants = g_hash_table_new_full(g_int64_hash, g_int64_equal, (GDestroyNotify)g_free, (GDestroyNotify)janus_videoroom_publisher_dereference); + videoroom->participants = g_hash_table_new_full(string_ids ? g_str_hash : g_int64_hash, string_ids ? g_str_equal : g_int64_equal, + (GDestroyNotify)g_free, (GDestroyNotify)janus_videoroom_publisher_dereference); videoroom->private_ids = g_hash_table_new(NULL, NULL); videoroom->allowed = g_hash_table_new_full(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL); if(allowed != NULL) { @@ -2945,8 +3059,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi /* Compute a list of the supported codecs for the summary */ char audio_codecs[100], video_codecs[100]; janus_videoroom_codecstr(videoroom, audio_codecs, video_codecs, sizeof(audio_codecs), "|"); - JANUS_LOG(LOG_VERB, "Created videoroom: %"SCNu64" (%s, %s, %s/%s codecs, secret: %s, pin: %s, pvtid: %s)\n", - videoroom->room_id, videoroom->room_name, + JANUS_LOG(LOG_VERB, "Created VideoRoom: %s (%s, %s, %s/%s codecs, secret: %s, pin: %s, pvtid: %s)\n", + videoroom->room_id_str, videoroom->room_name, videoroom->is_private ? "private" : "public", audio_codecs, video_codecs, videoroom->room_secret ? videoroom->room_secret : "no secret", @@ -2958,11 +3072,11 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(save) { /* This room is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Saving room %"SCNu64" permanently in config file\n", videoroom->room_id); + JANUS_LOG(LOG_VERB, "Saving room %s permanently in config file\n", videoroom->room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ], value[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, videoroom->room_id); + g_snprintf(cat, BUFSIZ, "room-%s", videoroom->room_id_str); janus_config_category *c = janus_config_get_create(config, NULL, janus_config_type_category, cat); /* Now for the values */ janus_config_add(config, c, janus_config_item_create("description", videoroom->room_name)); @@ -3023,32 +3137,46 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi janus_mutex_unlock(&config_mutex); } - g_hash_table_insert(rooms, janus_uint64_dup(videoroom->room_id), videoroom); + g_hash_table_insert(rooms, + string_ids ? (gpointer)g_strdup(videoroom->room_id_str) : (gpointer)janus_uint64_dup(videoroom->room_id), + videoroom); /* Show updated rooms list */ GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, rooms); while (g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom *vr = value; - JANUS_LOG(LOG_VERB, " ::: [%"SCNu64"][%s] %"SCNu32", max %d publishers, FIR frequency of %d seconds\n", vr->room_id, vr->room_name, vr->bitrate, vr->max_publishers, vr->fir_freq); + JANUS_LOG(LOG_VERB, " ::: [%s][%s] %"SCNu32", max %d publishers, FIR frequency of %d seconds\n", + vr->room_id_str, vr->room_name, vr->bitrate, vr->max_publishers, vr->fir_freq); } janus_mutex_unlock(&rooms_mutex); /* Send info back */ response = json_object(); json_object_set_new(response, "videoroom", json_string("created")); - json_object_set_new(response, "room", json_integer(videoroom->room_id)); + json_object_set_new(response, "room", string_ids ? json_string(videoroom->room_id_str) : json_integer(videoroom->room_id)); json_object_set_new(response, "permanent", save ? json_true() : json_false()); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("created")); - json_object_set_new(info, "room", json_integer(videoroom->room_id)); + json_object_set_new(info, "room", string_ids ? json_string(videoroom->room_id_str) : json_integer(videoroom->room_id)); gateway->notify_event(&janus_videoroom_plugin, session ? session->handle : NULL, info); } goto prepare_response; } else if(!strcasecmp(request_text, "edit")) { - /* Edit the properties for an existing videoroom */ - JANUS_LOG(LOG_VERB, "Attempt to edit the properties of an existing videoroom room\n"); + /* Edit the properties for an existing VideoRoom */ + JANUS_LOG(LOG_VERB, "Attempt to edit the properties of an existing VideoRoom room\n"); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; JANUS_VALIDATE_JSON_OBJECT(root, edit_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); @@ -3113,11 +3241,11 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(save) { /* This room is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Modifying room %"SCNu64" permanently in config file\n", videoroom->room_id); + JANUS_LOG(LOG_VERB, "Modifying room %s permanently in config file\n", videoroom->room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ], value[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, videoroom->room_id); + g_snprintf(cat, BUFSIZ, "room-%s", videoroom->room_id_str); /* Remove the old category first */ janus_config_remove(config, NULL, cat); /* Now write the room details again */ @@ -3183,18 +3311,29 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi /* Send info back */ response = json_object(); json_object_set_new(response, "videoroom", json_string("edited")); - json_object_set_new(response, "room", json_integer(videoroom->room_id)); + json_object_set_new(response, "room", string_ids ? json_string(videoroom->room_id_str) : json_integer(videoroom->room_id)); json_object_set_new(response, "permanent", save ? json_true() : json_false()); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("edited")); - json_object_set_new(info, "room", json_integer(videoroom->room_id)); + json_object_set_new(info, "room", string_ids ? json_string(videoroom->room_id_str) : json_integer(videoroom->room_id)); gateway->notify_event(&janus_videoroom_plugin, session ? session->handle : NULL, info); } goto prepare_response; } else if(!strcasecmp(request_text, "destroy")) { - JANUS_LOG(LOG_VERB, "Attempt to destroy an existing videoroom room\n"); + JANUS_LOG(LOG_VERB, "Attempt to destroy an existing VideoRoom room\n"); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; JANUS_VALIDATE_JSON_OBJECT(root, destroy_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); @@ -3209,7 +3348,15 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi g_snprintf(error_cause, 512, "No configuration file, can't destroy room permanently"); goto prepare_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); janus_videoroom *videoroom = NULL; error_code = janus_videoroom_access_room(root, TRUE, FALSE, &videoroom, error_cause, sizeof(error_cause)); @@ -3224,7 +3371,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi JANUS_LOG(LOG_VERB, "Notifying all participants\n"); json_t *destroyed = json_object(); json_object_set_new(destroyed, "videoroom", json_string("destroyed")); - json_object_set_new(destroyed, "room", json_integer(room_id)); + json_object_set_new(destroyed, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); GHashTableIter iter; gpointer value; janus_mutex_lock(&videoroom->mutex); @@ -3246,18 +3393,18 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("destroyed")); - json_object_set_new(info, "room", json_integer(room_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); gateway->notify_event(&janus_videoroom_plugin, session ? session->handle : NULL, info); } janus_mutex_unlock(&rooms_mutex); if(save) { /* This change is permanent: save to the configuration file too * FIXME: We should check if anything fails... */ - JANUS_LOG(LOG_VERB, "Destroying room %"SCNu64" permanently in config file\n", room_id); + JANUS_LOG(LOG_VERB, "Destroying room %s permanently in config file\n", room_id_str); janus_mutex_lock(&config_mutex); char cat[BUFSIZ]; /* The room ID is the category (prefixed by "room-") */ - g_snprintf(cat, BUFSIZ, "room-%"SCNu64, room_id); + g_snprintf(cat, BUFSIZ, "room-%s", room_id_str); janus_config_remove(config, NULL, cat); /* Save modified configuration */ if(janus_config_save(config, config_folder, JANUS_VIDEOROOM_PACKAGE) < 0) @@ -3268,13 +3415,13 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi /* Done */ response = json_object(); json_object_set_new(response, "videoroom", json_string("destroyed")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "permanent", save ? json_true() : json_false()); goto prepare_response; } else if(!strcasecmp(request_text, "list")) { /* List all rooms (but private ones) and their details (except for the secret, of course...) */ json_t *list = json_array(); - JANUS_LOG(LOG_VERB, "Getting the list of video rooms\n"); + JANUS_LOG(LOG_VERB, "Getting the list of VideoRoom rooms\n"); janus_mutex_lock(&rooms_mutex); GHashTableIter iter; gpointer value; @@ -3292,7 +3439,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi } if(!g_atomic_int_get(&room->destroyed)) { json_t *rl = json_object(); - json_object_set_new(rl, "room", json_integer(room->room_id)); + json_object_set_new(rl, "room", string_ids ? json_string(room->room_id_str) : json_integer(room->room_id)); json_object_set_new(rl, "description", json_string(room->room_name)); json_object_set_new(rl, "pin_required", room->room_pin ? json_true() : json_false()); json_object_set_new(rl, "max_publishers", json_integer(room->max_publishers)); @@ -3328,6 +3475,28 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi JANUS_VALIDATE_JSON_OBJECT(root, rtp_forward_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, pid_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, pidstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; if(lock_rtpfwd && admin_key != NULL) { @@ -3442,8 +3611,24 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi } srtp_crypto = json_string_value(s_crypto); } - guint64 room_id = json_integer_value(room); - guint64 publisher_id = json_integer_value(pub_id); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } + guint64 publisher_id = 0; + char publisher_id_num[30], *publisher_id_str = NULL; + if(!string_ids) { + publisher_id = json_integer_value(pub_id); + g_snprintf(publisher_id_num, sizeof(publisher_id_num), "%"SCNu64, publisher_id); + publisher_id_str = publisher_id_num; + } else { + publisher_id_str = (char *)json_string_value(pub_id); + } const char *host = json_string_value(json_host), *resolved_host = NULL; /* Check if we need to resolve this host address */ struct addrinfo *res = NULL, *start = NULL; @@ -3484,13 +3669,14 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi goto prepare_response; janus_refcount_increase(&videoroom->ref); janus_mutex_lock(&videoroom->mutex); - janus_videoroom_publisher *publisher = g_hash_table_lookup(videoroom->participants, &publisher_id); + janus_videoroom_publisher *publisher = g_hash_table_lookup(videoroom->participants, + string_ids ? (gpointer)publisher_id_str : (gpointer)&publisher_id); if(publisher == NULL) { janus_mutex_unlock(&videoroom->mutex); janus_refcount_decrease(&videoroom->ref); - JANUS_LOG(LOG_ERR, "No such publisher (%"SCNu64")\n", publisher_id); + JANUS_LOG(LOG_ERR, "No such publisher (%s)\n", publisher_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_FEED; - g_snprintf(error_cause, 512, "No such feed (%"SCNu64")", publisher_id); + g_snprintf(error_cause, 512, "No such feed (%s)", publisher_id_str); goto prepare_response; } janus_refcount_increase(&publisher->ref); /* This is just to handle the request for now */ @@ -3502,7 +3688,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi janus_refcount_decrease(&publisher->ref); janus_mutex_unlock(&videoroom->mutex); janus_refcount_decrease(&videoroom->ref); - JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP stream for publisher (%"SCNu64")\n", publisher_id); + JANUS_LOG(LOG_ERR, "Could not open UDP socket for RTP stream for publisher (%s)\n", publisher_id_str); error_code = JANUS_VIDEOROOM_ERROR_UNKNOWN_ERROR; g_snprintf(error_cause, 512, "Could not open UDP socket for RTP stream"); goto prepare_response; @@ -3542,8 +3728,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("rtp_forward")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "publisher_id", json_integer(publisher_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(info, "media", json_string("audio")); json_object_set_new(info, "stream_id", json_integer(audio_handle)); json_object_set_new(info, "host", json_string(host)); @@ -3563,8 +3749,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("rtp_forward")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "publisher_id", json_integer(publisher_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(info, "media", json_string("video")); if(video_handle[1] > 0 || video_handle[2] > 0) json_object_set_new(info, "video_substream", json_integer(0)); @@ -3581,8 +3767,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("rtp_forward")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "publisher_id", json_integer(publisher_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(info, "media", json_string("video")); json_object_set_new(info, "video_substream", json_integer(1)); json_object_set_new(info, "stream_id", json_integer(video_handle[1])); @@ -3598,8 +3784,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("rtp_forward")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "publisher_id", json_integer(publisher_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(info, "media", json_string("video")); json_object_set_new(info, "video_substream", json_integer(2)); json_object_set_new(info, "stream_id", json_integer(video_handle[2])); @@ -3616,8 +3802,8 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("rtp_forward")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "publisher_id", json_integer(publisher_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(info, "media", json_string("data")); json_object_set_new(info, "stream_id", json_integer(data_handle)); json_object_set_new(info, "host", json_string(host)); @@ -3629,12 +3815,34 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi janus_refcount_decrease(&publisher->ref); janus_refcount_decrease(&videoroom->ref); json_object_set_new(rtp_stream, "host", json_string(host)); - json_object_set_new(response, "publisher_id", json_integer(publisher_id)); + json_object_set_new(response, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(response, "rtp_stream", rtp_stream); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "videoroom", json_string("rtp_forward")); goto prepare_response; } else if(!strcasecmp(request_text, "stop_rtp_forward")) { + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, pid_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, pidstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; JANUS_VALIDATE_JSON_OBJECT(root, stop_rtp_forward_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); @@ -3656,8 +3864,24 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi json_t *pub_id = json_object_get(root, "publisher_id"); json_t *id = json_object_get(root, "stream_id"); - guint64 room_id = json_integer_value(room); - guint64 publisher_id = json_integer_value(pub_id); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } + guint64 publisher_id = 0; + char publisher_id_num[30], *publisher_id_str = NULL; + if(!string_ids) { + publisher_id = json_integer_value(pub_id); + g_snprintf(publisher_id_num, sizeof(publisher_id_num), "%"SCNu64, publisher_id); + publisher_id_str = publisher_id_num; + } else { + publisher_id_str = (char *)json_string_value(pub_id); + } guint32 stream_id = json_integer_value(id); janus_mutex_lock(&rooms_mutex); janus_videoroom *videoroom = NULL; @@ -3667,13 +3891,14 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi goto prepare_response; janus_mutex_lock(&videoroom->mutex); janus_refcount_increase(&videoroom->ref); - janus_videoroom_publisher *publisher = g_hash_table_lookup(videoroom->participants, &publisher_id); + janus_videoroom_publisher *publisher = g_hash_table_lookup(videoroom->participants, + string_ids ? (gpointer)publisher_id_str : (gpointer)&publisher_id); if(publisher == NULL) { janus_mutex_unlock(&videoroom->mutex); janus_refcount_decrease(&videoroom->ref); - JANUS_LOG(LOG_ERR, "No such publisher (%"SCNu64")\n", publisher_id); + JANUS_LOG(LOG_ERR, "No such publisher (%s)\n", publisher_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_FEED; - g_snprintf(error_cause, 512, "No such feed (%"SCNu64")", publisher_id); + g_snprintf(error_cause, 512, "No such feed (%s)", publisher_id_str); goto prepare_response; } janus_refcount_increase(&publisher->ref); /* Just to handle the message now */ @@ -3694,38 +3919,63 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi janus_refcount_decrease(&videoroom->ref); response = json_object(); json_object_set_new(response, "videoroom", json_string("stop_rtp_forward")); - json_object_set_new(response, "room", json_integer(room_id)); - json_object_set_new(response, "publisher_id", json_integer(publisher_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(response, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(response, "stream_id", json_integer(stream_id)); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("stop_rtp_forward")); - json_object_set_new(info, "room", json_integer(room_id)); - json_object_set_new(info, "publisher_id", json_integer(publisher_id)); + json_object_set_new(info, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(info, "publisher_id", string_ids ? json_string(publisher_id_str) : json_integer(publisher_id)); json_object_set_new(info, "stream_id", json_integer(stream_id)); gateway->notify_event(&janus_videoroom_plugin, NULL, info); } goto prepare_response; } else if(!strcasecmp(request_text, "exists")) { /* Check whether a given room exists or not, returns true/false */ - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); - gboolean room_exists = g_hash_table_contains(rooms, &room_id); + gboolean room_exists = g_hash_table_contains(rooms, string_ids ? (gpointer)room_id_str : (gpointer)&room_id); janus_mutex_unlock(&rooms_mutex); response = json_object(); json_object_set_new(response, "videoroom", json_string("success")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "exists", room_exists ? json_true() : json_false()); goto prepare_response; } else if(!strcasecmp(request_text, "allowed")) { - JANUS_LOG(LOG_VERB, "Attempt to edit the list of allowed participants in an existing videoroom room\n"); + JANUS_LOG(LOG_VERB, "Attempt to edit the list of allowed participants in an existing VideoRoom room\n"); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; JANUS_VALIDATE_JSON_OBJECT(root, allowed_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); @@ -3742,7 +3992,15 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi g_snprintf(error_cause, 512, "Unsupported action '%s' (allowed)", action_text); goto prepare_response; } - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); janus_videoroom *videoroom = NULL; error_code = janus_videoroom_access_room(root, TRUE, FALSE, &videoroom, error_cause, sizeof(error_cause)); @@ -3760,10 +4018,10 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi goto prepare_response; } if(!strcasecmp(action_text, "enable")) { - JANUS_LOG(LOG_VERB, "Enabling the check on allowed authorization tokens for room %"SCNu64"\n", room_id); + JANUS_LOG(LOG_VERB, "Enabling the check on allowed authorization tokens for room %s\n", room_id_str); videoroom->check_allowed = TRUE; } else if(!strcasecmp(action_text, "disable")) { - JANUS_LOG(LOG_VERB, "Disabling the check on allowed authorization tokens for room %"SCNu64" (free entry)\n", room_id); + JANUS_LOG(LOG_VERB, "Disabling the check on allowed authorization tokens for room %s (free entry)\n", room_id_str); videoroom->check_allowed = FALSE; } else { gboolean add = !strcasecmp(action_text, "add"); @@ -3802,7 +4060,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi /* Prepare response */ response = json_object(); json_object_set_new(response, "videoroom", json_string("success")); - json_object_set_new(response, "room", json_integer(videoroom->room_id)); + json_object_set_new(response, "room", string_ids ? json_string(videoroom->room_id_str) : json_integer(videoroom->room_id)); json_t *list = json_array(); if(strcasecmp(action_text, "disable")) { if(g_hash_table_size(videoroom->allowed) > 0) { @@ -3821,7 +4079,27 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi JANUS_LOG(LOG_VERB, "VideoRoom room allowed list updated\n"); goto prepare_response; } else if(!strcasecmp(request_text, "kick")) { - JANUS_LOG(LOG_VERB, "Attempt to kick a participant from an existing videoroom room\n"); + JANUS_LOG(LOG_VERB, "Attempt to kick a participant from an existing VideoRoom room\n"); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, id_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, idstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto prepare_response; JANUS_VALIDATE_JSON_OBJECT(root, kick_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); @@ -3829,7 +4107,15 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi goto prepare_response; json_t *room = json_object_get(root, "room"); json_t *id = json_object_get(root, "id"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); janus_videoroom *videoroom = NULL; error_code = janus_videoroom_access_room(root, TRUE, FALSE, &videoroom, error_cause, sizeof(error_cause)); @@ -3848,14 +4134,23 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi janus_refcount_decrease(&videoroom->ref); goto prepare_response; } - guint64 user_id = json_integer_value(id); - janus_videoroom_publisher *participant = g_hash_table_lookup(videoroom->participants, &user_id); + guint64 user_id = 0; + char user_id_num[30], *user_id_str = NULL; + if(!string_ids) { + user_id = json_integer_value(id); + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; + } else { + user_id_str = (char *)json_string_value(id); + } + janus_videoroom_publisher *participant = g_hash_table_lookup(videoroom->participants, + string_ids ? (gpointer)user_id_str : (gpointer)&user_id); if(participant == NULL) { janus_mutex_unlock(&videoroom->mutex); janus_refcount_decrease(&videoroom->ref); - JANUS_LOG(LOG_ERR, "No such user %"SCNu64" in room %"SCNu64"\n", user_id, room_id); + JANUS_LOG(LOG_ERR, "No such user %s in room %s\n", user_id_str, room_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_FEED; - g_snprintf(error_cause, 512, "No such user %"SCNu64" in room %"SCNu64, user_id, room_id); + g_snprintf(error_cause, 512, "No such user %s in room %s", user_id_str, room_id_str); goto prepare_response; } if(participant->kicked) { @@ -3875,7 +4170,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi /* Prepare an event for this */ json_t *kicked = json_object(); json_object_set_new(kicked, "videoroom", json_string("event")); - json_object_set_new(kicked, "room", json_integer(participant->room_id)); + json_object_set_new(kicked, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); json_object_set_new(kicked, "leaving", json_string("ok")); json_object_set_new(kicked, "reason", json_string("kicked")); int ret = gateway->push_event(participant->session->handle, &janus_videoroom_plugin, NULL, kicked, NULL); @@ -3906,7 +4201,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi /* Tell the core to tear down the PeerConnection, hangup_media will do the rest */ if(participant && participant->session) gateway->close_pc(participant->session->handle); - JANUS_LOG(LOG_INFO, "Kicked user %"SCNu64" from room %"SCNu64"\n", user_id, room_id); + JANUS_LOG(LOG_INFO, "Kicked user %s from room %s\n", user_id_str, room_id_str); /* Prepare response */ response = json_object(); json_object_set_new(response, "videoroom", json_string("success")); @@ -3915,13 +4210,27 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi goto prepare_response; } else if(!strcasecmp(request_text, "listparticipants")) { /* List all participants in a room, specifying whether they're publishers or just attendees */ - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); + } janus_mutex_lock(&rooms_mutex); janus_videoroom *videoroom = NULL; error_code = janus_videoroom_access_room(root, FALSE, FALSE, &videoroom, error_cause, sizeof(error_cause)); @@ -3938,7 +4247,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi while (!g_atomic_int_get(&videoroom->destroyed) && g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom_publisher *p = value; json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(p->user_id)); + json_object_set_new(pl, "id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if(p->display) json_object_set_new(pl, "display", json_string(p->display)); json_object_set_new(pl, "publisher", (p->sdp && p->session->started) ? json_true() : json_false()); @@ -3952,41 +4261,38 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi janus_refcount_decrease(&videoroom->ref); response = json_object(); json_object_set_new(response, "videoroom", json_string("participants")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "participants", list); goto prepare_response; } else if(!strcasecmp(request_text, "listforwarders")) { /* List all forwarders in a room */ - JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, - error_code, error_cause, TRUE, - JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto prepare_response; json_t *room = json_object_get(root, "room"); - guint64 room_id = json_integer_value(room); - janus_mutex_lock(&rooms_mutex); - janus_videoroom *videoroom = g_hash_table_lookup(rooms, &room_id); - if(videoroom == NULL) { - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); - error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); - janus_mutex_unlock(&rooms_mutex); - goto prepare_response; - } - if(g_atomic_int_get(&videoroom->destroyed)) { - JANUS_LOG(LOG_ERR, "No such room (%"SCNu64")\n", room_id); - error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", room_id); - janus_mutex_unlock(&rooms_mutex); - goto prepare_response; + guint64 room_id = 0; + char room_id_num[30], *room_id_str = NULL; + if(!string_ids) { + room_id = json_integer_value(room); + g_snprintf(room_id_num, sizeof(room_id_num), "%"SCNu64, room_id); + room_id_str = room_id_num; + } else { + room_id_str = (char *)json_string_value(room); } - /* A secret may be required for this action */ - JANUS_CHECK_SECRET(videoroom->room_secret, root, "secret", error_code, error_cause, - JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT, JANUS_VIDEOROOM_ERROR_UNAUTHORIZED); - if(error_code != 0) { - janus_mutex_unlock(&rooms_mutex); + janus_mutex_lock(&rooms_mutex); + janus_videoroom *videoroom = NULL; + error_code = janus_videoroom_access_room(root, TRUE, FALSE, &videoroom, error_cause, sizeof(error_cause)); + janus_mutex_unlock(&rooms_mutex); + if(error_code != 0) goto prepare_response; - } /* Return a list of all forwarders */ json_t *list = json_array(); GHashTableIter iter; @@ -4001,7 +4307,7 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi continue; } json_t *pl = json_object(); - json_object_set_new(pl, "publisher_id", json_integer(p->user_id)); + json_object_set_new(pl, "publisher_id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if(p->display) json_object_set_new(pl, "display", json_string(p->display)); json_t *flist = json_array(); @@ -4057,10 +4363,9 @@ static json_t *janus_videoroom_process_synchronous_request(janus_videoroom_sessi json_array_append_new(list, pl); } janus_mutex_unlock(&videoroom->mutex); - janus_mutex_unlock(&rooms_mutex); response = json_object(); json_object_set_new(response, "videoroom", json_string("forwarders")); - json_object_set_new(response, "room", json_integer(room_id)); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(response, "rtp_forwarders", list); goto prepare_response; } else { @@ -4252,7 +4557,7 @@ void janus_videoroom_setup_media(janus_plugin_session *handle) { /* Notify all other participants that there's a new boy in town */ json_t *list = json_array(); json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(participant->user_id)); + json_object_set_new(pl, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); if(participant->display) json_object_set_new(pl, "display", json_string(participant->display)); if(participant->audio) @@ -4266,7 +4571,7 @@ void janus_videoroom_setup_media(janus_plugin_session *handle) { json_array_append_new(list, pl); json_t *pub = json_object(); json_object_set_new(pub, "videoroom", json_string("event")); - json_object_set_new(pub, "room", json_integer(participant->room_id)); + json_object_set_new(pub, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); json_object_set_new(pub, "publishers", list); if (participant->room) { janus_mutex_lock(&participant->room->mutex); @@ -4278,8 +4583,8 @@ void janus_videoroom_setup_media(janus_plugin_session *handle) { if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("published")); - json_object_set_new(info, "room", json_integer(participant->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); + json_object_set_new(info, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); gateway->notify_event(&janus_videoroom_plugin, session->handle, info); } janus_refcount_decrease(&participant->ref); @@ -4293,8 +4598,8 @@ void janus_videoroom_setup_media(janus_plugin_session *handle) { if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("subscribed")); - json_object_set_new(info, "room", json_integer(p->room_id)); - json_object_set_new(info, "feed", json_integer(p->user_id)); + json_object_set_new(info, "room", string_ids ? json_string(p->room_id_str) : json_integer(p->room_id)); + json_object_set_new(info, "feed", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); gateway->notify_event(&janus_videoroom_plugin, session->handle, info); } } @@ -4350,8 +4655,8 @@ void janus_videoroom_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp janus_mutex_lock(&videoroom->mutex); json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string(participant->talking ? "talking" : "stopped-talking")); - json_object_set_new(event, "room", json_integer(videoroom->room_id)); - json_object_set_new(event, "id", json_integer(participant->user_id)); + json_object_set_new(event, "room", string_ids ? json_string(videoroom->room_id_str) : json_integer(videoroom->room_id)); + json_object_set_new(event, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(event, "audio-level-dBov-avg", json_real(audio_dBov_avg)); janus_videoroom_notify_participants(participant, event); json_decref(event); @@ -4360,8 +4665,8 @@ void janus_videoroom_incoming_rtp(janus_plugin_session *handle, janus_plugin_rtp if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "videoroom", json_string(participant->talking ? "talking" : "stopped-talking")); - json_object_set_new(info, "room", json_integer(videoroom->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", string_ids ? json_string(videoroom->room_id_str) : json_integer(videoroom->room_id)); + json_object_set_new(info, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(event, "audio-level-dBov-avg", json_real(audio_dBov_avg)); gateway->notify_event(&janus_videoroom_plugin, session->handle, info); } @@ -4745,8 +5050,8 @@ static void janus_videoroom_recorder_create(janus_videoroom_publisher *participa } } else { /* Build a filename */ - g_snprintf(filename, 255, "videoroom-%"SCNu64"-user-%"SCNu64"-%"SCNi64"-audio", - participant->room_id, participant->user_id, now); + g_snprintf(filename, 255, "videoroom-%s-user-%s-%"SCNi64"-audio", + participant->room_id_str, participant->user_id_str, now); participant->arc = janus_recorder_create(participant->room->rec_dir, janus_audiocodec_name(participant->acodec), filename); if(participant->arc == NULL) { @@ -4770,8 +5075,8 @@ static void janus_videoroom_recorder_create(janus_videoroom_publisher *participa } } else { /* Build a filename */ - g_snprintf(filename, 255, "videoroom-%"SCNu64"-user-%"SCNu64"-%"SCNi64"-video", - participant->room_id, participant->user_id, now); + g_snprintf(filename, 255, "videoroom-%s-user-%s-%"SCNi64"-video", + participant->room_id_str, participant->user_id_str, now); participant->vrc = janus_recorder_create(participant->room->rec_dir, janus_videocodec_name(participant->vcodec), filename); if(participant->vrc == NULL) { @@ -4791,8 +5096,8 @@ static void janus_videoroom_recorder_create(janus_videoroom_publisher *participa } } else { /* Build a filename */ - g_snprintf(filename, 255, "videoroom-%"SCNu64"-user-%"SCNu64"-%"SCNi64"-data", - participant->room_id, participant->user_id, now); + g_snprintf(filename, 255, "videoroom-%s-user-%s-%"SCNi64"-data", + participant->room_id_str, participant->user_id_str, now); participant->drc = janus_recorder_create(participant->room->rec_dir, "text", filename); if(participant->drc == NULL) { @@ -4936,8 +5241,8 @@ static void janus_videoroom_hangup_media_internal(janus_plugin_session *handle) if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("unsubscribed")); - json_object_set_new(info, "room", json_integer(publisher->room_id)); - json_object_set_new(info, "feed", json_integer(publisher->user_id)); + json_object_set_new(info, "room", string_ids ? json_string(publisher->room_id_str) : json_integer(publisher->room_id)); + json_object_set_new(info, "feed", string_ids ? json_string(publisher->user_id_str) : json_integer(publisher->user_id)); gateway->notify_event(&janus_videoroom_plugin, session->handle, info); } janus_mutex_lock(&publisher->subscribers_mutex); @@ -5014,6 +5319,17 @@ static void *janus_videoroom_handler(void *data) { g_snprintf(error_cause, 512, "Invalid request on unconfigured participant"); goto error; } + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, room_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, roomstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto error; JANUS_VALIDATE_JSON_OBJECT(root, join_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); @@ -5040,6 +5356,17 @@ static void *janus_videoroom_handler(void *data) { janus_refcount_decrease(&videoroom->ref); goto error; } + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, idopt_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, idstropt_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto error; /* A token might be required to join */ if(videoroom->check_allowed) { json_t *token = json_object_get(root, "token"); @@ -5056,30 +5383,56 @@ static void *janus_videoroom_handler(void *data) { json_t *display = json_object_get(root, "display"); const char *display_text = display ? json_string_value(display) : NULL; guint64 user_id = 0; + char user_id_num[30], *user_id_str = NULL; + gboolean user_id_allocated = FALSE; json_t *id = json_object_get(root, "id"); if(id) { - user_id = json_integer_value(id); - if(g_hash_table_lookup(videoroom->participants, &user_id) != NULL) { + if(!string_ids) { + user_id = json_integer_value(id); + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; + } else { + user_id_str = (char *)json_string_value(id); + } + if(g_hash_table_lookup(videoroom->participants, + string_ids ? (gpointer)user_id_str : (gpointer)&user_id) != NULL) { + /* User ID already taken */ janus_mutex_unlock(&videoroom->mutex); janus_refcount_decrease(&videoroom->ref); - /* User ID already taken */ - JANUS_LOG(LOG_ERR, "User ID %"SCNu64" already exists\n", user_id); error_code = JANUS_VIDEOROOM_ERROR_ID_EXISTS; - g_snprintf(error_cause, 512, "User ID %"SCNu64" already exists", user_id); + JANUS_LOG(LOG_ERR, "User ID %s already exists\n", user_id_str); + g_snprintf(error_cause, 512, "User ID %s already exists", user_id_str); goto error; } } - if(user_id == 0) { - /* Generate a random ID */ - while(user_id == 0) { - user_id = janus_random_uint64(); - if(g_hash_table_lookup(videoroom->participants, &user_id) != NULL) { - /* User ID already taken, try another one */ - user_id = 0; + if(!string_ids) { + if(user_id == 0) { + /* Generate a random ID */ + while(user_id == 0) { + user_id = janus_random_uint64(); + if(g_hash_table_lookup(videoroom->participants, &user_id) != NULL) { + /* User ID already taken, try another one */ + user_id = 0; + } } + g_snprintf(user_id_num, sizeof(user_id_num), "%"SCNu64, user_id); + user_id_str = user_id_num; } + JANUS_LOG(LOG_VERB, " -- Participant ID: %"SCNu64"\n", user_id); + } else { + if(user_id_str == NULL) { + /* Generate a random ID */ + while(user_id_str == NULL) { + user_id_str = janus_random_uuid(); + if(g_hash_table_lookup(videoroom->participants, user_id_str) != NULL) { + /* User ID already taken, try another one */ + g_clear_pointer(&user_id_str, g_free); + } + } + user_id_allocated = TRUE; + } + JANUS_LOG(LOG_VERB, " -- Participant ID: %s\n", user_id_str); } - JANUS_LOG(LOG_VERB, " -- Publisher ID: %"SCNu64"\n", user_id); /* Process the request */ json_t *audio = NULL, *video = NULL, *data = NULL, *bitrate = NULL, *record = NULL, *recfile = NULL; @@ -5096,9 +5449,11 @@ static void *janus_videoroom_handler(void *data) { janus_videoroom_publisher *publisher = g_malloc0(sizeof(janus_videoroom_publisher)); publisher->session = session; publisher->room_id = videoroom->room_id; + publisher->room_id_str = videoroom->room_id_str ? g_strdup(videoroom->room_id_str) : NULL; publisher->room = videoroom; videoroom = NULL; publisher->user_id = user_id; + publisher->user_id_str = user_id_str ? g_strdup(user_id_str) : NULL; publisher->display = display_text ? g_strdup(display_text) : NULL; publisher->sdp = NULL; /* We'll deal with this later */ publisher->audio = FALSE; /* We'll deal with this later */ @@ -5149,27 +5504,33 @@ static void *janus_videoroom_handler(void *data) { /* In case we also wanted to configure */ if(audio) { publisher->audio_active = json_is_true(audio); - JANUS_LOG(LOG_VERB, "Setting audio property: %s (room %"SCNu64", user %"SCNu64")\n", publisher->audio_active ? "true" : "false", publisher->room_id, publisher->user_id); + JANUS_LOG(LOG_VERB, "Setting audio property: %s (room %s, user %s)\n", + publisher->audio_active ? "true" : "false", publisher->room_id_str, publisher->user_id_str); } if(video) { publisher->video_active = json_is_true(video); - JANUS_LOG(LOG_VERB, "Setting video property: %s (room %"SCNu64", user %"SCNu64")\n", publisher->video_active ? "true" : "false", publisher->room_id, publisher->user_id); + JANUS_LOG(LOG_VERB, "Setting video property: %s (room %s, user %s)\n", + publisher->video_active ? "true" : "false", publisher->room_id_str, publisher->user_id_str); } if(data) { publisher->data_active = json_is_true(data); - JANUS_LOG(LOG_VERB, "Setting data property: %s (room %"SCNu64", user %"SCNu64")\n", publisher->data_active ? "true" : "false", publisher->room_id, publisher->user_id); + JANUS_LOG(LOG_VERB, "Setting data property: %s (room %s, user %s)\n", + publisher->data_active ? "true" : "false", publisher->room_id_str, publisher->user_id_str); } if(bitrate) { publisher->bitrate = json_integer_value(bitrate); - JANUS_LOG(LOG_VERB, "Setting video bitrate: %"SCNu32" (room %"SCNu64", user %"SCNu64")\n", publisher->bitrate, publisher->room_id, publisher->user_id); + JANUS_LOG(LOG_VERB, "Setting video bitrate: %"SCNu32" (room %s, user %s)\n", + publisher->bitrate, publisher->room_id_str, publisher->user_id_str); } if(record) { publisher->recording_active = json_is_true(record); - JANUS_LOG(LOG_VERB, "Setting record property: %s (room %"SCNu64", user %"SCNu64")\n", publisher->recording_active ? "true" : "false", publisher->room_id, publisher->user_id); + JANUS_LOG(LOG_VERB, "Setting record property: %s (room %s, user %s)\n", + publisher->recording_active ? "true" : "false", publisher->room_id_str, publisher->user_id_str); } if(recfile) { publisher->recording_base = g_strdup(json_string_value(recfile)); - JANUS_LOG(LOG_VERB, "Setting recording basename: %s (room %"SCNu64", user %"SCNu64")\n", publisher->recording_base, publisher->room_id, publisher->user_id); + JANUS_LOG(LOG_VERB, "Setting recording basename: %s (room %s, user %s)\n", + publisher->recording_base, publisher->room_id_str, publisher->user_id_str); } /* Done */ janus_mutex_lock(&session->mutex); @@ -5183,7 +5544,9 @@ static void *janus_videoroom_handler(void *data) { GHashTableIter iter; gpointer value; janus_refcount_increase(&publisher->ref); - g_hash_table_insert(publisher->room->participants, janus_uint64_dup(publisher->user_id), publisher); + g_hash_table_insert(publisher->room->participants, + string_ids ? (gpointer)g_strdup(publisher->user_id_str) : (gpointer)janus_uint64_dup(publisher->user_id), + publisher); g_hash_table_iter_init(&iter, publisher->room->participants); while (!g_atomic_int_get(&publisher->room->destroyed) && g_hash_table_iter_next(&iter, NULL, &value)) { janus_videoroom_publisher *p = value; @@ -5191,7 +5554,7 @@ static void *janus_videoroom_handler(void *data) { /* Check if we're also notifying normal joins and not just publishers */ if(p != publisher && publisher->room->notify_joining) { json_t *al = json_object(); - json_object_set_new(al, "id", json_integer(p->user_id)); + json_object_set_new(al, "id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if(p->display) json_object_set_new(al, "display", json_string(p->display)); json_array_append_new(attendees, al); @@ -5199,7 +5562,7 @@ static void *janus_videoroom_handler(void *data) { continue; } json_t *pl = json_object(); - json_object_set_new(pl, "id", json_integer(p->user_id)); + json_object_set_new(pl, "id", string_ids ? json_string(p->user_id_str) : json_integer(p->user_id)); if(p->display) json_object_set_new(pl, "display", json_string(p->display)); if(p->audio) @@ -5214,9 +5577,10 @@ static void *janus_videoroom_handler(void *data) { } event = json_object(); json_object_set_new(event, "videoroom", json_string("joined")); - json_object_set_new(event, "room", json_integer(publisher->room->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(publisher->room->room_id_str) : + json_integer(publisher->room->room_id)); json_object_set_new(event, "description", json_string(publisher->room->room_name)); - json_object_set_new(event, "id", json_integer(user_id)); + json_object_set_new(event, "id", string_ids ? json_string(user_id_str) : json_integer(user_id)); json_object_set_new(event, "private_id", json_integer(publisher->pvt_id)); json_object_set_new(event, "publishers", list); if(attendees != NULL) @@ -5228,14 +5592,17 @@ static void *janus_videoroom_handler(void *data) { if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("joined")); - json_object_set_new(info, "room", json_integer(publisher->room->room_id)); - json_object_set_new(info, "id", json_integer(user_id)); + json_object_set_new(info, "room", string_ids ? json_string(publisher->room->room_id_str) : + json_integer(publisher->room->room_id)); + json_object_set_new(info, "id", string_ids ? json_string(user_id_str) : json_integer(user_id)); json_object_set_new(info, "private_id", json_integer(publisher->pvt_id)); if(display_text != NULL) json_object_set_new(info, "display", json_string(display_text)); gateway->notify_event(&janus_videoroom_plugin, session->handle, info); } janus_mutex_unlock(&publisher->room->mutex); + if(user_id_allocated) + g_free(user_id_str); } else if(!strcasecmp(ptype_text, "subscriber") || !strcasecmp(ptype_text, "listener")) { JANUS_LOG(LOG_VERB, "Configuring new subscriber\n"); gboolean legacy = !strcasecmp(ptype_text, "listener"); @@ -5250,6 +5617,17 @@ static void *janus_videoroom_handler(void *data) { janus_mutex_unlock(&videoroom->mutex); goto error; } + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, feed_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, feedstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } + if(error_code != 0) + goto error; janus_mutex_lock(&sessions_mutex); session = janus_videoroom_lookup_session(msg->handle); if(!session) { @@ -5266,7 +5644,15 @@ static void *janus_videoroom_handler(void *data) { continue; } json_t *feed = json_object_get(root, "feed"); - guint64 feed_id = json_integer_value(feed); + guint64 feed_id = 0; + char feed_id_num[30], *feed_id_str = NULL; + if(!string_ids) { + feed_id = json_integer_value(feed); + g_snprintf(feed_id_num, sizeof(feed_id_num), "%"SCNu64, feed_id); + feed_id_str = feed_id_num; + } else { + feed_id_str = (char *)json_string_value(feed); + } json_t *pvt = json_object_get(root, "private_id"); guint64 pvt_id = json_integer_value(pvt); json_t *cpc = json_object_get(root, "close_pc"); @@ -5300,11 +5686,12 @@ static void *janus_videoroom_handler(void *data) { goto error; } janus_videoroom_publisher *owner = NULL; - janus_videoroom_publisher *publisher = g_hash_table_lookup(videoroom->participants, &feed_id); + janus_videoroom_publisher *publisher = g_hash_table_lookup(videoroom->participants, + string_ids ? (gpointer)feed_id_str : (gpointer)&feed_id); if(publisher == NULL || g_atomic_int_get(&publisher->destroyed) || publisher->sdp == NULL) { - JANUS_LOG(LOG_ERR, "No such feed (%"SCNu64")\n", feed_id); + JANUS_LOG(LOG_ERR, "No such feed (%s)\n", feed_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_FEED; - g_snprintf(error_cause, 512, "No such feed (%"SCNu64")", feed_id); + g_snprintf(error_cause, 512, "No such feed (%s)", feed_id_str); janus_mutex_unlock(&sessions_mutex); janus_mutex_unlock(&videoroom->mutex); goto error; @@ -5331,6 +5718,7 @@ static void *janus_videoroom_handler(void *data) { janus_videoroom_subscriber *subscriber = g_malloc0(sizeof(janus_videoroom_subscriber)); subscriber->session = session; subscriber->room_id = videoroom->room_id; + subscriber->room_id_str = videoroom->room_id_str ? g_strdup(videoroom->room_id_str) : NULL; subscriber->room = videoroom; videoroom = NULL; subscriber->feed = publisher; @@ -5399,8 +5787,8 @@ static void *janus_videoroom_handler(void *data) { janus_mutex_unlock(&sessions_mutex); event = json_object(); json_object_set_new(event, "videoroom", json_string("attached")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); - json_object_set_new(event, "id", json_integer(feed_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); + json_object_set_new(event, "id", string_ids ? json_string(feed_id_str) : json_integer(feed_id)); if(publisher->display) json_object_set_new(event, "display", json_string(publisher->display)); if(legacy) @@ -5442,8 +5830,8 @@ static void *janus_videoroom_handler(void *data) { if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("subscribing")); - json_object_set_new(info, "room", json_integer(subscriber->room_id)); - json_object_set_new(info, "feed", json_integer(feed_id)); + json_object_set_new(info, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); + json_object_set_new(info, "feed", string_ids ? json_string(feed_id_str) : json_integer(feed_id)); json_object_set_new(info, "private_id", json_integer(pvt_id)); gateway->notify_event(&janus_videoroom_plugin, session->handle, info); } @@ -5529,7 +5917,8 @@ static void *janus_videoroom_handler(void *data) { janus_mutex_unlock(&participant->subscribers_mutex); } participant->audio_active = audio_active; - JANUS_LOG(LOG_VERB, "Setting audio property: %s (room %"SCNu64", user %"SCNu64")\n", participant->audio_active ? "true" : "false", participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting audio property: %s (room %s, user %s)\n", + participant->audio_active ? "true" : "false", participant->room_id_str, participant->user_id_str); } if(audiocodec && json_string_value(json_object_get(msg->jsep, "sdp")) != NULL) { /* The participant would like to use an audio codec in particular */ @@ -5538,16 +5927,16 @@ static void *janus_videoroom_handler(void *data) { (acodec != participant->room->acodec[0] && acodec != participant->room->acodec[1] && acodec != participant->room->acodec[2])) { - JANUS_LOG(LOG_ERR, "Participant asked for audio codec '%s', but it's not allowed (room %"SCNu64", user %"SCNu64")\n", - json_string_value(audiocodec), participant->room_id, participant->user_id); + JANUS_LOG(LOG_ERR, "Participant asked for audio codec '%s', but it's not allowed (room %s, user %s)\n", + json_string_value(audiocodec), participant->room_id_str, participant->user_id_str); janus_refcount_decrease(&participant->ref); error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT; g_snprintf(error_cause, 512, "Audio codec unavailable in this room"); goto error; } participant->acodec = acodec; - JANUS_LOG(LOG_VERB, "Participant asked for audio codec '%s' (room %"SCNu64", user %"SCNu64")\n", - json_string_value(audiocodec), participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Participant asked for audio codec '%s' (room %s, user %s)\n", + json_string_value(audiocodec), participant->room_id_str, participant->user_id_str); } if(video) { gboolean video_active = json_is_true(video); @@ -5564,7 +5953,8 @@ static void *janus_videoroom_handler(void *data) { janus_mutex_unlock(&participant->subscribers_mutex); } participant->video_active = video_active; - JANUS_LOG(LOG_VERB, "Setting video property: %s (room %"SCNu64", user %"SCNu64")\n", participant->video_active ? "true" : "false", participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting video property: %s (room %s, user %s)\n", + participant->video_active ? "true" : "false", participant->room_id_str, participant->user_id_str); } if(videocodec && json_string_value(json_object_get(msg->jsep, "sdp")) != NULL) { /* The participant would like to use a video codec in particular */ @@ -5573,25 +5963,27 @@ static void *janus_videoroom_handler(void *data) { (vcodec != participant->room->vcodec[0] && vcodec != participant->room->vcodec[1] && vcodec != participant->room->vcodec[2])) { - JANUS_LOG(LOG_ERR, "Participant asked for video codec '%s', but it's not allowed (room %"SCNu64", user %"SCNu64")\n", - json_string_value(videocodec), participant->room_id, participant->user_id); + JANUS_LOG(LOG_ERR, "Participant asked for video codec '%s', but it's not allowed (room %s, user %s)\n", + json_string_value(videocodec), participant->room_id_str, participant->user_id_str); janus_refcount_decrease(&participant->ref); error_code = JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT; g_snprintf(error_cause, 512, "Video codec unavailable in this room"); goto error; } participant->vcodec = vcodec; - JANUS_LOG(LOG_VERB, "Participant asked for video codec '%s' (room %"SCNu64", user %"SCNu64")\n", - json_string_value(videocodec), participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Participant asked for video codec '%s' (room %s, user %s)\n", + json_string_value(videocodec), participant->room_id_str, participant->user_id_str); } if(data) { gboolean data_active = json_is_true(data); participant->data_active = data_active; - JANUS_LOG(LOG_VERB, "Setting data property: %s (room %"SCNu64", user %"SCNu64")\n", participant->data_active ? "true" : "false", participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting data property: %s (room %s, user %s)\n", + participant->data_active ? "true" : "false", participant->room_id_str, participant->user_id_str); } if(bitrate) { participant->bitrate = json_integer_value(bitrate); - JANUS_LOG(LOG_VERB, "Setting video bitrate: %"SCNu32" (room %"SCNu64", user %"SCNu64")\n", participant->bitrate, participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting video bitrate: %"SCNu32" (room %s, user %s)\n", + participant->bitrate, participant->room_id_str, participant->user_id_str); /* Send a new REMB */ if(session->started) participant->remb_latest = janus_get_monotonic_time(); @@ -5605,11 +5997,13 @@ static void *janus_videoroom_handler(void *data) { gboolean prev_recording_active = participant->recording_active; if(record) { participant->recording_active = json_is_true(record); - JANUS_LOG(LOG_VERB, "Setting record property: %s (room %"SCNu64", user %"SCNu64")\n", participant->recording_active ? "true" : "false", participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting record property: %s (room %s, user %s)\n", + participant->recording_active ? "true" : "false", participant->room_id_str, participant->user_id_str); } if(recfile) { participant->recording_base = g_strdup(json_string_value(recfile)); - JANUS_LOG(LOG_VERB, "Setting recording basename: %s (room %"SCNu64", user %"SCNu64")\n", participant->recording_base, participant->room_id, participant->user_id); + JANUS_LOG(LOG_VERB, "Setting recording basename: %s (room %s, user %s)\n", + participant->recording_base, participant->room_id_str, participant->user_id_str); } /* Do we need to do something with the recordings right now? */ if(participant->recording_active != prev_recording_active) { @@ -5638,7 +6032,7 @@ static void *janus_videoroom_handler(void *data) { g_free(old_display); json_t *display_event = json_object(); json_object_set_new(display_event, "videoroom", json_string("event")); - json_object_set_new(display_event, "id", json_integer(participant->user_id)); + json_object_set_new(display_event, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(display_event, "display", json_string(participant->display)); if(participant->room && !g_atomic_int_get(&participant->room->destroyed)) { janus_videoroom_notify_participants(participant, display_event); @@ -5654,14 +6048,14 @@ static void *janus_videoroom_handler(void *data) { /* Done */ event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(participant->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); json_object_set_new(event, "configured", json_string("ok")); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("configured")); - json_object_set_new(info, "room", json_integer(participant->room_id)); - json_object_set_new(info, "id", json_integer(participant->user_id)); + json_object_set_new(info, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); + json_object_set_new(info, "id", string_ids ? json_string(participant->user_id_str) : json_integer(participant->user_id)); json_object_set_new(info, "audio_active", participant->audio_active ? json_true() : json_false()); json_object_set_new(info, "video_active", participant->video_active ? json_true() : json_false()); json_object_set_new(info, "data_active", participant->data_active ? json_true() : json_false()); @@ -5693,13 +6087,13 @@ static void *janus_videoroom_handler(void *data) { /* Done */ event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(participant->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); json_object_set_new(event, "unpublished", json_string("ok")); } else if(!strcasecmp(request_text, "leave")) { /* Prepare an event to confirm the request */ event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(participant->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(participant->room_id_str) : json_integer(participant->room_id)); json_object_set_new(event, "leaving", json_string("ok")); /* This publisher is leaving, tell everybody */ janus_videoroom_leave_or_unpublish(participant, TRUE, FALSE); @@ -5747,7 +6141,7 @@ static void *janus_videoroom_handler(void *data) { subscriber->paused = FALSE; event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "started", json_string("ok")); } else if(!strcasecmp(request_text, "configure")) { JANUS_VALIDATE_JSON_OBJECT(root, configure_parameters, @@ -5822,7 +6216,7 @@ static void *janus_videoroom_handler(void *data) { /* No need to do anything, we're already getting the right substream, so notify the user */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "substream", json_integer(subscriber->sim_context.substream)); gateway->push_event(msg->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -5840,7 +6234,7 @@ static void *janus_videoroom_handler(void *data) { /* No need to do anything, we're already getting the right temporal, so notify the user */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "temporal", json_integer(subscriber->sim_context.templayer)); gateway->push_event(msg->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -5861,7 +6255,7 @@ static void *janus_videoroom_handler(void *data) { /* No need to do anything, we're already getting the right spatial layer, so notify the user */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "spatial_layer", json_integer(subscriber->spatial_layer)); gateway->push_event(msg->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -5880,7 +6274,7 @@ static void *janus_videoroom_handler(void *data) { /* No need to do anything, we're already getting the right temporal layer, so notify the user */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "temporal_layer", json_integer(subscriber->temporal_layer)); gateway->push_event(msg->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -5890,7 +6284,7 @@ static void *janus_videoroom_handler(void *data) { } event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "configured", json_string("ok")); /* The user may be interested in an ICE restart */ gboolean do_restart = restart ? json_is_true(restart) : FALSE; @@ -5993,38 +6387,58 @@ static void *janus_videoroom_handler(void *data) { subscriber->paused = TRUE; event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "paused", json_string("ok")); } else if(!strcasecmp(request_text, "switch")) { /* This subscriber wants to switch to a different publisher */ JANUS_VALIDATE_JSON_OBJECT(root, subscriber_parameters, error_code, error_cause, TRUE, JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + if(error_code != 0) + goto error; + if(!string_ids) { + JANUS_VALIDATE_JSON_OBJECT(root, feed_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } else { + JANUS_VALIDATE_JSON_OBJECT(root, feedstr_parameters, + error_code, error_cause, TRUE, + JANUS_VIDEOROOM_ERROR_MISSING_ELEMENT, JANUS_VIDEOROOM_ERROR_INVALID_ELEMENT); + } if(error_code != 0) goto error; json_t *feed = json_object_get(root, "feed"); - guint64 feed_id = json_integer_value(feed); + guint64 feed_id = 0; + char feed_id_num[30], *feed_id_str = NULL; + if(!string_ids) { + feed_id = json_integer_value(feed); + g_snprintf(feed_id_num, sizeof(feed_id_num), "%"SCNu64, feed_id); + feed_id_str = feed_id_num; + } else { + feed_id_str = (char *)json_string_value(feed); + } json_t *audio = json_object_get(root, "audio"); json_t *video = json_object_get(root, "video"); json_t *data = json_object_get(root, "data"); if(!subscriber->room) { - JANUS_LOG(LOG_ERR, "Room Destroyed \n"); + JANUS_LOG(LOG_ERR, "Room Destroyed\n"); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room "); + g_snprintf(error_cause, 512, "No such room"); goto error; } if(g_atomic_int_get(&subscriber->destroyed)) { - JANUS_LOG(LOG_ERR, "Room Destroyed (%"SCNu64")\n", subscriber->room_id); + JANUS_LOG(LOG_ERR, "Room Destroyed (%s)\n", subscriber->room_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_ROOM; - g_snprintf(error_cause, 512, "No such room (%"SCNu64")", subscriber->room_id); + g_snprintf(error_cause, 512, "No such room (%s)", subscriber->room_id_str); goto error; } janus_mutex_lock(&subscriber->room->mutex); - janus_videoroom_publisher *publisher = g_hash_table_lookup(subscriber->room->participants, &feed_id); + janus_videoroom_publisher *publisher = g_hash_table_lookup(subscriber->room->participants, + string_ids ? (gpointer)feed_id_str : (gpointer)&feed_id); if(publisher == NULL || g_atomic_int_get(&publisher->destroyed) || publisher->sdp == NULL) { - JANUS_LOG(LOG_ERR, "No such feed (%"SCNu64")\n", feed_id); + JANUS_LOG(LOG_ERR, "No such feed (%s)\n", feed_id_str); error_code = JANUS_VIDEOROOM_ERROR_NO_SUCH_FEED; - g_snprintf(error_cause, 512, "No such feed (%"SCNu64")", feed_id); + g_snprintf(error_cause, 512, "No such feed (%s)", feed_id_str); janus_mutex_unlock(&subscriber->room->mutex); goto error; } @@ -6085,27 +6499,28 @@ static void *janus_videoroom_handler(void *data) { event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); json_object_set_new(event, "switched", json_string("ok")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); - json_object_set_new(event, "id", json_integer(feed_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); + json_object_set_new(event, "id", string_ids ? json_string(feed_id_str) : json_integer(feed_id)); if(publisher->display) json_object_set_new(event, "display", json_string(publisher->display)); /* Also notify event handlers */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("switched")); - json_object_set_new(info, "room", json_integer(publisher->room_id)); - json_object_set_new(info, "feed", json_integer(publisher->user_id)); + json_object_set_new(info, "room", string_ids ? json_string(publisher->room_id_str) : json_integer(publisher->room_id)); + json_object_set_new(info, "feed", string_ids ? json_string(publisher->user_id_str) : json_integer(publisher->user_id)); gateway->notify_event(&janus_videoroom_plugin, session->handle, info); } } else if(!strcasecmp(request_text, "leave")) { guint64 room_id = subscriber ? subscriber->room_id : 0; + char *room_id_str = subscriber ? subscriber->room_id_str : NULL; /* Tell the core to tear down the PeerConnection, hangup_media will do the rest */ janus_videoroom_hangup_media(session->handle); gateway->close_pc(session->handle); /* Send an event back */ event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(room_id)); + json_object_set_new(event, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); json_object_set_new(event, "left", json_string("ok")); session->started = FALSE; } else { @@ -6297,7 +6712,7 @@ static void *janus_videoroom_handler(void *data) { /* Replace the session name */ g_free(answer->s_name); char s_name[100]; - g_snprintf(s_name, sizeof(s_name), "VideoRoom %"SCNu64, videoroom->room_id); + g_snprintf(s_name, sizeof(s_name), "VideoRoom %s", videoroom->room_id_str); answer->s_name = g_strdup(s_name); /* Which media are REALLY available? (some may have been rejected) */ participant->audio = FALSE; @@ -6315,9 +6730,12 @@ static void *janus_videoroom_handler(void *data) { } temp = temp->next; } - JANUS_LOG(LOG_VERB, "Per the answer, the publisher %s going to send an audio stream\n", participant->audio ? "is" : "is NOT"); - JANUS_LOG(LOG_VERB, "Per the answer, the publisher %s going to send a video stream\n", participant->video ? "is" : "is NOT"); - JANUS_LOG(LOG_VERB, "Per the answer, the publisher %s going to open a data channel\n", participant->data ? "is" : "is NOT"); + JANUS_LOG(LOG_VERB, "Per the answer, the publisher %s going to send an audio stream\n", + participant->audio ? "is" : "is NOT"); + JANUS_LOG(LOG_VERB, "Per the answer, the publisher %s going to send a video stream\n", + participant->video ? "is" : "is NOT"); + JANUS_LOG(LOG_VERB, "Per the answer, the publisher %s going to open a data channel\n", + participant->data ? "is" : "is NOT"); /* Update the event with info on the codecs that we'll be handling */ if(event) { if(participant->audio) @@ -6550,7 +6968,7 @@ static void janus_videoroom_relay_rtp_packet(gpointer data, gpointer user_data) /* Notify the viewer */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "spatial_layer", json_integer(subscriber->spatial_layer)); if(subscriber->temporal_layer == -1) { /* We just started: initialize the temporal layer and notify that too */ @@ -6580,7 +6998,7 @@ static void janus_videoroom_relay_rtp_packet(gpointer data, gpointer user_data) /* Notify the viewer */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "spatial_layer", json_integer(subscriber->spatial_layer)); gateway->push_event(subscriber->session->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -6610,7 +7028,7 @@ static void janus_videoroom_relay_rtp_packet(gpointer data, gpointer user_data) /* Notify the viewer */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "temporal_layer", json_integer(subscriber->temporal_layer)); gateway->push_event(subscriber->session->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -6626,7 +7044,7 @@ static void janus_videoroom_relay_rtp_packet(gpointer data, gpointer user_data) /* Notify the viewer */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "temporal_layer", json_integer(subscriber->temporal_layer)); gateway->push_event(subscriber->session->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -6681,7 +7099,7 @@ static void janus_videoroom_relay_rtp_packet(gpointer data, gpointer user_data) /* Notify the user about the substream change */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "substream", json_integer(subscriber->sim_context.substream)); gateway->push_event(subscriber->session->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); @@ -6690,7 +7108,7 @@ static void janus_videoroom_relay_rtp_packet(gpointer data, gpointer user_data) /* Notify the user about the temporal layer change */ json_t *event = json_object(); json_object_set_new(event, "videoroom", json_string("event")); - json_object_set_new(event, "room", json_integer(subscriber->room_id)); + json_object_set_new(event, "room", string_ids ? json_string(subscriber->room_id_str) : json_integer(subscriber->room_id)); json_object_set_new(event, "temporal", json_integer(subscriber->sim_context.templayer)); gateway->push_event(subscriber->session->handle, &janus_videoroom_plugin, NULL, event, NULL); json_decref(event); diff --git a/utils.c b/utils.c index bd2af6e7c6..e838e2c013 100644 --- a/utils.c +++ b/utils.c @@ -90,6 +90,10 @@ guint64 janus_random_uint64(void) { return num; } +char *janus_random_uuid(void) { + return g_uuid_string_random(); +} + guint64 *janus_uint64_dup(guint64 num) { guint64 *numdup = g_malloc(sizeof(guint64)); *numdup = num; diff --git a/utils.h b/utils.h index 6f5ab63e18..d879ebbab8 100644 --- a/utils.h +++ b/utils.h @@ -69,6 +69,10 @@ guint32 janus_random_uint32(void); * @returns A random 64-bit unsigned integer */ guint64 janus_random_uint64(void); +/*! \brief Helper to generate random UUIDs (needed by some plugins) + * @returns A random UUID string, which must be deallocated with \c g_free */ +char *janus_random_uuid(void); + /*! \brief Helper to generate an allocated copy of a guint64 number * @note While apparently silly, this is needed in order to make sure guint64 values * used as keys in GHashTable operations are not lost: using temporary guint64 numbers