* forward-port of all eyetv relates sources in my branch
authorFelix Paul Kühne <fkuehne@videolan.org>
Mon, 5 Mar 2007 18:15:27 +0000 (18:15 +0000)
committerFelix Paul Kühne <fkuehne@videolan.org>
Mon, 5 Mar 2007 18:15:27 +0000 (18:15 +0000)
    - this stuff is highly unfinished; needs much more work and testing
    - don't be surprised if you don't see anything when trying it out, this port is basically a big reminder for me to keep working on it ;-)
    - the access module is probably going to be ported from CoreFoundation-driven C to Cocoa-based Obj-C
    - everything will be 10.4-only, since EyeTV is only available this way as well
    - the plugin to put into EyeTV is compiled in UB-mode by default and incorporates Public Domain code provided by Elgato Systems GmbH

16 files changed:
configure.ac
extras/MacOSX/eyetvplugin/English.lproj/InfoPlist.strings [new file with mode: 0644]
extras/MacOSX/eyetvplugin/EyeTVPluginDefs.h [new file with mode: 0644]
extras/MacOSX/eyetvplugin/Info.plist [new file with mode: 0644]
extras/MacOSX/eyetvplugin/eyetvplugin.c [new file with mode: 0644]
extras/MacOSX/eyetvplugin/eyetvplugin.h [new file with mode: 0644]
extras/MacOSX/eyetvplugin/eyetvplugin.xcodeproj/project.pbxproj [new file with mode: 0644]
modules/access/Modules.am
modules/access/eyetv.c [new file with mode: 0644]
modules/gui/macosx/Modules.am
modules/gui/macosx/eyetv.h [new file with mode: 0644]
modules/gui/macosx/eyetv.m [new file with mode: 0644]
modules/gui/macosx/intf.h
modules/gui/macosx/intf.m
modules/gui/macosx/open.h
modules/gui/macosx/open.m

index 6929989..bc34af8 100644 (file)
@@ -5030,13 +5030,16 @@ AC_ARG_ENABLE(macosx,
   [  --enable-macosx         MacOS X support (default enabled on MacOS X)],
   [if test "${enable_macosx}" = "yes"
    then
-     VLC_ADD_BUILTINS([macosx])
-     VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL])
+     VLC_ADD_PLUGINS([access_eyetv])
+     VLC_ADD_LDFLAGS([access_eyetv], [-framework CoreFoundation])
+     VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL -framework QTKit])
      VLC_ADD_OBJCFLAGS( [macosx],[-fobjc-exceptions] )
    fi],
   [AC_CHECK_HEADERS(Cocoa/Cocoa.h,
+     VLC_ADD_PLUGINS([access_eyetv])
+     VLC_ADD_LDFLAGS([access_eyetv], [-framework CoreFoundation])
      VLC_ADD_BUILTINS([macosx])
-     VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL])
+     VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL -framework QTKit])
      VLC_ADD_OBJCFLAGS( [macosx],[-fobjc-exceptions] )
    )])
 CFLAGS=$ORIGCFLAGS
diff --git a/extras/MacOSX/eyetvplugin/English.lproj/InfoPlist.strings b/extras/MacOSX/eyetvplugin/English.lproj/InfoPlist.strings
new file mode 100644 (file)
index 0000000..decf297
Binary files /dev/null and b/extras/MacOSX/eyetvplugin/English.lproj/InfoPlist.strings differ
diff --git a/extras/MacOSX/eyetvplugin/EyeTVPluginDefs.h b/extras/MacOSX/eyetvplugin/EyeTVPluginDefs.h
new file mode 100644 (file)
index 0000000..0343e8b
--- /dev/null
@@ -0,0 +1,233 @@
+/* This is public domain code developed by Elgato Systems GmbH. No GPL-covered \r
+ * changes were added to this file by any members of the VideoLAN team. If you\r
+ * want to do so, add a modified GPL header here, but keep a message emphasising\r
+ * the non-licensed parts of this header file. \r
+ * Ideally, VideoLAN-related changes should only go to eyetvplugin.h.\r
+ * \r
+ * $Id$\r
+ */\r
+\r
+\r
+#pragma once\r
+\r
+/*\r
+\r
+       The EyeTV Plugin API\r
+       ====================\r
+       \r
+       The EyeTV Software gives third parties access to the incoming MPEG-2 transport stream. \r
+       At this time the API is available for the following products:\r
+               \r
+               - EyeTV 200 (analog)\r
+               - EyeTV 300 (DVB-S) \r
+               - EyeTV 400 (DVB-T)\r
+               \r
+       A plugin receives device plugged/unplugged notifications, it can request or release \r
+       individual PIDs and most importantly it has access to transport stream packets in \r
+       real time, as they arrive from the device.  Note that the plugin is called before EyeTV \r
+       itself looks at the packets, so it is even possible to modify the data.\r
+       \r
+       Plugins currently live in EyeTV.app/Contens/Plugins/\r
+       \r
+       A plugin is packaged as a bundle with a single entry point:\r
+       \r
+               long EyeTVPluginDispatcher(EyeTVPluginSelector                  selector,  \r
+                                                                               void                                    *refCon, \r
+                                                                               EyeTVPluginDeviceID             deviceID, \r
+                                                                               long                                    param1, \r
+                                                                               long                                    param2,  \r
+                                                                               long                                    param3, \r
+                                                                               long                                    param4);\r
+\r
+       \r
+       PID Filtering\r
+       =============\r
+       \r
+       EyeTV employs both hardware and software PID filtering.  A plugin's dispatch routine \r
+       is called with the kEyeTVPluginSelector_PacketsArrived selector after the hardware \r
+       PID filter (naturally) but prior to the software PID filter, so the plugin has access \r
+       to all packets that are delivered by the hardware.  \r
+       \r
+       A plugin can request PIDs that are not needed by EyeTV from the hardware PID filter by \r
+       means of a callback routine, see eyeTVPluginSelector_SetCallback.\r
+\r
+       Note that hardware PID filtering is on for single processor machines (to reduce the CPU \r
+       load), but off for multi-processor machines (to improve channel switch times).  \r
+       This behaviour is controlled by the "hardware PID filter" key in com.elgato.eyetv.plist, \r
+       which defaults to "Auto" ("Off" on MP machines, "On" on single-processor machines).  EyeTV\r
+       does not offer GUI to change this setting.  A plugin hence needs to be prepared to handle \r
+       both an entire transponder or multiplex and to request PIDs it might need.\r
+       \r
+       Note that the plugin is called on the real-time thread that receives the transport stream\r
+       packets and that the packet buffers passed to the plugin are the actual hardware DMA buffers.\r
+       Please return as quickly as possible from the kEyeTVPluginSelector_PacketsArrived call and\r
+       avoid blocking the calling thread.\r
+\r
+\r
+\r
+\r
+\r
+       Revision History:\r
+\r
+       02/27/2004:             Initial Release.\r
+\r
+*/\r
+       \r
+\r
+\r
+#define EYETV_PLUGIN_API_VERSION                               0x04021901\r
+#define EYETV_PLUGIN_API_MIN_VERSION                   0x04021901\r
+\r
+typedef long long      EyeTVPluginDeviceID;\r
+typedef long           EyeTVPluginDeviceType;\r
+typedef long           EyeTVPluginSelector;\r
+\r
+enum {\r
+       kEyeTVPIDType_Video             = 0,\r
+       kEyeTVPIDType_MPEGAudio         = 1,\r
+       kEyeTVPIDType_VBI                       = 2, /* teletext */\r
+       kEyeTVPIDType_PCR                       = 3,\r
+       kEyeTVPIDType_PMT                       = 4,\r
+       kEyeTVPIDType_Unknown           = 5,\r
+       kEyeTVPIDType_AC3Audio          = 6\r
+};\r
+\r
+\r
+typedef struct EyeTVPluginPIDInfo EyeTVPluginPIDInfo;\r
+struct EyeTVPluginPIDInfo {\r
+       long                                    pid;\r
+       long                                    pidType;        \r
+};\r
+\r
+\r
+\r
+/***********************************************************************************\r
+*\r
+*      EyeTVPluginCallbackParams,\r
+*\r
+***********************************************************************************/\r
+enum {\r
+       kEyeTVPluginCallbackSelector_RetainPIDs = 0,    \r
+       kEyeTVPluginCallbackSelector_ReleasePIDs = 1            \r
+};\r
+\r
+typedef struct EyeTVPluginCallbackParams EyeTVPluginCallbackParams;  \r
+struct EyeTVPluginCallbackParams {\r
+       EyeTVPluginDeviceID             deviceID;       //      the deviceID\r
+       long                                    selector;       //      callback selector, see above\r
+       long                                    *pids;          //      list of pids to release/retain\r
+       long                                    pidsCount;      //      count of pids\r
+};\r
+\r
+\r
+/***********************************************************************************\r
+*\r
+*      typedef for the callback function,\r
+*\r
+***********************************************************************************/\r
+typedef long(* EyeTVPluginCallbackProc)(EyeTVPluginCallbackParams *params);\r
+\r
+\r
+\r
+/***********************************************************************************\r
+*\r
+*      EyeTVPluginParamStructs\r
+*\r
+***********************************************************************************/\r
+\r
+\r
+typedef struct EyeTVPluginInitializeParams     EyeTVPluginInitializeParams;\r
+struct EyeTVPluginInitializeParams {\r
+       long                                                    apiVersion;             // version of the EyeTV_PLUGIN_API\r
+       EyeTVPluginCallbackProc                 callback;               // the callback\r
+}; /* 8 bytes */\r
+\r
+\r
+\r
+typedef struct EyeTVPluginGetInfoParams        EyeTVPluginGetInfoParams;\r
+struct EyeTVPluginGetInfoParams {\r
+       long                                                    *pluginAPIVersion;              // <- EYETV_PLUGIN_API_VERSION\r
+       char                                                    *pluginName;            // <- points to a 128-byte buffer, the plugin is expected to fill the buffer with\r
+                                                                                                               //        a UTF-8 encoded string.       \r
+       char                                                    *description;           // <- points to a 1024-byte buffer, the plugin is expected to fill the buffer with\r
+                                                                                                               //        a UTF-8 encoded string describing the plugin.\r
+}; /* 12 bytes */\r
+\r
+\r
+\r
+enum {\r
+       kEyeTVPluginDeviceType_Unknown = 0,     \r
+       kEyeTVPluginDeviceType_e200 = 1,\r
+       kEyeTVPluginDeviceType_e300 = 2,\r
+       kEyeTVPluginDeviceType_e400 = 3\r
+} ;\r
+\r
+typedef struct EyeTVPluginDeviceAddedParams EyeTVPluginDeviceAddedParams;\r
+struct EyeTVPluginDeviceAddedParams {\r
+       EyeTVPluginDeviceType                   deviceType;             \r
+}; /* 4 bytes */\r
+\r
+\r
+typedef struct EyeTVPluginPacketsArrivedParams EyeTVPluginPacketsArrivedParams;\r
+struct EyeTVPluginPacketsArrivedParams {\r
+       long                                                    **packets;              // points to an array of packets\r
+       long                                                    packetCount;    \r
+}; /* 8 bytes */\r
+\r
+\r
+\r
+typedef struct EyeTVPluginServiceChangedParams EyeTVPluginServiceChangedParams;\r
+struct EyeTVPluginServiceChangedParams {\r
+       long                                                    headendID;              // new headend ID. For E300 it's the orbital position of the satellite\r
+                                                                                                       // in tenth of a degree\r
+       long                                                    transponderID;  // new transponder ID (The Frequency in kHz)\r
+       long                                                    serviceID;              // new service ID (the ID of the used service as included in the DVB Stream)\r
+       EyeTVPluginPIDInfo                              *pidList;               // points to the list of active PIDs;\r
+       long                                                    pidCount;               // the length of pidList\r
+}; /* 20 bytes */\r
+\r
+\r
+\r
+\r
+/***********************************************************************************\r
+*\r
+*      EyeTVPluginParams\r
+*              \r
+***********************************************************************************/\r
+typedef struct EyeTVPluginParams EyeTVPluginParams;\r
+struct EyeTVPluginParams {\r
+       EyeTVPluginDeviceID             deviceID;       // ID of the device\r
+       EyeTVPluginSelector             selector;       // selector\r
+       void                                    *refCon;        // refCon\r
+\r
+       union {                                                                                         \r
+               EyeTVPluginInitializeParams                     initialize;                     // kEyeTVPluginSelector_Initialize\r
+                                                                                                                               // kEyeTVPluginSelector_Terminate, no additional parameters\r
+               EyeTVPluginGetInfoParams                        info;                           // kEyeTVPluginSelector_GetInfo\r
+               EyeTVPluginDeviceAddedParams            deviceAdded;            // kEyeTVPluginSelector_DeviceAdded\r
+                                                                                                                               // kEyeTVPluginSelector_DeviceRemoved, no additional parameters\r
+               EyeTVPluginPacketsArrivedParams         packetsArrived;         // kEyeTVPluginSelector_PacketsArrived\r
+               EyeTVPluginServiceChangedParams         serviceChanged;         // kEyeTVPluginSelector_ServiceChanged\r
+       \r
+       };\r
+};\r
+\r
+\r
+enum {         // EyeTVPluginSelector\r
+       kEyeTVPluginSelector_Initialize = 0,            \r
+       kEyeTVPluginSelector_Terminate = 1,                     \r
+       kEyeTVPluginSelector_GetInfo = 2,                       \r
+       kEyeTVPluginSelector_DeviceAdded = 3,           \r
+       kEyeTVPluginSelector_DeviceRemoved = 4,         \r
+       kEyeTVPluginSelector_PacketsArrived = 5,        \r
+       kEyeTVPluginSelector_ServiceChanged = 6 \r
+};                                             \r
+\r
+\r
+\r
+/***********************************************************************************\r
+*\r
+*      EyeTVPluginEntryProc\r
+*\r
+***********************************************************************************/\r
+typedef long(* EyeTVPluginEntryProc)(EyeTVPluginParams *params);\r
diff --git a/extras/MacOSX/eyetvplugin/Info.plist b/extras/MacOSX/eyetvplugin/Info.plist
new file mode 100644 (file)
index 0000000..b502a44
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>English</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleName</key>
+       <string>${PRODUCT_NAME}</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>org.videolan.vlceyetvplugin</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0</string>
+       <key>CFPlugInDynamicRegisterFunction</key>
+       <string></string>
+       <key>CFPlugInDynamicRegistration</key>
+       <string>NO</string>
+       <key>CFPlugInFactories</key>
+       <dict>
+               <key>00000000-0000-0000-0000-000000000000</key>
+               <string>MyFactoryFunction</string>
+       </dict>
+       <key>CFPlugInTypes</key>
+       <dict>
+               <key>00000000-0000-0000-0000-000000000000</key>
+               <array>
+                       <string>00000000-0000-0000-0000-000000000000</string>
+               </array>
+       </dict>
+       <key>CFPlugInUnloadFunction</key>
+       <string></string>
+</dict>
+</plist>
diff --git a/extras/MacOSX/eyetvplugin/eyetvplugin.c b/extras/MacOSX/eyetvplugin/eyetvplugin.c
new file mode 100644 (file)
index 0000000..41363da
--- /dev/null
@@ -0,0 +1,629 @@
+/*****************************************************************************\r
+* eyetvplugin.c: Plug-In for the EyeTV software to connect to VLC\r
+*****************************************************************************\r
+* Copyright (C) 2006-2007 the VideoLAN team\r
+* $Id$\r
+*\r
+* Authors: Felix Kühne <fkuehne at videolan dot org>\r
+*\r
+* This program is free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* This program is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with this program; if not, write to the Free Software\r
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\r
+*****************************************************************************/\r
+\r
+#include "eyetvplugin.h"\r
+\r
+#define MAX_PIDS                       256\r
+#define MAX_ACTIVE_PIDS                256\r
+#define MAX_DEVICES                    16\r
+#define VLC_NOTIFICATION_OBJECT "VLCEyeTVSupport"\r
+\r
+#pragma push\r
+#pragma pack(1)\r
+\r
+\r
+/* Structure for TS-Packets */\r
+typedef struct \r
+{\r
+       unsigned long                   sync_byte : 8,\r
+                                                       transport_error_indicator : 1,\r
+                                                       payload_unit_start_indicator : 1,\r
+                                                       transport_priority : 1,\r
+                                                       PID : 13,\r
+                                                       transport_scrambling_control : 2,\r
+                                                       adaptation_field_control : 2,\r
+                                                       continuity_counter : 4;\r
+\r
+       unsigned char                   data[188-4];\r
+\r
+} TransportStreamPacket;\r
+\r
+#pragma pop\r
+\r
+\r
+/* Structure to hold Information on devices */\r
+typedef struct\r
+{\r
+       EyeTVPluginDeviceID                     deviceID;\r
+       EyeTVPluginDeviceType           deviceType;\r
+\r
+       long                                            headendID;\r
+       long                                            transponderID;\r
+       long                                            serviceID;\r
+\r
+       long                                            pidsCount;\r
+       long                                            pids[MAX_PIDS];\r
+\r
+       EyeTVPluginPIDInfo                      activePIDs[MAX_ACTIVE_PIDS];\r
+       long                                            activePIDsCount;\r
+\r
+} DeviceInfo;\r
+\r
+\r
+/* Structure to hold global data to communicate with EyeTV */\r
+typedef struct \r
+{\r
+       EyeTVPluginCallbackProc                 callback;\r
+       long                                                    deviceCount;\r
+       DeviceInfo                                              devices[MAX_DEVICES];\r
+       long long                                               packetCount;\r
+\r
+} VLCEyeTVPluginGlobals_t;\r
+\r
+/* 2nd structure to store our own global data which isn't shared with EyeTV\r
+ * a bit empty at the moment, but it will get larger as development progresses */\r
+typedef struct\r
+{\r
+    int                     i_deviceCount;\r
+    CFMessagePortRef        messagePortToVLC;\r
+    bool                    b_msgPortOpen;\r
+} VLCEyeTVPluginOwnGlobals_t;\r
+\r
+VLCEyeTVPluginOwnGlobals_t *nativeGlobals;\r
+\r
+\r
+/* return the DeviceInfo with ID deviceID */\r
+static DeviceInfo *GetDeviceInfo(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID)\r
+{\r
+       int i;\r
+       \r
+       if( globals ) \r
+       {\r
+               for( i=0; i<globals->deviceCount; i++) \r
+               {\r
+                       if( globals->devices[i].deviceID == deviceID ) \r
+                       {\r
+                               return &globals->devices[i];\r
+                       }\r
+               }\r
+       }\r
+\r
+       return NULL;\r
+}\r
+\r
+#pragma mark -\r
+\r
+/* initialise the plug-in */\r
+static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long apiVersion, EyeTVPluginCallbackProc callback)\r
+{\r
+       printf("VLC media player Plug-In: Initialize\n");\r
+       long result = 0;\r
+    \r
+    /* init our own storage */\r
+    extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;\r
+    nativeGlobals = malloc( sizeof( VLCEyeTVPluginOwnGlobals_t ) );\r
+    \r
+    /* notify a potential VLC instance about our initialisation */\r
+    CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),\r
+                                          CFSTR("PluginInit"), \r
+                                          CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                          /*userInfo*/ NULL, \r
+                                          TRUE );\r
+    \r
+    /* init our notification support */\r
+    CFNotificationCenterAddObserver( CFNotificationCenterGetDistributedCenter(),\r
+                                     /* observer */ NULL, \r
+                                     /* callBack */ VLCEyeTVPluginGlobalNotificationReceived,\r
+                                     /* name, NULL==all */ NULL,\r
+                                     CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                     CFNotificationSuspensionBehaviorDeliverImmediately );\r
+       \r
+       *globals = (VLCEyeTVPluginGlobals_t *) calloc(1, sizeof( VLCEyeTVPluginGlobals_t ) );\r
+       ( *globals )->callback = callback;\r
+               \r
+       return result;\r
+}\r
+\r
+/* we will be terminated soon, clean up */\r
+static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals)\r
+{\r
+    extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;\r
+    \r
+       printf("VLC media player Plug-In: Terminate\n");\r
+       \r
+       long result = 0;\r
+       \r
+    /* notify a potential VLC instance about our termination */\r
+    CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),\r
+                                          CFSTR("PluginQuit"), \r
+                                          CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                          /*userInfo*/ NULL, \r
+                                          TRUE );\r
+    \r
+    /* remove us from the global notification centre */\r
+    CFNotificationCenterRemoveEveryObserver( CFNotificationCenterGetDistributedCenter(),\r
+                                             (void *)VLCEyeTVPluginGlobalNotificationReceived );\r
+    \r
+    /* invalidate and free msg port */\r
+    if( nativeGlobals->messagePortToVLC )\r
+    {\r
+        CFMessagePortInvalidate( nativeGlobals->messagePortToVLC );\r
+       free( nativeGlobals->messagePortToVLC );\r
+        printf( "msgport invalidated and freed\n" );\r
+    }\r
+    else\r
+        printf( "no msgport to free\n" );\r
+    \r
+       if( globals ) \r
+       {\r
+               free( globals );\r
+       }\r
+\r
+    if( nativeGlobals )\r
+        free( nativeGlobals );\r
+    \r
+       return result;\r
+}\r
+\r
+/* called when EyeTV asks various stuff about us */\r
+static long VLCEyeTVPluginGetInformation(VLCEyeTVPluginGlobals_t *globals, long* outAPIVersion, char* outName, char *outDescription)\r
+{\r
+       printf("VLC media player Plug-In: GetInfo\n");\r
+       long result = 0;\r
+       \r
+       if( globals ) \r
+       {\r
+               if( outAPIVersion )\r
+               {\r
+                       *outAPIVersion = EYETV_PLUGIN_API_VERSION;\r
+               }\r
+               \r
+               if( outName )\r
+               {\r
+                       char* name = "VLC media player Plug-In";\r
+                       strcpy( &outName[0], name);\r
+               }\r
+               \r
+               if( outDescription )\r
+               {\r
+                       char* desc = "This Plug-In connects EyeTV to the VLC media player for streaming purposes.";\r
+                       strcpy( &outDescription[0], desc);\r
+               }\r
+       }\r
+       \r
+       return result;\r
+}\r
+\r
+/* called if we received a global notification */\r
+void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, \r
+                                              void *observer, \r
+                                              CFStringRef name, \r
+                                              const void *object, \r
+                                              CFDictionaryRef userInfo )\r
+{\r
+    CFIndex maxlen;\r
+    char *theName, *theObject;\r
+    extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;\r
+\r
+    maxlen = CFStringGetMaximumSizeForEncoding( CFStringGetLength( name ),\r
+                                                kCFStringEncodingUTF8) + 1;\r
+    theName = malloc(maxlen);\r
+    CFStringGetCString( name, \r
+                        theName, \r
+                        maxlen,\r
+                        kCFStringEncodingUTF8);\r
+    \r
+    maxlen = CFStringGetMaximumSizeForEncoding( CFStringGetLength( name ),\r
+                                                kCFStringEncodingUTF8) + 1;\r
+    theObject = malloc(maxlen);\r
+    CFStringGetCString( object, \r
+                        theObject, \r
+                        maxlen,\r
+                        kCFStringEncodingUTF8);\r
+    printf( "notication received with name: %s and object: %s\n", theName, theObject );\r
+    \r
+    /* when VLC launches after us, we need to inform it about our existance and the current state of available devices */\r
+    if( CFStringCompare( name, CFSTR( "VLCOSXGUIInit" ), 0) == kCFCompareEqualTo )\r
+    {\r
+        /* we're here */\r
+        CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),\r
+                                              CFSTR("PluginInit"), \r
+                                              CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                              /*userInfo*/ NULL, \r
+                                              TRUE );\r
+        if( nativeGlobals && ( nativeGlobals->i_deviceCount > 0 ) )\r
+        {\r
+            /* at least one device is apparently connected */\r
+            CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),\r
+                                                  CFSTR("DeviceAdded"), \r
+                                                  CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                                  /*userInfo*/ NULL, \r
+                                                  TRUE );\r
+        }\r
+    }\r
+    \r
+    /* VLC wants us to start sending data */\r
+    if( CFStringCompare( name, CFSTR( "VLCAccessStartDataSending" ), 0) == kCFCompareEqualTo )\r
+    {\r
+        nativeGlobals->messagePortToVLC = CFMessagePortCreateRemote( kCFAllocatorDefault,\r
+                                                                     CFSTR("VLCEyeTVMsgPort") );\r
+        if( nativeGlobals->messagePortToVLC == NULL )\r
+            printf( "getting messagePortToVLC failed!\n" );\r
+        else\r
+        {\r
+            nativeGlobals->b_msgPortOpen = TRUE;\r
+            printf( "msg port opened / data sending switched on\n" );\r
+        }\r
+    }\r
+    \r
+    /* VLC wants us to stop sending data */\r
+    if( CFStringCompare( name, CFSTR( "VLCAccessStopDataSending" ), 0) == kCFCompareEqualTo )\r
+    {\r
+        nativeGlobals->b_msgPortOpen = FALSE;\r
+        printf( "data sending switched off\n" );\r
+    }\r
+}\r
+\r
+/* called if a device is added */\r
+static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, EyeTVPluginDeviceType deviceType)\r
+{\r
+       printf("VLC media player Plug-In: Device with type %i and ID %i added\n", (int)deviceType, (int)deviceID);\r
+    \r
+       long result = 0;\r
+       DeviceInfo *deviceInfo;\r
+    extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;\r
+    \r
+       \r
+       if( globals ) \r
+       {\r
+               if( globals->deviceCount < MAX_DEVICES ) \r
+               {\r
+                       deviceInfo = &( globals->devices[globals->deviceCount] );\r
+                       memset(deviceInfo, 0, sizeof(DeviceInfo));\r
+                       \r
+                       deviceInfo->deviceID = deviceID;\r
+                       deviceInfo->deviceType = deviceType;\r
+\r
+                       globals->deviceCount++;\r
+\r
+            if( nativeGlobals )\r
+                nativeGlobals->i_deviceCount = globals->deviceCount;\r
+\r
+            /* notify a potential VLC instance about the addition */\r
+            CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),\r
+                                                  CFSTR("DeviceAdded"), \r
+                                                  CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                                  /*userInfo*/ NULL, \r
+                                                  TRUE );\r
+               }\r
+       }\r
+\r
+       return result;\r
+}\r
+\r
+/* called if a device is removed */\r
+static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID)\r
+{\r
+       printf("VLC media player Plug-In: DeviceRemoved\n");\r
+    \r
+    extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;\r
+       long result = 0;\r
+       int i;\r
+       \r
+       if( globals ) \r
+       {\r
+               for( i = 0; i < globals->deviceCount; i++ )\r
+               {\r
+                       if ( globals->devices[i].deviceID == deviceID ) \r
+                       {\r
+                               globals->deviceCount--;\r
+\r
+                               if( i<globals->deviceCount )\r
+                               {\r
+                                       globals->devices[i] = globals->devices[globals->deviceCount];\r
+                               }\r
+                \r
+                if( nativeGlobals )\r
+                    nativeGlobals->i_deviceCount = globals->deviceCount;\r
+                \r
+                /* notify a potential VLC instance about the removal */\r
+                CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),\r
+                                                      CFSTR("DeviceRemoved"), \r
+                                                      CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                                      /*userInfo*/ NULL, \r
+                                                      TRUE );\r
+                       }\r
+               }\r
+       }\r
+       \r
+       return result;\r
+}\r
+\r
+/* This function is called, whenever packets are received by EyeTV. For reasons of performance,\r
+ * the data is the original data, not a copy. That means, EyeTV waits until this method is \r
+ * finished. Therefore all in this method should be as fast as possible. */\r
+int i=0;\r
+static long VLCEyeTVPluginPacketsArrived(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, long **packets, long packetsCount)\r
+{\r
+       long                                result = 0;\r
+       int                                 i, j, isNewPID;\r
+       TransportStreamPacket               *packet;\r
+    extern VLCEyeTVPluginOwnGlobals_t   *nativeGlobals;\r
+    SInt32                              i_returnValue;\r
+    CFMutableDataRef                    theMutableRef;\r
+    uint8_t                             *p_bufferForSending = malloc(4);\r
+    bool                                b_nonSendData;\r
+    int                                 i_lastSentPacket;\r
+    \r
+    if( globals && nativeGlobals ) \r
+       {\r
+               DeviceInfo *deviceInfo = GetDeviceInfo(globals, deviceID);\r
+\r
+               if( deviceInfo ) \r
+               {\r
+            /* alloc the buffer if wanted */\r
+            if( nativeGlobals->b_msgPortOpen == TRUE )\r
+                theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) );\r
+            \r
+            for( i = 0; i < packetsCount; i++ ) \r
+                       {\r
+                               packet = ( TransportStreamPacket* )packets[i];\r
+                               isNewPID = 1;\r
+                               \r
+                               /* search for PID */\r
+                               for( j = 0; j < deviceInfo->pidsCount; j++ ) \r
+                               {\r
+                                       if( packet->PID == deviceInfo->pids[j] ) \r
+                                       {\r
+                                               isNewPID = 0;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                \r
+                               /* add new PIDs to the DeviceInfo */\r
+                               if( isNewPID ) \r
+                               {\r
+                                       printf ("VLC media player Plug-In: SamplePacketsArrived, newPID = %6d\n", packet->PID);\r
+                                       \r
+                                       if( deviceInfo->pidsCount < MAX_PIDS ) \r
+                                       {\r
+                                               deviceInfo->pids[deviceInfo->pidsCount++] = packet->PID;\r
+                                       }\r
+                               }\r
+                               else\r
+                {\r
+                    /* forward data to VLC if wanted */\r
+                    /* FIXME: we only receive ARD for now */\r
+                    if( nativeGlobals->b_msgPortOpen == TRUE && (\r
+                        packet->PID == 1401 ||\r
+                        packet->PID == 1402 ||\r
+                        packet->PID == 1400 ||\r
+                        packet->PID == 1404 ||\r
+                        packet->PID == 3070 ||\r
+                        packet->PID == 3072 ||\r
+                        packet->PID == 3074 ||\r
+                        packet->PID == 5074 ||\r
+                        packet->PID == 0 ||\r
+                        packet->PID == 17 ||\r
+                        packet->PID == 19 ||\r
+                        packet->PID == 20 ) )\r
+                    {\r
+                        /* in a good world, this wouldn't be necessary */\r
+                        if( theMutableRef == NULL )\r
+                            theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) );\r
+                            \r
+                        /* collect data to send larger packets */\r
+                        \r
+                        /* enlarge buffer if necessary */\r
+                        if( i > 0 )\r
+                            CFDataIncreaseLength( theMutableRef, 188 );\r
+                        \r
+                        /* add missing header */\r
+                        memcpy( p_bufferForSending, packet, 4 );\r
+                        CFDataAppendBytes( theMutableRef, p_bufferForSending, sizeof(p_bufferForSending) );\r
+\r
+                        free( p_bufferForSending );\r
+                        p_bufferForSending = malloc(4);\r
+                        \r
+                        /* add payload */\r
+                        CFDataAppendBytes( theMutableRef, packet->data, sizeof(packet->data) );\r
+                        \r
+                        b_nonSendData = TRUE;\r
+                        \r
+                    }\r
+                }\r
+                \r
+                globals->packetCount++;\r
+                \r
+                if( globals->packetCount%10000 == 0 ) \r
+                    printf("->  %lld Packets received so far...\n",globals->packetCount);\r
+            }\r
+\r
+            if( nativeGlobals->b_msgPortOpen == TRUE )\r
+            {\r
+                printf( "sending %i bytes of data\n", CFDataGetLength( theMutableRef ) );\r
+                i_returnValue = CFMessagePortSendRequest( nativeGlobals->messagePortToVLC,\r
+                                                          /* arbitrary int val */ globals->packetCount,\r
+                                                          /* the data */ theMutableRef,\r
+                                                          /* no timeout for sending */ 0,\r
+                                                          /* no timeout for resp */ 0,\r
+                                                          /* no resp. wanted */ NULL,\r
+                                                          NULL );\r
+                b_nonSendData = FALSE;\r
+                i_lastSentPacket = globals->packetCount;\r
+                if( i_returnValue == kCFMessagePortSendTimeout )\r
+                    printf( "time out while sending\n" );\r
+                else if( i_returnValue == kCFMessagePortReceiveTimeout )\r
+                    printf( "time out while waiting for resp\n" );\r
+                else if( i_returnValue == kCFMessagePortIsInvalid )\r
+                {\r
+                    /* suppress any further attemps */ \r
+                    printf( "message port is invalid!\n" );\r
+                    nativeGlobals->b_msgPortOpen = FALSE;\r
+                }\r
+                else if( i_returnValue == kCFMessagePortTransportError ) \r
+                    printf( "transport error while sending!\n" );\r
+                else\r
+                {\r
+                    //printf( "success, freeing resources\n" );\r
+                    free( theMutableRef );\r
+                    theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) );\r
+                }\r
+            }\r
+\r
+        }\r
+       }\r
+    else\r
+        printf( "warning: either globals or nativeGlobals are NIL in VLCEyeTVPluginPacketsArrived" );\r
+\r
+    /* clean up before leaving function */\r
+    //if( nativeGlobals->b_msgPortOpen == TRUE )\r
+     //   free( theMutableRef );\r
+    \r
+    free( p_bufferForSending );\r
+    \r
+       return result;\r
+}\r
+\r
+/*     VLCEyeTVPluginServiceChanged,\r
+ *\r
+ *     - *globals              : The plug-in Globals\r
+ *     - deviceID              : Identifies the active Device\r
+ *   - headendID               : The HeadendID, for e300 it's the orbital position of the satelite in \r
+ *                                       tenth degrees east\r
+ *   - transponderID : The Frequency in kHz\r
+ *   - serviceID               : original ServiceID from the DVB-Stream (e300, e400)\r
+ *     - pidList               : List of active PIDs   \r
+ *\r
+ *     Whenever a service changes, this function is called. Service-related plug-in data should be updated here.\r
+ */\r
+static long VLCEyeTVPluginServiceChanged(VLCEyeTVPluginGlobals_t *globals, \r
+                                                                                       EyeTVPluginDeviceID deviceID, \r
+                                                                                       long headendID, \r
+                                                                                       long transponderID, \r
+                                                                                       long serviceID, \r
+                                                                                       EyeTVPluginPIDInfo *pidList, \r
+                                                                                       long pidsCount)\r
+{\r
+       long result = 0;\r
+       int     i;\r
+       \r
+       printf("\nVLC media player Plug-In: ServiceChanged:\n");\r
+       printf(  "=====================================\n");\r
+       \r
+       if( globals ) \r
+       {\r
+               DeviceInfo *deviceInfo = GetDeviceInfo( globals, deviceID );\r
+               if( deviceInfo ) \r
+               {\r
+                       deviceInfo->headendID = headendID;\r
+                       printf("HeadendID: %ld, ", headendID);\r
+                       \r
+                       deviceInfo->transponderID = transponderID;\r
+                       printf("TransponderID: %ld, ", transponderID);\r
+                       \r
+                       deviceInfo->serviceID = serviceID;\r
+                       printf("ServiceID: %ld\n\n", serviceID);\r
+                       \r
+                       deviceInfo->activePIDsCount = pidsCount;\r
+\r
+                       for( i = 0; i < pidsCount; i++ )\r
+                       {\r
+                               deviceInfo->activePIDs[i] = pidList[i];\r
+                               printf("Active PID: %ld, type: %ld\n", pidList[i].pid, pidList[i].pidType);\r
+                       }\r
+\r
+                       deviceInfo->pidsCount = 0;\r
+                       \r
+               }\r
+       }\r
+       printf(  "=====================================\n");\r
+       \r
+    /* notify a potential VLC instance about the service change */\r
+    CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),\r
+                                          CFSTR("ServiceChanged"), \r
+                                          CFSTR(VLC_NOTIFICATION_OBJECT), \r
+                                          /*userInfo*/ NULL, \r
+                                          TRUE );\r
+    \r
+    return result;\r
+}\r
+\r
+\r
+#pragma mark -\r
+/* EyeTVPluginDispatcher,\r
+ *\r
+ *     - selector : See 'EyeTVPluginDefs.h'\r
+ *     - *refCon :  The RefCon to the plug-in-related Data\r
+ *     - deviceID : Identifies the Device\r
+ *     - params : Parameters for functioncall\r
+ *\r
+ * This function is a part of the interface for the communication with EyeTV. If something happens,\r
+ * EyeTV thinks, we should know of, it calls this function with the corresponding selector. */\r
+\r
+#pragma export on\r
+\r
+long EyeTVPluginDispatcher( EyeTVPluginParams* params )\r
+{\r
+       long result = 0;\r
+\r
+       switch( params->selector ) \r
+       {\r
+               case kEyeTVPluginSelector_Initialize:\r
+                       result = VLCEyeTVPluginInitialize((VLCEyeTVPluginGlobals_t**)params->refCon, \r
+                                                                       params->initialize.apiVersion, params->initialize.callback);\r
+                       break;\r
+                       \r
+               case kEyeTVPluginSelector_Terminate:\r
+                       result = VLCEyeTVPluginTerminate((VLCEyeTVPluginGlobals_t*)params->refCon);\r
+                       break;\r
+\r
+               case kEyeTVPluginSelector_GetInfo:\r
+                       result = VLCEyeTVPluginGetInformation((VLCEyeTVPluginGlobals_t*)params->refCon, \r
+                                                                       params->info.pluginAPIVersion, params->info.pluginName, params->info.description);\r
+                       break;\r
+\r
+               case kEyeTVPluginSelector_DeviceAdded:\r
+                       result = VLCEyeTVPluginDeviceAdded((VLCEyeTVPluginGlobals_t*)params->refCon, \r
+                                                                       params->deviceID, params->deviceAdded.deviceType);\r
+                       break;\r
+               \r
+               case kEyeTVPluginSelector_DeviceRemoved:\r
+                       result = VLCEyeTVPluginDeviceRemoved((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID);\r
+                       break;\r
+\r
+               case kEyeTVPluginSelector_PacketsArrived:\r
+                       result = VLCEyeTVPluginPacketsArrived((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID, \r
+                                                                       params->packetsArrived.packets, params->packetsArrived.packetCount);\r
+                       break;\r
+\r
+               case kEyeTVPluginSelector_ServiceChanged:\r
+                       result = VLCEyeTVPluginServiceChanged((VLCEyeTVPluginGlobals_t*)params->refCon, \r
+                                                                       params->deviceID, params->serviceChanged.headendID, \r
+                                                                       params->serviceChanged.transponderID, params->serviceChanged.serviceID, \r
+                                                                       params->serviceChanged.pidList, params->serviceChanged.pidCount);\r
+                       break;\r
+       }\r
+\r
+       return result;\r
+}\r
diff --git a/extras/MacOSX/eyetvplugin/eyetvplugin.h b/extras/MacOSX/eyetvplugin/eyetvplugin.h
new file mode 100644 (file)
index 0000000..43db147
--- /dev/null
@@ -0,0 +1,34 @@
+/*****************************************************************************\r
+* eyetvplugin.h: Plug-In for the EyeTV software to connect to VLC\r
+*****************************************************************************\r
+* Copyright (C) 2006-2007 the VideoLAN team\r
+* $Id$\r
+*\r
+* Authors: Felix Kühne <fkuehne at videolan dot org>\r
+*\r
+* This program is free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* This program is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with this program; if not, write to the Free Software\r
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\r
+*****************************************************************************/\r
+\r
+#include "EyeTVPluginDefs.h"\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <stdio.h>\r
+#include <CoreFoundation/CoreFoundation.h>\r
+\r
+void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, \r
+                                              void *observer, \r
+                                              CFStringRef name, \r
+                                              const void *object, \r
+                                              CFDictionaryRef userInfo );
\ No newline at end of file
diff --git a/extras/MacOSX/eyetvplugin/eyetvplugin.xcodeproj/project.pbxproj b/extras/MacOSX/eyetvplugin/eyetvplugin.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..50e0f91
--- /dev/null
@@ -0,0 +1,243 @@
+// !$*UTF8*$!
+{
+       archiveVersion = 1;
+       classes = {
+       };
+       objectVersion = 42;
+       objects = {
+
+/* Begin PBXBuildFile section */
+               8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */; };
+               8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; };
+               CC09359B0AE11E6A00647FD0 /* eyetvplugin.c in Sources */ = {isa = PBXBuildFile; fileRef = CC09359A0AE11E6A00647FD0 /* eyetvplugin.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+               089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
+               0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+               8D576316048677EA00EA77CD /* VLC EyeTV Plug-In.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "VLC EyeTV Plug-In.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
+               8D576317048677EA00EA77CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+               CC09359A0AE11E6A00647FD0 /* eyetvplugin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eyetvplugin.c; sourceTree = "<group>"; };
+               CC09359C0AE11E7900647FD0 /* EyeTVPluginDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EyeTVPluginDefs.h; sourceTree = "<group>"; };
+               CC3AE2920AE2E4EE00ACC87C /* eyetvplugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eyetvplugin.h; sourceTree = "<group>"; };
+               CC74BC500AE2714300AD738B /* eyetv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eyetv.c; path = ../../../modules/access/eyetv.c; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+               8D576313048677EA00EA77CD /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+               089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */ = {
+                       isa = PBXGroup;
+                       children = (
+                               CC74BC530AE2715100AD738B /* access module */,
+                               08FB77AFFE84173DC02AAC07 /* Source */,
+                               089C167CFE841241C02AAC07 /* Resources */,
+                               089C1671FE841209C02AAC07 /* External Frameworks and Libraries */,
+                               19C28FB6FE9D52B211CA2CBB /* Products */,
+                       );
+                       name = "VLC EyeTV Plug-In";
+                       sourceTree = "<group>";
+               };
+               089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = {
+                       isa = PBXGroup;
+                       children = (
+                               0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */,
+                       );
+                       name = "External Frameworks and Libraries";
+                       sourceTree = "<group>";
+               };
+               089C167CFE841241C02AAC07 /* Resources */ = {
+                       isa = PBXGroup;
+                       children = (
+                               8D576317048677EA00EA77CD /* Info.plist */,
+                               8D5B49A704867FD3000E48DA /* InfoPlist.strings */,
+                       );
+                       name = Resources;
+                       sourceTree = "<group>";
+               };
+               08FB77AFFE84173DC02AAC07 /* Source */ = {
+                       isa = PBXGroup;
+                       children = (
+                               CC3AE2920AE2E4EE00ACC87C /* eyetvplugin.h */,
+                               CC09359A0AE11E6A00647FD0 /* eyetvplugin.c */,
+                               CC09359C0AE11E7900647FD0 /* EyeTVPluginDefs.h */,
+                       );
+                       name = Source;
+                       sourceTree = "<group>";
+               };
+               19C28FB6FE9D52B211CA2CBB /* Products */ = {
+                       isa = PBXGroup;
+                       children = (
+                               8D576316048677EA00EA77CD /* VLC EyeTV Plug-In.bundle */,
+                       );
+                       name = Products;
+                       sourceTree = "<group>";
+               };
+               CC74BC530AE2715100AD738B /* access module */ = {
+                       isa = PBXGroup;
+                       children = (
+                               CC74BC500AE2714300AD738B /* eyetv.c */,
+                       );
+                       name = "access module";
+                       sourceTree = "<group>";
+               };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+               8D57630D048677EA00EA77CD /* VLC EyeTV Plug-In */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget "VLC EyeTV Plug-In" */;
+                       buildPhases = (
+                               8D57630F048677EA00EA77CD /* Resources */,
+                               8D576311048677EA00EA77CD /* Sources */,
+                               8D576313048677EA00EA77CD /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = "VLC EyeTV Plug-In";
+                       productInstallPath = "$(HOME)/Library/Bundles";
+                       productName = "VLC EyeTV Plug-In";
+                       productReference = 8D576316048677EA00EA77CD /* VLC EyeTV Plug-In.bundle */;
+                       productType = "com.apple.product-type.bundle";
+               };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+               089C1669FE841209C02AAC07 /* Project object */ = {
+                       isa = PBXProject;
+                       buildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject "eyetvplugin" */;
+                       compatibilityVersion = "Xcode 2.4";
+                       hasScannedForEncodings = 1;
+                       mainGroup = 089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */;
+                       projectDirPath = "";
+                       projectRoot = "";
+                       shouldCheckCompatibility = 1;
+                       targets = (
+                               8D57630D048677EA00EA77CD /* VLC EyeTV Plug-In */,
+                       );
+               };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+               8D57630F048677EA00EA77CD /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+               8D576311048677EA00EA77CD /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               CC09359B0AE11E6A00647FD0 /* eyetvplugin.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+               8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               089C167EFE841241C02AAC07 /* English */,
+                       );
+                       name = InfoPlist.strings;
+                       sourceTree = "<group>";
+               };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+               1DEB911B08733D790010E9CD /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               COPY_PHASE_STRIP = NO;
+                               GCC_C_LANGUAGE_STANDARD = "compiler-default";
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_ENABLE_FIX_AND_CONTINUE = YES;
+                               GCC_MODEL_TUNING = G5;
+                               GCC_OPTIMIZATION_LEVEL = 0;
+                               INFOPLIST_FILE = Info.plist;
+                               INSTALL_PATH = "$(HOME)/Library/Bundles";
+                               PRODUCT_NAME = "VLC EyeTV Plug-In";
+                               WRAPPER_EXTENSION = bundle;
+                               ZERO_LINK = YES;
+                       };
+                       name = Debug;
+               };
+               1DEB911C08733D790010E9CD /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ARCHS = (
+                                       ppc,
+                                       i386,
+                               );
+                               GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+                               GCC_MODEL_TUNING = G5;
+                               INFOPLIST_FILE = Info.plist;
+                               INSTALL_PATH = "$(HOME)/Library/Bundles";
+                               PRODUCT_NAME = "VLC EyeTV Plug-In";
+                               WRAPPER_EXTENSION = bundle;
+                       };
+                       name = Release;
+               };
+               1DEB911F08733D790010E9CD /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               PREBINDING = NO;
+                               SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+                       };
+                       name = Debug;
+               };
+               1DEB912008733D790010E9CD /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               PREBINDING = NO;
+                               SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+                       };
+                       name = Release;
+               };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+               1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget "VLC EyeTV Plug-In" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1DEB911B08733D790010E9CD /* Debug */,
+                               1DEB911C08733D790010E9CD /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               1DEB911E08733D790010E9CD /* Build configuration list for PBXProject "eyetvplugin" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               1DEB911F08733D790010E9CD /* Debug */,
+                               1DEB912008733D790010E9CD /* Release */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+/* End XCConfigurationList section */
+       };
+       rootObject = 089C1669FE841209C02AAC07 /* Project object */;
+}
index 5847df2..530082a 100644 (file)
@@ -7,6 +7,7 @@ SOURCES_access_http = http.c
 SOURCES_access_ftp = ftp.c
 SOURCES_access_smb = smb.c
 SOURCES_access_gnomevfs = gnomevfs.c
+SOURCES_access_eyetv = eyetv.c
 SOURCES_dvdnav = dvdnav.c
 SOURCES_dvdread = dvdread.c
 SOURCES_dc1394 = dc1394.c
diff --git a/modules/access/eyetv.c b/modules/access/eyetv.c
new file mode 100644 (file)
index 0000000..5478e32
--- /dev/null
@@ -0,0 +1,318 @@
+/*****************************************************************************\r
+ * eyetv.c : Access module to connect to our plugin running within EyeTV\r
+ *****************************************************************************\r
+ * Copyright (C) 2006-2007 the VideoLAN team\r
+ * $Id$\r
+ *\r
+ * Author: Felix Kühne <fkuehne at videolan dot org>\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\r
+ *****************************************************************************/\r
+\r
+/*****************************************************************************\r
+ * Preamble\r
+ *****************************************************************************/\r
+#include <stdlib.h>\r
+\r
+#include <vlc/vlc.h>\r
+#include <vlc_access.h>\r
+\r
+#include <CoreFoundation/CoreFoundation.h>\r
+\r
+/* TODO:\r
+ * watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */\r
+\r
+/*****************************************************************************\r
+ * Module descriptior\r
+ *****************************************************************************/\r
+static int  Open ( vlc_object_t * );\r
+static void Close( vlc_object_t * );\r
+\r
+vlc_module_begin();\r
+    set_shortname( "EyeTV" );\r
+    set_description( _("EyeTV access module") );\r
+    set_category( CAT_INPUT );\r
+    set_subcategory( SUBCAT_INPUT_ACCESS );\r
+\r
+    set_capability( "access2", 0 );\r
+    add_shortcut( "eyetv" );\r
+    set_callbacks( Open, Close );\r
+vlc_module_end();\r
+\r
+/*****************************************************************************\r
+ * Access: local prototypes\r
+ *****************************************************************************/\r
+typedef struct\r
+{\r
+    VLC_COMMON_MEMBERS\r
+    \r
+    vlc_mutex_t     lock;\r
+    vlc_cond_t      wait;\r
+    \r
+    CFMessagePortRef    inputMessagePortFromEyeTV;\r
+} eyetv_thread_t;\r
+\r
+struct access_sys_t\r
+{\r
+    eyetv_thread_t      *p_thread;\r
+};\r
+\r
+CFDataRef dataFromEyetv;\r
+int lastPacketId;\r
+int lastForwardedPacketId;\r
+\r
+static int Read( access_t *, uint8_t *, int );\r
+static int Control( access_t *, int, va_list );\r
+static void Thread( vlc_object_t * );\r
+CFDataRef msgPortCallback( CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info );\r
+\r
+/*****************************************************************************\r
+ * Open: sets up the module and its threads\r
+ *****************************************************************************/\r
+static int Open( vlc_object_t *p_this )\r
+{\r
+    access_t        *p_access = (access_t *)p_this;\r
+    access_sys_t    *p_sys;\r
+    eyetv_thread_t  *p_thread;\r
+    CFMessagePortContext context;\r
+    memset(&context, 0, sizeof(context)); \r
+    \r
+    /* Init p_access */\r
+    access_InitFields( p_access ); \\r
+    ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL ); \\r
+    MALLOC_ERR( p_access->p_sys, access_sys_t ); \\r
+    p_sys = p_access->p_sys; memset( p_sys, 0, sizeof( access_sys_t ) );\r
+\r
+    msg_Dbg( p_access, "coming up" );\r
+\r
+    /* create receiving thread which will keep the message port alive without blocking */\r
+    p_sys->p_thread = p_thread = vlc_object_create( p_access, sizeof( eyetv_thread_t ) );\r
+    vlc_object_attach( p_thread, p_this );\r
+    vlc_mutex_init( p_access, &p_thread->lock );\r
+    vlc_cond_init( p_access, &p_thread->wait );\r
+    msg_Dbg( p_access, "thread created, msg port following now" );\r
+    \r
+    /* set up our own msg port\r
+    * we may give the msgport such a generic name, because EyeTV may only run\r
+    * once per entire machine, so we can't interfere with other instances.\r
+    * we just trust the user no to launch multiple VLC instances trying to \r
+    * access EyeTV at the same time. If this happens, the latest launched\r
+    * instance will win. */\r
+    p_sys->p_thread->inputMessagePortFromEyeTV =  CFMessagePortCreateLocal( kCFAllocatorDefault,\r
+                                                                  CFSTR("VLCEyeTVMsgPort"),\r
+                                                                  &msgPortCallback,\r
+                                                                  &context,\r
+                                                                  /* no info to free */ NULL );\r
+    if( p_sys->p_thread->inputMessagePortFromEyeTV == NULL )\r
+    {\r
+        msg_Err( p_access, "opening local msg port failed" );\r
+        free( p_sys->p_thread->inputMessagePortFromEyeTV );\r
+        vlc_mutex_destroy( &p_thread->lock );\r
+        vlc_cond_destroy( &p_thread->wait );\r
+        vlc_object_detach( p_thread );\r
+        vlc_object_destroy( p_thread );\r
+        free( p_sys );\r
+        return VLC_EGENERIC;\r
+    }\r
+    else\r
+        msg_Dbg( p_access, "remote msg port opened" );\r
+    \r
+    /* let the thread run */\r
+    if( vlc_thread_create( p_thread, "EyeTV Receiver Thread", Thread,\r
+                           VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) )\r
+    {\r
+        msg_Err( p_access, "couldn't launch eyetv receiver thread" );\r
+        vlc_mutex_destroy( &p_thread->lock );\r
+        vlc_cond_destroy( &p_thread->wait );\r
+        vlc_object_detach( p_thread );\r
+        vlc_object_destroy( p_thread );\r
+        free( p_sys );\r
+        return VLC_EGENERIC;\r
+    }\r
+\r
+    msg_Dbg( p_access, "receiver thread created and launched" );\r
+    \r
+    /* tell the EyeTV plugin to open up its msg port and start sending */\r
+    CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),\r
+                                          CFSTR("VLCAccessStartDataSending"), \r
+                                          CFSTR("VLCEyeTVSupport"), \r
+                                          /*userInfo*/ NULL, \r
+                                          TRUE );\r
+    \r
+    msg_Dbg( p_access, "plugin notified" );\r
+    \r
+    /* we don't need such a high priority */\r
+    //vlc_thread_set_priority( p_access, VLC_THREAD_PRIORITY_LOW );\r
+    \r
+    return VLC_SUCCESS;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Close: closes msg-port, free resources\r
+ *****************************************************************************/\r
+static void Close( vlc_object_t *p_this )\r
+{\r
+    access_t     *p_access = (access_t *)p_this;\r
+    access_sys_t *p_sys = p_access->p_sys;\r
+    \r
+    msg_Dbg( p_access, "closing" );\r
+    \r
+    /* tell the EyeTV plugin to close its msg port and stop sending */\r
+    CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),\r
+                                          CFSTR("VLCAccessStopDataSending"), \r
+                                          CFSTR("VLCEyeTVSupport"), \r
+                                          /*userInfo*/ NULL, \r
+                                          TRUE );\r
+    \r
+    msg_Dbg( p_access, "plugin notified" );\r
+    \r
+    /* stop receiver thread */\r
+    p_sys->p_thread->b_die = VLC_TRUE;\r
+    vlc_mutex_lock( &p_sys->p_thread->lock );\r
+    vlc_cond_signal( &p_sys->p_thread->wait );\r
+    vlc_mutex_unlock( &p_sys->p_thread->lock );\r
+    vlc_thread_join( p_sys->p_thread );\r
+    \r
+    /* close msg port */\r
+    CFMessagePortInvalidate( p_sys->p_thread->inputMessagePortFromEyeTV );\r
+    free( p_sys->p_thread->inputMessagePortFromEyeTV );\r
+    msg_Dbg( p_access, "msg port closed and freed" );\r
+    \r
+    /* free thread */\r
+    vlc_mutex_destroy( &p_sys->p_thread->lock );\r
+    vlc_cond_destroy( &p_sys->p_thread->wait );\r
+    vlc_object_detach( p_sys->p_thread );\r
+    vlc_object_destroy( p_sys->p_thread );\r
+    \r
+    free( p_sys );\r
+}\r
+\r
+static void Thread( vlc_object_t *p_this )\r
+{\r
+    eyetv_thread_t *p_thread= (eyetv_thread_t*)p_this;\r
+    CFRunLoopSourceRef runLoopSource;\r
+    \r
+    /* create our run loop source for the port and attach it to our current loop */\r
+    runLoopSource = CFMessagePortCreateRunLoopSource( kCFAllocatorDefault,\r
+                                                      p_thread->inputMessagePortFromEyeTV,\r
+                                                      0 );\r
+    CFRunLoopAddSource( CFRunLoopGetCurrent(),\r
+                        runLoopSource,\r
+                        kCFRunLoopDefaultMode );\r
+    \r
+    CFRunLoopRun();\r
+}\r
+\r
+\r
+/*****************************************************************************\r
+* msgPortCallback: receives data from the EyeTV plugin\r
+*****************************************************************************/\r
+CFDataRef msgPortCallback( CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info )\r
+{\r
+    extern CFDataRef dataFromEyetv;\r
+    extern int lastPacketId;\r
+    \r
+    /* copy callback data to module data */\r
+    dataFromEyetv = CFDataCreateCopy( kCFAllocatorDefault, data );\r
+#if 0\r
+    printf( "packet %i contained %i bytes, forwarding %i bytes\n",\r
+            (int)msgid,\r
+            (int)CFDataGetLength( data ),\r
+            (int)CFDataGetLength( dataFromEyetv ) );\r
+#endif\r
+\r
+    lastPacketId = msgid;\r
+    \r
+    return NULL; /* we've got nothing to return */\r
+}\r
+\r
+/*****************************************************************************\r
+* Read: forwarding data from EyeTV plugin which was received above\r
+*****************************************************************************/\r
+static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )\r
+{\r
+    access_sys_t *p_sys = p_access->p_sys;\r
+    extern CFDataRef dataFromEyetv;\r
+    extern int lastPacketId;\r
+    extern int lastForwardedPacketId;\r
+    \r
+    /* wait for a new buffer before forwarding */\r
+    while( lastPacketId == lastForwardedPacketId && !p_access->b_die )\r
+    {\r
+        msleep( INPUT_ERROR_SLEEP );\r
+    }\r
+    \r
+    /* read data here, copy it to p_buffer, fill i_len with respective length\r
+     * and return info with i_read; i_read = 0 == EOF */\r
+    if( dataFromEyetv )\r
+    {\r
+        CFDataGetBytes( dataFromEyetv,\r
+                        CFRangeMake( 0, CFDataGetLength( dataFromEyetv ) ),\r
+                        (uint8_t *)p_buffer );\r
+        i_len = (int)CFDataGetLength( dataFromEyetv );\r
+#if 0\r
+        msg_Dbg( p_access, "%i bytes with id %i received in read function, pushing to core",\r
+             (int)CFDataGetLength( dataFromEyetv ), lastPacketId );\r
+#endif\r
+        lastForwardedPacketId = lastPacketId;\r
+        if( i_len == 0)\r
+        {\r
+            msg_Err( p_access, "you looosed!" );\r
+            return 0;\r
+        }\r
+    }\r
+    \r
+    if( p_access->b_die )\r
+        return 0;\r
+    \r
+    return i_len;\r
+}\r
+\r
+/*****************************************************************************\r
+ * Control:\r
+ *****************************************************************************/\r
+static int Control( access_t *p_access, int i_query, va_list args )\r
+{/*\r
+    vlc_bool_t   *pb_bool;\r
+    int          *pi_int;\r
+    int64_t      *pi_64;\r
+    \r
+    switch( i_query )\r
+    {\r
+        * *\r
+        case ACCESS_SET_PAUSE_STATE:\r
+            * Nothing to do *\r
+            break;\r
+\r
+        case ACCESS_CAN_SEEK:\r
+        case ACCESS_CAN_FASTSEEK:\r
+        case ACCESS_CAN_PAUSE:\r
+        case ACCESS_CAN_CONTROL_PACE:\r
+        case ACCESS_GET_MTU:\r
+        case ACCESS_GET_PTS_DELAY:            \r
+        case ACCESS_GET_TITLE_INFO:\r
+        case ACCESS_SET_TITLE:\r
+        case ACCESS_SET_SEEKPOINT:\r
+        case ACCESS_SET_PRIVATE_ID_STATE:\r
+            return VLC_EGENERIC;\r
+            \r
+        default:\r
+            msg_Warn( p_access, "unimplemented query in control" );\r
+            return VLC_EGENERIC;\r
+            \r
+    }\r
+    return VLC_SUCCESS;*/\r
+    return VLC_EGENERIC;\r
+}\r
index 887a4d1..f71479e 100644 (file)
@@ -46,5 +46,7 @@ SOURCES_macosx = \
        fspanel.h \
        update.h \
        update.m \
+       eyetv.h \
+       eyetv.m \
        $(NULL)
 
diff --git a/modules/gui/macosx/eyetv.h b/modules/gui/macosx/eyetv.h
new file mode 100644 (file)
index 0000000..1c82c35
--- /dev/null
@@ -0,0 +1,41 @@
+/*****************************************************************************\r
+* eyetv.h: small class to control the notification parts of the EyeTV plugin\r
+*****************************************************************************\r
+* Copyright (C) 2006-2007 the VideoLAN team\r
+* $Id$\r
+*\r
+* Authors: Felix Kühne <fkuehne at videolan dot org>\r
+*\r
+* This program is free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* This program is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with this program; if not, write to the Free Software\r
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\r
+*****************************************************************************/\r
+\r
+#import <Cocoa/Cocoa.h>\r
+\r
+\r
+@interface VLCEyeTVController : NSObject \r
+{\r
+    BOOL b_eyeTVactive;\r
+    BOOL b_deviceConnected;\r
+}\r
+- (void)globalNotificationReceived: (NSNotification *)theNotification;\r
+- (BOOL)isEyeTVrunning;\r
+- (BOOL)isDeviceConnected;\r
+- (void)launchEyeTV;\r
+- (void)switchChannelUp:(BOOL)b_yesOrNo;\r
+- (void)selectChannel:(int)theChannelNum;\r
+- (int)getNumberOfChannels;\r
+- (NSString *)getNameOfChannel:(int)theChannelNum;\r
+\r
+@end\r
diff --git a/modules/gui/macosx/eyetv.m b/modules/gui/macosx/eyetv.m
new file mode 100644 (file)
index 0000000..19e5d43
--- /dev/null
@@ -0,0 +1,170 @@
+/*****************************************************************************\r
+* eyetv.m: small class to control the notification parts of the EyeTV plugin\r
+*****************************************************************************\r
+* Copyright (C) 2006-2007 the VideoLAN team\r
+* $Id$\r
+*\r
+* Authors: Felix Kühne <fkuehne at videolan dot org>\r
+*\r
+* This program is free software; you can redistribute it and/or modify\r
+* it under the terms of the GNU General Public License as published by\r
+* the Free Software Foundation; either version 2 of the License, or\r
+* (at your option) any later version.\r
+*\r
+* This program is distributed in the hope that it will be useful,\r
+* but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+* GNU General Public License for more details.\r
+*\r
+* You should have received a copy of the GNU General Public License\r
+* along with this program; if not, write to the Free Software\r
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.\r
+*****************************************************************************/\r
+\r
+#import "eyetv.h"
+/* for apple event interaction [carbon] */\r
+#import <ApplicationServices/ApplicationServices.h> \r
+/* for various VLC core related calls */
+#import "intf.h"\r
+\r
+@implementation VLCEyeTVController\r
+\r
+static VLCEyeTVController *_o_sharedInstance = nil;\r
+\r
++ (VLCEyeTVController *)sharedInstance\r
+{\r
+    return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];\r
+}\r
+\r
+- (id)init \r
+{\r
+    if (_o_sharedInstance) {\r
+        [self dealloc];\r
+    } else {\r
+        _o_sharedInstance = [super init];\r
+\r
+        [[NSDistributedNotificationCenter defaultCenter] 
+                    addObserver: self\r
+                       selector: @selector(globalNotificationReceived:)\r
+                           name: NULL\r
+                         object: @"VLCEyeTVSupport"\r
+             suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];\r
+    }\r
+    \r
+    return _o_sharedInstance;\r
+}\r
+\r
+- (void)globalNotificationReceived: (NSNotification *)theNotification\r
+{\r
+    msg_Dbg( VLCIntf, "notification received in VLC with name %s and object %s",
+             [[theNotification name] UTF8String], [[theNotification object] UTF8String] );\r
+\r
+    /* update our info on the used device */\r
+    if( [[theNotification name] isEqualToString: @"DeviceAdded"] )\r
+        b_deviceConnected = YES;\r
+    if( [[theNotification name] isEqualToString: @"DeviceRemoved"] )\r
+        b_deviceConnected = NO;\r
+\r
+    /* is eyetv running? */\r
+    if( [[theNotification name] isEqualToString: @"PluginInit"] )\r
+        b_eyeTVactive = YES;\r
+    if( [[theNotification name] isEqualToString: @"PluginQuit"] )\r
+        b_eyeTVactive = NO;\r
+}\r
+\r
+- (BOOL)isEyeTVrunning\r
+{\r
+    return b_eyeTVactive;\r
+}\r
+\r
+- (BOOL)isDeviceConnected\r
+{\r
+    return b_deviceConnected;\r
+}\r
+\r
+\r
+- (void)launchEyeTV\r
+{\r
+    OSStatus stat;\r
+    FSRef eyetvPath;\r
+\r
+    stat = LSFindApplicationForInfo ( 'EyTV',\r
+                                       CFSTR("com.elgato.eyetv"),\r
+                                       NULL,\r
+                                       &eyetvPath,\r
+                                       NULL );\r
+    if( stat != noErr )\r
+        msg_Err( VLCIntf, "finding EyeTV failed with error code %i", (int)stat );\r
+    \r
+    stat = LSOpenFSRef( &eyetvPath, NULL );\r
+    if( stat != noErr )\r
+        msg_Err( VLCIntf, "opening EyeTV failed with error code %i", (int)stat );\r
+    \r
+}\r
+\r
+- (void)switchChannelUp:(BOOL)b_yesOrNo\r
+{\r
+    OSErr err;\r
+    AppleEvent ourAE = {typeNull, nil};\r
+    AEBuildError theBuildError;\r
+    const OSType eyetvSignature = 'EyTV';   /* carbon FOURCC style */\r
+    OSType eyetvCommand;\r
+    \r
+    if( b_yesOrNo == YES )\r
+    {\r
+        eyetvCommand = 'Chup';     /* same style */\r
+        msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel up" );\r
+    }\r
+    else\r
+    {\r
+        eyetvCommand = 'Chdn';     /* same style again */\r
+        msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel down" );\r
+    }\r
+    \r
+    err = AEBuildAppleEvent(\r
+                            /* EyeTV script suite */ eyetvSignature,\r
+                            /* command */ eyetvCommand,\r
+                            /* signature type */ typeApplSignature,\r
+                            /* signature */ &eyetvSignature,\r
+                            /* signature size */ sizeof(eyetvSignature),\r
+                            /* basic return id */ kAutoGenerateReturnID,\r
+                            /* generic transaction id */ kAnyTransactionID,\r
+                            /* to-be-created AE */ &ourAE,\r
+                            /* get some possible errors */ &theBuildError, \r
+                            /* got no params for now */ "" );\r
+    if( err != aeBuildSyntaxNoErr )\r
+    {\r
+        msg_Err( VLCIntf, "Error %i encountered while trying to the build the AE to launch eyetv.\n" \\r
+                 "additionally, the following info was returned: AEBuildErrorCode:%i at pos:%i", \r
+                 (int)err, theBuildError.fError, theBuildError.fErrorPos);\r
+        return;\r
+    }\r
+    else\r
+        msg_Dbg( VLCIntf, "AE created successfully, trying to send now" );\r
+    \r
+    err = AESendMessage(\r
+                        /* our AE */ &ourAE,\r
+                        /* no need for a response-AE */ NULL,\r
+                        /* we neither want a response nor user interaction */ kAENoReply | kAENeverInteract,\r
+                        /* we don't need a special time-out */ kAEDefaultTimeout );\r
+    if( err != noErr )\r
+        msg_Err( VLCIntf, "Error %i encountered while trying to tell EyeTV to switch channel", (int)err );\r
+    \r
+    err = AEDisposeDesc(&ourAE);\r
+}\r
+\r
+- (void)selectChannel: (int)theChannelNum\r
+{\r
+}\r
+\r
+- (int)getNumberOfChannels\r
+{\r
+    return 2;\r
+}\r
+\r
+- (NSString *)getNameOfChannel: (int)theChannelNum\r
+{\r
+    return @"dummy name";\r
+}\r
+\r
+@end\r
index d9b2c1f..e413209 100644 (file)
@@ -105,6 +105,7 @@ struct intf_sys_t
     id o_interaction_list;      /* VLCInteractionList*/
     id o_sfilters;              /* VLCsFilters    */
     id o_update;                /* VLCUpdate      */
+    id o_eyetv;                 /* VLCEyeTVController */
     BOOL nib_main_loaded;       /* reference to the main-nib */
     BOOL nib_open_loaded;       /* reference to the open-nib */
     BOOL nib_about_loaded;      /* reference to the about-nib */
@@ -307,6 +308,7 @@ struct intf_sys_t
 - (id)getMainIntfPgbar;
 - (id)getControllerWindow;
 - (id)getVoutMenu;
+- (id)getEyeTVController;
 - (void)applicationWillTerminate:(NSNotification *)notification;
 - (NSString *)localizedString:(char *)psz;
 - (char *)delocalizeString:(NSString *)psz;
index e0048ae..58bd0a8 100644 (file)
@@ -48,6 +48,7 @@
 #import "embeddedwindow.h"
 #import "update.h"
 #import "AppleRemote.h"
+#import "eyetv.h"
 
 #import <vlc_input.h>
 
@@ -359,6 +360,14 @@ static VLCMain *_o_sharedMainInstance = nil;
        [o_remote setClickCountEnabledButtons: kRemoteButtonPlay];
     [o_remote setDelegate: _o_sharedMainInstance];
 
+    o_eyetv = [[VLCEyeTVController alloc] init];
+
+    /* announce our launch to a potential eyetv plugin */
+    [[NSDistributedNotificationCenter defaultCenter] postNotificationName: @"VLCOSXGUIInit"
+                                                                   object: @"VLCEyeTVSupport"
+                                                                 userInfo: NULL
+                                                       deliverImmediately: YES];
+
     return _o_sharedMainInstance;
 }
 
@@ -1017,6 +1026,13 @@ static VLCMain *_o_sharedMainInstance = nil;
     return o_vout_menu;
 }
 
+- (id)getEyeTVController
+{
+    if( o_eyetv )
+        return o_eyetv;
+    return nil;
+}
+
 - (void)manage
 {
     playlist_t * p_playlist;
@@ -1621,6 +1637,9 @@ static VLCMain *_o_sharedMainInstance = nil;
     if( o_interaction_list != nil )
         [o_interaction_list release];
 
+    if( o_eyetv != nil )
+        [o_eyetv release];
+
     if( o_img_pause_pressed != nil )
     {
         [o_img_pause_pressed release];
index 119ef7f..0ca9e72 100644 (file)
@@ -42,10 +42,15 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
     IBOutlet id o_btn_ok;
     IBOutlet id o_btn_cancel;
 
+    IBOutlet id o_output_ckbox;
+    IBOutlet id o_sout_options;
+
+    /* open file */
     IBOutlet id o_file_path;
     IBOutlet id o_file_btn_browse;
     IBOutlet id o_file_stream;
 
+    /* open disc */
     IBOutlet id o_disc_type;
     IBOutlet id o_disc_device;
     IBOutlet id o_disc_device_lbl;
@@ -59,6 +64,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
     IBOutlet id o_disc_videots_btn_browse;
     IBOutlet id o_disc_dvd_menus;
 
+    /* open network */
     IBOutlet id o_net_mode;
     IBOutlet id o_net_udp_port;
     IBOutlet id o_net_udp_port_lbl;
@@ -72,6 +78,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
     IBOutlet id o_net_http_url_lbl;
     IBOutlet id o_net_timeshift_ckbox;
 
+    /* open subtitle file */
     IBOutlet id o_file_sub_ckbox;
     IBOutlet id o_file_sub_btn_settings;
     IBOutlet id o_file_sub_sheet;
@@ -94,8 +101,19 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
     IBOutlet id o_file_sub_font_box;
     IBOutlet id o_file_sub_file_box;
 
-    IBOutlet id o_output_ckbox;
-    IBOutlet id o_sout_options;
+    /* open eyetv support */
+    IBOutlet id o_eyetv_tabView;
+    IBOutlet id o_eyetv_channels_pop;
+    IBOutlet id o_eyetv_currentChannel_lbl;
+    IBOutlet id o_eyetv_chn_status_txt;
+    IBOutlet id o_eyetv_chn_bgbar;
+    IBOutlet id o_eyetv_launchEyeTV_btn;
+    IBOutlet id o_eyetv_nextProgram_btn;
+    IBOutlet id o_eyetv_noDevice_lbl;
+    IBOutlet id o_eyetv_noDeviceLong_lbl;
+    IBOutlet id o_eyetv_noEyeTV_lbl;
+    IBOutlet id o_eyetv_noEyeTVLong_lbl;
+    IBOutlet id o_eyetv_previousProgram_btn;
     
     BOOL b_autoplay;
 }
@@ -125,6 +143,11 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
 - (IBAction)openNetStepperChanged:(id)sender;
 - (void)openNetInfoChanged:(NSNotification *)o_notification;
 
+- (IBAction)eyetvSwitchChannel:(id)sender;
+- (IBAction)eyetvLaunch:(id)sender;
+- (void)eyetvChanged:(NSNotification *)o_notification;
+- (void)setupChannelInfo;
+
 - (IBAction)subsChanged:(id)sender;
 - (IBAction)subSettings:(id)sender;
 - (IBAction)subFileBrowse:(id)sender;
index d5524db..499b32e 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * open.m: MacOS X module for vlc
  *****************************************************************************
- * Copyright (C) 2002-2006 the VideoLAN team
+ * Copyright (C) 2002-2007 the VideoLAN team
  * $Id$
  *
  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net> 
 #include <IOKit/storage/IOCDMedia.h>
 #include <IOKit/storage/IODVDMedia.h>
 
-#include "intf.h"
-#include "playlist.h"
-#include "open.h"
-#include "output.h"
-#import <vlc_interface.h>
+#import "intf.h"
+#import "playlist.h"
+#import "open.h"
+#import "output.h"
+#import "eyetv.h"
 
 /*****************************************************************************
  * GetEjectableMediaOfClass 
@@ -189,7 +189,10 @@ static VLCOpen *_o_sharedMainInstance = nil;
 
     [o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
     [o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
-
+    
+    [o_eyetv_chn_bgbar setUsesThreadedAnimation: YES];
+    /* FIXME: implement EyeTV l10n here */
+    
     [self setSubPanel];
 
 
@@ -231,6 +234,21 @@ static VLCOpen *_o_sharedMainInstance = nil;
         selector: @selector(openNetInfoChanged:)
         name: NSControlTextDidChangeNotification
         object: o_net_http_url];
+
+    /* wake up with the correct GUI */
+    if( [[[VLCMain sharedInstance] getEyeTVController] isEyeTVrunning] == YES )
+        [o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
+    if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES )
+    {
+        [o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"];
+        [self setupChannelInfo];
+    }
+    
+    [[NSDistributedNotificationCenter defaultCenter] addObserver: self
+                                                        selector: @selector(eyetvChanged:)
+                                                            name: NULL
+                                                          object: @"VLCEyeTVSupport"
+                                              suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
     
     /* register clicks on text fields */
     [[NSNotificationCenter defaultCenter] addObserver: self
@@ -779,6 +797,83 @@ static VLCOpen *_o_sharedMainInstance = nil;
     }
 }
 
+- (IBAction)eyetvSwitchChannel:(id)sender
+{
+    if( sender == o_eyetv_nextProgram_btn )
+        [[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: YES];
+    else if( sender == o_eyetv_previousProgram_btn )
+        [[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: NO];
+    else if( sender == o_eyetv_channels_pop )
+        [[[VLCMain sharedInstance] getEyeTVController] selectChannel: 
+            [sender indexOfSelectedItem]];
+    else
+        msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
+}
+
+- (IBAction)eyetvLaunch:(id)sender
+{
+    [[[VLCMain sharedInstance] getEyeTVController] launchEyeTV];
+}
+
+- (void)eyetvChanged:(NSNotification *)o_notification
+{
+    if( [[o_notification name] isEqualToString: @"DeviceAdded"] )
+    {
+        msg_Dbg( VLCIntf, "eyetv device was added" );
+        [o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"];
+        [self setupChannelInfo];
+    }
+    else if( [[o_notification name] isEqualToString: @"DeviceRemoved"] )
+    {
+        /* leave the channel selection like that,
+         * switch to our "no device" tab */
+        msg_Dbg( VLCIntf, "eyetv device was removed" );
+        [o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
+    }
+    else if( [[o_notification name] isEqualToString: @"PluginQuit"] )
+    {
+        /* switch to the "launch eyetv" tab */
+        msg_Dbg( VLCIntf, "eyetv was terminated" );
+        [o_eyetv_tabView selectTabViewItemWithIdentifier:@"noeyetv"];
+    }
+    else if( [[o_notification name] isEqualToString: @"PluginInit"] )
+    {
+        /* we got no device yet */
+        msg_Dbg( VLCIntf, "eyetv was launched, no device yet" );
+        [o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
+    }
+    else
+        msg_Warn( VLCIntf, "unknown external notify '%s' received", [[o_notification name] UTF8String] );
+}
+
+/* little helper method, since this code needs to be run by multiple objects */
+- (void)setupChannelInfo
+{
+    /* set up channel selection */
+    [o_eyetv_channels_pop removeAllItems];
+    [o_eyetv_chn_bgbar setHidden: NO];
+    [o_eyetv_chn_bgbar animate: self];
+    [o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
+    [o_eyetv_chn_status_txt setHidden: NO];
+    
+    /* retrieve info */
+    int x = 0;
+    int channelCount = ( [[[VLCMain sharedInstance] getEyeTVController] getNumberOfChannels] + 1 );
+    while( x != channelCount )
+    {
+        /* we have to add items this way, because we accept duplicates 
+         * additionally, we save a bit of time */
+        [[o_eyetv_channels_pop menu] addItemWithTitle: [[[VLCMain sharedInstance] getEyeTVController] getNameOfChannel: x]
+                                               action: nil
+                                        keyEquivalent: @""];
+        x += 1;
+    }
+    
+    /* clean up GUI */
+    [o_eyetv_chn_bgbar setHidden: YES];
+    [o_eyetv_chn_status_txt setHidden: YES];
+}
+
 - (IBAction)subsChanged:(id)sender
 {
     if ([o_file_sub_ckbox state] == NSOnState)