1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2011-2012
6  *			All rights reserved
7  *
8  *  This file is part of GPAC / Sampe On-Scvreen Display sub-project
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 #include <gpac/modules/term_ext.h>
27 #include <gpac/internal/terminal_dev.h>
28 #include <gpac/internal/compositor_dev.h>
29 #include <gpac/nodes_mpeg4.h>
30 #include <gpac/network.h>
31 
32 #define XMIN 160
33 #define XMAX 480
34 
35 #define YMAX 360
36 #define YMIN 120
37 
38 typedef struct
39 {
40 	GF_Terminal *term;
41 	GF_Socket *sock;
42 	Bool mouse_down;
43 	u32 cnt;
44 	Float last_min_x, last_max_x, last_min_y, last_max_y;
45 } GF_NetControl;
46 
netctrl_process(GF_TermExt * termext,u32 action,void * param)47 static Bool netctrl_process(GF_TermExt *termext, u32 action, void *param)
48 {
49 	const char *sOpt, *server_ip;
50 	int port;
51 	Float face_min_x, face_max_x, face_min_y, face_max_y, gaze_x, gaze_y;
52 	GF_Event event;
53 	GF_NetControl *netctrl = termext->udta;
54 	char message[1024];
55 	GF_Err e;
56 	u32 bytes;
57 	u32 face = 0;
58 
59 	switch (action) {
60 	case GF_TERM_EXT_START:
61 		netctrl->term = (GF_Terminal *) param;
62 
63 		sOpt = gf_opts_get_key("NetControler", "Enabled");
64 		if (!sOpt || strcmp(sOpt, "yes")) return 0;
65 		sOpt = gf_opts_get_key("NetControler", "ServerIP");
66 		if (sOpt) server_ip = sOpt;
67 		else server_ip = "127.0.0.1";
68 		sOpt = gf_opts_get_key("NetControler", "Port");
69 		if (sOpt) port = atoi(sOpt);
70 		else port = 20320;
71 
72 		termext->caps |= GF_TERM_EXTENSION_NOT_THREADED;
73 		netctrl->sock = gf_sk_new(GF_SOCK_TYPE_UDP);
74 
75 		if (netctrl->sock < 0)   {
76 			GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[NetControl] Failed to open socket for %s:%d\n", server_ip, port));
77 			return 0;
78 		}
79 
80 		e = gf_sk_bind(netctrl->sock, server_ip, port, NULL, 0, 0);
81 		if (e != GF_OK) {
82 			if (netctrl->sock) gf_sk_del(netctrl->sock);
83 			netctrl->sock = NULL;
84 			GF_LOG(GF_LOG_ERROR, GF_LOG_INTERACT, ("[NetControl] Failed to bind to socket %s:%d\n", server_ip, port));
85 			return 0;
86 		}
87 
88 		return 1;
89 
90 	case GF_TERM_EXT_STOP:
91 		if (netctrl->sock) gf_sk_del(netctrl->sock);
92 		break;
93 
94 	case GF_TERM_EXT_PROCESS:
95 		gf_sk_receive(netctrl->sock, message, 1024, 0, &bytes);
96 		if (!bytes) break;
97 		message[bytes] = '\0';
98 		GF_LOG(GF_LOG_DEBUG, GF_LOG_INTERACT, ("[NetControl] received message %s\n", message));
99 
100 		if (!strncmp(message, "gpac splice ", 12) || !strncmp(message, "gpac add ", 9)
101 			|| !strncmp(message, "gpac select ", 12)
102 		) {
103 			gf_term_scene_update(netctrl->term, NULL, message);
104 			break;
105 		}
106 
107 		if (strncmp(message, "gpac:face=", 10)) break;
108 
109 		sscanf(message, "gpac:face=%d,%f,%f,%f,%f", &face, &face_min_x, &face_max_x, &face_min_y, &face_max_y);
110 
111 
112 		memset(&event, 0, sizeof(GF_Event));
113 		event.mouse.button = GF_MOUSE_LEFT;
114 		if (face == 0) {
115 			if (netctrl->last_min_x < 0.01) {
116 				netctrl->term->compositor->auto_rotate = 2;
117 			} else if (netctrl->last_max_x > 0.90) {
118 				netctrl->term->compositor->auto_rotate = 1;
119 			} else if (netctrl->last_min_y < 0.01) {
120 				netctrl->term->compositor->auto_rotate = 4;
121 			} else if (netctrl->last_max_y > 0.90) {
122 				netctrl->term->compositor->auto_rotate = 3;
123 			} else {
124 				netctrl->cnt++;
125 				if ((netctrl->cnt>=50) && (netctrl->mouse_down)) {
126 					netctrl->term->compositor->auto_rotate = 0;
127 					netctrl->mouse_down = GF_FALSE;
128 					event.type = GF_EVENT_MOUSEUP;
129 					netctrl->term->compositor->video_out->on_event(netctrl->term->compositor->video_out->evt_cbk_hdl, &event);
130 				}
131 			}
132 			break;
133 		}
134 
135 		netctrl->last_min_x = face_min_x;
136 		netctrl->last_max_x = face_max_x;
137 		netctrl->last_min_y = face_min_y;
138 		netctrl->last_max_y = face_max_y;
139 
140 		gaze_x = (face_min_x+face_max_x)/2;
141 		gaze_y = (face_min_y+face_max_y)/2;
142 
143 		event.mouse.x = (1-gaze_x) * netctrl->term->compositor->display_width;
144 		event.mouse.y = (1-gaze_y) * netctrl->term->compositor->display_height;
145 
146 		if (!netctrl->mouse_down) {
147 			//don't grab if mouse is down
148 			if (netctrl->term->compositor->navigation_state) break;
149 			netctrl->mouse_down = GF_TRUE;
150 			event.type = GF_EVENT_MOUSEDOWN;
151 			netctrl->term->compositor->video_out->on_event(netctrl->term->compositor->video_out->evt_cbk_hdl, &event);
152 			netctrl->cnt = 0;
153 		}
154 		event.type = GF_EVENT_MOUSEMOVE;
155 		netctrl->term->compositor->video_out->on_event(netctrl->term->compositor->video_out->evt_cbk_hdl, &event);
156 		break;
157 	}
158 	return 0;
159 }
160 
161 
netctrl_new()162 GF_TermExt *netctrl_new()
163 {
164 	GF_TermExt *dr;
165 	GF_NetControl *netctrl;
166 	dr = (GF_TermExt*)gf_malloc(sizeof(GF_TermExt));
167 	memset(dr, 0, sizeof(GF_TermExt));
168 	GF_REGISTER_MODULE_INTERFACE(dr, GF_TERM_EXT_INTERFACE, "GPAC NetControl", "gpac distribution");
169 
170 	GF_SAFEALLOC(netctrl, GF_NetControl);
171 	dr->process = netctrl_process;
172 	dr->udta = netctrl;
173 	return dr;
174 }
175 
176 
netctrl_delete(GF_BaseInterface * ifce)177 void netctrl_delete(GF_BaseInterface *ifce)
178 {
179 	GF_TermExt *dr = (GF_TermExt *) ifce;
180 	GF_NetControl *netctrl = dr->udta;
181 	gf_free(netctrl);
182 	gf_free(dr);
183 }
184 
185 GPAC_MODULE_EXPORT
QueryInterfaces()186 const u32 *QueryInterfaces()
187 {
188 	static u32 si [] = {
189 		GF_TERM_EXT_INTERFACE,
190 		0
191 	};
192 	return si;
193 }
194 
195 GPAC_MODULE_EXPORT
LoadInterface(u32 InterfaceType)196 GF_BaseInterface *LoadInterface(u32 InterfaceType)
197 {
198 	if (InterfaceType == GF_TERM_EXT_INTERFACE) return (GF_BaseInterface *)netctrl_new();
199 	return NULL;
200 }
201 
202 GPAC_MODULE_EXPORT
ShutdownInterface(GF_BaseInterface * ifce)203 void ShutdownInterface(GF_BaseInterface *ifce)
204 {
205 	switch (ifce->InterfaceType) {
206 	case GF_TERM_EXT_INTERFACE:
207 		netctrl_delete(ifce);
208 		break;
209 	}
210 }
211 
212 GPAC_MODULE_STATIC_DECLARATION( netctrl )
213