]> git.sesse.net Git - vlc/blob - modules/access/eyetv.m
direct3d11: implement the pixel format fallback
[vlc] / modules / access / eyetv.m
1 /*****************************************************************************
2  * eyetv.m : Access module to connect to our plugin running within EyeTV
3  *****************************************************************************
4  * Copyright (C) 2006-2007 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Author: Felix Kühne <fkuehne at videolan dot org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_access.h>
35
36 #include <vlc_network.h>
37
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <sys/un.h>
41 #include <unistd.h>
42
43 #import <Foundation/Foundation.h>
44
45 #define MTU 65535
46
47 /* TODO:
48  * watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */
49
50 /*****************************************************************************
51  * Module descriptior
52  *****************************************************************************/
53 static int  Open (vlc_object_t *);
54 static void Close(vlc_object_t *);
55
56 #define CHANNEL_TEXT N_("Channel number")
57 #define CHANNEL_LONGTEXT N_(\
58     "EyeTV program number, or use 0 for last channel, " \
59     "-1 for S-Video input, -2 for Composite input")
60
61 vlc_module_begin ()
62     set_shortname("EyeTV")
63     set_description(N_("EyeTV input"))
64     set_category(CAT_INPUT)
65     set_subcategory(SUBCAT_INPUT_ACCESS)
66
67     add_integer("eyetv-channel", 0,
68                  CHANNEL_TEXT, CHANNEL_LONGTEXT, false)
69
70     set_capability("access", 0)
71     add_shortcut("eyetv")
72     set_callbacks(Open, Close)
73 vlc_module_end ()
74
75 /*****************************************************************************
76  * Access: local prototypes
77  *****************************************************************************/
78 struct access_sys_t
79 {
80     int eyetvSock;
81 };
82
83 static block_t *BlockRead(access_t *);
84 static int Control(access_t *, int, va_list);
85
86 static void selectChannel(vlc_object_t *p_this, int theChannelNum)
87 {
88     NSAppleScript *script;
89     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
90     switch(theChannelNum) {
91         case -2: // Composite
92             script = [[NSAppleScript alloc] initWithSource:
93                         @"tell application \"EyeTV\"\n"
94                          "  input_change input source composite video input\n"
95                          "  volume_change level 0\n"
96                          "  show player_window\n"
97                          "  tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
98                          "end tell"];
99             break;
100         case -1: // S-Video
101             script = [[NSAppleScript alloc] initWithSource:
102                         @"tell application \"EyeTV\"\n"
103                          "  input_change input source S video input\n"
104                          "  volume_change level 0\n"
105                          "  show player_window\n"
106                          "  tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
107                          "end tell"];
108             break;
109         case 0: // Last
110             script = [[NSAppleScript alloc] initWithSource:
111                         @"tell application \"EyeTV\"\n"
112                          "  volume_change level 0\n"
113                          "  show player_window\n"
114                          "  tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
115                          "end tell"];
116             break;
117         default:
118             if (theChannelNum > 0) {
119                 NSString *channel_change = [NSString stringWithFormat:
120                     @"tell application \"EyeTV\"\n"
121                      "  channel_change channel number %d\n"
122                      "  volume_change level 0\n"
123                      "  show player_window\n"
124                      "  tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
125                      "end tell", theChannelNum];
126                 script = [[NSAppleScript alloc] initWithSource:channel_change];
127             }
128             else
129                 return;
130     }
131     NSDictionary *errorDict;
132     NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&errorDict];
133     if (nil == descriptor) {
134         NSString *errorString = [errorDict objectForKey:NSAppleScriptErrorMessage];
135         msg_Err(p_this, "EyeTV source change failed with error status '%s'", [errorString UTF8String]);
136     }
137     [script release];
138     [pool release];
139 }
140
141 /*****************************************************************************
142  * Open: sets up the module and its threads
143  *****************************************************************************/
144 static int Open(vlc_object_t *p_this)
145 {
146     access_t        *p_access = (access_t *)p_this;
147     access_sys_t    *p_sys;
148
149     struct sockaddr_un publicAddr, peerAddr;
150     int publicSock;
151
152     /* Init p_access */
153     access_InitFields(p_access);
154     ACCESS_SET_CALLBACKS(NULL, BlockRead, Control, NULL);
155     p_sys = p_access->p_sys = calloc(1, sizeof(access_sys_t));
156     if (!p_sys)
157         return VLC_ENOMEM;
158
159     msg_Dbg(p_access, "coming up");
160     selectChannel(p_this, var_InheritInteger(p_access, "eyetv-channel"));
161
162     /* socket */
163     memset(&publicAddr, 0, sizeof(publicAddr));
164     publicAddr.sun_family = AF_UNIX;
165     strncpy(publicAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(publicAddr.sun_path)-1);
166     /* remove previous public path if it wasn't cleanly removed */
167     if ((0 != unlink(publicAddr.sun_path)) && (ENOENT != errno)) {
168         msg_Err(p_access, "local socket path is not usable (errno=%d)", errno);
169         free(p_sys);
170         return VLC_EGENERIC;
171     }
172
173     publicSock = socket(PF_UNIX, SOCK_STREAM, 0);
174     if (publicSock == -1) {
175         msg_Err(p_access, "create local socket failed (errno=%d)", errno);
176         free(p_sys);
177         return VLC_EGENERIC;
178     }
179
180     if (bind(publicSock, (struct sockaddr *)&publicAddr, sizeof(struct sockaddr_un)) == -1) {
181         msg_Err(p_access, "bind local socket failed (errno=%d)", errno);
182         close(publicSock);
183         free(p_sys);
184         return VLC_EGENERIC;
185     }
186
187     /* we are not expecting more than one connection */
188     if (listen(publicSock, 1) == -1) {
189         msg_Err(p_access, "cannot accept connection (errno=%d)", errno);
190         close(publicSock);
191         free(p_sys);
192         return VLC_EGENERIC;
193     } else {
194         socklen_t peerSockLen = sizeof(struct sockaddr_un);
195         int peerSock;
196
197         /* tell the EyeTV plugin to open start sending */
198         CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter (),
199                                               CFSTR("VLCAccessStartDataSending"),
200                                               CFSTR("VLCEyeTVSupport"),
201                                               /*userInfo*/ NULL,
202                                               TRUE);
203
204         msg_Dbg(p_access, "plugin notified");
205
206         peerSock = accept(publicSock, (struct sockaddr *)&peerAddr, &peerSockLen);
207         if (peerSock == -1) {
208             msg_Err(p_access, "cannot wait for connection (errno=%d)", errno);
209             close(publicSock);
210             free(p_sys);
211             return VLC_EGENERIC;
212         }
213
214         msg_Dbg(p_access, "plugin connected");
215
216         p_sys->eyetvSock = peerSock;
217
218         /* remove public access */
219         close(publicSock);
220         unlink(publicAddr.sun_path);
221     }
222     return VLC_SUCCESS;
223 }
224
225 /*****************************************************************************
226  * Close: closes msg-port, free resources
227  *****************************************************************************/
228 static void Close(vlc_object_t *p_this)
229 {
230     access_t     *p_access = (access_t *)p_this;
231     access_sys_t *p_sys = p_access->p_sys;
232
233     msg_Dbg(p_access, "closing");
234
235     /* tell the EyeTV plugin to close its msg port and stop sending */
236     CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter (),
237                                           CFSTR("VLCAccessStopDataSending"),
238                                           CFSTR("VLCEyeTVSupport"),
239                                           /*userInfo*/ NULL,
240                                           TRUE);
241     msg_Dbg(p_access, "plugin notified");
242
243     close(p_sys->eyetvSock);
244     msg_Dbg(p_access, "msg port closed and freed");
245
246     free(p_sys);
247 }
248
249 /*****************************************************************************
250 * BlockRead: forwarding data from EyeTV plugin which was received above
251 *****************************************************************************/
252 static block_t *BlockRead(access_t *p_access)
253 {
254     access_sys_t *p_sys = p_access->p_sys;
255     block_t      *p_block;
256     ssize_t len;
257
258     if (p_access->info.b_eof)
259         return NULL;
260
261     /* Read data */
262     p_block = block_Alloc(MTU);
263     len = net_Read(p_access, p_sys->eyetvSock, NULL,
264                     p_block->p_buffer, MTU, false);
265
266     if (len < 0) {
267         block_Release(p_block);
268         return NULL;
269     }
270
271     return block_Realloc(p_block, 0, p_block->i_buffer = len);
272 }
273
274 /*****************************************************************************
275  * Control:
276  *****************************************************************************/
277 static int Control(access_t *p_access, int i_query, va_list args)
278 {
279     bool   *pb_bool;
280     int          *pi_int;
281     int64_t      *pi_64;
282     access_sys_t  *p_sys = (access_sys_t *) p_access->p_sys;
283
284     switch(i_query) {
285         case ACCESS_CAN_SEEK:
286         case ACCESS_CAN_FASTSEEK:
287             pb_bool = (bool*)va_arg(args, bool*);
288             *pb_bool = false;
289             break;
290         case ACCESS_CAN_PAUSE:
291             pb_bool = (bool*)va_arg(args, bool*);
292             *pb_bool = false;
293             break;
294         case ACCESS_CAN_CONTROL_PACE:
295             pb_bool = (bool*)va_arg(args, bool*);
296             *pb_bool = false;
297             break;
298         case ACCESS_GET_PTS_DELAY:
299             pi_64 = (int64_t*)va_arg(args, int64_t *);
300             *pi_64 =
301                 INT64_C(1000) * var_InheritInteger(p_access, "live-caching");
302             break;
303         default:
304             return VLC_EGENERIC;
305     }
306     return VLC_SUCCESS;
307 }