Revision c81c126e

View differences:

Makefile
14 14
MONGOOSE_OPTS+=-DMG_DISABLE_MQTT -DMG_DISABLE_JSON_RPC -DMG_DISABLE_SOCKETPAIR  -DMG_DISABLE_CGI # -DMG_DISABLE_HTTP_WEBSOCKET
15 15
LDFLAGS+=-lpstreamer -lgrapes -lm
16 16

  
17
all: $(EXE)
17
all: $(EXE) Tools/janus
18 18

  
19 19
$(EXE): $(LIBS) $(OBJS) peerstreamer-ng.c
20 20
	$(CC) -o peerstreamer-ng  peerstreamer-ng.c $(OBJS) Libs/mongoose/mongoose.o $(CFLAGS) $(LDFLAGS)
......
41 41
	git submodule init Libs/janus-gateway/
42 42
	git submodule update Libs/janus-gateway/
43 43
	cd $(PWD)/Libs/janus-gateway/ && ./autogen.sh
44
	cd $(PWD)/Libs/janus-gateway/ && SRTP15X_CFLAGS="-I$(PWD)/Libs/janus-gateway/Libs/libsrtp/include" SRTP15X_LIBS="-L$(PWD)/Libs/janus-gateway/Libs/libsrtp" PKG_CONFIG_PATH=$(PWD)/Libs/janus-gateway/Libs/libsrtp ./configure --disable-all-plugins --disable-all-transports --disable-all-handlers --enable-rest --disable-turn-rest-api --enable-static --prefix=$(PWD)/Tools/janus --enable-plugin-echotest  #--enable-libsrtp2
44
	cd $(PWD)/Libs/janus-gateway/ && SRTP15X_CFLAGS="-I$(PWD)/Libs/janus-gateway/Libs/libsrtp/include" SRTP15X_LIBS="-L$(PWD)/Libs/janus-gateway/Libs/libsrtp" PKG_CONFIG_PATH=$(PWD)/Libs/janus-gateway/Libs/libsrtp ./configure --disable-all-plugins --disable-all-transports --disable-all-handlers --enable-rest --disable-turn-rest-api --enable-static --prefix=$(PWD)/Tools/janus --enable-plugin-streaming #--enable-libsrtp2
45 45
	make -C Libs/janus-gateway/ install
46 46

  
47 47
tests:
Test/Makefile
9 9
CFLAGS += -g -W -Wall -Wno-unused-function -Wno-unused-parameter -O0 -I../Libs/mongoose/  -I../src -I../Libs/pstreamer/include -I../Libs/GRAPES/include
10 10
CFLAGS+=-L../Libs/GRAPES/src  -L../Libs/pstreamer/src 
11 11

  
12
all: $(LIBS) $(TARGET_SRC) $(TARGET_OBJS) $(OBJS)
12
all: $(LIBS) $(TARGET_SRC) $(TARGET_OBJS) $(OBJS) ../Tools/janus
13

  
14
../Tools/janus:
15
	make -C ../ Tools/janus
13 16

  
14 17
Libs/mongoose/mongoose.o:
15 18
	git submodule init Libs/mongoose/
Test/janus_instance_test.c
1
/*
2
 *
3
 *  copyright (c) 2017 luca baldesi
4
 *
5
 */
6

  
7
#include<assert.h>
8
#include<janus_instance.h>
9
#include<mongoose.h>
10
#include<task_manager.h>
11
#include<unistd.h>
12
#include<libgen.h>
13

  
14
char janus_conf[6969];
15

  
16
void janus_instance_create_test()
17
{
18
	struct janus_instance * janus;
19
	struct task_manager * tm = NULL;
20
	struct mg_mgr * srv = NULL;
21

  
22
	janus = janus_instance_create(srv, tm, NULL);
23
	assert(janus == NULL);
24
	janus_instance_destroy(&janus);
25

  
26
	tm = task_manager_new();
27
	srv = (struct mg_mgr*) malloc(sizeof(struct mg_mgr));
28
	mg_mgr_init(srv, NULL);
29
	janus = janus_instance_create(srv, tm, NULL);
30
	assert(janus != NULL);
31

  
32
	janus_instance_destroy(&janus);
33
	task_manager_destroy(&tm);
34
	mg_mgr_free(srv);
35
	free(srv);
36

  
37
	fprintf(stderr,"%s successfully passed!\n",__func__);
38
}
39

  
40
void janus_instance_launch_test()
41
{
42
	struct janus_instance * janus = NULL;
43
	struct task_manager * tm = NULL;
44
	struct mg_mgr * srv = NULL;
45
	int8_t res;
46

  
47
	// invalid input
48
	res = janus_instance_launch(janus);
49
	assert(res);
50

  
51
	// wrong file
52
	tm = task_manager_new();
53
	srv = (struct mg_mgr*) malloc(sizeof(struct mg_mgr));
54
	mg_mgr_init(srv, NULL);
55
	janus = janus_instance_create(srv, tm, "janus_executable=/tmp/97897243xxx");
56
	assert(janus != NULL);
57
	res = janus_instance_launch(janus);
58
	assert(res);
59
	janus_instance_destroy(&janus);
60

  
61
	// common case
62
	janus = janus_instance_create(srv, tm, janus_conf);
63
	assert(janus != NULL);
64
	res = janus_instance_launch(janus);
65
	assert(res == 0);
66

  
67
	sleep(1);
68
	janus_instance_destroy(&janus);
69
	task_manager_destroy(&tm);
70
	mg_mgr_free(srv);
71
	free(srv);
72

  
73
	fprintf(stderr,"%s successfully passed!\n",__func__);
74
}
75

  
76
void janus_instance_create_streaming_point_test()
77
{
78
	struct janus_instance * janus = NULL;
79
	struct task_manager * tm = NULL;
80
	struct mg_mgr * srv = NULL;
81
	int8_t res;
82

  
83
	// invalid input
84
	res = janus_instance_launch(janus);
85
	assert(res);
86

  
87
	// wrong file
88
	tm = task_manager_new();
89
	srv = (struct mg_mgr*) malloc(sizeof(struct mg_mgr));
90
	mg_mgr_init(srv, NULL);
91
	janus = janus_instance_create(srv, tm, janus_conf);
92
	res = janus_instance_launch(janus);
93
	assert(res == 0);
94
	sleep(1);
95

  
96
	res = janus_instance_create_streaming_point(NULL, NULL, 0, 0, NULL);
97
	assert(res);
98
	//res = janus_instance_create_streaming_point(janus, &mountpoint, 6000, 6002, NULL);
99
	// HARD to test without running mongoose..
100
	//assert(res == 0);
101
	//sleep(1);
102
	//assert(mountpoint);
103

  
104
	janus_instance_destroy(&janus);
105
	task_manager_destroy(&tm);
106
	mg_mgr_free(srv);
107
	free(srv);
108
	fprintf(stderr,"%s successfully passed!\n",__func__);
109
}
110

  
111
int main(int argv, char ** argc)
112
{
113
	sprintf(janus_conf, "janus_executable=%s/../Tools/janus/bin/janus", dirname(argc[0]));
114

  
115
	janus_instance_create_test();
116
	janus_instance_launch_test();
117
	janus_instance_create_streaming_point_test();
118
	return 0;
119
}
Test/pstreamer_manager_test.c
19 19
	pstreamer_manager_destroy(NULL);
20 20
	pstreamer_manager_destroy(&psm);
21 21

  
22
	psm = pstreamer_manager_new(6000);
22
	psm = pstreamer_manager_new(6000, NULL);
23 23

  
24 24
	pstreamer_manager_destroy(&psm);
25 25

  
......
31 31
	struct pstreamer_manager * psm = NULL;
32 32
	const struct pstreamer * ps = NULL;
33 33

  
34
	ps = pstreamer_manager_create_streamer(NULL, NULL, NULL, NULL, NULL);
34
	ps = pstreamer_manager_create_streamer(NULL, NULL, NULL, NULL, NULL, NULL);
35 35
	assert(ps == NULL);
36 36

  
37
	psm = pstreamer_manager_new(6000);
37
	psm = pstreamer_manager_new(6000, NULL);
38 38

  
39
	ps = pstreamer_manager_create_streamer(psm, NULL, NULL, NULL, NULL);
39
	ps = pstreamer_manager_create_streamer(psm, NULL, NULL, NULL, NULL, NULL);
40 40
	assert(ps == NULL);
41 41

  
42
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1");
42
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1", NULL);
43 43
	assert(ps);
44 44

  
45
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "24", "127.0.0.1");
45
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "24", "127.0.0.1", NULL);
46 46
	assert(ps);
47 47

  
48
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1");
48
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1", NULL);
49 49
	assert(ps == NULL);
50 50

  
51 51
	pstreamer_manager_destroy(&psm);
......
62 62
	json = pstreamer_to_json(NULL);
63 63
	assert(json == NULL);
64 64

  
65
	psm = pstreamer_manager_new(6000);
66
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1");
65
	psm = pstreamer_manager_new(6000, NULL);
66
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1", NULL);
67 67

  
68 68
	json = pstreamer_to_json(ps);
69
	assert(strcmp(json, "{\"id\":\"42\",\"source_ip\":\"10.0.0.1\",\"source_port\":\"6000\"}") == 0);
69
	fprintf(stderr, "[DEBUG] %s\n", json);
70
	assert(strcmp(json, "{\"id\":\"42\",\"source_ip\":\"10.0.0.1\",\"source_port\":\"6000\",\"janus_streaming_id\":\"0\"}") == 0);
70 71
	free(json);
71 72

  
72 73
	pstreamer_manager_destroy(&psm);
......
82 83
	res = pstreamer_manager_destroy_streamer(NULL, NULL);
83 84
	assert(res);
84 85

  
85
	psm = pstreamer_manager_new(6000);
86
	psm = pstreamer_manager_new(6000, NULL);
86 87
	res = pstreamer_manager_destroy_streamer(psm, NULL);
87 88
	assert(res);
88 89

  
89
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1");
90
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "24", "127.0.0.1");
90
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1", NULL);
91
	ps = pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "24", "127.0.0.1", NULL);
91 92

  
92 93
	res = pstreamer_manager_destroy_streamer(psm, ps);
93 94
	assert(res == 0);
......
105 106
	res = pstreamer_manager_set_streamer_options(psm, NULL);
106 107
	assert(res == -1);
107 108

  
108
	psm = pstreamer_manager_new(6000);
109
	psm = pstreamer_manager_new(6000, NULL);
109 110

  
110 111
	res = pstreamer_manager_set_streamer_options(psm, NULL);
111 112
	assert(res == -1);
......
113 114
	res = pstreamer_manager_set_streamer_options(psm, "iface=lo");
114 115
	assert(res == 0);
115 116

  
116
	pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1");
117
	pstreamer_manager_create_streamer(psm, "10.0.0.1", "6000", "42", "127.0.0.1", NULL);
117 118
	pstreamer_manager_destroy(&psm);
118 119
	fprintf(stderr,"%s successfully passed!\n",__func__);
119 120
}
Tools/janus_conf/janus.plugin.streaming.cfg
1
; [stream-name]
2
; type = rtp|live|ondemand|rtsp
3
;        rtp = stream originated by an external tool (e.g., gstreamer or
4
;              ffmpeg) and sent to the plugin via RTP
5
;        live = local file streamed live to multiple listeners
6
;               (multiple listeners = same streaming context)
7
;        ondemand = local file streamed on-demand to a single listener
8
;                   (multiple listeners = different streaming contexts)
9
;        rtsp = stream originated by an external RTSP feed (only
10
;               available if libcurl support was compiled)
11
; id = <unique numeric ID> (if missing, a random one will be generated)
12
; description = This is my awesome stream
13
; is_private = yes|no (private streams don't appear when you do a 'list'
14
;			request)
15
; secret = <optional password needed for manipulating (e.g., destroying
16
;			or enabling/disabling) the stream>
17
; pin = <optional password needed for watching the stream>
18
; filename = path to the local file to stream (only for live/ondemand)
19
; audio = yes|no (do/don't stream audio)
20
; video = yes|no (do/don't stream video)
21
;    The following options are only valid for the 'rtp' type:
22
; data = yes|no (do/don't stream text via datachannels)
23
; audioport = local port for receiving audio frames
24
; audiomcast = multicast group port for receiving audio frames, if any
25
; audioiface = network interface or IP address to bind to, if any (binds to all otherwise)
26
; audiopt = <audio RTP payload type> (e.g., 111)
27
; audiortpmap = RTP map of the audio codec (e.g., opus/48000/2)
28
; videoport = local port for receiving video frames
29
; videomcast = multicast group port for receiving video frames, if any
30
; videoiface = network interface or IP address to bind to, if any (binds to all otherwise)
31
; videopt = <video RTP payload type> (e.g., 100)
32
; videortpmap = RTP map of the video codec (e.g., VP8/90000)
33
; videobufferkf = yes|no (whether the plugin should store the latest
34
;		keyframe and send it immediately for new viewers, EXPERIMENTAL)
35
; videosimulcast = yes|no (do|don't enable video simulcasting)
36
; videoport2 = second local port for receiving video frames (only for rtp, and simulcasting)
37
; videoport3 = third local port for receiving video frames (only for rtp, and simulcasting)
38
; dataport = local port for receiving data messages to relay
39
; dataiface = network interface or IP address to bind to, if any (binds to all otherwise)
40
; databuffermsg = yes|no (whether the plugin should store the latest
41
;		message and send it immediately for new viewers)
42
;
43
; The following options are only valid for the 'rstp' type:
44
; url = RTSP stream URL (only for restreaming RTSP)
45
; rtsp_user = RTSP authorization username (only if type=rtsp)
46
; rtsp_pwd = RTSP authorization password (only if type=rtsp)
47
; rtspiface = network interface or IP address to bind to, if any (binds to all otherwise), when receiving RTSP streams
48
;
49
; Notice that, for 'rtsp' mountpoints, normally the plugin uses the exact
50
; SDP rtpmap and fmtp attributes the remote camera or RTSP server sent.
51
; In case the values set remotely are known to conflict with WebRTC viewers,
52
; you can override both using the settings introduced above.
53
;
54
; To test the [gstreamer-sample] example, check the test_gstreamer.sh
55
; script in the plugins/streams folder. To test the live and on-demand
56
; audio file streams, instead, the install.sh installation script
57
; automatically downloads a couple of files (radio.alaw, music.mulaw)
58
; to the plugins/streams folder. 
59

  
60
[general]
61
;admin_key = supersecret		; If set, mountpoints can be created via API
62
								; only if this key is provided in the request
63
;events = no					; Whether events should be sent to event
64
								; handlers (default is yes)
65

  
66
;[gstreamer-sample]
67
;type = rtp
68
;id = 1
69
;description = Opus/VP8 live stream coming from gstreamer
70
;audio = yes
71
;video = yes
72
;audioport = 5002
73
;audiopt = 111
74
;audiortpmap = opus/48000/2
75
;videoport = 5004
76
;videopt = 100
77
;videortpmap = VP8/90000
78
;secret = adminpwd
79
;
80
;[file-live-sample]
81
;type = live
82
;id = 2
83
;description = a-law file source (radio broadcast)
84
;filename = /home/baldo/src/peerstreamer-src/Tools/janus1/share/janus/streams/radio.alaw		; See install.sh
85
;audio = yes
86
;video = no
87
;secret = adminpwd
88
;
89
;[file-ondemand-sample]
90
;type = ondemand
91
;id = 3
92
;description = mu-law file source (music)
93
;filename = /home/baldo/src/peerstreamer-src/Tools/janus1/share/janus/streams/music.mulaw	; See install.sh
94
;audio = yes
95
;video = no
96
;secret = adminpwd
97

  
98
;
99
; Firefox Nightly supports H.264 through Cisco's OpenH264 plugin. The only
100
; supported profile is the baseline one. This is an example of how to create
101
; a H.264 mountpoint: you can feed it an x264enc+rtph264pay pipeline in
102
; gstreamer.
103
;
104
;[h264-sample]
105
;type = rtp
106
;id = 10
107
;description = H.264 live stream coming from gstreamer
108
;audio = no
109
;video = yes
110
;videoport = 8004
111
;videopt = 126
112
;videortpmap = H264/90000
113
;videofmtp = profile-level-id=42e01f\;packetization-mode=1
114

  
115
;
116
; This is a sample configuration for Opus/VP8 multicast streams
117
;
118
;[gstreamer-multicast]
119
;type = rtp
120
;id = 20
121
;description = Opus/VP8 live multicast stream coming from gstreamer 
122
;audio = yes
123
;video = yes
124
;audioport = 5002
125
;audiomcast = 232.3.4.5
126
;audiopt = 111
127
;audiortpmap = opus/48000/2
128
;videoport = 5004
129
;videomcast = 232.3.4.5
130
;videopt = 100
131
;videortpmap = VP8/90000
132

  
133
;
134
; This is a sample configuration for an RTSP stream: you can specify
135
; the url to connect to and whether or not authentication is needed
136
; using the url/rtsp_user/rtsp_pwd settings (but notice that digest
137
; authentication will only work if you installed libcurl >= 7.45.0)
138
; NOTE WELL: the plugin does NOT transcode, so the RTSP stream MUST be
139
; in a format the browser can digest (e.g., VP8 or H.264 baseline for video)
140
; Again, you can override rtpmap and/or fmtp, if needed
141
;
142
;[rtsp-test]
143
;type = rtsp
144
;id = 99
145
;description = RTSP Test
146
;audio = no
147
;video = yes
148
;url=rtsp://127.0.0.1:8554/unicast
149
;rtsp_user=username
150
;rtsp_pwd=password
peerstreamer-ng.c
123 123
	c->router = router_create(10);
124 124
	load_path_handlers(c->router);
125 125
	c->tm = task_manager_new();
126
	c->psm = pstreamer_manager_new(6001);
127 126

  
128 127
	c->mongoose_srv = (struct mg_mgr*) malloc(sizeof(struct mg_mgr));
129 128
	mg_mgr_init(c->mongoose_srv, c);
130 129

  
130
	c->janus = janus_instance_create(c->mongoose_srv, c->tm, NULL);
131
	janus_instance_launch(c->janus);
132
	c->psm = pstreamer_manager_new(6001, c->janus);
133

  
131 134
	parse_args(c, argc, argv);
132 135
	pstreamer_manager_set_streamer_options(c->psm, c->streamer_opts);
133 136
	c->pb = pschannel_bucket_new(c->csvfile);
......
158 161
		free(c->streamer_opts);
159 162
	router_destroy(&(c->router));
160 163
	pstreamer_manager_destroy(&(c->psm));  // this must be destroyed before task managers!
164
	sleep(1); //  let janus get the http notications for interrupting streaming sessions
165
	janus_instance_destroy(&(c->janus));  // this has to be destroyed after pstreamer_manager and before task_manager
161 166
	task_manager_destroy(&(c->tm));
162 167
	pschannel_bucket_destroy(&(c->pb));
163 168
	mg_mgr_free(c->mongoose_srv);
src/context.h
15 15
	struct mg_mgr * mongoose_srv;
16 16
	struct pschannel_bucket * pb;
17 17
	struct pstreamer_manager * psm;
18
	struct janus_instance * janus;
18 19
	char * csvfile;
19 20
	char * streamer_opts;
20 21
};
src/janus_instance.c
1
/*******************************************************************
2
* PeerStreamer-ng is a P2P video streaming application exposing a ReST
3
* interface.
4
* Copyright (C) 2017 Luca Baldesi <luca.baldesi@unitn.it>
5
*
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Affero General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
* GNU Affero General Public License for more details.
15
*
16
* You should have received a copy of the GNU Affero General Public License
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*******************************************************************/
19

  
20
#include<janus_instance.h>
21
#include<signal.h>
22
#include<string.h>
23
#include<debug.h>
24
#include<unistd.h>
25
#include<tokens.h>
26
#include<grapes_config.h>
27

  
28
#define INVALID_PID -1
29

  
30
#define JANUS_MSG_SESSION_CREATE "{\"transaction\": \"random\", \"janus\": \"create\"}"
31
#define JANUS_MSG_SESSION_KEEPALIVE "{\"transaction\": \"ciao\", \"janus\": \"keepalive\"}"
32
#define JANUS_MSG_PLUGIN_CREATE "{\"transaction\": \"ciao\", \"janus\": \"attach\", \"plugin\":\"janus.plugin.streaming\"}"
33

  
34

  
35
struct janus_instance {
36
	pid_t janus_pid;
37
	char* endpoint;
38
	char * executable;
39
	char * conf_param;
40
	char * logfile;
41
	struct mg_mgr *mongoose_srv;
42
	struct periodic_task * heartbeat;
43
	uint64_t management_session;
44
	uint64_t plugin_handle;
45
	struct task_manager * tm;
46
};
47

  
48
uint64_t janus_instance_msg_get_id(char *msg)
49
{
50
	char ** records;
51
	uint32_t ntoks, i;
52
	uint64_t res = 0;
53
	
54
	records = tokens_create(msg, ' ', &ntoks);
55
	if ((i = tokens_check(records, ntoks, "\"id\":")) > 0)
56
	{
57
		if (records[i+1][strlen(records[i+1])-1] == ',')
58
			records[i+1][strlen(records[i+1])-1] = '\0';
59
		sscanf(records[i+1], "%"PRId64"", &res);
60
		debug("ID string: %s\t ID integer: %"PRId64"\n", records[i+1], res);
61
	}
62
	tokens_destroy(&records, ntoks);
63
	return res;
64
}
65

  
66
char * janus_instance_handle_path(const struct janus_instance * janus)
67
{
68
	char * res = NULL;
69
	if (janus && janus->management_session && janus->plugin_handle && janus->endpoint)
70
	{
71
		res = malloc(sizeof(char) * (strlen(janus->endpoint) + 43));  // each identifier comprises of 20 characters at most
72
		sprintf(res, "%s/%"PRId64"/%"PRId64"", janus->endpoint, janus->management_session, janus->plugin_handle);
73
	}
74
	return res;
75
}
76

  
77
char * janus_instance_session_path(const struct janus_instance * janus)
78
{
79
	char * res = NULL;
80
	if (janus && janus->management_session && janus->endpoint)
81
	{
82
		res = malloc(sizeof(char) * (strlen(janus->endpoint) + 22));  // session identifier can be at most 20 characters long
83
		sprintf(res, "%s/%"PRId64"", janus->endpoint, janus->management_session);
84
	}
85
	return res;
86
}
87

  
88
struct janus_instance * janus_instance_create(struct mg_mgr *mongoose_srv, struct task_manager *tm, const char *config)
89
{
90
	struct janus_instance * ji = NULL;
91
	struct tag* tags;
92

  
93
	if (mongoose_srv && tm)
94
	{
95
		tags = grapes_config_parse(config);
96

  
97
		ji = malloc(sizeof(struct janus_instance));
98
		ji->endpoint = strdup(grapes_config_value_str_default(tags, "janus_endpoint", "127.0.0.1:8088/janus"));
99
		ji->executable = strdup(grapes_config_value_str_default(tags, "janus_executable", "Tools/janus/bin/janus"));
100
		ji->conf_param = strdup(grapes_config_value_str_default(tags, "janus_param", "--configs-folder=Tools/janus_conf"));
101
		ji->logfile = strdup(grapes_config_value_str_default(tags, "janus_logfile", "janus.log"));
102
		ji->janus_pid = INVALID_PID;
103
		ji->management_session = 0;
104
		ji->plugin_handle = 0;
105
		ji->tm = tm;
106
		ji->heartbeat = NULL;
107
		ji->mongoose_srv = mongoose_srv;
108

  
109
		if(tags)
110
			free(tags);
111
	}
112
	return ji;
113
}
114

  
115
void janus_instance_destroy(struct janus_instance ** ji)
116
{
117
	if (ji && (*ji))
118
	{
119
		if ((*ji)->janus_pid != INVALID_PID)
120
			kill((*ji)->janus_pid, SIGTERM);
121
			
122
		if ((*ji)->heartbeat)
123
			task_manager_destroy_task((*ji)->tm, &((*ji)->heartbeat));
124
		free((*ji)->endpoint);
125
		free((*ji)->executable);
126
		free((*ji)->conf_param);
127
		free((*ji)->logfile);
128
		free(*ji);
129
		*ji = NULL;
130
	}
131
}
132

  
133
void janus_instance_generic_handler(struct mg_connection *nc, int ev, void *ev_data)
134
{
135
	struct http_message *hm = (struct http_message *) ev_data;
136

  
137
	switch (ev) {
138
		case MG_EV_CONNECT:
139
			if (*(int *) ev_data != 0)
140
				debug("Janus communication failure\n");
141
			break;
142
		case MG_EV_HTTP_REPLY:
143
			switch (hm->resp_code) {
144
				case 200:
145
				default:
146
					debug("Janus answers: %d\n", hm->resp_code);
147
			}
148
			nc->flags |= MG_F_SEND_AND_CLOSE;
149
			break;
150
		case MG_EV_CLOSE:
151
			debug("Janus server closed connection\n");
152
			break;
153
		default:
154
			break;
155
	}
156
}
157

  
158
void janus_instance_plugin_handler(struct mg_connection *nc, int ev, void *ev_data)
159
{
160
	struct janus_instance * janus;
161
	struct http_message *hm = (struct http_message *) ev_data;
162
	char *buff;
163

  
164
	janus = nc->user_data;
165
	switch (ev) {
166
		case MG_EV_CONNECT:
167
			if (*(int *) ev_data != 0)
168
				debug("Janus communication failure\n");
169
			break;
170
		case MG_EV_HTTP_REPLY:
171
			switch (hm->resp_code) {
172
				case 200:
173
					buff = malloc(sizeof(char) * (hm->body.len + 1));
174
					strncpy(buff, hm->body.p, hm->body.len);
175
					buff[hm->body.len] = '\0';  // make sure string terminates
176
					janus->plugin_handle = janus_instance_msg_get_id(buff);
177
					free(buff);
178
					debug("Got plugin handle!\n");
179
				default:
180
					debug("Janus answers: %d\n", hm->resp_code);
181
			}
182
			nc->flags |= MG_F_SEND_AND_CLOSE;
183
			break;
184
		case MG_EV_CLOSE:
185
			debug("Janus server closed connection\n");
186
			break;
187
		default:
188
			break;
189
	}
190
}
191

  
192
void janus_instance_session_handler(struct mg_connection *nc, int ev, void *ev_data)
193
{
194
	struct janus_instance * janus;
195
	struct mg_connection * conn;
196
	struct http_message *hm = (struct http_message *) ev_data;
197
	char *buff;
198

  
199
	janus = nc->user_data;
200
	switch (ev) {
201
		case MG_EV_CONNECT:
202
			if (*(int *) ev_data != 0)
203
				debug("Janus communication failure\n");
204
			break;
205
		case MG_EV_HTTP_REPLY:
206
			switch (hm->resp_code) {
207
				case 200:
208
					buff = malloc(sizeof(char) * (hm->body.len + 1));
209
					strncpy(buff, hm->body.p, hm->body.len);
210
					buff[hm->body.len] = '\0';  // make sure string terminates
211
					janus->management_session = janus_instance_msg_get_id(buff);
212
					free(buff);
213
					buff = malloc(sizeof(char) * (strlen(janus->endpoint) + 22));
214
					sprintf(buff, "%s/%"PRId64"", janus->endpoint, janus->management_session);
215
					conn = mg_connect_http(janus->mongoose_srv, janus_instance_plugin_handler, buff, NULL, JANUS_MSG_PLUGIN_CREATE);
216
					free(buff);
217
					if (conn)
218
						conn->user_data = (void *) janus;
219
				default:
220
					debug("Janus answers: %d\n", hm->resp_code);
221
			}
222
			nc->flags |= MG_F_SEND_AND_CLOSE;
223
			break;
224
		case MG_EV_CLOSE:
225
			debug("Janus server closed connection\n");
226
			break;
227
		default:
228
			break;
229
	}
230
}
231

  
232
int8_t	janus_instance_create_management_handle(struct janus_instance *janus)
233
{
234
	struct mg_connection * conn;
235
	int8_t res = -1;
236

  
237
	if (janus)
238
	{
239
		conn = mg_connect_http(janus->mongoose_srv, janus_instance_session_handler, janus->endpoint, NULL, JANUS_MSG_SESSION_CREATE);
240
		if (conn)
241
		{
242
			conn->user_data = (void *) janus;
243
			res = 0;
244
		} 
245
	}
246
	return res;
247
}
248

  
249
uint8_t janus_instance_heartbeat(struct periodic_task * pt)
250
{
251
	struct janus_instance * janus;
252
	struct mg_connection * conn;
253
	char * uri;
254

  
255
	janus = (struct janus_instance *) periodic_task_get_data(pt);
256
	uri = janus_instance_session_path(janus);
257
	if (uri)
258
	{
259
		conn = mg_connect_http(janus->mongoose_srv, janus_instance_generic_handler, uri, NULL, JANUS_MSG_SESSION_KEEPALIVE);
260
		if (conn)
261
			conn->user_data = (void *) janus;
262
		free(uri);
263
	}
264
	return 0;
265
}
266

  
267
int8_t janus_instance_launch(struct janus_instance * ji)
268
{
269
	int8_t res = -1;
270
	struct stat s;
271
	char * argv[4];
272
	int fd;
273

  
274
	if (ji && ji->janus_pid == INVALID_PID)
275
	{
276
		res = stat(ji->executable, &s);
277
		// check exe existence
278
		if (res == 0 && S_ISREG(s.st_mode))
279
		{
280
			ji->janus_pid = fork();
281
			if (ji->janus_pid != INVALID_PID)
282
			{
283
				if (ji->janus_pid) // the parent
284
				{
285
					sleep(1); // let janus bootstrap
286
					res = janus_instance_create_management_handle(ji);
287
					if (res == 0)
288
						ji->heartbeat = task_manager_new_task(ji->tm, janus_instance_heartbeat, NULL, 30000, ji);
289
				}
290
				else // the child
291
				{
292
					fd = creat(ji->logfile, 'w');
293
					dup2(fd, 1);   // make stdout go to file
294
					dup2(fd, 2);   // make stderr go to file - you may choose to not do this
295
					close(fd);
296

  
297
					argv[0] = ji->executable;
298
					argv[1] = ji->conf_param;
299
					argv[2] = NULL;
300
					res = execve(ji->executable, argv, NULL);
301
					info("Error on launching Janus execution\n");
302
				}
303
			} else
304
			{
305
				info("Error on forking\n");
306
				res = -1;
307
			}
308

  
309
			
310
		} else
311
			info("Janus executable not found\n");
312
	}
313
	return res;
314
}
315

  
316
void janus_instance_streaming_point_handler(struct mg_connection *nc, int ev, void *ev_data)
317
{
318
	uint64_t * mp_id;
319
	struct http_message *hm = (struct http_message *) ev_data;
320
	char *buff;
321
	void ** data;
322
	struct streamer_creation_callback * scc;
323

  
324
	data = nc->user_data;
325
	mp_id = data[0];
326
	scc = data[1];
327
	switch (ev) {
328
		case MG_EV_CONNECT:
329
			if (*(int *) ev_data != 0)
330
				debug("Janus communication failure\n");
331
				debug("Ora triggero!\n");
332
			break;
333
		case MG_EV_HTTP_REPLY:
334
			switch (hm->resp_code) {
335
				case 200:
336
					buff = malloc(sizeof(char) * (hm->body.len + 1));
337
					strncpy(buff, hm->body.p, hm->body.len);
338
					buff[hm->body.len] = '\0';  // make sure string terminates
339
					debug(buff);
340
					*mp_id = janus_instance_msg_get_id(buff);
341
					free(buff);
342
				default:
343
					debug("Janus answers: %d\n", hm->resp_code);
344
			}
345
			nc->flags |= MG_F_SEND_AND_CLOSE;
346
			break;
347
		case MG_EV_CLOSE:
348
			debug("Janus server closed connection\n");
349
			if (scc)
350
			{
351
				debug("Janus instance calls creation trigger\n");
352
				streamer_creation_callback_trigger(scc, *mp_id ? 0 : 1);
353
				streamer_creation_callback_destroy(&scc);
354
				free(data);
355
			}
356
			break;
357
		default:
358
			break;
359
	}
360
}
361

  
362
int8_t janus_instance_create_streaming_point(struct janus_instance const * janus, uint64_t *mp_id, uint16_t audio_port, uint16_t video_port, struct streamer_creation_callback *scc)
363
{
364
	struct mg_connection * conn;
365
	int8_t res = -1;
366
	char * uri;
367
	char * fmt = "{\"transaction\":\"random_str\",\"janus\":\"message\",\"body\":{\"request\":\"create\",\"type\":\"rtp\",\
368
				  \"audio\":true,\"audioport\":%"PRId16",\"audiopt\":111,\"audiortpmap\":\"opus/48000/2\",\
369
				  \"video\":true,\"videoport\":%"PRId16",\"videopt\": 100,\"videortpmap\":\"VP8/90000\"}}";
370
	char buff[280];
371
	void ** data;
372

  
373
	if (janus && mp_id && audio_port && video_port)
374
	{
375
		uri = janus_instance_handle_path(janus);
376
		if (uri)
377
		{
378
			sprintf(buff, fmt, audio_port, video_port);
379
		   debug("Conctating Janus to create a new mountpoint\n");	
380
			conn = mg_connect_http(janus->mongoose_srv, janus_instance_streaming_point_handler, uri, NULL, buff);
381
			if (conn)
382
			{
383
				data = malloc(sizeof(void *) * 2);
384
				data[0] = mp_id;
385
				data[1] = scc;
386
				conn->user_data = data;
387
				res = 0;
388
			} else
389
			   debug("Aaargh, no connection!\n");	
390
			free(uri);
391
		}
392
	}
393
	return res;
394
}
395

  
396
int8_t janus_instance_destroy_streaming_point(struct janus_instance const * janus, uint64_t mp_id)
397
{
398
	struct mg_connection * conn;
399
	int8_t res = -1;
400
	char * uri;
401
	char * fmt = "{\"transaction\":\"random_str\",\"janus\":\"message\",\"body\":{\"request\":\"destroy\",\"id\": %"PRId64"}}";
402
	char buff[120];
403

  
404
	if (janus && mp_id)
405
	{
406
		uri = janus_instance_handle_path(janus);
407
		if (uri)
408
		{
409
			sprintf(buff, fmt, mp_id);
410
			conn = mg_connect_http(janus->mongoose_srv, janus_instance_generic_handler, uri, NULL, buff);
411
			if (conn)
412
			{
413
				conn->user_data = (void *) mp_id;
414
				res = 0;
415
			} 
416
			free(uri);
417
		}
418
	}
419
	return res;
420
}
src/janus_instance.h
1
/*******************************************************************
2
* PeerStreamer-ng is a P2P video streaming application exposing a ReST
3
* interface.
4
* Copyright (C) 2017 Luca Baldesi <luca.baldesi@unitn.it>
5
*
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Affero General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
* GNU Affero General Public License for more details.
15
*
16
* You should have received a copy of the GNU Affero General Public License
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*******************************************************************/
19

  
20
#ifndef __JANUS_INSTANCE_H__
21
#define __JANUS_INSTANCE_H__
22

  
23
#include<stdint.h>
24
#include<mongoose.h>
25
#include<task_manager.h>
26
#include<streamer_creation_callback.h>
27

  
28
struct janus_instance;
29
struct streamer_creation_callback;
30

  
31
struct janus_instance * janus_instance_create(struct mg_mgr *mongoose_srv, struct task_manager *tm, const char *config);
32

  
33
void janus_instance_destroy(struct janus_instance ** ji);
34

  
35
/*Returns 0 on success*/
36
int8_t janus_instance_launch(struct janus_instance * ji);
37

  
38
int8_t janus_instance_create_streaming_point(struct janus_instance const * janus, uint64_t *mp_id, uint16_t audio_port, uint16_t video_port, struct streamer_creation_callback *scc);
39

  
40
int8_t janus_instance_destroy_streaming_point(struct janus_instance const * janus, uint64_t mp_id);
41

  
42
#endif
src/path_handlers.c
26 26
#include<pschannel.h>
27 27
#include<context.h>
28 28
#include<mongoose.h>
29
#include<sdpfile.h>
29
#include<streamer_creation_callback.h>
30 30

  
31 31
void mg_connection_remote_ip(char * ip, const struct mg_connection *nc)
32 32
{
......
71 71
	free(channels);
72 72
}
73 73

  
74
int8_t streamer_creation_handler(struct mg_connection *nc, const struct pstreamer * ps, int8_t ret)
75
{
76
	char * json = NULL;
77
	int8_t res = -1;
78

  
79
	info("Inside creation handler\n");
80
	if (ps)
81
		json = pstreamer_to_json(ps);
82

  
83
	if (ret == 0 && json)
84
	{
85
		mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
86
		mg_printf_http_chunk(nc, json);
87
		res = 0;
88
		info("Stream created and served\n");
89
	} else {
90
		mg_printf(nc, "%s", "HTTP/1.1 500 Internal server error\r\nTransfer-Encoding: chunked\r\n\r\n");
91
		// destroy ps?
92
		info("Stream cannot be correctly served\n");
93
		if (ret)
94
			debug(json);
95
		else
96
			debug("PS does not exist");
97
	}
98
	if (json)
99
		free(json);
100
	mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */
101

  
102
	return res;
103
}
104

  
74 105
void streamer_create(struct mg_connection *nc, struct http_message *hm)
75 106
{
76 107
	const struct context * c;
77 108
	char ipaddr[MAX_IPADDR_LENGTH];
78 109
	char rtp_dst_ip[MAX_IPADDR_LENGTH];
79 110
	char port[MAX_PORT_LENGTH];
80
	char * id, *sdpuri;
81
	const struct pstreamer * ps;
82
	const struct pschannel * ch;
111
	char * id;
112
	const struct pstreamer * ps = NULL;
113
	const struct pschannel * ch = NULL;
83 114

  
84 115
	c = (const struct context *) nc->user_data;
85 116
	mg_get_http_var(&hm->body, "ipaddr", ipaddr, MAX_IPADDR_LENGTH);
......
94 125
	if (ch)
95 126
	{
96 127
		debug("Channel: %s\n", ch->name);
97
		ps = pstreamer_manager_create_streamer(c->psm, ipaddr, port, id, rtp_dst_ip); 
128
		ps = pstreamer_manager_create_streamer(c->psm, ipaddr, port, id, rtp_dst_ip, streamer_creation_callback_new(nc, streamer_creation_handler)); 
98 129
		if(ps)
99 130
		{
100 131
			pstreamer_schedule_tasks((struct pstreamer*)ps, c->tm);
101 132
			info("Streamer instance created\n");
102
			sdpuri = sdpfile_create(c, ch, ps, rtp_dst_ip);
103
			if (sdpuri)
104
			{
105
				mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n");
106
				mg_printf_http_chunk(nc, "{\"id\":\"%s\",\"name\":\"%s\",\"sdpfile\":\"%s\"}", id, ch->name, sdpuri);
107
				mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */
108
				free(sdpuri);
109
				info("SDPfile served\n");
110
			} else {
111
				info("SDPfile not available\n");
112
				mg_printf(nc, "%s", "HTTP/1.1 422 Unprocessable Entity\r\nTransfer-Encoding: chunked\r\n\r\n");
113
				mg_send_http_chunk(nc, "", 0); /* Send empty chunk, the end of response */
114
			}
115 133
		} else {
116 134
			info("Streamer could not be launched\n");
117 135
			mg_printf(nc, "%s", "HTTP/1.1 409 Conflict\r\nTransfer-Encoding: chunked\r\n\r\n");
src/periodic_task_intfs.c
73 73
	ps = (struct psinstance *) periodic_task_get_data(pt);
74 74
	if (ret == 0)
75 75
	{
76
		debug("Topology update\n");
76
		//debug("Topology update\n");
77 77
		psinstance_topology_update(ps);
78 78
	}
79 79
	return 0;
......
109 109
		debug("Received a message\n");
110 110
		psinstance_handle_msg(ps);
111 111
	}
112
	if (ret == 0)
113
		debug("PStreamer message handling timeout\n");
112
	//if (ret == 0)
113
	//	debug("PStreamer message handling timeout\n");
114 114
	return 0;
115 115
}
116 116

  
......
131 131

  
132 132
	iface = (struct mg_iface *) periodic_task_get_data(pt);
133 133

  
134
	if (ret == 0)
135
		debug("Mongoose timeout\n");
134
	//if (ret == 0)
135
	//	debug("Mongoose timeout\n");
136 136
	return mongoose_select_action(iface, ret, readfds, writefds, errfds);
137 137
}
138 138

  
src/pstreamer.c
42 42
	struct periodic_task * msg_task;
43 43
	struct task_manager * tm;
44 44
	timeout topology_interval;
45
	uint64_t janus_streaming_id;
45 46
};
46 47

  
47 48
struct pstreamer_manager {
48 49
	struct ord_set * streamers;
49 50
	uint16_t initial_streaming_port;
50 51
	char * streamer_opts;
52
	struct janus_instance const * janus;
51 53
};
52 54

  
53 55
int8_t pstreamer_init(struct pstreamer * ps, const char * rtp_dst_ip, const char * opts)
......
67 69
	ps->msg_task = NULL;
68 70
	ps->tm = NULL;
69 71
	ps->topology_interval = 400;
72
	ps->janus_streaming_id = 0;
70 73

  
71 74
	if (ps->psc)
72 75
		return 0;
......
104 107

  
105 108
char * pstreamer_to_json(const struct pstreamer * ps)
106 109
{
107
	char fmt[] = "{\"id\":\"%s\",\"source_ip\":\"%s\",\"source_port\":\"%d\"}";
110
	char fmt[] = "{\"id\":\"%s\",\"source_ip\":\"%s\",\"source_port\":\"%d\",\"janus_streaming_id\":\"%"PRId64"\"}";
108 111
	size_t reslength;
109 112
	char * res = NULL;
110 113

  
......
112 115
	{
113 116
		reslength = strlen(fmt) - 2*3 + PSID_LENGTH + MAX_IPADDR_LENGTH + MAX_PORT_LENGTH + 1;
114 117
		res = malloc(reslength * sizeof(char));
115
		sprintf(res, fmt, ps->id, ps->source_ip, ps->source_port);
118
		sprintf(res, fmt, ps->id, ps->source_ip, ps->source_port, ps->janus_streaming_id);
116 119
	}
117 120
	return res;
118 121
}
119 122

  
120
struct pstreamer_manager * pstreamer_manager_new(uint16_t starting_port)
123
struct pstreamer_manager * pstreamer_manager_new(uint16_t starting_port, const struct janus_instance *janus)
121 124
{
122 125
	struct pstreamer_manager * psm = NULL;
123 126

  
......
127 130
	 * (as the first one is the pstreamer port). So starting_port must be an odd number */
128 131
	psm->initial_streaming_port = (starting_port % 2 == 1) ? starting_port : starting_port + 1;
129 132
	psm->streamer_opts = NULL;
133
	psm->janus = janus;
130 134

  
131 135
	return psm;
132 136
}
......
162 166
	if (psm && *psm)
163 167
	{
164 168
		ord_set_for_each(ps, (*psm)->streamers)
169
		{
170
			if ((*psm)->janus)
171
				janus_instance_destroy_streaming_point((*psm)->janus, ((struct pstreamer*)ps)->janus_streaming_id);
165 172
			pstreamer_deinit((struct pstreamer *)ps);
173
		}
166 174

  
167 175
		ord_set_destroy(&((*psm)->streamers), 1);
168 176
		if((*psm)->streamer_opts)
......
230 238
	return (const struct pstreamer*) ptr;
231 239
}
232 240

  
233
const struct pstreamer * pstreamer_manager_create_streamer(struct pstreamer_manager * psm, const char * source_ip, const char * source_port, const char * id, const char * rtp_dst_ip)
241
const struct pstreamer * pstreamer_manager_create_streamer(struct pstreamer_manager * psm, const char * source_ip, const char * source_port, const char * id, const char * rtp_dst_ip, struct streamer_creation_callback * scc)
234 242
{
235 243
	struct pstreamer * ps = NULL;
236 244
	const void * ptr = NULL;
......
246 254
		if (ptr == NULL)
247 255
		{
248 256
			pstreamer_touch(ps);
257
			streamer_creation_set_pstreamer_ref(scc, ps);
258
			if (psm->janus)
259
			{
260
				debug("calling janus upon notification of perstreamer creation\n");
261
				janus_instance_create_streaming_point(psm->janus, &(ps->janus_streaming_id), ps->base_port+1, ps->base_port+3, scc);
262
			}
263
			else
264
				if (scc)
265
					streamer_creation_callback_trigger(scc, 0);
249 266
			pstreamer_init(ps, rtp_dst_ip, psm->streamer_opts);
250 267
			ord_set_insert(psm->streamers, ps, 0);
251 268
		} else
......
264 281

  
265 282
	if (psm && ps)
266 283
	{
284
		if(psm->janus)
285
			janus_instance_destroy_streaming_point(psm->janus, ps->janus_streaming_id);
267 286
		pstreamer_deinit((struct pstreamer *)ps);
268 287
		res = ord_set_remove(psm->streamers, ps, 1);
269 288
	}
src/pstreamer.h
24 24
#include<stdint.h>
25 25
#include<name_lengths.h>
26 26
#include<task_manager.h>
27
#include<janus_instance.h>
28
#include<streamer_creation_callback.h>
27 29

  
28 30
struct pstreamer;
29 31
struct pstreamer_manager;
32
struct janus_instance;
33
struct streamer_creation_callback;
30 34

  
31
struct pstreamer_manager * pstreamer_manager_new(uint16_t starting_port);
35
struct pstreamer_manager * pstreamer_manager_new(uint16_t starting_port, const struct janus_instance *janus);
32 36

  
33 37
void pstreamer_manager_destroy(struct pstreamer_manager ** psm);
34 38

  
35
const struct pstreamer * pstreamer_manager_create_streamer(struct pstreamer_manager * psm, const char * source_ip, const char * source_port, const char * id, const char * rtp_dst_ip);
39
const struct pstreamer * pstreamer_manager_create_streamer(struct pstreamer_manager * psm, const char * source_ip, const char * source_port, const char * id, const char * rtp_dst_ip, struct streamer_creation_callback * scc);
36 40

  
37 41
char * pstreamer_to_json(const struct pstreamer * ps);
38 42

  
src/streamer_creation_callback.c
1
/*******************************************************************
2
* PeerStreamer-ng is a P2P video streaming application exposing a ReST
3
* interface.
4
* Copyright (C) 2017 Luca Baldesi <luca.baldesi@unitn.it>
5
*
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Affero General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
* GNU Affero General Public License for more details.
15
*
16
* You should have received a copy of the GNU Affero General Public License
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*******************************************************************/
19

  
20
#include<streamer_creation_callback.h>
21

  
22
struct streamer_creation_callback {
23
	streamer_creation_handler_t callback;	
24
	const struct pstreamer * ps;
25
	struct mg_connection *nc;
26
};
27

  
28
int8_t streamer_creation_set_pstreamer_ref(struct streamer_creation_callback * scc, const struct pstreamer *ps)
29
{
30
	if (scc && ps)
31
	{
32
		scc->ps = ps;
33
		return 0;
34
	}
35
	return -1;
36
}
37

  
38
struct streamer_creation_callback * streamer_creation_callback_new(struct mg_connection *nc, streamer_creation_handler_t handler)
39
{
40
	struct streamer_creation_callback * scc = NULL;
41

  
42
	if (nc && handler)
43
	{
44
		scc = malloc(sizeof(struct streamer_creation_callback));
45
		scc->ps = NULL;
46
		scc->callback = handler;
47
		scc->nc = nc;
48
	}
49
	return scc;
50
}
51

  
52
int8_t streamer_creation_callback_trigger(struct streamer_creation_callback * scc, int8_t ret)
53
{
54
	int8_t res = -1;
55
	if (scc)
56
		res = scc->callback(scc->nc, scc->ps, ret);
57
	return res;
58
}
59

  
60
void streamer_creation_callback_destroy(struct streamer_creation_callback ** scc)
61
{
62
	if (scc && *scc)
63
	{
64
		free(*scc);
65
		*scc = NULL;
66
	}
67
}
68

  
69

  
src/streamer_creation_callback.h
1
/*******************************************************************
2
* PeerStreamer-ng is a P2P video streaming application exposing a ReST
3
* interface.
4
* Copyright (C) 2017 Luca Baldesi <luca.baldesi@unitn.it>
5
*
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU Affero General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
* GNU Affero General Public License for more details.
15
*
16
* You should have received a copy of the GNU Affero General Public License
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*******************************************************************/
19

  
20
#ifndef __STREAMER_CREATION_CALLBACK_H__
21
#define __STREAMER_CREATION_CALLBACK_H__
22

  
23
#include<pstreamer.h>
24
#include<stdint.h>
25
#include<mongoose.h>
26

  
27
struct pstreamer;
28
struct streamer_creation_callback;
29

  
30
typedef int8_t (*streamer_creation_handler_t)(struct mg_connection *nc, const struct pstreamer *ps, int8_t ret);
31

  
32
struct streamer_creation_callback * streamer_creation_callback_new(struct mg_connection *nc, streamer_creation_handler_t handler);
33
 
34
int8_t streamer_creation_set_pstreamer_ref(struct streamer_creation_callback * scc, const struct pstreamer *ps);
35

  
36
int8_t streamer_creation_callback_trigger(struct streamer_creation_callback * scc, int8_t ret);
37

  
38
void streamer_creation_callback_destroy(struct streamer_creation_callback ** scc);
39

  
40
#endif

Also available in: Unified diff