From d0014716ade3bb67595aa55da0f7ef38a1da81e7 Mon Sep 17 00:00:00 2001 From: Ishak Numanagic Date: Tue, 29 Jun 2021 10:46:29 +0200 Subject: [PATCH 1/7] Add pause/resume recording functionality Record&Play and SIP plugin --- html/recordplaytest.html | 7 ++++++- html/recordplaytest.js | 12 ++++++++++++ plugins/janus_recordplay.c | 29 ++++++++++++++++++++++++++++- plugins/janus_sip.c | 36 +++++++++++++++++++++++++++++++++--- record.c | 22 ++++++++++++++++++++++ record.h | 12 ++++++++++++ 6 files changed, 113 insertions(+), 5 deletions(-) diff --git a/html/recordplaytest.html b/html/recordplaytest.html index 290ef3bfdc..b818987aa6 100644 --- a/html/recordplaytest.html +++ b/html/recordplaytest.html @@ -89,7 +89,12 @@

Recorder/Playout

-

Remote Video

+

+ Remote Video + + + +

diff --git a/html/recordplaytest.js b/html/recordplaytest.js index 9000740458..994247ab05 100644 --- a/html/recordplaytest.js +++ b/html/recordplaytest.js @@ -497,6 +497,18 @@ function startRecording() { recordplay.hangup(); } }); + + $('#pause').on('click', () => { + recordplay.send({message: {request: 'pause'}}); + $('#pause').attr('hidden', true); + $('#resume').attr('hidden', false); + }); + + $('#resume').on('click', () => { + recordplay.send({message: {request: 'resume'}}); + $('#pause').attr('hidden', false); + $('#resume').attr('hidden', true); + }); }); } diff --git a/plugins/janus_recordplay.c b/plugins/janus_recordplay.c index 7055e4be40..1d94b6713f 100644 --- a/plugins/janus_recordplay.c +++ b/plugins/janus_recordplay.c @@ -1104,7 +1104,8 @@ struct janus_plugin_result *janus_recordplay_handle_message(janus_plugin_session json_object_set_new(response, "settings", settings); goto plugin_response; } else if(!strcasecmp(request_text, "record") || !strcasecmp(request_text, "play") - || !strcasecmp(request_text, "start") || !strcasecmp(request_text, "stop")) { + || !strcasecmp(request_text, "start") || !strcasecmp(request_text, "stop") + || !strcasecmp(request_text, "pause") || !strcasecmp(request_text, "resume")) { /* These messages are handled asynchronously */ janus_recordplay_message *msg = g_malloc(sizeof(janus_recordplay_message)); msg->handle = handle; @@ -2007,6 +2008,32 @@ static void *janus_recordplay_handler(void *data) { } /* Tell the core to tear down the PeerConnection, hangup_media will do the rest */ gateway->close_pc(session->handle); + } else if (!strcasecmp(request_text, "pause") || !strcasecmp(request_text, "resume")) { + JANUS_LOG(LOG_VERB, "Record&Play: Got pause/resume request\n"); + int pause = !strcasecmp(request_text, "pause"); + result = json_object(); + json_object_set_new(result, "status", json_string(pause ? "paused" : "resumed")); + if(session->recording) { + 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")); + if(session->recording) + 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_LOG(LOG_ERR, "Unknown request '%s'\n", request_text); error_code = JANUS_RECORDPLAY_ERROR_INVALID_REQUEST; diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index f4e4c9368e..7c1c05778b 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -4357,10 +4357,11 @@ static void *janus_sip_handler(void *data) { goto error; json_t *action = json_object_get(root, "action"); const char *action_text = json_string_value(action); - if(strcasecmp(action_text, "start") && strcasecmp(action_text, "stop")) { - JANUS_LOG(LOG_ERR, "Invalid action (should be start|stop)\n"); + if(strcasecmp(action_text, "start") && strcasecmp(action_text, "stop") && + strcasecmp(action_text, "pause") && strcasecmp(action_text, "resume")) { + JANUS_LOG(LOG_ERR, "Invalid action (should be start|stop|pause|resume)\n"); error_code = JANUS_SIP_ERROR_INVALID_ELEMENT; - g_snprintf(error_cause, 512, "Invalid action (should be start|stop)"); + g_snprintf(error_cause, 512, "Invalid action (should be start|stop|pause|resume)"); goto error; } gboolean record_audio = FALSE, record_video = FALSE, /* No media is recorded by default */ @@ -4502,6 +4503,35 @@ static void *janus_sip_handler(void *data) { gateway->send_pli(session->handle); } } + } else if(!strcasecmp(action_text, "pause")) { + if(record_audio) { + janus_recorder_pause(&session->arc); + } + if(record_video) { + janus_recorder_pause(&session->vrc); + } + if(record_peer_audio) { + janus_recorder_pause(&session->arc_peer); + } + if(record_peer_video) { + janus_recorder_pause(&session->vrc_peer); + } + } else if(!strcasecmp(action_text, "resume")) { + if(record_audio) { + janus_recorder_resume(&session->arc); + } + if(record_video) { + janus_recorder_resume(&session->vrc); + } + if(record_peer_audio) { + janus_recorder_resume(&session->arc_peer); + } + if(record_peer_video) { + janus_recorder_resume(&session->vrc_peer); + } + if(record_video || record_peer_video) { + gateway->send_pli(&session->handle); + } } else { /* Stop recording something: notice that this never returns an error, even when we were not recording anything */ janus_sip_recorder_close(session, record_audio, record_peer_audio, record_video, record_peer_video); diff --git a/record.c b/record.c index c24c86a22b..e2a1d916a8 100644 --- a/record.c +++ b/record.c @@ -255,6 +255,24 @@ janus_recorder *janus_recorder_create_full(const char *dir, const char *codec, c return rc; } +int janus_recorder_pause(janus_recorder *recorder) { + if(!recorder) + return -1; + janus_mutex_lock_nodebug(&recorder->mutex); + g_atomic_int_set(&recorder->paused, 1); + janus_mutex_unlock_nodebug(&recorder->mutex); + return 0; +} + +int janus_recorder_resume(janus_recorder *recorder) { + if(!recorder) + return -1; + janus_mutex_lock_nodebug(&recorder->mutex); + g_atomic_int_set(&recorder->paused, 0); + janus_mutex_unlock_nodebug(&recorder->mutex); + return 0; +} + int janus_recorder_add_extmap(janus_recorder *recorder, int id, const char *extmap) { if(!recorder || g_atomic_int_get(&recorder->header) || id < 1 || id > 15 || extmap == NULL) return -1; @@ -292,6 +310,10 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt janus_mutex_unlock_nodebug(&recorder->mutex); return -4; } + if(g_atomic_int_get(&recorder->paused)) { + janus_mutex_unlock_nodebug(&recorder->mutex); + return -5; + } gint64 now = janus_get_monotonic_time(); if(!g_atomic_int_get(&recorder->header)) { /* Write info header as a JSON formatted info */ diff --git a/record.h b/record.h index 482c9fc060..46d27baf76 100644 --- a/record.h +++ b/record.h @@ -60,6 +60,8 @@ typedef struct janus_recorder { volatile int header; /*! \brief Whether this recorder instance can be used for writing or not */ volatile int writable; + /*! \brief Whether recorder instance is paused or not */ + volatile int paused; /*! \brief Mutex to lock/unlock this recorder instance */ janus_mutex mutex; /*! \brief Atomic flag to check if this instance has been destroyed */ @@ -92,6 +94,16 @@ janus_recorder *janus_recorder_create(const char *dir, const char *codec, const * @param[in] filename Filename to use for the recording * @returns A valid janus_recorder instance in case of success, NULL otherwise */ janus_recorder *janus_recorder_create_full(const char *dir, const char *codec, const char *fmtp, const char *filename); +/*! \brief Pause recording packets + * \note This is to allow pause and resume recorder functionality. + * @param[in] recorder The janus_recorder to pause + * @returns 0 in case of success, a negative integer otherwise */ +int janus_recorder_pause(janus_recorder *recorder); +/*! \brief Resume recording packets + * \note This is to allow pause and resume recorder functionality. + * @param[in] recorder The janus_recorder to resume + * @returns 0 in case of success, a negative integer otherwise */ +int janus_recorder_resume(janus_recorder *recorder); /*! \brief Add an RTP extension to this recording * \note This will only be possible BEFORE the first frame is written, as it needs to * be reflected in the .mjr header: doing this after that will return an error. From 3769bb2504b72fe03964f5825a5900ce4b17dc52 Mon Sep 17 00:00:00 2001 From: Ishak Numanagic Date: Tue, 13 Jul 2021 08:42:51 +0200 Subject: [PATCH 2/7] CR --- record.c | 30 +++++++++++++++++++++++++++--- record.h | 7 +++++-- rtp.c | 46 ++++++++++++++++++++++++++++++++++------------ rtp.h | 8 ++++---- 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/record.c b/record.c index e2a1d916a8..0f31b16fc2 100644 --- a/record.c +++ b/record.c @@ -110,6 +110,7 @@ janus_recorder *janus_recorder_create_full(const char *dir, const char *codec, c /* Create the recorder */ janus_recorder *rc = g_malloc0(sizeof(janus_recorder)); janus_refcount_init(&rc->ref, janus_recorder_free); + janus_rtp_switching_context_reset(&rc->context); rc->dir = NULL; rc->filename = NULL; rc->file = NULL; @@ -259,7 +260,7 @@ int janus_recorder_pause(janus_recorder *recorder) { if(!recorder) return -1; janus_mutex_lock_nodebug(&recorder->mutex); - g_atomic_int_set(&recorder->paused, 1); + recorder->paused = janus_get_monotonic_time(); janus_mutex_unlock_nodebug(&recorder->mutex); return 0; } @@ -268,7 +269,14 @@ int janus_recorder_resume(janus_recorder *recorder) { if(!recorder) return -1; janus_mutex_lock_nodebug(&recorder->mutex); - g_atomic_int_set(&recorder->paused, 0); + if(recorder->type == JANUS_RECORDER_AUDIO) { + recorder->context.a_seq_reset = TRUE; + recorder->context.a_time_offset -= janus_get_monotonic_time() - recorder->paused; + } else if(recorder->type == JANUS_RECORDER_VIDEO) { + recorder->context.v_seq_reset = TRUE; + recorder->context.v_time_offset -= janus_get_monotonic_time() - recorder->paused; + } + recorder->paused = 0; janus_mutex_unlock_nodebug(&recorder->mutex); return 0; } @@ -310,7 +318,7 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt janus_mutex_unlock_nodebug(&recorder->mutex); return -4; } - if(g_atomic_int_get(&recorder->paused)) { + if(recorder->paused > 0) { janus_mutex_unlock_nodebug(&recorder->mutex); return -5; } @@ -406,17 +414,33 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt res, sizeof(gint64), g_strerror(errno)); } } + /* Edit packet header if needed */ + rtp_header *header = (rtp_header *)buffer; + uint32_t ssrc = ntohl(header->ssrc); + uint16_t seq = ntohs(header->seq_number); + timestamp = ntohl(header->timestamp); + if(recorder->type != JANUS_RECORDER_DATA) { + janus_rtp_header_update(header, &recorder->context, recorder->type == JANUS_RECORDER_VIDEO, 0); + } /* Save packet on file */ int temp = 0, tot = length; while(tot > 0) { temp = fwrite(buffer+length-tot, sizeof(char), tot, recorder->file); if(temp <= 0) { JANUS_LOG(LOG_ERR, "Error saving frame...\n"); + /* Restore packet header data */ + header->ssrc = htonl(ssrc); + header->seq_number = htons(seq); + header->timestamp = htonl(timestamp); janus_mutex_unlock_nodebug(&recorder->mutex); return -6; } tot -= temp; } + /* Restore packet header data */ + header->ssrc = htonl(ssrc); + header->seq_number = htons(seq); + header->timestamp = htonl(timestamp); /* Done */ janus_mutex_unlock_nodebug(&recorder->mutex); return 0; diff --git a/record.h b/record.h index 46d27baf76..401f598a2c 100644 --- a/record.h +++ b/record.h @@ -27,6 +27,7 @@ #include "mutex.h" #include "refcount.h" +#include "rtp.h" /*! \brief Media types we can record */ @@ -60,8 +61,10 @@ typedef struct janus_recorder { volatile int header; /*! \brief Whether this recorder instance can be used for writing or not */ volatile int writable; - /*! \brief Whether recorder instance is paused or not */ - volatile int paused; + /*! \brief Pause start timestamp */ + gint64 paused; + /*! \brief RTP switching context for rewriting RTP headers */ + janus_rtp_switching_context context; /*! \brief Mutex to lock/unlock this recorder instance */ janus_mutex mutex; /*! \brief Atomic flag to check if this instance has been destroyed */ diff --git a/rtp.c b/rtp.c index 18c634a135..438738d654 100644 --- a/rtp.c +++ b/rtp.c @@ -595,16 +595,24 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte uint32_t ssrc = ntohl(header->ssrc); uint32_t timestamp = ntohl(header->timestamp); uint16_t seq = ntohs(header->seq_number); + gint64 ts_diff = 0; if(video) { if(ssrc != context->v_last_ssrc) { /* Video SSRC changed: update both sequence number and timestamp */ JANUS_LOG(LOG_VERB, "Video SSRC changed, %"SCNu32" --> %"SCNu32"\n", context->v_last_ssrc, ssrc); context->v_last_ssrc = ssrc; + context->v_ts_reset = TRUE; + context->v_seq_reset = TRUE; + /* Reset skew compensation data */ + context->v_new_ssrc = TRUE; + } + if(context->v_ts_reset) { + /* Video timestamp was paused for a while */ + JANUS_LOG(LOG_VERB, "Video RTP timestamp reset requested"); + context->v_ts_reset = FALSE; context->v_base_ts_prev = context->v_last_ts; context->v_base_ts = timestamp; - context->v_base_seq_prev = context->v_last_seq; - context->v_base_seq = seq; /* How much time since the last video RTP packet? We compute an offset accordingly */ if(context->v_last_time > 0) { gint64 time_diff = janus_get_monotonic_time() - context->v_last_time; @@ -615,18 +623,20 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte context->v_last_ts += (guint32)time_diff; JANUS_LOG(LOG_VERB, "Computed offset for video RTP timestamp: %"SCNu32"\n", (guint32)time_diff); } - /* Reset skew compensation data */ - context->v_new_ssrc = TRUE; + } + if(context->v_time_offset != 0) { + ts_diff = (context->v_time_offset*90)/1000; /* We're assuming 90khz here */ } if(context->v_seq_reset) { - /* Video sequence number was paused for a while: just update that */ + /* Video sequence number was paused for a while */ + JANUS_LOG(LOG_VERB, "Video RTP sequence number reset requested"); context->v_seq_reset = FALSE; context->v_base_seq_prev = context->v_last_seq; context->v_base_seq = seq; } /* Compute a coherent timestamp and sequence number */ context->v_prev_ts = context->v_last_ts; - context->v_last_ts = (timestamp-context->v_base_ts) + context->v_base_ts_prev; + context->v_last_ts = (guint32)((timestamp-context->v_base_ts) + context->v_base_ts_prev + ts_diff); context->v_prev_seq = context->v_last_seq; context->v_last_seq = (seq-context->v_base_seq)+context->v_base_seq_prev+1; /* Update the timestamp and sequence number in the RTP packet */ @@ -640,10 +650,17 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte JANUS_LOG(LOG_VERB, "Audio SSRC changed, %"SCNu32" --> %"SCNu32"\n", context->a_last_ssrc, ssrc); context->a_last_ssrc = ssrc; + context->a_ts_reset = TRUE; + context->a_seq_reset = TRUE; + /* Reset skew compensation data */ + context->a_new_ssrc = TRUE; + } + if(context->a_ts_reset) { + /* Audio timestamp was paused for a while */ + JANUS_LOG(LOG_VERB, "Audio RTP timestamp reset requested"); + context->a_ts_reset = FALSE; context->a_base_ts_prev = context->a_last_ts; context->a_base_ts = timestamp; - context->a_base_seq_prev = context->a_last_seq; - context->a_base_seq = seq; /* How much time since the last audio RTP packet? We compute an offset accordingly */ if(context->a_last_time > 0) { gint64 time_diff = janus_get_monotonic_time() - context->a_last_time; @@ -658,18 +675,23 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte context->a_last_ts += (guint32)time_diff; JANUS_LOG(LOG_VERB, "Computed offset for audio RTP timestamp: %"SCNu32"\n", (guint32)time_diff); } - /* Reset skew compensation data */ - context->a_new_ssrc = TRUE; + } + if(context->a_time_offset != 0) { + int akhz = 48; + if(header->type == 0 || header->type == 8 || header->type == 9) + akhz = 8; /* We're assuming 48khz here (Opus), unless it's G.711/G.722 (8khz) */ + ts_diff = (context->a_time_offset*90)/1000; /* We're assuming 90khz here */ } if(context->a_seq_reset) { - /* Audio sequence number was paused for a while: just update that */ + /* Audio sequence number was paused for a while */ + JANUS_LOG(LOG_VERB, "Audio RTP sequence number reset requested"); context->a_seq_reset = FALSE; context->a_base_seq_prev = context->a_last_seq; context->a_base_seq = seq; } /* Compute a coherent timestamp and sequence number */ context->a_prev_ts = context->a_last_ts; - context->a_last_ts = (timestamp-context->a_base_ts) + context->a_base_ts_prev; + context->a_last_ts = (guint32)((timestamp-context->a_base_ts) + context->a_base_ts_prev + ts_diff); context->a_prev_seq = context->a_last_seq; context->a_last_seq = (seq-context->a_base_seq)+context->a_base_seq_prev+1; /* Update the timestamp and sequence number in the RTP packet */ diff --git a/rtp.h b/rtp.h index 34a6705f9a..f01a78bcc8 100644 --- a/rtp.h +++ b/rtp.h @@ -226,14 +226,14 @@ typedef struct janus_rtp_switching_context { v_last_ssrc, v_last_ts, v_base_ts, v_base_ts_prev, v_prev_ts, v_target_ts, v_start_ts; uint16_t a_last_seq, a_prev_seq, a_base_seq, a_base_seq_prev, v_last_seq, v_prev_seq, v_base_seq, v_base_seq_prev; - gboolean a_seq_reset, a_new_ssrc, - v_seq_reset, v_new_ssrc; + gboolean a_ts_reset, a_seq_reset, a_new_ssrc, + v_ts_reset, v_seq_reset, v_new_ssrc; gint16 a_seq_offset, v_seq_offset; gint32 a_prev_delay, a_active_delay, a_ts_offset, v_prev_delay, v_active_delay, v_ts_offset; - gint64 a_last_time, a_reference_time, a_start_time, a_evaluating_start_time, - v_last_time, v_reference_time, v_start_time, v_evaluating_start_time; + gint64 a_last_time, a_reference_time, a_start_time, a_evaluating_start_time, a_time_offset, + v_last_time, v_reference_time, v_start_time, v_evaluating_start_time, v_time_offset; } janus_rtp_switching_context; /*! \brief Set (or reset) the context fields to their default values From fe2a0a5020eb05c32e115710605c88a0f7beec99 Mon Sep 17 00:00:00 2001 From: Ishak Numanagic Date: Wed, 14 Jul 2021 09:23:47 +0200 Subject: [PATCH 3/7] CR --- record.c | 12 +++++++----- record.h | 4 ++-- rtp.c | 14 ++------------ rtp.h | 4 ++-- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/record.c b/record.c index 0f31b16fc2..4d905836b3 100644 --- a/record.c +++ b/record.c @@ -260,7 +260,7 @@ int janus_recorder_pause(janus_recorder *recorder) { if(!recorder) return -1; janus_mutex_lock_nodebug(&recorder->mutex); - recorder->paused = janus_get_monotonic_time(); + g_atomic_int_set(&recorder->paused, TRUE); janus_mutex_unlock_nodebug(&recorder->mutex); return 0; } @@ -270,13 +270,15 @@ int janus_recorder_resume(janus_recorder *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_time_offset -= janus_get_monotonic_time() - recorder->paused; + 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_time_offset -= janus_get_monotonic_time() - recorder->paused; + recorder->context.v_last_time = janus_get_monotonic_time(); } - recorder->paused = 0; + g_atomic_int_set(&recorder->paused, FALSE); janus_mutex_unlock_nodebug(&recorder->mutex); return 0; } @@ -318,7 +320,7 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt janus_mutex_unlock_nodebug(&recorder->mutex); return -4; } - if(recorder->paused > 0) { + if(g_atomic_int_get(&recorder->paused)) { janus_mutex_unlock_nodebug(&recorder->mutex); return -5; } diff --git a/record.h b/record.h index 401f598a2c..34768dff93 100644 --- a/record.h +++ b/record.h @@ -61,8 +61,8 @@ typedef struct janus_recorder { volatile int header; /*! \brief Whether this recorder instance can be used for writing or not */ volatile int writable; - /*! \brief Pause start timestamp */ - gint64 paused; + /*! \brief Whether writing RTP packets is paused */ + volatile int paused; /*! \brief RTP switching context for rewriting RTP headers */ janus_rtp_switching_context context; /*! \brief Mutex to lock/unlock this recorder instance */ diff --git a/rtp.c b/rtp.c index 438738d654..ee400b666b 100644 --- a/rtp.c +++ b/rtp.c @@ -595,7 +595,6 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte uint32_t ssrc = ntohl(header->ssrc); uint32_t timestamp = ntohl(header->timestamp); uint16_t seq = ntohs(header->seq_number); - gint64 ts_diff = 0; if(video) { if(ssrc != context->v_last_ssrc) { /* Video SSRC changed: update both sequence number and timestamp */ @@ -624,9 +623,6 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte JANUS_LOG(LOG_VERB, "Computed offset for video RTP timestamp: %"SCNu32"\n", (guint32)time_diff); } } - if(context->v_time_offset != 0) { - ts_diff = (context->v_time_offset*90)/1000; /* We're assuming 90khz here */ - } if(context->v_seq_reset) { /* Video sequence number was paused for a while */ JANUS_LOG(LOG_VERB, "Video RTP sequence number reset requested"); @@ -636,7 +632,7 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte } /* Compute a coherent timestamp and sequence number */ context->v_prev_ts = context->v_last_ts; - context->v_last_ts = (guint32)((timestamp-context->v_base_ts) + context->v_base_ts_prev + ts_diff); + context->v_last_ts = (timestamp-context->v_base_ts) + context->v_base_ts_prev; context->v_prev_seq = context->v_last_seq; context->v_last_seq = (seq-context->v_base_seq)+context->v_base_seq_prev+1; /* Update the timestamp and sequence number in the RTP packet */ @@ -676,12 +672,6 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte JANUS_LOG(LOG_VERB, "Computed offset for audio RTP timestamp: %"SCNu32"\n", (guint32)time_diff); } } - if(context->a_time_offset != 0) { - int akhz = 48; - if(header->type == 0 || header->type == 8 || header->type == 9) - akhz = 8; /* We're assuming 48khz here (Opus), unless it's G.711/G.722 (8khz) */ - ts_diff = (context->a_time_offset*90)/1000; /* We're assuming 90khz here */ - } if(context->a_seq_reset) { /* Audio sequence number was paused for a while */ JANUS_LOG(LOG_VERB, "Audio RTP sequence number reset requested"); @@ -691,7 +681,7 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte } /* Compute a coherent timestamp and sequence number */ context->a_prev_ts = context->a_last_ts; - context->a_last_ts = (guint32)((timestamp-context->a_base_ts) + context->a_base_ts_prev + ts_diff); + context->a_last_ts = (timestamp-context->a_base_ts) + context->a_base_ts_prev; context->a_prev_seq = context->a_last_seq; context->a_last_seq = (seq-context->a_base_seq)+context->a_base_seq_prev+1; /* Update the timestamp and sequence number in the RTP packet */ diff --git a/rtp.h b/rtp.h index f01a78bcc8..9c5e21691b 100644 --- a/rtp.h +++ b/rtp.h @@ -232,8 +232,8 @@ typedef struct janus_rtp_switching_context { v_seq_offset; gint32 a_prev_delay, a_active_delay, a_ts_offset, v_prev_delay, v_active_delay, v_ts_offset; - gint64 a_last_time, a_reference_time, a_start_time, a_evaluating_start_time, a_time_offset, - v_last_time, v_reference_time, v_start_time, v_evaluating_start_time, v_time_offset; + gint64 a_last_time, a_reference_time, a_start_time, a_evaluating_start_time, + v_last_time, v_reference_time, v_start_time, v_evaluating_start_time; } janus_rtp_switching_context; /*! \brief Set (or reset) the context fields to their default values From 3c794c0b81a2778e4b75490cb00237bbb08b12c9 Mon Sep 17 00:00:00 2001 From: Ishak Numanagic Date: Mon, 2 Aug 2021 15:59:50 +0200 Subject: [PATCH 4/7] CR --- html/recordplaytest.html | 3 +-- html/recordplaytest.js | 17 ++++++-------- plugins/janus_recordplay.c | 11 +++++---- plugins/janus_sip.c | 47 +++++++++++++++----------------------- record.c | 36 ++++++++++++++++------------- record.h | 2 +- rtp.c | 12 +++++----- 7 files changed, 60 insertions(+), 68 deletions(-) diff --git a/html/recordplaytest.html b/html/recordplaytest.html index b818987aa6..83595e019e 100644 --- a/html/recordplaytest.html +++ b/html/recordplaytest.html @@ -92,8 +92,7 @@

Recorder/Playout

Remote Video - - +

diff --git a/html/recordplaytest.js b/html/recordplaytest.js index 994247ab05..e69fbed4e4 100644 --- a/html/recordplaytest.js +++ b/html/recordplaytest.js @@ -497,18 +497,15 @@ function startRecording() { recordplay.hangup(); } }); - - $('#pause').on('click', () => { + $('#pause-resume').unbind('click').on('click', function() { + if($(this).text() === 'Pause') { recordplay.send({message: {request: 'pause'}}); - $('#pause').attr('hidden', true); - $('#resume').attr('hidden', false); - }); - - $('#resume').on('click', () => { + $(this).text('Resume'); + } else { recordplay.send({message: {request: 'resume'}}); - $('#pause').attr('hidden', false); - $('#resume').attr('hidden', true); - }); + $(this).text('Pause'); + } + }); }); } diff --git a/plugins/janus_recordplay.c b/plugins/janus_recordplay.c index 1d94b6713f..be65069f36 100644 --- a/plugins/janus_recordplay.c +++ b/plugins/janus_recordplay.c @@ -2010,17 +2010,16 @@ static void *janus_recordplay_handler(void *data) { gateway->close_pc(session->handle); } else if (!strcasecmp(request_text, "pause") || !strcasecmp(request_text, "resume")) { JANUS_LOG(LOG_VERB, "Record&Play: Got pause/resume request\n"); - int pause = !strcasecmp(request_text, "pause"); - result = json_object(); - json_object_set_new(result, "status", json_string(pause ? "paused" : "resumed")); if(session->recording) { + gboolean pause = !strcasecmp(request_text, "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")); - if(session->recording) - json_object_set_new(info, "id", json_integer(session->recording->id)); + json_object_set_new(info, "id", json_integer(session->recording->id)); gateway->notify_event(&janus_recordplay_plugin, session->handle, info); } if(pause) { @@ -2033,6 +2032,8 @@ static void *janus_recordplay_handler(void *data) { janus_recorder_resume(session->drc); gateway->send_pli(session->handle); } + } else { + JANUS_LOG(LOG_VERB, "Record&Play: Not recording, ignoring pause/resume request\n"); } } else { JANUS_LOG(LOG_ERR, "Unknown request '%s'\n", request_text); diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 7c1c05778b..5999798381 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -4358,7 +4358,7 @@ static void *janus_sip_handler(void *data) { json_t *action = json_object_get(root, "action"); const char *action_text = json_string_value(action); if(strcasecmp(action_text, "start") && strcasecmp(action_text, "stop") && - strcasecmp(action_text, "pause") && strcasecmp(action_text, "resume")) { + strcasecmp(action_text, "pause") && strcasecmp(action_text, "resume")) { JANUS_LOG(LOG_ERR, "Invalid action (should be start|stop|pause|resume)\n"); error_code = JANUS_SIP_ERROR_INVALID_ELEMENT; g_snprintf(error_cause, 512, "Invalid action (should be start|stop|pause|resume)"); @@ -4504,34 +4504,25 @@ static void *janus_sip_handler(void *data) { } } } else if(!strcasecmp(action_text, "pause")) { - if(record_audio) { - janus_recorder_pause(&session->arc); - } - if(record_video) { - janus_recorder_pause(&session->vrc); - } - if(record_peer_audio) { - janus_recorder_pause(&session->arc_peer); - } - if(record_peer_video) { - janus_recorder_pause(&session->vrc_peer); - } + if(record_audio) + janus_recorder_pause(session->arc); + if(record_video) + janus_recorder_pause(session->vrc); + if(record_peer_audio) + janus_recorder_pause(session->arc_peer); + if(record_peer_video) + janus_recorder_pause(session->vrc_peer); } else if(!strcasecmp(action_text, "resume")) { - if(record_audio) { - janus_recorder_resume(&session->arc); - } - if(record_video) { - janus_recorder_resume(&session->vrc); - } - if(record_peer_audio) { - janus_recorder_resume(&session->arc_peer); - } - if(record_peer_video) { - janus_recorder_resume(&session->vrc_peer); - } - if(record_video || record_peer_video) { - gateway->send_pli(&session->handle); - } + if(record_audio) + janus_recorder_resume(session->arc); + if(record_video) + janus_recorder_resume(session->vrc); + if(record_peer_audio) + janus_recorder_resume(session->arc_peer); + if(record_peer_video) + janus_recorder_resume(session->vrc_peer); + if(record_video || record_peer_video) + gateway->send_pli(session->handle); } else { /* Stop recording something: notice that this never returns an error, even when we were not recording anything */ janus_sip_recorder_close(session, record_audio, record_peer_audio, record_video, record_peer_video); diff --git a/record.c b/record.c index 4d905836b3..3bce58ecbd 100644 --- a/record.c +++ b/record.c @@ -259,9 +259,7 @@ janus_recorder *janus_recorder_create_full(const char *dir, const char *codec, c int janus_recorder_pause(janus_recorder *recorder) { if(!recorder) return -1; - janus_mutex_lock_nodebug(&recorder->mutex); - g_atomic_int_set(&recorder->paused, TRUE); - janus_mutex_unlock_nodebug(&recorder->mutex); + g_atomic_int_set(&recorder->paused, 1); return 0; } @@ -278,7 +276,7 @@ int janus_recorder_resume(janus_recorder *recorder) { recorder->context.v_seq_reset = TRUE; recorder->context.v_last_time = janus_get_monotonic_time(); } - g_atomic_int_set(&recorder->paused, FALSE); + g_atomic_int_set(&recorder->paused, 0); janus_mutex_unlock_nodebug(&recorder->mutex); return 0; } @@ -417,11 +415,13 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt } } /* Edit packet header if needed */ - rtp_header *header = (rtp_header *)buffer; - uint32_t ssrc = ntohl(header->ssrc); - uint16_t seq = ntohs(header->seq_number); - timestamp = ntohl(header->timestamp); + janus_rtp_header *header = (janus_rtp_header *)buffer; + uint32_t ssrc; + uint16_t seq; if(recorder->type != JANUS_RECORDER_DATA) { + ssrc = ntohl(header->ssrc); + seq = ntohs(header->seq_number); + timestamp = ntohl(header->timestamp); janus_rtp_header_update(header, &recorder->context, recorder->type == JANUS_RECORDER_VIDEO, 0); } /* Save packet on file */ @@ -430,19 +430,23 @@ int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint lengt temp = fwrite(buffer+length-tot, sizeof(char), tot, recorder->file); if(temp <= 0) { JANUS_LOG(LOG_ERR, "Error saving frame...\n"); - /* Restore packet header data */ - header->ssrc = htonl(ssrc); - header->seq_number = htons(seq); - header->timestamp = htonl(timestamp); + if(recorder->type != JANUS_RECORDER_DATA) { + /* Restore packet header data */ + header->ssrc = htonl(ssrc); + header->seq_number = htons(seq); + header->timestamp = htonl(timestamp); + } janus_mutex_unlock_nodebug(&recorder->mutex); return -6; } tot -= temp; } - /* Restore packet header data */ - header->ssrc = htonl(ssrc); - header->seq_number = htons(seq); - header->timestamp = htonl(timestamp); + if(recorder->type != JANUS_RECORDER_DATA) { + /* Restore packet header data */ + header->ssrc = htonl(ssrc); + header->seq_number = htons(seq); + header->timestamp = htonl(timestamp); + } /* Done */ janus_mutex_unlock_nodebug(&recorder->mutex); return 0; diff --git a/record.h b/record.h index 34768dff93..6e75a0f548 100644 --- a/record.h +++ b/record.h @@ -61,7 +61,7 @@ typedef struct janus_recorder { volatile int header; /*! \brief Whether this recorder instance can be used for writing or not */ volatile int writable; - /*! \brief Whether writing RTP packets is paused */ + /*! \brief Whether writing s/RTP packets/data is paused */ volatile int paused; /*! \brief RTP switching context for rewriting RTP headers */ janus_rtp_switching_context context; diff --git a/rtp.c b/rtp.c index ee400b666b..b547ce109a 100644 --- a/rtp.c +++ b/rtp.c @@ -608,7 +608,7 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte } if(context->v_ts_reset) { /* Video timestamp was paused for a while */ - JANUS_LOG(LOG_VERB, "Video RTP timestamp reset requested"); + JANUS_LOG(LOG_HUGE, "Video RTP timestamp reset requested"); context->v_ts_reset = FALSE; context->v_base_ts_prev = context->v_last_ts; context->v_base_ts = timestamp; @@ -620,12 +620,12 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte time_diff = 1; context->v_base_ts_prev += (guint32)time_diff; context->v_last_ts += (guint32)time_diff; - JANUS_LOG(LOG_VERB, "Computed offset for video RTP timestamp: %"SCNu32"\n", (guint32)time_diff); + JANUS_LOG(LOG_HUGE, "Computed offset for video RTP timestamp: %"SCNu32"\n", (guint32)time_diff); } } if(context->v_seq_reset) { /* Video sequence number was paused for a while */ - JANUS_LOG(LOG_VERB, "Video RTP sequence number reset requested"); + JANUS_LOG(LOG_HUGE, "Video RTP sequence number reset requested"); context->v_seq_reset = FALSE; context->v_base_seq_prev = context->v_last_seq; context->v_base_seq = seq; @@ -653,7 +653,7 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte } if(context->a_ts_reset) { /* Audio timestamp was paused for a while */ - JANUS_LOG(LOG_VERB, "Audio RTP timestamp reset requested"); + JANUS_LOG(LOG_HUGE, "Audio RTP timestamp reset requested"); context->a_ts_reset = FALSE; context->a_base_ts_prev = context->a_last_ts; context->a_base_ts = timestamp; @@ -669,12 +669,12 @@ void janus_rtp_header_update(janus_rtp_header *header, janus_rtp_switching_conte context->a_base_ts_prev += (guint32)time_diff; context->a_prev_ts += (guint32)time_diff; context->a_last_ts += (guint32)time_diff; - JANUS_LOG(LOG_VERB, "Computed offset for audio RTP timestamp: %"SCNu32"\n", (guint32)time_diff); + JANUS_LOG(LOG_HUGE, "Computed offset for audio RTP timestamp: %"SCNu32"\n", (guint32)time_diff); } } if(context->a_seq_reset) { /* Audio sequence number was paused for a while */ - JANUS_LOG(LOG_VERB, "Audio RTP sequence number reset requested"); + JANUS_LOG(LOG_HUGE, "Audio RTP sequence number reset requested"); context->a_seq_reset = FALSE; context->a_base_seq_prev = context->a_last_seq; context->a_base_seq = seq; From 20508e0e183591eec0755bf943f2a14255b9e23b Mon Sep 17 00:00:00 2001 From: Ishak Numanagic Date: Wed, 29 Sep 2021 13:53:02 +0200 Subject: [PATCH 5/7] CR --- html/recordplaytest.js | 2 ++ plugins/janus_recordplay.c | 43 ++++++++++++++++++++++---------------- plugins/janus_sip.c | 39 +++++++++++++++++++++++++--------- record.c | 32 +++++++++++++++------------- 4 files changed, 74 insertions(+), 42 deletions(-) diff --git a/html/recordplaytest.js b/html/recordplaytest.js index e69fbed4e4..74ee7bed95 100644 --- a/html/recordplaytest.js +++ b/html/recordplaytest.js @@ -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 @@ -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 }); } diff --git a/plugins/janus_recordplay.c b/plugins/janus_recordplay.c index be65069f36..4fb557d50d 100644 --- a/plugins/janus_recordplay.c +++ b/plugins/janus_recordplay.c @@ -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 */ @@ -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); @@ -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"); - 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"); } } else { JANUS_LOG(LOG_VERB, "Record&Play: Not recording, ignoring pause/resume request\n"); @@ -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); diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 5999798381..14ff40fedb 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -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"); + 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); @@ -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); } else { /* Stop recording something: notice that this never returns an error, even when we were not recording anything */ diff --git a/record.c b/record.c index 3bce58ecbd..11e562957a 100644 --- a/record.c +++ b/record.c @@ -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); - return 0; + return -2; } int janus_recorder_add_extmap(janus_recorder *recorder, int id, const char *extmap) { @@ -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) { ssrc = ntohl(header->ssrc); seq = ntohs(header->seq_number); From 2e7503e206b476c359be29b16e7b80c778cc48ba Mon Sep 17 00:00:00 2001 From: Ishak Numanagic Date: Wed, 29 Sep 2021 15:03:24 +0200 Subject: [PATCH 6/7] CR --- plugins/janus_recordplay.c | 22 +++++++++---------- plugins/janus_sip.c | 44 +++++++++++--------------------------- 2 files changed, 23 insertions(+), 43 deletions(-) diff --git a/plugins/janus_recordplay.c b/plugins/janus_recordplay.c index 4fb557d50d..571528d18e 100644 --- a/plugins/janus_recordplay.c +++ b/plugins/janus_recordplay.c @@ -2014,17 +2014,17 @@ 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"); + 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 (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); @@ -2035,8 +2035,6 @@ static void *janus_recordplay_handler(void *data) { janus_recorder_resume(session->drc); gateway->send_pli(session->handle); } - } else { - JANUS_LOG(LOG_VERB, "Record&Play: Tried to pause/resume recording of same state, ignoring\n"); } } else { JANUS_LOG(LOG_VERB, "Record&Play: Not recording, ignoring pause/resume request\n"); diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 14ff40fedb..03f6f28950 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -4374,29 +4374,12 @@ 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; - gint update_bitmap = - record_audio | - record_video << 1 | - record_peer_audio << 2 | - record_peer_video << 3; - if(!update_bitmap) { + if(!record_audio && !record_video && !record_peer_audio && !record_peer_video) { 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"); - 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); @@ -4521,26 +4504,25 @@ static void *janus_sip_handler(void *data) { } } } else if(!strcasecmp(action_text, "pause")) { - gint pause_bitmap = ~recorder_bitmap & update_bitmap; - if(pause_bitmap & 1) + if(record_audio) janus_recorder_pause(session->arc); - if(pause_bitmap & 2) + if(record_video) janus_recorder_pause(session->vrc); - if(pause_bitmap & 4) + if(record_peer_audio) janus_recorder_pause(session->arc_peer); - if(pause_bitmap & 8) + if(record_peer_video) janus_recorder_pause(session->vrc_peer); } else if(!strcasecmp(action_text, "resume")) { - gint resume_bitmap = recorder_bitmap & update_bitmap; - if(resume_bitmap & 1) + gboolean send_pli = FALSE; + if(record_audio) janus_recorder_resume(session->arc); - if(resume_bitmap & 2) - janus_recorder_resume(session->vrc); - if(resume_bitmap & 4) + if(record_video && !janus_recorder_resume(session->vrc)) + send_pli = TRUE; + if(record_peer_audio) janus_recorder_resume(session->arc_peer); - if(resume_bitmap & 8) - janus_recorder_resume(session->vrc_peer); - if(resume_bitmap & 10) + if(record_peer_video && !janus_recorder_resume(session->vrc_peer)) + send_pli = TRUE; + if(send_pli) gateway->send_pli(session->handle); } else { /* Stop recording something: notice that this never returns an error, even when we were not recording anything */ From 6986f32d36829c3d4947d8e16638f1023616a6d3 Mon Sep 17 00:00:00 2001 From: Ishak Numanagic Date: Wed, 29 Sep 2021 15:26:36 +0200 Subject: [PATCH 7/7] CR --- plugins/janus_sip.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/plugins/janus_sip.c b/plugins/janus_sip.c index 03f6f28950..03106f2967 100644 --- a/plugins/janus_sip.c +++ b/plugins/janus_sip.c @@ -4513,17 +4513,14 @@ static void *janus_sip_handler(void *data) { if(record_peer_video) janus_recorder_pause(session->vrc_peer); } else if(!strcasecmp(action_text, "resume")) { - gboolean send_pli = FALSE; if(record_audio) janus_recorder_resume(session->arc); if(record_video && !janus_recorder_resume(session->vrc)) - send_pli = TRUE; + gateway->send_pli(session->handle); if(record_peer_audio) janus_recorder_resume(session->arc_peer); - if(record_peer_video && !janus_recorder_resume(session->vrc_peer)) - send_pli = TRUE; - if(send_pli) - gateway->send_pli(session->handle); + if(record_peer_video) + janus_recorder_resume(session->vrc_peer); } else { /* Stop recording something: notice that this never returns an error, even when we were not recording anything */ janus_sip_recorder_close(session, record_audio, record_peer_audio, record_video, record_peer_video);