1 /*****************************************************************************
2 * eyetv.c : Access module to connect to our plugin running within EyeTV
3 *****************************************************************************
4 * Copyright (C) 2006-2007 the VideoLAN team
7 * Author: Felix Kühne <fkuehne at videolan dot org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
33 #include <vlc_access.h>
35 #include <vlc_network.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
42 #import <Foundation/Foundation.h>
45 * watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */
47 /*****************************************************************************
49 *****************************************************************************/
50 static int Open ( vlc_object_t * );
51 static void Close( vlc_object_t * );
53 #define CHANNEL_TEXT N_("Channel number")
54 #define CHANNEL_LONGTEXT N_( \
55 "EyeTV program number, or use 0 for last channel, " \
56 "-1 for S-Video input, -2 for Composite input" )
58 set_shortname( "EyeTV" );
59 set_description( _("EyeTV access module") );
60 set_category( CAT_INPUT );
61 set_subcategory( SUBCAT_INPUT_ACCESS );
63 add_integer( "eyetv-channel", 0, NULL,
64 CHANNEL_TEXT, CHANNEL_LONGTEXT, VLC_FALSE );
66 set_capability( "access2", 0 );
67 add_shortcut( "eyetv" );
68 set_callbacks( Open, Close );
71 /*****************************************************************************
72 * Access: local prototypes
73 *****************************************************************************/
79 static ssize_t Read( access_t *, uint8_t *, size_t );
80 static int Control( access_t *, int, va_list );
82 static void selectChannel( vlc_object_t *p_this, int theChannelNum )
84 NSAppleScript *script;
85 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
86 switch( theChannelNum )
89 script = [[NSAppleScript alloc] initWithSource:
90 @"tell application \"EyeTV\"\n"
91 " input_change input source composite video input\n"
92 " volume_change level 0\n"
93 " show player_window\n"
94 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
98 script = [[NSAppleScript alloc] initWithSource:
99 @"tell application \"EyeTV\"\n"
100 " input_change input source S video input\n"
101 " volume_change level 0\n"
102 " show player_window\n"
103 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
107 script = [[NSAppleScript alloc] initWithSource:
108 @"tell application \"EyeTV\"\n"
109 " volume_change level 0\n"
110 " show player_window\n"
111 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
115 if( theChannelNum > 0 )
117 NSString *channel_change = [NSString stringWithFormat:
118 @"tell application \"EyeTV\"\n"
119 " channel_change channel number %d\n"
120 " volume_change level 0\n"
121 " show player_window\n"
122 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
123 "end tell", theChannelNum];
124 script = [[NSAppleScript alloc] initWithSource:channel_change];
129 NSDictionary *errorDict;
130 NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&errorDict];
131 if( nil == descriptor )
133 NSString *errorString = [errorDict objectForKey:NSAppleScriptErrorMessage];
134 msg_Err( p_this, "EyeTV source change failed with error status '%s'", [errorString UTF8String] );
140 /*****************************************************************************
141 * Open: sets up the module and its threads
142 *****************************************************************************/
143 static int Open( vlc_object_t *p_this )
145 access_t *p_access = (access_t *)p_this;
148 struct sockaddr_un publicAddr, peerAddr;
154 access_InitFields( p_access ); \
155 ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL ); \
156 MALLOC_ERR( p_access->p_sys, access_sys_t ); \
157 p_sys = p_access->p_sys; memset( p_sys, 0, sizeof( access_sys_t ) );
159 var_Create( p_access, "eyetv-channel", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
160 var_Get( p_access, "eyetv-channel", &val);
162 msg_Dbg( p_access, "coming up" );
164 selectChannel(p_this, val.i_int);
167 memset(&publicAddr, 0, sizeof(publicAddr));
168 publicAddr.sun_family = AF_UNIX;
169 strncpy(publicAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(publicAddr.sun_path)-1);
170 /* remove previous public path if it wasn't cleanly removed */
171 if( (0 != unlink(publicAddr.sun_path)) && (ENOENT != errno) )
173 msg_Err( p_access, "local socket path is not usable (errno=%d)", errno );
178 publicSock = socket(AF_UNIX, SOCK_STREAM, 0);
179 if( publicSock == -1 )
181 msg_Err( p_access, "create local socket failed (errno=%d)", errno );
186 if( bind(publicSock, (struct sockaddr *)&publicAddr, sizeof(struct sockaddr_un)) == -1 )
188 msg_Err( p_access, "bind local socket failed (errno=%d)", errno );
194 /* we are not expecting more than one connection */
195 if( listen(publicSock, 1) == -1 )
197 msg_Err( p_access, "cannot accept connection (errno=%d)", errno );
204 socklen_t peerSockLen = sizeof(struct sockaddr_un);
207 /* tell the EyeTV plugin to open start sending */
208 CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
209 CFSTR("VLCAccessStartDataSending"),
210 CFSTR("VLCEyeTVSupport"),
214 msg_Dbg( p_access, "plugin notified" );
216 peerSock = accept(publicSock, (struct sockaddr *)&peerAddr, &peerSockLen);
219 msg_Err( p_access, "cannot wait for connection (errno=%d)", errno );
225 msg_Dbg( p_access, "plugin connected" );
227 p_sys->eyetvSock = peerSock;
229 /* remove public access */
231 unlink(publicAddr.sun_path);
236 /*****************************************************************************
237 * Close: closes msg-port, free resources
238 *****************************************************************************/
239 static void Close( vlc_object_t *p_this )
241 access_t *p_access = (access_t *)p_this;
242 access_sys_t *p_sys = p_access->p_sys;
244 msg_Dbg( p_access, "closing" );
246 /* tell the EyeTV plugin to close its msg port and stop sending */
247 CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
248 CFSTR("VLCAccessStopDataSending"),
249 CFSTR("VLCEyeTVSupport"),
253 msg_Dbg( p_access, "plugin notified" );
255 close(p_sys->eyetvSock);
257 msg_Dbg( p_access, "msg port closed and freed" );
262 /*****************************************************************************
263 * Read: forwarding data from EyeTV plugin which was received above
264 *****************************************************************************/
265 static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
267 access_sys_t *p_sys = p_access->p_sys;
270 if( p_access->info.b_eof )
273 i_read = net_Read( p_access, p_sys->eyetvSock, NULL, p_buffer, i_len,
276 p_access->info.b_eof = VLC_TRUE;
277 else if( i_read > 0 )
278 p_access->info.i_pos += i_read;
283 /*****************************************************************************
285 *****************************************************************************/
286 static int Control( access_t *p_access, int i_query, va_list args )
295 case ACCESS_SET_PAUSE_STATE:
299 case ACCESS_CAN_SEEK:
300 case ACCESS_CAN_FASTSEEK:
301 case ACCESS_CAN_PAUSE:
302 case ACCESS_CAN_CONTROL_PACE:
304 case ACCESS_GET_PTS_DELAY:
305 case ACCESS_GET_TITLE_INFO:
306 case ACCESS_SET_TITLE:
307 case ACCESS_SET_SEEKPOINT:
308 case ACCESS_SET_PRIVATE_ID_STATE:
309 case ACCESS_GET_CONTENT_TYPE:
313 msg_Warn( p_access, "unimplemented query in control" );
317 return VLC_SUCCESS;*/