diff --git a/src/plugins/janus_audiobridge.c b/src/plugins/janus_audiobridge.c index 60d8cacc53..e3fd9e1ad1 100644 --- a/src/plugins/janus_audiobridge.c +++ b/src/plugins/janus_audiobridge.c @@ -75,23 +75,24 @@ room-: { * (invalid JSON, invalid request) which will always result in a * synchronous error response even for asynchronous requests. * - * \c create , \c edit , \c destroy , \c exists, \c allowed, \c kick, \c list, - * \c mute , \c unmute , \c mute_room , \c unmute_room , \c listparticipants , - * \c resetdecoder , \c rtp_forward, \c stop_rtp_forward , \c list_forwarders , - * \c play_file , \c is_playing and \c stop_file are synchronous requests, - * which means you'll get a response directly within the context of the - * transaction. \c create allows you to create a new audio conference bridge - * dynamically, as an alternative to using the configuration file; \c edit - * allows you to dynamically edit some room properties (e.g., the PIN); + * \c create, \c edit, \c destroy, \c exists, \c allowed, \c kick, \c list, + * \c mute, \c unmute, \c mute_room, \c unmute_room, \c listparticipants, + * \c listannouncements, \c resetdecoder, \c rtp_forward, \c stop_rtp_forward, + * \c list_forwarders, \c play_file, \c is_playing and \c stop_file are + * synchronous requests, which means you'll get a response directly within + * the context of the transaction. \c create allows you to create a new audio + * conference bridge dynamically, as an alternative to using the configuration file; + * \c edit allows you to dynamically edit some room properties (e.g., the PIN); * \c destroy removes an audio conference bridge and destroys it, kicking * all the users out as part of the process; \c exists allows you to * check whether a specific audio conference exists; \c allowed allows * you to edit who's allowed to join a room via ad-hoc tokens; \c list * lists all the available rooms, while \c listparticipants lists all - * the participants of a specific room and their details; \c resetdecoder - * marks the Opus decoder for the participant as invalid, and forces it - * to be recreated (which might be needed if the audio for generated by - * the participant becomes garbled); \c rtp_forward allows you to forward + * the participants of a specific room and their details; \c listannouncements + * lists all playing announcements of a specific room and their details; + * \c resetdecoder marks the Opus decoder for the participant as invalid, and + * forces it to be recreated (which might be needed if the audio for generated + * by the participant becomes garbled); \c rtp_forward allows you to forward * the mix of an AudioBridge room via RTP to a separate component (e.g., * for broadcasting it to a wider audience, or for processing/recording), * whereas \c stop_rtp_forward can remove an existing forwarder; a list @@ -750,6 +751,37 @@ room-: { "file_id" : "", "playing" : } +\endverbatim + * + * To get a list of the announcements in a specific room, you + * can make use of the \c listannouncements request, which has to be + * formatted as follows: + * +\verbatim +{ + "request" : "listannouncements", + "secret" : "", + "room" : +} +\endverbatim + * + * A successful request will produce a list of announcements in a + * \c announcements response: + * +\verbatim +{ + "audiobridge" : "announcements", + "room" : , + "announcements" : [ // Array of announcement objects + { // Announcement #1 + "file_id" : "", + "filename": "", + "playing" : , + "loop": + } + // Other announcements + ] +} \endverbatim * * As anticipated, when not looping a playback will automatically stop and @@ -5448,6 +5480,77 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s json_object_set_new(response, "playing", playing ? json_true() : json_false()); goto prepare_response; #endif + } else if(!strcasecmp(request_text, "listannouncements")) { + /* List all announcements in a room */ + 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 = 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, + string_ids ? (gpointer)room_id_str : (gpointer)&room_id); + if(audiobridge == NULL) { + 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 (%s)\n", room_id_str); + error_code = JANUS_AUDIOBRIDGE_ERROR_NO_SUCH_ROOM; + g_snprintf(error_cause, 512, "No such room (%s)", room_id_str); + janus_mutex_unlock(&rooms_mutex); + goto prepare_response; + } + janus_refcount_increase(&audiobridge->ref); + /* A secret may be required for this action */ + JANUS_CHECK_SECRET(audiobridge->room_secret, root, "secret", error_code, error_cause, + JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED); + if(error_code != 0) { + janus_mutex_unlock(&rooms_mutex); + janus_refcount_decrease(&audiobridge->ref); + goto prepare_response; + } + /* Return a list of all announcements */ + json_t *list = json_array(); + GHashTableIter iter; + gpointer value; + g_hash_table_iter_init(&iter, audiobridge->anncs); + while(g_hash_table_iter_next(&iter, NULL, &value)) { + janus_audiobridge_participant *p = value; + json_t *pl = json_object(); + json_object_set_new(pl, "file_id", json_string(p->annc->id)); + if(p->annc->filename) + json_object_set_new(pl, "filename", json_string(p->annc->filename)); + json_object_set_new(pl, "playing", p->annc->started ? json_true() : json_false()); + json_object_set_new(pl, "loop", p->annc->loop ? json_true() : json_false()); + json_array_append_new(list, pl); + } + janus_refcount_decrease(&audiobridge->ref); + janus_mutex_unlock(&rooms_mutex); + response = json_object(); + json_object_set_new(response, "audiobridge", json_string("announcements")); + json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id)); + json_object_set_new(response, "announcements", list); + goto prepare_response; } else if(!strcasecmp(request_text, "stop_file")) { #ifndef HAVE_LIBOGG JANUS_LOG(LOG_VERB, "Playing files unsupported in this instance\n");