int janus_text2pcap_close(janus_text2pcap *instance) { if(instance == NULL) return -1; janus_mutex_lock_nodebug(&instance->mutex); if(!g_atomic_int_compare_and_exchange(&instance->writable, 1, 0)) { janus_mutex_unlock_nodebug(&instance->mutex); return 0; } fclose(instance->file); instance->file = NULL; janus_mutex_unlock_nodebug(&instance->mutex); return 0; }
int janus_recorder_close(janus_recorder *recorder) { if(!recorder || !recorder->writable) return -1; janus_mutex_lock_nodebug(&recorder->mutex); recorder->writable = 0; if(recorder->file) { fseek(recorder->file, 0L, SEEK_END); size_t fsize = ftell(recorder->file); fseek(recorder->file, 0L, SEEK_SET); JANUS_LOG(LOG_INFO, "File is %zu bytes: %s\n", fsize, recorder->filename); } janus_mutex_unlock_nodebug(&recorder->mutex); return 0; }
int janus_recorder_free(janus_recorder *recorder) { if(!recorder) return -1; janus_recorder_close(recorder); janus_mutex_lock_nodebug(&recorder->mutex); g_free(recorder->dir); recorder->dir = NULL; g_free(recorder->filename); recorder->filename = NULL; fclose(recorder->file); recorder->file = NULL; g_free(recorder->codec); recorder->codec = NULL; janus_mutex_unlock_nodebug(&recorder->mutex); g_free(recorder); return 0; }
int janus_recorder_close(janus_recorder *recorder) { if(!recorder || !recorder->writable) return -1; janus_mutex_lock_nodebug(&recorder->mutex); recorder->writable = 0; if(recorder->file) { fseek(recorder->file, 0L, SEEK_END); size_t fsize = ftell(recorder->file); fseek(recorder->file, 0L, SEEK_SET); JANUS_LOG(LOG_INFO, "File is %zu bytes: %s\n", fsize, recorder->filename); } if(rec_tempname) { /* We need to rename the file, to remove the temporary extension */ char newname[1024]; memset(newname, 0, 1024); g_snprintf(newname, strlen(recorder->filename)-strlen(rec_tempext), "%s", recorder->filename); char oldpath[1024]; memset(oldpath, 0, 1024); char newpath[1024]; memset(newpath, 0, 1024); if(recorder->dir) { g_snprintf(newpath, 1024, "%s/%s", recorder->dir, newname); g_snprintf(oldpath, 1024, "%s/%s", recorder->dir, recorder->filename); } else { g_snprintf(newpath, 1024, "%s", newname); g_snprintf(oldpath, 1024, "%s", recorder->filename); } if(rename(oldpath, newpath) != 0) { JANUS_LOG(LOG_ERR, "Error renaming %s to %s...\n", recorder->filename, newname); } else { JANUS_LOG(LOG_INFO, "Recording renamed: %s\n", newname); g_free(recorder->filename); recorder->filename = g_strdup(newname); } } janus_mutex_unlock_nodebug(&recorder->mutex); return 0; }
int janus_recorder_save_frame(janus_recorder *recorder, char *buffer, uint length) { if(!recorder) return -1; janus_mutex_lock_nodebug(&recorder->mutex); if(!buffer || length < 1) { janus_mutex_unlock_nodebug(&recorder->mutex); return -2; } if(!recorder->file) { janus_mutex_unlock_nodebug(&recorder->mutex); return -3; } if(!recorder->writable) { janus_mutex_unlock_nodebug(&recorder->mutex); return -4; } if(!recorder->header) { /* Write info header as a JSON formatted info */ json_t *info = json_object(); /* FIXME Codecs should be configurable in the future */ const char *type = NULL; if(recorder->type == JANUS_RECORDER_AUDIO) type = "a"; else if(recorder->type == JANUS_RECORDER_VIDEO) type = "v"; else if(recorder->type == JANUS_RECORDER_DATA) type = "d"; json_object_set_new(info, "t", json_string(type)); /* Audio/Video/Data */ json_object_set_new(info, "c", json_string(recorder->codec)); /* Media codec */ json_object_set_new(info, "s", json_integer(recorder->created)); /* Created time */ json_object_set_new(info, "u", json_integer(janus_get_real_time())); /* First frame written time */ gchar *info_text = json_dumps(info, JSON_PRESERVE_ORDER); json_decref(info); uint16_t info_bytes = htons(strlen(info_text)); fwrite(&info_bytes, sizeof(uint16_t), 1, recorder->file); fwrite(info_text, sizeof(char), strlen(info_text), recorder->file); free(info_text); /* Done */ recorder->header = 1; } /* Write frame header */ fwrite(frame_header, sizeof(char), strlen(frame_header), recorder->file); uint16_t header_bytes = htons(recorder->type == JANUS_RECORDER_DATA ? (length+sizeof(gint64)) : length); fwrite(&header_bytes, sizeof(uint16_t), 1, recorder->file); if(recorder->type == JANUS_RECORDER_DATA) { /* If it's data, then we need to prepend timing related info, as it's not there by itself */ gint64 now = htonll(janus_get_real_time()); fwrite(&now, sizeof(gint64), 1, recorder->file); } /* 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"); janus_mutex_unlock_nodebug(&recorder->mutex); return -5; } tot -= temp; } /* Done */ janus_mutex_unlock_nodebug(&recorder->mutex); return 0; }
int janus_text2pcap_dump(janus_text2pcap *instance, janus_text2pcap_packet type, gboolean incoming, char *buf, int len, const char *format, ...) { if(instance == NULL || buf == NULL || len < 1) return -1; janus_mutex_lock_nodebug(&instance->mutex); if(instance->file == NULL || !g_atomic_int_get(&instance->writable)) { janus_mutex_unlock_nodebug(&instance->mutex); return -1; } /* If we're saving to .pcap directly, generate a packet header and save the payload */ if(!instance->text) { /* Are we truncating? */ int size = instance->truncate ? (len > instance->truncate ? instance->truncate : len) : len; int hsize = sizeof(janus_text2pcap_ethernet_header) + sizeof(janus_text2pcap_ip_header) + sizeof(janus_text2pcap_udp_header); int hsize_cut = hsize + size; int hsize_tot = hsize + len; /* We need a fake Ethernet/IP/UDP encapsulation for this packet */ janus_text2pcap_ethernet_header eth; janus_text2pcap_ethernet_header_init(ð); janus_text2pcap_ip_header ip; janus_text2pcap_ip_header_init(&ip, incoming, len); janus_text2pcap_udp_header udp; janus_text2pcap_udp_header_init(&udp, incoming, len); /* Now prepare the packet header */ struct timeval tv; gettimeofday(&tv, NULL); janus_text2pcap_packet_header header = { tv.tv_sec, tv.tv_usec, hsize_cut, hsize_tot }; fwrite(&header, sizeof(char), sizeof(header), instance->file); fwrite(ð, sizeof(char), sizeof(eth), instance->file); fwrite(&ip, sizeof(char), sizeof(ip), instance->file); fwrite(&udp, sizeof(char), sizeof(udp), instance->file); /* The write the packet itself (or part of it) */ int temp = 0, tot = size; while(tot > 0) { temp = fwrite(buf+size-tot, sizeof(char), tot, instance->file); if(temp <= 0) { JANUS_LOG(LOG_ERR, "Error dumping packet...\n"); janus_mutex_unlock_nodebug(&instance->mutex); return -2; } tot -= temp; } /* Done */ janus_mutex_unlock_nodebug(&instance->mutex); return 0; } /* If we got here, we need to prepare a text representation of the packet */ char buffer[5000], timestamp[20], usec[10], byte[10]; memset(timestamp, 0, sizeof(timestamp)); memset(usec, 0, sizeof(usec)); time_t t = time(NULL); struct tm *tm = localtime(&t); struct timeval tv; gettimeofday(&tv, NULL); strftime(timestamp, sizeof(timestamp), "%H:%M:%S", tm); g_snprintf(usec, sizeof(usec), ".%06ld", tv.tv_usec); g_strlcat(timestamp, usec, sizeof(timestamp)); memset(buffer, 0, sizeof(buffer)); g_snprintf(buffer, sizeof(buffer), "%s %s 000000 ", incoming ? "I" : "O", timestamp); int i=0; int stop = instance->truncate ? (len > instance->truncate ? instance->truncate : len) : len; for(i=0; i<stop; i++) { memset(byte, 0, sizeof(byte)); g_snprintf(byte, sizeof(byte), " %02x", (unsigned char)buf[i]); g_strlcat(buffer, byte, sizeof(buffer)); } g_strlcat(buffer, " ", sizeof(buffer)); g_strlcat(buffer, janus_text2pcap_packet_string(type), sizeof(buffer)); if(format) { /* This callback has variable arguments (error string) */ char custom[512]; va_list ap; va_start(ap, format); g_vsnprintf(custom, sizeof(custom), format, ap); va_end(ap); g_strlcat(buffer, " ", sizeof(buffer)); g_strlcat(buffer, custom, sizeof(buffer)); } g_strlcat(buffer, "\r\n", sizeof(buffer)); /* Save textified packet on file */ int temp = 0, buflen = strlen(buffer), tot = buflen; while(tot > 0) { temp = fwrite(buffer+buflen-tot, sizeof(char), tot, instance->file); if(temp <= 0) { JANUS_LOG(LOG_ERR, "Error dumping packet...\n"); janus_mutex_unlock_nodebug(&instance->mutex); return -2; } tot -= temp; } /* Done */ janus_mutex_unlock_nodebug(&instance->mutex); return 0; }