Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AudioBridge stop_all_files api #3403

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 144 additions & 4 deletions src/plugins/janus_audiobridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ room-<unique room ID>: {
* \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
* \c list_forwarders, \c play_file, \c is_playing, \c stop_file and \c stop_all_files
* 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);
Expand All @@ -100,7 +100,8 @@ room-<unique room ID>: {
* \c list_forwarders request; finally, \c play_file allows you to
* reproduce an audio .opus file in a mix (e.g., to play an announcement
* or some background music), \c is_playing checks if a specific file is
* still playing, while \c stop_file will stop such a playback instead.
* still playing, while \c stop_file will stop such a playback instead and
* \c stop_all_files will stop all announcements.
*
* The \c join , \c configure , \c changeroom and \c leave requests
* instead are all asynchronous, which means you'll get a notification
Expand Down Expand Up @@ -720,7 +721,8 @@ room-<unique room ID>: {
* A similar event is also sent whenever the playback stops, whether it's
* because the file ended and \c loop was \c FALSE (which will automatically
* clear the resources) or because a \c stop_file request asked for the
* playback to be interrupted:
* playback to be interrupted or \c stop_all_files request asked for all
* playbacks to be interrupted:
*
\verbatim
{
Expand Down Expand Up @@ -806,6 +808,29 @@ room-<unique room ID>: {
"room" : <unique numeric ID, same as request>,
"file_id" : "<unique string ID of the now interrupted announcement>"
}
\endverbatim
*
* In case you want to stop all playbacks of a room immediatly,
* you can use the \c stop_all_files request:
*
\verbatim
{
"request" : "stop_all_files",
"room" : <unique numeric ID of the room where the playback is taking place>,
"secret" : "<room password, if configured>"
}
\endverbatim
*
* A successful request will result in a \c success response:
*
\verbatim
{
"audiobridge" : "success",
"room" : <unique numeric ID, same as request>,
"file_id_list" : [
// Array of file_Id: "<unique string ID of the now interrupted announcement>""
]
}
\endverbatim
*
* That completes the list of synchronous requests you can send to the
Expand Down Expand Up @@ -5663,6 +5688,121 @@ static json_t *janus_audiobridge_process_synchronous_request(janus_audiobridge_s
json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id));
json_object_set_new(response, "file_id", json_string(file_id));
goto prepare_response;
#endif
} else if(!strcasecmp(request_text, "stop_all_files")) {
#ifndef HAVE_LIBOGG
JANUS_LOG(LOG_VERB, "Playing files unsupported in this instance\n");
error_code = JANUS_AUDIOBRIDGE_ERROR_INVALID_REQUEST;
g_snprintf(error_cause, 512, "Playing files unsupported in this instance");
goto prepare_response;
#else
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_playfile && admin_key != NULL) {
/* An admin key was specified: make sure it was provided, and that it's valid */
JANUS_VALIDATE_JSON_OBJECT(root, adminkey_parameters,
error_code, error_cause, TRUE,
JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT);
if(error_code != 0)
goto prepare_response;
JANUS_CHECK_SECRET(admin_key, root, "admin_key", error_code, error_cause,
JANUS_AUDIOBRIDGE_ERROR_MISSING_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_INVALID_ELEMENT, JANUS_AUDIOBRIDGE_ERROR_UNAUTHORIZED);
if(error_code != 0)
goto prepare_response;
}
/* Parse parameters */
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);
}
/* Update 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);
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);
goto prepare_response;
}
/* 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);
goto prepare_response;
}
janus_mutex_lock(&audiobridge->mutex);
if(audiobridge->destroyed) {
janus_mutex_unlock(&audiobridge->mutex);
janus_mutex_unlock(&rooms_mutex);
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);
goto prepare_response;
}

/* Get list of started announcements and send a stop announcement notification */
GHashTableIter iter;
gpointer value;
json_t *list_annc_removed = json_array();
g_hash_table_iter_init(&iter, audiobridge->anncs);
while(g_hash_table_iter_next(&iter, NULL, &value)) {
janus_audiobridge_participant *p = value;
gboolean started = (p && p->annc && p->annc->started);
if(p)
janus_refcount_increase(&p->ref);
if(started) {
JANUS_LOG(LOG_INFO, "[%s] Announcement stopped (%s)\n", audiobridge->room_id_str, p->annc->id);
json_t *event = json_object();
json_object_set_new(event, "audiobridge", json_string("announcement-stopped"));
json_object_set_new(event, "room",
string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id));
json_object_set_new(event, "file_id", json_string(p->annc->id));
janus_audiobridge_notify_participants(p, event, TRUE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you passing TRUE here? That's notify_source_participant, which should be FALSE in this case because the janus_audiobridge_participant instance you're passing to the function is an announcement, and so not a real participant with a Janus API session we can notify about stuff.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @lminiero

How should we continue? Should we change stop_file and play_file to FALSE too

My own preference is to leave TRUE since in we want to notify participants about these events

json_decref(event);
/* Also notify event handlers */
if(notify_events && gateway->events_is_enabled()) {
json_t *info = json_object();
json_object_set_new(info, "event", json_string("announcement-stopped"));
json_object_set_new(info, "room",
string_ids ? json_string(audiobridge->room_id_str) : json_integer(audiobridge->room_id));
json_object_set_new(info, "file_id", json_string(p->annc->id));
gateway->notify_event(&janus_audiobridge_plugin, NULL, info);
}
json_array_append_new(list_annc_removed, json_string(p->annc->id));
}
g_hash_table_iter_remove(&iter);
if(p)
janus_refcount_decrease(&p->ref);
}

janus_mutex_unlock(&audiobridge->mutex);
janus_mutex_unlock(&rooms_mutex);

/* Done, prepare response */
response = json_object();
json_object_set_new(response, "audiobridge", json_string("success"));
json_object_set_new(response, "room", string_ids ? json_string(room_id_str) : json_integer(room_id));
json_object_set_new(response, "file_id_list", list_annc_removed);
goto prepare_response;
#endif
} else if(!strcasecmp(request_text, "suspend") || !strcasecmp(request_text, "resume")) {
gboolean suspend = !strcasecmp(request_text, "suspend");
Expand Down
Loading