janus_text2pcap *janus_text2pcap_create(const char *dir, const char *filename, int truncate, gboolean text) { janus_text2pcap *tp; char newname[1024]; char *fname; FILE *f; if(truncate < 0) return NULL; /* Copy given filename or generate a random one */ if (filename == NULL) { g_snprintf(newname, sizeof(newname), "janus-text2pcap-%"SCNu32".%s", janus_random_uint32(), text ? "txt" : "pcap"); } else { g_strlcpy(newname, filename, sizeof(newname)); } if(dir != NULL) { /* Create the directory, if needed */ if(janus_mkdir(dir, 0755) < 0) { JANUS_LOG(LOG_ERR, "mkdir error: %d\n", errno); return NULL; } fname = g_strdup_printf("%s/%s", dir, newname); } else { fname = g_strdup(newname); } /* Try opening the file now */ f = fopen(fname, "ab"); if (f == NULL) { JANUS_LOG(LOG_ERR, "fopen(%s) error: %d\n", fname, errno); g_free(fname); return NULL; } /* Create the text2pcap instance */ tp = g_malloc(sizeof(janus_text2pcap)); tp->filename = fname; tp->file = f; tp->truncate = truncate; tp->text = text; g_atomic_int_set(&tp->writable, 1); janus_mutex_init(&tp->mutex); /* If we're saving to .pcap directly, generate a global header */ if(!text) { janus_text2pcap_global_header header = { 0xa1b2c3d4, 2, 4, 0, 0, 65535, 1 }; fwrite(&header, sizeof(char), sizeof(header), f); } return tp; }
janus_recorder *janus_recorder_create(const char *dir, const char *codec, const char *filename) { janus_recorder_medium type = JANUS_RECORDER_AUDIO; if(codec == NULL) { JANUS_LOG(LOG_ERR, "Missing codec information\n"); return NULL; } if(!strcasecmp(codec, "vp8") || !strcasecmp(codec, "vp9") || !strcasecmp(codec, "h264")) { type = JANUS_RECORDER_VIDEO; if(!strcasecmp(codec, "vp9")) { JANUS_LOG(LOG_WARN, "The post-processor currently doesn't support VP9: recording anyway for the future\n"); } } else if(!strcasecmp(codec, "opus") || !strcasecmp(codec, "g711") || !strcasecmp(codec, "pcmu") || !strcasecmp(codec, "pcma")) { type = JANUS_RECORDER_AUDIO; if(!strcasecmp(codec, "pcmu") || !strcasecmp(codec, "pcma")) codec = "g711"; } else if(!strcasecmp(codec, "text")) { /* FIXME We only handle text on data channels, so that's the only thing we can save too */ type = JANUS_RECORDER_DATA; } else { /* We don't recognize the codec: while we might go on anyway, we'd rather fail instead */ JANUS_LOG(LOG_ERR, "Unsupported codec '%s'\n", codec); return NULL; } /* Create the recorder */ janus_recorder *rc = g_malloc0(sizeof(janus_recorder)); if(rc == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); return NULL; } rc->dir = NULL; rc->filename = NULL; rc->file = NULL; rc->codec = g_strdup(codec); rc->created = janus_get_real_time(); if(dir != NULL) { /* Check if this directory exists, and create it if needed */ struct stat s; int err = stat(dir, &s); if(err == -1) { if(ENOENT == errno) { /* Directory does not exist, try creating it */ if(janus_mkdir(dir, 0755) < 0) { JANUS_LOG(LOG_ERR, "mkdir error: %d\n", errno); return NULL; } } else { JANUS_LOG(LOG_ERR, "stat error: %d\n", errno); return NULL; } } else { if(S_ISDIR(s.st_mode)) { /* Directory exists */ JANUS_LOG(LOG_VERB, "Directory exists: %s\n", dir); } else { /* File exists but it's not a directory? */ JANUS_LOG(LOG_ERR, "Not a directory? %s\n", dir); return NULL; } } } char newname[1024]; memset(newname, 0, 1024); if(filename == NULL) { /* Choose a random username */ g_snprintf(newname, 1024, "janus-recording-%"SCNu32".mjr", janus_random_uint32()); } else { /* Just append the extension */ g_snprintf(newname, 1024, "%s.mjr", filename); } /* Try opening the file now */ if(dir == NULL) { rc->file = fopen(newname, "wb"); } else { char path[1024]; memset(path, 0, 1024); g_snprintf(path, 1024, "%s/%s", dir, newname); rc->file = fopen(path, "wb"); } if(rc->file == NULL) { JANUS_LOG(LOG_ERR, "fopen error: %d\n", errno); return NULL; } if(dir) rc->dir = g_strdup(dir); rc->filename = g_strdup(newname); rc->type = type; /* Write the first part of the header */ fwrite(header, sizeof(char), strlen(header), rc->file); rc->writable = 1; /* We still need to also write the info header first */ rc->header = 0; janus_mutex_init(&rc->mutex); return rc; }
janus_recorder *janus_recorder_create(const char *dir, const char *codec, const char *filename) { janus_recorder_medium type = JANUS_RECORDER_AUDIO; if(codec == NULL) { JANUS_LOG(LOG_ERR, "Missing codec information\n"); return NULL; } if(!strcasecmp(codec, "vp8") || !strcasecmp(codec, "vp9") || !strcasecmp(codec, "h264")) { type = JANUS_RECORDER_VIDEO; } else if(!strcasecmp(codec, "opus") || !strcasecmp(codec, "g711") || !strcasecmp(codec, "pcmu") || !strcasecmp(codec, "pcma") || !strcasecmp(codec, "g722")) { type = JANUS_RECORDER_AUDIO; } else if(!strcasecmp(codec, "text")) { /* FIXME We only handle text on data channels, so that's the only thing we can save too */ type = JANUS_RECORDER_DATA; } else { /* We don't recognize the codec: while we might go on anyway, we'd rather fail instead */ JANUS_LOG(LOG_ERR, "Unsupported codec '%s'\n", codec); return NULL; } /* Create the recorder */ janus_recorder *rc = g_malloc0(sizeof(janus_recorder)); rc->dir = NULL; rc->filename = NULL; rc->file = NULL; rc->codec = g_strdup(codec); rc->created = janus_get_real_time(); const char *rec_dir = NULL; const char *rec_file = NULL; char *copy_for_parent = NULL; char *copy_for_base = NULL; /* Check dir and filename values */ if (filename != NULL) { /* Helper copies to avoid overwriting */ copy_for_parent = g_strdup(filename); copy_for_base = g_strdup(filename); /* Get filename parent folder */ const char *filename_parent = dirname(copy_for_parent); /* Get filename base file */ const char *filename_base = basename(copy_for_base); if (!dir) { /* If dir is NULL we have to create filename_parent and filename_base */ rec_dir = filename_parent; rec_file = filename_base; } else { /* If dir is valid we have to create dir and filename*/ rec_dir = dir; rec_file = filename; if (strcasecmp(filename_parent, ".") || strcasecmp(filename_base, filename)) { JANUS_LOG(LOG_WARN, "Unsupported combination of dir and filename %s %s\n", dir, filename); } } } if(rec_dir != NULL) { /* Check if this directory exists, and create it if needed */ struct stat s; int err = stat(rec_dir, &s); if(err == -1) { if(ENOENT == errno) { /* Directory does not exist, try creating it */ if(janus_mkdir(rec_dir, 0755) < 0) { JANUS_LOG(LOG_ERR, "mkdir error: %d\n", errno); return NULL; } } else { JANUS_LOG(LOG_ERR, "stat error: %d\n", errno); return NULL; } } else { if(S_ISDIR(s.st_mode)) { /* Directory exists */ JANUS_LOG(LOG_VERB, "Directory exists: %s\n", rec_dir); } else { /* File exists but it's not a directory? */ JANUS_LOG(LOG_ERR, "Not a directory? %s\n", rec_dir); return NULL; } } } char newname[1024]; memset(newname, 0, 1024); if(rec_file == NULL) { /* Choose a random username */ if(!rec_tempname) { /* Use .mjr as an extension right away */ g_snprintf(newname, 1024, "janus-recording-%"SCNu32".mjr", janus_random_uint32()); } else { /* Append the temporary extension to .mjr, we'll rename when closing */ g_snprintf(newname, 1024, "janus-recording-%"SCNu32".mjr.%s", janus_random_uint32(), rec_tempext); } } else { /* Just append the extension */ if(!rec_tempname) { /* Use .mjr as an extension right away */ g_snprintf(newname, 1024, "%s.mjr", rec_file); } else { /* Append the temporary extension to .mjr, we'll rename when closing */ g_snprintf(newname, 1024, "%s.mjr.%s", rec_file, rec_tempext); } } /* Try opening the file now */ if(rec_dir == NULL) { rc->file = fopen(newname, "wb"); } else { char path[1024]; memset(path, 0, 1024); g_snprintf(path, 1024, "%s/%s", rec_dir, newname); rc->file = fopen(path, "wb"); } if(rc->file == NULL) { JANUS_LOG(LOG_ERR, "fopen error: %d\n", errno); return NULL; } if(rec_dir) rc->dir = g_strdup(rec_dir); rc->filename = g_strdup(newname); rc->type = type; /* Write the first part of the header */ fwrite(header, sizeof(char), strlen(header), rc->file); g_atomic_int_set(&rc->writable, 1); /* We still need to also write the info header first */ g_atomic_int_set(&rc->header, 0); janus_mutex_init(&rc->mutex); /* Done */ g_atomic_int_set(&rc->destroyed, 0); janus_refcount_init(&rc->ref, janus_recorder_free); g_free(copy_for_parent); g_free(copy_for_base); return rc; }