no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / x10tv.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2016-2020 William Morrow
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published
7  * by the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21 #ifdef HAVE_X10TV
22
23 #include "channelinfo.h"
24 #include "cwindow.h"
25 #include "cwindowgui.h"
26 #include "edl.h"
27 #include "mbuttons.h"
28 #include "mwindow.h"
29 #include "mwindowgui.h"
30 #include "language.h"
31 #include "playbackengine.h"
32 #include "playtransport.h"
33 #include "record.h"
34 #include "recordgui.h"
35 #include "recordmonitor.h"
36 #include "remotecontrol.h"
37 #include "tracks.h"
38 #include "x10tv.h"
39
40 #include <dirent.h>
41 #include <linux/input.h>
42
43 X10TV::X10TV(MWindow *mwindow, int *fds, int nfds)
44 {
45         this->mwindow = mwindow;
46         this->ifds = new int[nfds];
47         this->nfds = nfds;
48         for( int i=0; i<nfds; ++i ) this->ifds[i] = fds[i];
49
50         ev = new input_event;
51         memset(ev, 0, sizeof(*ev));
52         ev->code = -1;
53         done = -1;
54         last_code = -1;
55         code = -1;
56         FD_ZERO(&rfds);
57         mfd = -1;
58 }
59
60 X10TV::~X10TV()
61 {
62         stop();
63         delete ev;
64 }
65
66 void X10TV::stop()
67 {
68         done = 1;
69         for( int i=nfds; --i>=0; ) {
70                 ioctl(ifds[i], EVIOCGRAB, 0);
71                 close(ifds[i]);
72         }
73         nfds = 0;
74         if( running() ) {
75                 cancel();
76                 join();
77         }
78 }
79
80 void X10TV::start()
81 {
82         FD_ZERO(&rfds);
83         mfd = -1;
84         for( int i=nfds; --i>=0; ) {
85                 int fd = ifds[i];
86                 ioctl(fd, EVIOCGRAB, 1);
87                 if( fd >= mfd ) mfd = fd+1;
88                 FD_SET(fd, &rfds);
89         }
90         done = 0;
91         Thread::start();
92 }
93
94 int X10TV::open_usb_inputs(int vendor, int product, int &version,
95                 int *ifds, int mxfds)
96 {
97         int ret = -1;
98         const char *dev_input = "/dev/input";
99         DIR *dir = opendir(dev_input);
100         if( !dir ) return ret;
101
102         struct dirent64 *dp;
103         struct input_id dev_id;
104         int nfds = 0;
105         while( nfds < mxfds && (dp = readdir64(dir)) != 0 ) {
106                 char *fn = dp->d_name;
107                 if( !strcmp(fn, ".") || !strcmp(fn, "..") ) continue;
108                 char path[PATH_MAX];  struct stat st;
109                 snprintf(path, PATH_MAX, "%s/%s", dev_input, fn);
110                 if( stat(path, &st) < 0 ) continue;
111                 if( !S_ISCHR(st.st_mode) ) continue;
112                 int fd = open(path, O_RDONLY);
113                 if( fd < 0 ) continue;
114                 if( !ioctl(fd, EVIOCGID, &dev_id) ) {
115                         if( dev_id.bustype == BUS_USB &&
116                             dev_id.vendor == vendor &&
117                             dev_id.product == product ) {
118                                 unsigned props = 0;
119                                 // quirk, reports pointing_stick for keys
120                                 unsigned mptrs =
121                                          (1<<INPUT_PROP_POINTING_STICK);
122                                 int ret = ioctl(fd, EVIOCGPROP(sizeof(props)), &props);
123                                 if( ret == sizeof(props) && (props & mptrs) ) {
124                                         version = dev_id.version;
125                                         ifds[nfds++] = fd;
126                                         continue;
127                                 }
128                         }
129                 }
130                 close(fd);
131         }
132         closedir(dir);
133         return nfds;
134 }
135
136
137 X10TV *X10TV::probe(MWindow *mwindow)
138 {
139         int ver = -1, ifds[16];
140         int nfds = open_usb_inputs(0x0bc7, 0x0004, ver, ifds, 16);
141         if( nfds <= 0 ) return 0;
142         printf("detected ATI X10 remote, ver=0x%04x\n", ver);
143         return new X10TV(mwindow, ifds, nfds);
144 }
145
146 void X10TV::run()
147 {
148         enable_cancel();
149         while( !done ) {
150                 fd_set rds = rfds;
151                 int ret = select(mfd, &rds, 0, 0, 0);
152                 if( ret < 0 ) break;
153                 int fd = -1, k = ret > 0 ? nfds : 0;
154                 while( --k >= 0 ) {
155                         int ifd = ifds[k];
156                         if( FD_ISSET(ifd, &rds) ) {
157                                 fd = ifd;  break;
158                         }
159                 }
160                 if( fd < 0 ) {
161                         printf("select failed\n");
162                         usleep(100000);  continue;
163                 }
164                 ret = read(fd, ev, sizeof(*ev));
165                 if( done ) break;
166                 if( ret != sizeof(*ev) ) {
167                         if( ret < 0 ) { perror("read event"); break; }
168                         fprintf(stderr, "bad read: %d\n", ret);
169                         break;
170                 }
171                 handle_event(fd);
172         }
173 }
174
175 int X10TV::check_menu_keys(int code)
176 {
177         int result = 1;
178         switch( code ) {
179         case X10_POWER:
180                 mwindow->quit();
181                 break;
182         case X10_TV: {
183                 Record *record = mwindow->gui->record;
184                 if( !record->running() )
185                         record->start();
186                 else
187                         record->record_gui->interrupt_thread->start(0);
188                 break; }
189         case X10_BOOK:
190 #ifdef HAVE_DVB
191                 mwindow->gui->channel_info->toggle_scan();
192 #endif
193                 break;
194         case X10_EDIT: {
195                 RemoteControl *remote_control = mwindow->gui->remote_control;
196                 if( !remote_control->deactivate() )
197                         remote_control->activate();
198                 break; }
199         default:
200                 result = 0;
201         }
202         return result;
203 }
204
205 void X10TV::handle_event(int fd)
206 {
207         switch(ev->type) {
208         case EV_KEY: {
209                 if( !ev->value ) break;
210                 this->last_code = this->code;
211                 this->code = ev->code;
212                 if( check_menu_keys(code) ) break;
213                 RemoteHandler *handler = mwindow->gui->remote_control->handler;
214                 if( handler )
215                         handler->process_key(ev->code);
216                 break; }
217         case EV_SYN:
218         case EV_MSC:
219                 break;
220         default: {
221                 time_t t = ev->time.tv_sec;
222                 struct tm *tp = localtime(&t);
223                 printf("x10tv event %d: %4d/%02d/%02d %02d:%02d:%02d.%03d = (%d, %d, 0x%x)\n",
224                         fd, tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday,
225                         tp->tm_hour, tp->tm_min, tp->tm_sec,
226                         (int)ev->time.tv_usec/1000, ev->type, ev->code, ev->value);
227                 break; }
228         }
229 }
230
231
232 int X10TVCWindowHandler::x10tv_process_code(int code)
233 {
234         MWindow *mwindow = x10tv->mwindow;
235         EDL *edl = mwindow->edl;
236         if( !edl ) return 0;
237         PlayTransport *transport = mwindow->gui->mbuttons->transport;
238         if( !transport->get_edl() ) return 0;
239         PlaybackEngine *engine = transport->engine;
240         double position = engine->get_tracking_position();
241         double length = edl->tracks->total_length();
242         int next_command = -1;
243
244         switch( code ) {
245         case X10_A:             break;
246         case X10_B:             break;
247         case X10_POWER:         break;
248         case X10_TV:            break;
249         case X10_DVD:           break;
250         case X10_WWW:           break;
251         case X10_BOOK:          break;
252         case X10_EDIT:          break;
253         case X10_VOLDN:         return 1;
254         case X10_VOLUP:         return 1;
255         case X10_MUTE:          break;
256         case X10_CH_DN:         break;
257         case X10_CH_UP:         break;
258 // select window tile config = BACK 1,2,3
259         case X10_1: case X10_2: case X10_3:
260                 if( mwindow->x10tv->last_code == X10_MENU ) {
261                         RemoteGUI *rgui = mwindow->gui->cwindow_remote_handler->gui;
262                         rgui->tile_windows(code - X10_1);
263                         return 1;
264                 } // fall thru
265 // select asset program config = TEXT 1,2,3,4,5,6
266         case X10_4: case X10_5: case X10_6:
267                 if( mwindow->x10tv->last_code == X10_SETUP ) {
268                         mwindow->select_asset(code - X10_1, 1);
269                         break;
270                 } // fall thru
271         case X10_7: case X10_8: case X10_9:
272         case X10_0:
273 // select position in 10 percent units
274                 position = length * (code - X10_0)/10.0;
275                 break;
276         case X10_MENU:          return 0;
277         case X10_SETUP:         return 0;
278         case X10_C:             return 1;
279         case X10_UP:  position += 60.0;  break;
280         case X10_D:             return 1;
281         case X10_PROPS:         return 1;
282         case X10_LT:  position -= 10.0;  break;
283         case X10_OK:            return 1;
284         case X10_RT:  position += 10.0;  break;
285         case X10_SCRN: {
286                 CWindowCanvas *canvas = mwindow->cwindow->gui->canvas;
287                 int on = canvas->get_fullscreen() ? 0 : 1;
288                 canvas->Canvas::set_fullscreen(on, 0);
289                 return 1; }
290         case X10_E:             return 1;
291         case X10_DN:  position -= 60.0;  break;
292         case X10_F:             return 1;
293         case X10_REW:   next_command = FAST_REWIND;     break;
294         case X10_PLAY:  next_command = NORMAL_FWD;      break;
295         case X10_FWD:   next_command = FAST_FWD;        break;
296         case X10_REC:   next_command = SLOW_REWIND;     break;
297         case X10_STOP:  next_command = STOP;            break;
298         case X10_PAUSE: next_command = SLOW_FWD;        break;
299
300         default:
301                 printf("x10tv cwindow: unknown code: %04x\n", code);
302                 return -1;
303         }
304
305         if( next_command < 0 ) {
306                 if( position < 0 ) position = 0;
307                 transport->change_position(position);
308         }
309         else
310                 transport->handle_transport(next_command);
311         return 0;
312 }
313
314 int X10TVCWindowHandler::process_key(int key)
315 {
316         return x10tv_process_code(key);
317 }
318
319 int X10TVRecordHandler::process_key(int key)
320 {
321         Record *record = x10tv->mwindow->gui->record;
322         return record->x10tv_process_code(key);
323 }
324
325
326 X10TVRecordHandler::X10TVRecordHandler(X10TV *x10tv, RemoteControl *remote_control)
327  : RemoteHandler(remote_control->gui, GREEN)
328 {
329         this->x10tv = x10tv;
330 }
331
332 X10TVCWindowHandler::X10TVCWindowHandler(X10TV *x10tv, RemoteControl *remote_control)
333  : RemoteHandler(remote_control->gui, BLUE)
334 {
335         this->x10tv = x10tv;
336 }
337
338 // HAVE_X10TV
339 #endif