/* 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;
}