1 /*****************************************************************************
2 * eyetv.c : Access module to connect to our plugin running within EyeTV
3 *****************************************************************************
4 * Copyright (C) 2006-2007 the VideoLAN team
5 * $Id: eyetv.c 23509 2007-12-09 17:39:28Z courmisch $
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 *****************************************************************************/
29 #include <vlc_access.h>
31 #include <vlc_network.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
38 #import <Foundation/Foundation.h>
41 * watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Open ( vlc_object_t * );
47 static void Close( vlc_object_t * );
49 #define CHANNEL_TEXT N_("Channel number")
50 #define CHANNEL_LONGTEXT N_( \
51 "EyeTV program number, or use 0 for last channel, " \
52 "-1 for S-Video input, -2 for Composite input" )
54 set_shortname( "EyeTV" );
55 set_description( _("EyeTV access module") );
56 set_category( CAT_INPUT );
57 set_subcategory( SUBCAT_INPUT_ACCESS );
59 add_integer( "eyetv-channel", 0, NULL,
60 CHANNEL_TEXT, CHANNEL_LONGTEXT, VLC_FALSE );
62 set_capability( "access2", 0 );
63 add_shortcut( "eyetv" );
64 set_callbacks( Open, Close );
67 /*****************************************************************************
68 * Access: local prototypes
69 *****************************************************************************/
75 static ssize_t Read( access_t *, uint8_t *, size_t );
76 static int Control( access_t *, int, va_list );
78 static void selectChannel( vlc_object_t *p_this, int theChannelNum )
80 NSAppleScript *script;
81 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
82 switch( theChannelNum )
85 script = [[NSAppleScript alloc] initWithSource:
86 @"tell application \"EyeTV\"\n"
87 " input_change input source composite video input\n"
88 " volume_change level 0\n"
89 " show player_window\n"
90 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
94 script = [[NSAppleScript alloc] initWithSource:
95 @"tell application \"EyeTV\"\n"
96 " input_change input source S video input\n"
97 " volume_change level 0\n"
98 " show player_window\n"
99 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
103 script = [[NSAppleScript alloc] initWithSource:
104 @"tell application \"EyeTV\"\n"
105 " volume_change level 0\n"
106 " show player_window\n"
107 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
111 if( theChannelNum > 0 )
113 NSString *channel_change = [NSString stringWithFormat:
114 @"tell application \"EyeTV\"\n"
115 " channel_change channel number %d\n"
116 " volume_change level 0\n"
117 " show player_window\n"
118 " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
119 "end tell", theChannelNum];
120 script = [[NSAppleScript alloc] initWithSource:channel_change];
125 NSDictionary *errorDict;
126 NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&errorDict];
127 if( nil == descriptor )
129 NSString *errorString = [errorDict objectForKey:NSAppleScriptErrorMessage];
130 msg_Err( p_this, "EyeTV source change failed with error status '%s'", [errorString UTF8String] );
136 /*****************************************************************************
137 * Open: sets up the module and its threads
138 *****************************************************************************/
139 static int Open( vlc_object_t *p_this )
141 access_t *p_access = (access_t *)p_this;
144 struct sockaddr_un publicAddr, peerAddr;
150 access_InitFields( p_access ); \
151 ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL ); \
152 MALLOC_ERR( p_access->p_sys, access_sys_t ); \
153 p_sys = p_access->p_sys; memset( p_sys, 0, sizeof( access_sys_t ) );
155 var_Create( p_access, "eyetv-channel", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
156 var_Get( p_access, "eyetv-channel", &val);
158 msg_Dbg( p_access, "coming up" );
160 selectChannel(p_this, val.i_int);
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) )
169 msg_Err( p_access, "local socket path is not usable (errno=%d)", errno );
174 publicSock = socket(AF_UNIX, SOCK_STREAM, 0);
175 if( publicSock == -1 )
177 msg_Err( p_access, "create local socket failed (errno=%d)", errno );
182 if( bind(publicSock, (struct sockaddr *)&publicAddr, sizeof(struct sockaddr_un)) == -1 )
184 msg_Err( p_access, "bind local socket failed (errno=%d)", errno );
190 /* we are not expecting more than one connection */
191 if( listen(publicSock, 1) == -1 )
193 msg_Err( p_access, "cannot accept connection (errno=%d)", errno );
200 socklen_t peerSockLen = sizeof(struct sockaddr_un);
203 /* tell the EyeTV plugin to open start sending */
204 CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
205 CFSTR("VLCAccessStartDataSending"),
206 CFSTR("VLCEyeTVSupport"),
210 msg_Dbg( p_access, "plugin notified" );
212 peerSock = accept(publicSock, (struct sockaddr *)&peerAddr, &peerSockLen);
215 msg_Err( p_access, "cannot wait for connection (errno=%d)", errno );
221 msg_Dbg( p_access, "plugin connected" );
223 p_sys->eyetvSock = peerSock;
225 /* remove public access */
227 unlink(publicAddr.sun_path);
232 /*****************************************************************************
233 * Close: closes msg-port, free resources
234 *****************************************************************************/
235 static void Close( vlc_object_t *p_this )
237 access_t *p_access = (access_t *)p_this;
238 access_sys_t *p_sys = p_access->p_sys;
240 msg_Dbg( p_access, "closing" );
242 /* tell the EyeTV plugin to close its msg port and stop sending */
243 CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
244 CFSTR("VLCAccessStopDataSending"),
245 CFSTR("VLCEyeTVSupport"),
249 msg_Dbg( p_access, "plugin notified" );
251 close(p_sys->eyetvSock);
253 msg_Dbg( p_access, "msg port closed and freed" );
258 /*****************************************************************************
259 * Read: forwarding data from EyeTV plugin which was received above
260 *****************************************************************************/
261 static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
263 access_sys_t *p_sys = p_access->p_sys;
266 if( p_access->info.b_eof )
269 i_read = net_Read( p_access, p_sys->eyetvSock, NULL, p_buffer, i_len,
272 p_access->info.b_eof = VLC_TRUE;
273 else if( i_read > 0 )
274 p_access->info.i_pos += i_read;
279 /*****************************************************************************
281 *****************************************************************************/
282 static int Control( access_t *p_access, int i_query, va_list args )
291 case ACCESS_SET_PAUSE_STATE:
295 case ACCESS_CAN_SEEK:
296 case ACCESS_CAN_FASTSEEK:
297 case ACCESS_CAN_PAUSE:
298 case ACCESS_CAN_CONTROL_PACE:
300 case ACCESS_GET_PTS_DELAY:
301 case ACCESS_GET_TITLE_INFO:
302 case ACCESS_SET_TITLE:
303 case ACCESS_SET_SEEKPOINT:
304 case ACCESS_SET_PRIVATE_ID_STATE:
305 case ACCESS_GET_CONTENT_TYPE:
309 msg_Warn( p_access, "unimplemented query in control" );
313 return VLC_SUCCESS;*/