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

Add pause/resume recording functionality to Record&Play and SIP plugins #2724

Merged
merged 7 commits into from
Oct 1, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions html/recordplaytest.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ function startRecording() {
$('#list').unbind('click').attr('disabled', true);
$('#recset').attr('disabled', true);
$('#recslist').attr('disabled', true);
$('#pause-resume').removeClass('hide');

// bitrate and keyframe interval can be set at any time:
// before, after, during recording
Expand Down Expand Up @@ -524,6 +525,7 @@ function startPlayout() {
$('#list').unbind('click').attr('disabled', true);
$('#recset').attr('disabled', true);
$('#recslist').attr('disabled', true);
$('#pause-resume').addClass('hide');
var play = { request: "play", id: parseInt(selectedRecording) };
recordplay.send({ message: play });
}
Expand Down
43 changes: 25 additions & 18 deletions plugins/janus_recordplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ typedef struct janus_recordplay_recording {
char *offer; /* The SDP offer that will be sent to watchers */
gboolean e2ee; /* Whether media in the recording is encrypted, e.g., using Insertable Streams */
GList *viewers; /* List of users watching this recording */
volatile gint paused; /* Whether this recording is paused */
volatile gint completed; /* Whether this recording was completed or still going on */
volatile gint destroyed; /* Whether this recording has been marked as destroyed */
janus_refcount ref; /* Reference counter */
Expand Down Expand Up @@ -1635,6 +1636,7 @@ static void *janus_recordplay_handler(void *data) {
rec->acodec = JANUS_AUDIOCODEC_NONE;
rec->vcodec = JANUS_VIDEOCODEC_NONE;
rec->e2ee = e2ee;
g_atomic_int_set(&rec->paused, 0);
g_atomic_int_set(&rec->destroyed, 0);
g_atomic_int_set(&rec->completed, 0);
janus_refcount_init(&rec->ref, janus_recordplay_recording_free);
Expand Down Expand Up @@ -2012,25 +2014,29 @@ static void *janus_recordplay_handler(void *data) {
JANUS_LOG(LOG_VERB, "Record&Play: Got pause/resume request\n");
if(session->recording) {
gboolean pause = !strcasecmp(request_text, "pause");
isnumanagic marked this conversation as resolved.
Show resolved Hide resolved
result = json_object();
json_object_set_new(result, "status", json_string(pause ? "paused" : "resumed"));
json_object_set_new(result, "id", json_integer(session->recording->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(pause ? "paused" : "resumed"));
json_object_set_new(info, "id", json_integer(session->recording->id));
gateway->notify_event(&janus_recordplay_plugin, session->handle, info);
}
if(pause) {
janus_recorder_pause(session->arc);
janus_recorder_pause(session->vrc);
janus_recorder_pause(session->drc);
if (g_atomic_int_compare_and_exchange(&session->recording->paused, !pause, pause)) {
result = json_object();
json_object_set_new(result, "status", json_string(pause ? "paused" : "resumed"));
json_object_set_new(result, "id", json_integer(session->recording->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(pause ? "paused" : "resumed"));
json_object_set_new(info, "id", json_integer(session->recording->id));
gateway->notify_event(&janus_recordplay_plugin, session->handle, info);
}
if(pause) {
janus_recorder_pause(session->arc);
janus_recorder_pause(session->vrc);
janus_recorder_pause(session->drc);
} else {
janus_recorder_resume(session->arc);
janus_recorder_resume(session->vrc);
janus_recorder_resume(session->drc);
gateway->send_pli(session->handle);
}
} else {
janus_recorder_resume(session->arc);
janus_recorder_resume(session->vrc);
janus_recorder_resume(session->drc);
gateway->send_pli(session->handle);
JANUS_LOG(LOG_VERB, "Record&Play: Tried to pause/resume recording of same state, ignoring\n");
isnumanagic marked this conversation as resolved.
Show resolved Hide resolved
}
} else {
JANUS_LOG(LOG_VERB, "Record&Play: Not recording, ignoring pause/resume request\n");
Expand Down Expand Up @@ -2231,6 +2237,7 @@ void janus_recordplay_update_recordings_list(void) {
if(janus_recordplay_generate_offer(rec) < 0) {
JANUS_LOG(LOG_WARN, "Could not generate offer for recording %"SCNu64"...\n", rec->id);
}
g_atomic_int_set(&rec->paused, 0);
g_atomic_int_set(&rec->destroyed, 0);
g_atomic_int_set(&rec->completed, 1);
janus_refcount_init(&rec->ref, janus_recordplay_recording_free);
Expand Down
39 changes: 29 additions & 10 deletions plugins/janus_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -4374,12 +4374,29 @@ static void *janus_sip_handler(void *data) {
record_peer_audio = peer_audio ? json_is_true(peer_audio) : FALSE;
json_t *peer_video = json_object_get(root, "peer_video");
record_peer_video = peer_video ? json_is_true(peer_video) : FALSE;
if(!record_audio && !record_video && !record_peer_audio && !record_peer_video) {
gint update_bitmap =
record_audio |
record_video << 1 |
record_peer_audio << 2 |
record_peer_video << 3;
if(!update_bitmap) {
JANUS_LOG(LOG_ERR, "Invalid request (at least one of audio, video, peer_audio and peer_video should be true)\n");
error_code = JANUS_SIP_ERROR_RECORDING_ERROR;
g_snprintf(error_cause, 512, "Invalid request (at least one of audio, video, peer_audio and peer_video should be true)");
goto error;
}
gint recorder_bitmap =
g_atomic_int_get(&session->arc->paused) |
g_atomic_int_get(&session->vrc->paused) << 1 |
g_atomic_int_get(&session->arc_peer->paused) << 2 |
g_atomic_int_get(&session->vrc_peer->paused) << 3;
if ((!strcasecmp(action_text, "pause") && !(~recorder_bitmap & update_bitmap)) ||
(!strcasecmp(action_text, "resume") && !(recorder_bitmap & update_bitmap))) {
JANUS_LOG(LOG_ERR, "Invalid pause/resume request (at least one of audio, video, peer_audio and peer_video should change recorder state)\n");
isnumanagic marked this conversation as resolved.
Show resolved Hide resolved
error_code = JANUS_SIP_ERROR_RECORDING_ERROR;
g_snprintf(error_cause, 512, "Invalid pause/resume request (at least one of audio, video, peer_audio and peer_video should change recorder state)");
goto error;
}
json_t *recfile = json_object_get(root, "filename");
const char *recording_base = json_string_value(recfile);
janus_mutex_lock(&session->rec_mutex);
Expand Down Expand Up @@ -4504,24 +4521,26 @@ static void *janus_sip_handler(void *data) {
}
}
} else if(!strcasecmp(action_text, "pause")) {
if(record_audio)
gint pause_bitmap = ~recorder_bitmap & update_bitmap;
if(pause_bitmap & 1)
janus_recorder_pause(session->arc);
if(record_video)
if(pause_bitmap & 2)
janus_recorder_pause(session->vrc);
if(record_peer_audio)
if(pause_bitmap & 4)
janus_recorder_pause(session->arc_peer);
if(record_peer_video)
if(pause_bitmap & 8)
janus_recorder_pause(session->vrc_peer);
} else if(!strcasecmp(action_text, "resume")) {
if(record_audio)
gint resume_bitmap = recorder_bitmap & update_bitmap;
if(resume_bitmap & 1)
janus_recorder_resume(session->arc);
if(record_video)
if(resume_bitmap & 2)
janus_recorder_resume(session->vrc);
if(record_peer_audio)
if(resume_bitmap & 4)
janus_recorder_resume(session->arc_peer);
if(record_peer_video)
if(resume_bitmap & 8)
janus_recorder_resume(session->vrc_peer);
if(record_video || record_peer_video)
if(resume_bitmap & 10)
gateway->send_pli(session->handle);
isnumanagic marked this conversation as resolved.
Show resolved Hide resolved
} else {
/* Stop recording something: notice that this never returns an error, even when we were not recording anything */
Expand Down
32 changes: 18 additions & 14 deletions record.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,26 +259,30 @@ janus_recorder *janus_recorder_create_full(const char *dir, const char *codec, c
int janus_recorder_pause(janus_recorder *recorder) {
if(!recorder)
return -1;
g_atomic_int_set(&recorder->paused, 1);
return 0;
if(g_atomic_int_compare_and_exchange(&recorder->paused, 0, 1))
return 0;
return -2;
}

int janus_recorder_resume(janus_recorder *recorder) {
if(!recorder)
return -1;
janus_mutex_lock_nodebug(&recorder->mutex);
if(recorder->type == JANUS_RECORDER_AUDIO) {
recorder->context.a_ts_reset = TRUE;
recorder->context.a_seq_reset = TRUE;
recorder->context.a_last_time = janus_get_monotonic_time();
} else if(recorder->type == JANUS_RECORDER_VIDEO) {
recorder->context.v_ts_reset = TRUE;
recorder->context.v_seq_reset = TRUE;
recorder->context.v_last_time = janus_get_monotonic_time();
if(g_atomic_int_compare_and_exchange(&recorder->paused, 1, 0)) {
if(recorder->type == JANUS_RECORDER_AUDIO) {
recorder->context.a_ts_reset = TRUE;
recorder->context.a_seq_reset = TRUE;
recorder->context.a_last_time = janus_get_monotonic_time();
} else if(recorder->type == JANUS_RECORDER_VIDEO) {
recorder->context.v_ts_reset = TRUE;
recorder->context.v_seq_reset = TRUE;
recorder->context.v_last_time = janus_get_monotonic_time();
}
janus_mutex_unlock_nodebug(&recorder->mutex);
return 0;
}
g_atomic_int_set(&recorder->paused, 0);
janus_mutex_unlock_nodebug(&recorder->mutex);
isnumanagic marked this conversation as resolved.
Show resolved Hide resolved
return 0;
return -2;
}

int janus_recorder_add_extmap(janus_recorder *recorder, int id, const char *extmap) {
Expand Down Expand Up @@ -416,8 +420,8 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt
}
/* Edit packet header if needed */
janus_rtp_header *header = (janus_rtp_header *)buffer;
uint32_t ssrc;
uint16_t seq;
uint32_t ssrc = 0;
uint16_t seq = 0;
if(recorder->type != JANUS_RECORDER_DATA) {
isnumanagic marked this conversation as resolved.
Show resolved Hide resolved
ssrc = ntohl(header->ssrc);
seq = ntohs(header->seq_number);
Expand Down