/* Plugin implementation */ int janus_streaming_init(janus_callbacks *callback, const char *config_path) { if(stopping) { /* Still stopping from before */ return -1; } if(callback == NULL || config_path == NULL) { /* Invalid arguments */ return -1; } /* Read configuration */ char filename[255]; sprintf(filename, "%s/%s.cfg", config_path, JANUS_STREAMING_PACKAGE); JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename); janus_config *config = janus_config_parse(filename); if(config != NULL) janus_config_print(config); mountpoints = g_hash_table_new(NULL, NULL); /* Parse configuration to populate the mountpoints */ if(config != NULL) { janus_config_category *cat = janus_config_get_categories(config); while(cat != NULL) { if(cat->name == NULL) { cat = cat->next; continue; } JANUS_LOG(LOG_VERB, "Adding stream '%s'\n", cat->name); janus_config_item *type = janus_config_get_item(cat, "type"); if(type == NULL || type->value == NULL) { JANUS_LOG(LOG_VERB, " -- Invalid type, skipping stream...\n"); cat = cat->next; continue; } if(!strcasecmp(type->value, "rtp")) { /* RTP live source (e.g., from gstreamer/ffmpeg/vlc/etc.) */ janus_config_item *id = janus_config_get_item(cat, "id"); janus_config_item *desc = janus_config_get_item(cat, "description"); janus_config_item *audio = janus_config_get_item(cat, "audio"); janus_config_item *video = janus_config_get_item(cat, "video"); janus_config_item *aport = janus_config_get_item(cat, "audioport"); janus_config_item *acodec = janus_config_get_item(cat, "audiopt"); janus_config_item *artpmap = janus_config_get_item(cat, "audiortpmap"); janus_config_item *vport = janus_config_get_item(cat, "videoport"); janus_config_item *vcodec = janus_config_get_item(cat, "videopt"); janus_config_item *vrtpmap = janus_config_get_item(cat, "videortpmap"); janus_streaming_mountpoint *live_rtp = calloc(1, sizeof(janus_streaming_mountpoint)); if(live_rtp == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); continue; } if(id == NULL || id->value == NULL) { JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, missing mandatory information...\n"); cat = cat->next; continue; } gboolean doaudio = audio && audio->value && !strcasecmp(audio->value, "yes"); gboolean dovideo = video && video->value && !strcasecmp(video->value, "yes"); if(!doaudio && !dovideo) { JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, no audio or video have to be streamed...\n"); g_free(live_rtp); cat = cat->next; continue; } if(doaudio && (aport == NULL || aport->value == NULL || acodec == NULL || acodec->value == NULL || artpmap == NULL || artpmap->value == NULL)) { JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, missing mandatory information for audio...\n"); cat = cat->next; continue; } if(dovideo && (vport == NULL || vport->value == NULL || vcodec == NULL || vcodec->value == NULL || vrtpmap == NULL || vrtpmap->value == NULL)) { JANUS_LOG(LOG_ERR, "Can't add 'rtp' stream, missing mandatory information for video...\n"); cat = cat->next; continue; } JANUS_LOG(LOG_VERB, "Audio %s, Video %s\n", doaudio ? "enabled" : "NOT enabled", dovideo ? "enabled" : "NOT enabled"); live_rtp->name = g_strdup(cat->name); live_rtp->id = atoi(id->value); char *description = NULL; if(desc != NULL && desc->value != NULL) description = g_strdup(desc->value); else description = g_strdup(cat->name); live_rtp->description = description; live_rtp->active = FALSE; live_rtp->streaming_type = janus_streaming_type_live; live_rtp->streaming_source = janus_streaming_source_rtp; janus_streaming_rtp_source *live_rtp_source = calloc(1, sizeof(janus_streaming_rtp_source)); if(live_rtp->name == NULL || description == NULL || live_rtp_source == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); if(live_rtp->name) g_free(live_rtp->name); if(description) g_free(description); if(live_rtp_source); g_free(live_rtp_source); g_free(live_rtp); continue; } live_rtp_source->audio_port = doaudio ? atoi(aport->value) : -1; live_rtp_source->video_port = dovideo ? atoi(vport->value) : -1; live_rtp->source = live_rtp_source; live_rtp->codecs.audio_pt = doaudio ? atoi(acodec->value) : -1; live_rtp->codecs.audio_rtpmap = doaudio ? g_strdup(artpmap->value) : NULL; live_rtp->codecs.video_pt = dovideo ? atoi(vcodec->value) : -1; live_rtp->codecs.video_rtpmap = dovideo ? g_strdup(vrtpmap->value) : NULL; live_rtp->listeners = NULL; g_hash_table_insert(mountpoints, GINT_TO_POINTER(live_rtp->id), live_rtp); g_thread_new(live_rtp->name, &janus_streaming_relay_thread, live_rtp); } else if(!strcasecmp(type->value, "live")) { /* a-Law file live source */ janus_config_item *id = janus_config_get_item(cat, "id"); janus_config_item *desc = janus_config_get_item(cat, "description"); janus_config_item *file = janus_config_get_item(cat, "filename"); janus_config_item *audio = janus_config_get_item(cat, "audio"); janus_config_item *video = janus_config_get_item(cat, "video"); if(id == NULL || id->value == NULL || file == NULL || file->value == NULL) { JANUS_LOG(LOG_ERR, "Can't add 'live' stream, missing mandatory information...\n"); cat = cat->next; continue; } gboolean doaudio = audio && audio->value && !strcasecmp(audio->value, "yes"); gboolean dovideo = video && video->value && !strcasecmp(video->value, "yes"); /* TODO We should support something more than raw a-Law and mu-Law streams... */ if(!doaudio || dovideo) { JANUS_LOG(LOG_ERR, "Can't add 'live' stream, we only support audio file streaming right now...\n"); cat = cat->next; continue; } if(!strstr(file->value, ".alaw") && !strstr(file->value, ".mulaw")) { JANUS_LOG(LOG_ERR, "Can't add 'ondemand' stream, unsupported format (we only support raw mu-Law and a-Law files right now)\n"); cat = cat->next; continue; } janus_streaming_mountpoint *live_file = calloc(1, sizeof(janus_streaming_mountpoint)); if(live_file == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); continue; } live_file->name = g_strdup(cat->name); live_file->id = atoi(id->value); char *description = NULL; if(desc != NULL && desc->value != NULL) description = g_strdup(desc->value); else description = g_strdup(cat->name); live_file->description = description; live_file->active = FALSE; live_file->streaming_type = janus_streaming_type_live; live_file->streaming_source = janus_streaming_source_file; janus_streaming_file_source *live_file_source = calloc(1, sizeof(janus_streaming_file_source)); if(live_file->name == NULL || description == NULL || live_file_source == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); if(live_file->name) g_free(live_file->name); if(description) g_free(description); if(live_file_source); g_free(live_file_source); g_free(live_file); continue; } live_file_source->filename = g_strdup(file->value); live_file->source = live_file_source; live_file->codecs.audio_pt = strstr(file->value, ".alaw") ? 8 : 0; live_file->codecs.audio_rtpmap = strstr(file->value, ".alaw") ? "PCMA/8000" : "PCMU/8000"; live_file->codecs.video_pt = -1; /* FIXME We don't support video for this type yet */ live_file->codecs.video_rtpmap = NULL; live_file->listeners = NULL; g_hash_table_insert(mountpoints, GINT_TO_POINTER(live_file->id), live_file); g_thread_new(live_file->name, &janus_streaming_filesource_thread, live_file); } else if(!strcasecmp(type->value, "ondemand")) { /* mu-Law file on demand source */ janus_config_item *id = janus_config_get_item(cat, "id"); janus_config_item *desc = janus_config_get_item(cat, "description"); janus_config_item *file = janus_config_get_item(cat, "filename"); janus_config_item *audio = janus_config_get_item(cat, "audio"); janus_config_item *video = janus_config_get_item(cat, "video"); if(id == NULL || id->value == NULL || file == NULL || file->value == NULL) { JANUS_LOG(LOG_ERR, "Can't add 'ondemand' stream, missing mandatory information...\n"); cat = cat->next; continue; } gboolean doaudio = audio && audio->value && !strcasecmp(audio->value, "yes"); gboolean dovideo = video && video->value && !strcasecmp(video->value, "yes"); /* TODO We should support something more than raw a-Law and mu-Law streams... */ if(!doaudio || dovideo) { JANUS_LOG(LOG_ERR, "Can't add 'ondemand' stream, we only support audio file streaming right now...\n"); cat = cat->next; continue; } if(!strstr(file->value, ".alaw") && !strstr(file->value, ".mulaw")) { JANUS_LOG(LOG_ERR, "Can't add 'ondemand' stream, unsupported format (we only support raw mu-Law and a-Law files right now)\n"); cat = cat->next; continue; } janus_streaming_mountpoint *ondemand_file = calloc(1, sizeof(janus_streaming_mountpoint)); if(ondemand_file == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); continue; } ondemand_file->name = g_strdup(cat->name); ondemand_file->id = atoi(id->value); char *description = NULL; if(desc != NULL && desc->value != NULL) description = g_strdup(desc->value); else description = g_strdup(cat->name); ondemand_file->description = description; ondemand_file->active = FALSE; ondemand_file->streaming_type = janus_streaming_type_on_demand; ondemand_file->streaming_source = janus_streaming_source_file; janus_streaming_file_source *ondemand_file_source = calloc(1, sizeof(janus_streaming_file_source)); if(ondemand_file->name == NULL || description == NULL || ondemand_file_source == NULL) { JANUS_LOG(LOG_FATAL, "Memory error!\n"); if(ondemand_file->name) g_free(ondemand_file->name); if(description) g_free(description); if(ondemand_file_source); g_free(ondemand_file_source); g_free(ondemand_file); continue; } ondemand_file_source->filename = g_strdup(file->value); ondemand_file->source = ondemand_file_source; ondemand_file->codecs.audio_pt = strstr(file->value, ".alaw") ? 8 : 0; ondemand_file->codecs.audio_rtpmap = strstr(file->value, ".alaw") ? "PCMA/8000" : "PCMU/8000"; ondemand_file->codecs.video_pt = -1; /* FIXME We don't support video for this type yet */ ondemand_file->codecs.video_rtpmap = NULL; ondemand_file->listeners = NULL; g_hash_table_insert(mountpoints, GINT_TO_POINTER(ondemand_file->id), ondemand_file); } cat = cat->next; } /* Done */ janus_config_destroy(config); config = NULL; } /* Show available mountpoints */ GList *mountpoints_list = g_hash_table_get_values(mountpoints); GList *m = mountpoints_list; while(m) { janus_streaming_mountpoint *mp = (janus_streaming_mountpoint *)m->data; JANUS_LOG(LOG_VERB, " ::: [%"SCNu64"][%s] %s (%s, %s)\n", mp->id, mp->name, mp->description, mp->streaming_type == janus_streaming_type_live ? "live" : "on demand", mp->streaming_source == janus_streaming_source_rtp ? "RTP source" : "file source"); m = m->next; } g_list_free(mountpoints_list); sessions = g_hash_table_new(NULL, NULL); janus_mutex_init(&sessions_mutex); messages = g_queue_new(); /* This is the callback we'll need to invoke to contact the gateway */ gateway = callback; initialized = 1; /* Launch the thread that will handle incoming messages */ GError *error = NULL; handler_thread = g_thread_try_new("janus streaming handler", janus_streaming_handler, NULL, &error); if(error != NULL) { initialized = 0; /* Something went wrong... */ JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch thread...\n", error->code, error->message ? error->message : "??"); return -1; } JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_STREAMING_NAME); return 0; }
/* Plugin implementation */ int janus_source_init(janus_callbacks *callback, const char *config_path) { if (g_atomic_int_get(&stopping)) { /* Still stopping from before */ return -1; } if (callback == NULL || config_path == NULL) { /* Invalid arguments */ return -1; } /* Read configuration */ char filename[255]; g_snprintf(filename, 255, "%s/%s.cfg", config_path, JANUS_SOURCE_PACKAGE); JANUS_LOG(LOG_VERB, "Configuration file: %s\n", filename); janus_config *config = janus_config_parse(filename); if (config != NULL) janus_config_print(config); /* Parse configuration */ if (config != NULL) { GList *cl = janus_config_get_categories(config); while (cl != NULL) { janus_config_category *cat = (janus_config_category *)cl->data; if (cat->name == NULL) { cl = cl->next; continue; } JANUS_LOG(LOG_VERB, "Parsing category '%s'\n", cat->name); janus_source_parse_ports_range(janus_config_get_item(cat, "udp_port_range"), &udp_min_port, &udp_max_port); janus_source_parse_keepalive_interval(janus_config_get_item(cat, "keepalive_interval"), &keepalive_interval); janus_source_parse_status_service_url(janus_config_get_item(cat, "keepalive_service_url"), &keepalive_service_url); janus_source_parse_status_service_url(janus_config_get_item(cat,"status_service_url"),&status_service_url); janus_source_parse_video_codec_priority(janus_config_get_item(cat, "video_codec_priority")); janus_source_parse_rtsp_interface_ip(janus_config_get_item(cat, "interface"),&rtsp_interface_ip); cl = cl->next; } janus_config_destroy(config); config = NULL; } if (udp_min_port <= 0 || udp_max_port <= 0) { udp_min_port = 4000; udp_max_port = 5000; JANUS_LOG(LOG_WARN, "Using default port range: %d-%d\n", udp_min_port, udp_max_port); } sessions = g_hash_table_new(NULL, NULL); janus_mutex_init(&sessions_mutex); messages = g_async_queue_new_full((GDestroyNotify)janus_source_message_free); /* This is the callback we'll need to invoke to contact the gateway */ gateway = callback; g_atomic_int_set(&initialized, 1); GError *error = NULL; /* Start the sessions watchdog */ watchdog = g_thread_try_new("source watchdog", &janus_source_watchdog, NULL, &error); if (error != NULL) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the SourcePlugin watchdog thread...\n", error->code, error->message ? error->message : "??"); return -1; } gst_init(NULL, NULL); gst_debug_set_threshold_from_string(gst_debug_str, FALSE); curl_handle = curl_init(); socket_utils_init(udp_min_port, udp_max_port); /* Launch the thread that will handle incoming messages */ handler_thread = g_thread_try_new("janus source handler", janus_source_handler, NULL, &error); if (error != NULL) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Source handler thread...\n", error->code, error->message ? error->message : "??"); return -1; } /* Launch the thread that will handle rtsp clients */ handler_rtsp_thread = g_thread_try_new("rtsp server", janus_source_rtsp_server_thread, NULL, &error); if (error != NULL) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the Source rtsp server thread...\n", error->code, error->message ? error->message : "??"); return -1; } /* Set PID */ memset(&PID, 0, JANUS_PID_SIZE); if (0 > janus_set_pid()) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_ERR, "Got an error while plugin id initialize."); return -1; } /*Start the keepalive thread */ keepalive = g_thread_try_new("source keepalive", &janus_source_keepalive, NULL, &error); if (error != NULL) { g_atomic_int_set(&initialized, 0); JANUS_LOG(LOG_ERR, "Got error %d (%s) trying to launch the SourcePlugin keepalive thread...\n", error->code, error->message ? error->message : "??"); return -1; } JANUS_LOG(LOG_INFO, "%s initialized!\n", JANUS_SOURCE_NAME); return 0; }