From: Damien Fouilleul Date: Mon, 14 Jan 2008 23:18:13 +0000 (+0000) Subject: eyetv: latest version of EyeTV capture plugin, needs lotta testing X-Git-Tag: 0.9.0-test0~3463 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=36868ee9e839aebe9dca54ca7019bde6312f598a;p=vlc eyetv: latest version of EyeTV capture plugin, needs lotta testing --- diff --git a/extras/MacOSX/eyetvplugin/eyetvplugin.c b/extras/MacOSX/eyetvplugin/eyetvplugin.c index 41363da515..5f2b455b99 100644 --- a/extras/MacOSX/eyetvplugin/eyetvplugin.c +++ b/extras/MacOSX/eyetvplugin/eyetvplugin.c @@ -1,629 +1,480 @@ -/***************************************************************************** -* eyetvplugin.c: Plug-In for the EyeTV software to connect to VLC -***************************************************************************** -* Copyright (C) 2006-2007 the VideoLAN team -* $Id$ -* -* Authors: Felix Kühne -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. -*****************************************************************************/ - -#include "eyetvplugin.h" - -#define MAX_PIDS 256 -#define MAX_ACTIVE_PIDS 256 -#define MAX_DEVICES 16 -#define VLC_NOTIFICATION_OBJECT "VLCEyeTVSupport" - -#pragma push -#pragma pack(1) - - -/* Structure for TS-Packets */ -typedef struct -{ - unsigned long sync_byte : 8, - transport_error_indicator : 1, - payload_unit_start_indicator : 1, - transport_priority : 1, - PID : 13, - transport_scrambling_control : 2, - adaptation_field_control : 2, - continuity_counter : 4; - - unsigned char data[188-4]; - -} TransportStreamPacket; - -#pragma pop - - -/* Structure to hold Information on devices */ -typedef struct -{ - EyeTVPluginDeviceID deviceID; - EyeTVPluginDeviceType deviceType; - - long headendID; - long transponderID; - long serviceID; - - long pidsCount; - long pids[MAX_PIDS]; - - EyeTVPluginPIDInfo activePIDs[MAX_ACTIVE_PIDS]; - long activePIDsCount; - -} DeviceInfo; - - -/* Structure to hold global data to communicate with EyeTV */ -typedef struct -{ - EyeTVPluginCallbackProc callback; - long deviceCount; - DeviceInfo devices[MAX_DEVICES]; - long long packetCount; - -} VLCEyeTVPluginGlobals_t; - -/* 2nd structure to store our own global data which isn't shared with EyeTV - * a bit empty at the moment, but it will get larger as development progresses */ -typedef struct -{ - int i_deviceCount; - CFMessagePortRef messagePortToVLC; - bool b_msgPortOpen; -} VLCEyeTVPluginOwnGlobals_t; - -VLCEyeTVPluginOwnGlobals_t *nativeGlobals; - - -/* return the DeviceInfo with ID deviceID */ -static DeviceInfo *GetDeviceInfo(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID) -{ - int i; - - if( globals ) - { - for( i=0; ideviceCount; i++) - { - if( globals->devices[i].deviceID == deviceID ) - { - return &globals->devices[i]; - } - } - } - - return NULL; -} - -#pragma mark - - -/* initialise the plug-in */ -static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long apiVersion, EyeTVPluginCallbackProc callback) -{ - printf("VLC media player Plug-In: Initialize\n"); - long result = 0; - - /* init our own storage */ - extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; - nativeGlobals = malloc( sizeof( VLCEyeTVPluginOwnGlobals_t ) ); - - /* notify a potential VLC instance about our initialisation */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), - CFSTR("PluginInit"), - CFSTR(VLC_NOTIFICATION_OBJECT), - /*userInfo*/ NULL, - TRUE ); - - /* init our notification support */ - CFNotificationCenterAddObserver( CFNotificationCenterGetDistributedCenter(), - /* observer */ NULL, - /* callBack */ VLCEyeTVPluginGlobalNotificationReceived, - /* name, NULL==all */ NULL, - CFSTR(VLC_NOTIFICATION_OBJECT), - CFNotificationSuspensionBehaviorDeliverImmediately ); - - *globals = (VLCEyeTVPluginGlobals_t *) calloc(1, sizeof( VLCEyeTVPluginGlobals_t ) ); - ( *globals )->callback = callback; - - return result; -} - -/* we will be terminated soon, clean up */ -static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals) -{ - extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; - - printf("VLC media player Plug-In: Terminate\n"); - - long result = 0; - - /* notify a potential VLC instance about our termination */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), - CFSTR("PluginQuit"), - CFSTR(VLC_NOTIFICATION_OBJECT), - /*userInfo*/ NULL, - TRUE ); - - /* remove us from the global notification centre */ - CFNotificationCenterRemoveEveryObserver( CFNotificationCenterGetDistributedCenter(), - (void *)VLCEyeTVPluginGlobalNotificationReceived ); - - /* invalidate and free msg port */ - if( nativeGlobals->messagePortToVLC ) - { - CFMessagePortInvalidate( nativeGlobals->messagePortToVLC ); - free( nativeGlobals->messagePortToVLC ); - printf( "msgport invalidated and freed\n" ); - } - else - printf( "no msgport to free\n" ); - - if( globals ) - { - free( globals ); - } - - if( nativeGlobals ) - free( nativeGlobals ); - - return result; -} - -/* called when EyeTV asks various stuff about us */ -static long VLCEyeTVPluginGetInformation(VLCEyeTVPluginGlobals_t *globals, long* outAPIVersion, char* outName, char *outDescription) -{ - printf("VLC media player Plug-In: GetInfo\n"); - long result = 0; - - if( globals ) - { - if( outAPIVersion ) - { - *outAPIVersion = EYETV_PLUGIN_API_VERSION; - } - - if( outName ) - { - char* name = "VLC media player Plug-In"; - strcpy( &outName[0], name); - } - - if( outDescription ) - { - char* desc = "This Plug-In connects EyeTV to the VLC media player for streaming purposes."; - strcpy( &outDescription[0], desc); - } - } - - return result; -} - -/* called if we received a global notification */ -void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, - void *observer, - CFStringRef name, - const void *object, - CFDictionaryRef userInfo ) -{ - CFIndex maxlen; - char *theName, *theObject; - extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; - - maxlen = CFStringGetMaximumSizeForEncoding( CFStringGetLength( name ), - kCFStringEncodingUTF8) + 1; - theName = malloc(maxlen); - CFStringGetCString( name, - theName, - maxlen, - kCFStringEncodingUTF8); - - maxlen = CFStringGetMaximumSizeForEncoding( CFStringGetLength( name ), - kCFStringEncodingUTF8) + 1; - theObject = malloc(maxlen); - CFStringGetCString( object, - theObject, - maxlen, - kCFStringEncodingUTF8); - printf( "notication received with name: %s and object: %s\n", theName, theObject ); - - /* when VLC launches after us, we need to inform it about our existance and the current state of available devices */ - if( CFStringCompare( name, CFSTR( "VLCOSXGUIInit" ), 0) == kCFCompareEqualTo ) - { - /* we're here */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), - CFSTR("PluginInit"), - CFSTR(VLC_NOTIFICATION_OBJECT), - /*userInfo*/ NULL, - TRUE ); - if( nativeGlobals && ( nativeGlobals->i_deviceCount > 0 ) ) - { - /* at least one device is apparently connected */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), - CFSTR("DeviceAdded"), - CFSTR(VLC_NOTIFICATION_OBJECT), - /*userInfo*/ NULL, - TRUE ); - } - } - - /* VLC wants us to start sending data */ - if( CFStringCompare( name, CFSTR( "VLCAccessStartDataSending" ), 0) == kCFCompareEqualTo ) - { - nativeGlobals->messagePortToVLC = CFMessagePortCreateRemote( kCFAllocatorDefault, - CFSTR("VLCEyeTVMsgPort") ); - if( nativeGlobals->messagePortToVLC == NULL ) - printf( "getting messagePortToVLC failed!\n" ); - else - { - nativeGlobals->b_msgPortOpen = TRUE; - printf( "msg port opened / data sending switched on\n" ); - } - } - - /* VLC wants us to stop sending data */ - if( CFStringCompare( name, CFSTR( "VLCAccessStopDataSending" ), 0) == kCFCompareEqualTo ) - { - nativeGlobals->b_msgPortOpen = FALSE; - printf( "data sending switched off\n" ); - } -} - -/* called if a device is added */ -static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, EyeTVPluginDeviceType deviceType) -{ - printf("VLC media player Plug-In: Device with type %i and ID %i added\n", (int)deviceType, (int)deviceID); - - long result = 0; - DeviceInfo *deviceInfo; - extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; - - - if( globals ) - { - if( globals->deviceCount < MAX_DEVICES ) - { - deviceInfo = &( globals->devices[globals->deviceCount] ); - memset(deviceInfo, 0, sizeof(DeviceInfo)); - - deviceInfo->deviceID = deviceID; - deviceInfo->deviceType = deviceType; - - globals->deviceCount++; - - if( nativeGlobals ) - nativeGlobals->i_deviceCount = globals->deviceCount; - - /* notify a potential VLC instance about the addition */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), - CFSTR("DeviceAdded"), - CFSTR(VLC_NOTIFICATION_OBJECT), - /*userInfo*/ NULL, - TRUE ); - } - } - - return result; -} - -/* called if a device is removed */ -static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID) -{ - printf("VLC media player Plug-In: DeviceRemoved\n"); - - extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; - long result = 0; - int i; - - if( globals ) - { - for( i = 0; i < globals->deviceCount; i++ ) - { - if ( globals->devices[i].deviceID == deviceID ) - { - globals->deviceCount--; - - if( ideviceCount ) - { - globals->devices[i] = globals->devices[globals->deviceCount]; - } - - if( nativeGlobals ) - nativeGlobals->i_deviceCount = globals->deviceCount; - - /* notify a potential VLC instance about the removal */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), - CFSTR("DeviceRemoved"), - CFSTR(VLC_NOTIFICATION_OBJECT), - /*userInfo*/ NULL, - TRUE ); - } - } - } - - return result; -} - -/* This function is called, whenever packets are received by EyeTV. For reasons of performance, - * the data is the original data, not a copy. That means, EyeTV waits until this method is - * finished. Therefore all in this method should be as fast as possible. */ -int i=0; -static long VLCEyeTVPluginPacketsArrived(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, long **packets, long packetsCount) -{ - long result = 0; - int i, j, isNewPID; - TransportStreamPacket *packet; - extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; - SInt32 i_returnValue; - CFMutableDataRef theMutableRef; - uint8_t *p_bufferForSending = malloc(4); - bool b_nonSendData; - int i_lastSentPacket; - - if( globals && nativeGlobals ) - { - DeviceInfo *deviceInfo = GetDeviceInfo(globals, deviceID); - - if( deviceInfo ) - { - /* alloc the buffer if wanted */ - if( nativeGlobals->b_msgPortOpen == TRUE ) - theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) ); - - for( i = 0; i < packetsCount; i++ ) - { - packet = ( TransportStreamPacket* )packets[i]; - isNewPID = 1; - - /* search for PID */ - for( j = 0; j < deviceInfo->pidsCount; j++ ) - { - if( packet->PID == deviceInfo->pids[j] ) - { - isNewPID = 0; - break; - } - } - - /* add new PIDs to the DeviceInfo */ - if( isNewPID ) - { - printf ("VLC media player Plug-In: SamplePacketsArrived, newPID = %6d\n", packet->PID); - - if( deviceInfo->pidsCount < MAX_PIDS ) - { - deviceInfo->pids[deviceInfo->pidsCount++] = packet->PID; - } - } - else - { - /* forward data to VLC if wanted */ - /* FIXME: we only receive ARD for now */ - if( nativeGlobals->b_msgPortOpen == TRUE && ( - packet->PID == 1401 || - packet->PID == 1402 || - packet->PID == 1400 || - packet->PID == 1404 || - packet->PID == 3070 || - packet->PID == 3072 || - packet->PID == 3074 || - packet->PID == 5074 || - packet->PID == 0 || - packet->PID == 17 || - packet->PID == 19 || - packet->PID == 20 ) ) - { - /* in a good world, this wouldn't be necessary */ - if( theMutableRef == NULL ) - theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) ); - - /* collect data to send larger packets */ - - /* enlarge buffer if necessary */ - if( i > 0 ) - CFDataIncreaseLength( theMutableRef, 188 ); - - /* add missing header */ - memcpy( p_bufferForSending, packet, 4 ); - CFDataAppendBytes( theMutableRef, p_bufferForSending, sizeof(p_bufferForSending) ); - - free( p_bufferForSending ); - p_bufferForSending = malloc(4); - - /* add payload */ - CFDataAppendBytes( theMutableRef, packet->data, sizeof(packet->data) ); - - b_nonSendData = TRUE; - - } - } - - globals->packetCount++; - - if( globals->packetCount%10000 == 0 ) - printf("-> %lld Packets received so far...\n",globals->packetCount); - } - - if( nativeGlobals->b_msgPortOpen == TRUE ) - { - printf( "sending %i bytes of data\n", CFDataGetLength( theMutableRef ) ); - i_returnValue = CFMessagePortSendRequest( nativeGlobals->messagePortToVLC, - /* arbitrary int val */ globals->packetCount, - /* the data */ theMutableRef, - /* no timeout for sending */ 0, - /* no timeout for resp */ 0, - /* no resp. wanted */ NULL, - NULL ); - b_nonSendData = FALSE; - i_lastSentPacket = globals->packetCount; - if( i_returnValue == kCFMessagePortSendTimeout ) - printf( "time out while sending\n" ); - else if( i_returnValue == kCFMessagePortReceiveTimeout ) - printf( "time out while waiting for resp\n" ); - else if( i_returnValue == kCFMessagePortIsInvalid ) - { - /* suppress any further attemps */ - printf( "message port is invalid!\n" ); - nativeGlobals->b_msgPortOpen = FALSE; - } - else if( i_returnValue == kCFMessagePortTransportError ) - printf( "transport error while sending!\n" ); - else - { - //printf( "success, freeing resources\n" ); - free( theMutableRef ); - theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) ); - } - } - - } - } - else - printf( "warning: either globals or nativeGlobals are NIL in VLCEyeTVPluginPacketsArrived" ); - - /* clean up before leaving function */ - //if( nativeGlobals->b_msgPortOpen == TRUE ) - // free( theMutableRef ); - - free( p_bufferForSending ); - - return result; -} - -/* VLCEyeTVPluginServiceChanged, - * - * - *globals : The plug-in Globals - * - deviceID : Identifies the active Device - * - headendID : The HeadendID, for e300 it's the orbital position of the satelite in - * tenth degrees east - * - transponderID : The Frequency in kHz - * - serviceID : original ServiceID from the DVB-Stream (e300, e400) - * - pidList : List of active PIDs - * - * Whenever a service changes, this function is called. Service-related plug-in data should be updated here. - */ -static long VLCEyeTVPluginServiceChanged(VLCEyeTVPluginGlobals_t *globals, - EyeTVPluginDeviceID deviceID, - long headendID, - long transponderID, - long serviceID, - EyeTVPluginPIDInfo *pidList, - long pidsCount) -{ - long result = 0; - int i; - - printf("\nVLC media player Plug-In: ServiceChanged:\n"); - printf( "=====================================\n"); - - if( globals ) - { - DeviceInfo *deviceInfo = GetDeviceInfo( globals, deviceID ); - if( deviceInfo ) - { - deviceInfo->headendID = headendID; - printf("HeadendID: %ld, ", headendID); - - deviceInfo->transponderID = transponderID; - printf("TransponderID: %ld, ", transponderID); - - deviceInfo->serviceID = serviceID; - printf("ServiceID: %ld\n\n", serviceID); - - deviceInfo->activePIDsCount = pidsCount; - - for( i = 0; i < pidsCount; i++ ) - { - deviceInfo->activePIDs[i] = pidList[i]; - printf("Active PID: %ld, type: %ld\n", pidList[i].pid, pidList[i].pidType); - } - - deviceInfo->pidsCount = 0; - - } - } - printf( "=====================================\n"); - - /* notify a potential VLC instance about the service change */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), - CFSTR("ServiceChanged"), - CFSTR(VLC_NOTIFICATION_OBJECT), - /*userInfo*/ NULL, - TRUE ); - - return result; -} - - -#pragma mark - -/* EyeTVPluginDispatcher, - * - * - selector : See 'EyeTVPluginDefs.h' - * - *refCon : The RefCon to the plug-in-related Data - * - deviceID : Identifies the Device - * - params : Parameters for functioncall - * - * This function is a part of the interface for the communication with EyeTV. If something happens, - * EyeTV thinks, we should know of, it calls this function with the corresponding selector. */ - -#pragma export on - -long EyeTVPluginDispatcher( EyeTVPluginParams* params ) -{ - long result = 0; - - switch( params->selector ) - { - case kEyeTVPluginSelector_Initialize: - result = VLCEyeTVPluginInitialize((VLCEyeTVPluginGlobals_t**)params->refCon, - params->initialize.apiVersion, params->initialize.callback); - break; - - case kEyeTVPluginSelector_Terminate: - result = VLCEyeTVPluginTerminate((VLCEyeTVPluginGlobals_t*)params->refCon); - break; - - case kEyeTVPluginSelector_GetInfo: - result = VLCEyeTVPluginGetInformation((VLCEyeTVPluginGlobals_t*)params->refCon, - params->info.pluginAPIVersion, params->info.pluginName, params->info.description); - break; - - case kEyeTVPluginSelector_DeviceAdded: - result = VLCEyeTVPluginDeviceAdded((VLCEyeTVPluginGlobals_t*)params->refCon, - params->deviceID, params->deviceAdded.deviceType); - break; - - case kEyeTVPluginSelector_DeviceRemoved: - result = VLCEyeTVPluginDeviceRemoved((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID); - break; - - case kEyeTVPluginSelector_PacketsArrived: - result = VLCEyeTVPluginPacketsArrived((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID, - params->packetsArrived.packets, params->packetsArrived.packetCount); - break; - - case kEyeTVPluginSelector_ServiceChanged: - result = VLCEyeTVPluginServiceChanged((VLCEyeTVPluginGlobals_t*)params->refCon, - params->deviceID, params->serviceChanged.headendID, - params->serviceChanged.transponderID, params->serviceChanged.serviceID, - params->serviceChanged.pidList, params->serviceChanged.pidCount); - break; - } - - return result; -} +/***************************************************************************** +* eyetvplugin.c: Plug-In for the EyeTV software to connect to VLC +***************************************************************************** +* Copyright (C) 2006-2007 the VideoLAN team +* $Id$ +* +* Authors: Felix Kühne +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. +*****************************************************************************/ + +#include "eyetvplugin.h" + +#include +#include +#include +#include + +#define MAX_PIDS 256 +#define MAX_ACTIVE_PIDS 256 +#define MAX_DEVICES 16 +#define VLC_NOTIFICATION_OBJECT "VLCEyeTVSupport" + +#pragma push +#pragma pack(1) + +typedef struct +{ + uint32_t sync_byte : 8, + transport_error_indicator : 1, + payload_unit_start_indicator : 1, + transport_priority : 1, + PID : 13, + transport_scrambling_control : 2, + adaptation_field_control : 2, + continuity_counter : 4; +} TransportStreamHeader; + +/* Structure for TS-Packets */ +typedef struct +{ + TransportStreamHeader header; + uint8_t payload[184]; + +} TransportStreamPacket; + +#pragma pop + + +/* Structure to hold global data to communicate with EyeTV */ +typedef struct +{ + EyeTVPluginCallbackProc callback; + /* Structure to hold current active service */ + EyeTVPluginDeviceID activeDeviceID; + long activePIDsCount; + EyeTVPluginPIDInfo activePIDs[MAX_ACTIVE_PIDS]; + long seenPIDs[MAX_ACTIVE_PIDS]; +} VLCEyeTVPluginGlobals_t; + +static int i_deviceCount; +static int vlcSock; + +#pragma mark - + +/* initialise the plug-in */ +static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long apiVersion, EyeTVPluginCallbackProc callback) +{ + printf("VLC media player Plug-In: Initialize\n"); + long result = 0; + + /* init our own storage */ + i_deviceCount = 0; + vlcSock = -1; + + /* notify a potential VLC instance about our initialisation */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), + CFSTR("PluginInit"), + CFSTR(VLC_NOTIFICATION_OBJECT), + /*userInfo*/ NULL, + TRUE ); + + /* init our notification support */ + CFNotificationCenterAddObserver( CFNotificationCenterGetDistributedCenter(), + /* observer */ NULL, + /* callBack */ VLCEyeTVPluginGlobalNotificationReceived, + /* name, NULL==all */ NULL, + CFSTR(VLC_NOTIFICATION_OBJECT), + CFNotificationSuspensionBehaviorDeliverImmediately ); + + *globals = (VLCEyeTVPluginGlobals_t *) calloc(1, sizeof( VLCEyeTVPluginGlobals_t ) ); + ( *globals )->callback = callback; + + return result; +} + +/* we will be terminated soon, clean up */ +static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals) +{ + long result = 0; + + printf("VLC media player Plug-In: Terminate\n"); + + /* notify a potential VLC instance about our termination */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), + CFSTR("PluginQuit"), + CFSTR(VLC_NOTIFICATION_OBJECT), + /*userInfo*/ NULL, + TRUE ); + + /* remove us from the global notification centre */ + CFNotificationCenterRemoveEveryObserver( CFNotificationCenterGetDistributedCenter(), + (void *)VLCEyeTVPluginGlobalNotificationReceived ); + + /* close data connection */ + if( vlcSock != -1 ) + { + close( vlcSock ); + vlcSock = -1; + } + + if( globals ) + { + long i; + for( i=0; iactivePIDsCount; ++i ) + { + printf("activePID: %ld, count=%ld\n", globals->activePIDs[i].pid, globals->seenPIDs[i] ); + } + free( globals ); + } + + return result; +} + +/* called when EyeTV asks various stuff about us */ +static long VLCEyeTVPluginGetInformation(VLCEyeTVPluginGlobals_t *globals, long* outAPIVersion, char* outName, char *outDescription) +{ + printf("VLC media player Plug-In: GetInfo\n"); + long result = 0; + + if( globals ) + { + if( outAPIVersion ) + { + *outAPIVersion = EYETV_PLUGIN_API_VERSION; + } + + if( outName ) + { + strcpy( outName, "VLC media player Plug-In"); + } + + if( outDescription ) + { + strcpy( outDescription, "This Plug-In connects EyeTV to the VLC media player for streaming purposes."); + } + } + + return result; +} + +/* called if we received a global notification */ +void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, + void *observer, + CFStringRef name, + const void *object, + CFDictionaryRef userInfo ) +{ + /* when VLC launches after us, we need to inform it about our existance and the current state of available devices */ + if( CFStringCompare( name, CFSTR( "VLCOSXGUIInit" ), 0) == kCFCompareEqualTo ) + { + /* we're here */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), + CFSTR("PluginInit"), + CFSTR(VLC_NOTIFICATION_OBJECT), + /*userInfo*/ NULL, + TRUE ); + if( i_deviceCount > 0 ) + { + /* at least one device is apparently connected */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), + CFSTR("DeviceAdded"), + CFSTR(VLC_NOTIFICATION_OBJECT), + /*userInfo*/ NULL, + TRUE ); + } + } + + /* VLC wants us to start sending data */ + if( CFStringCompare( name, CFSTR( "VLCAccessStartDataSending" ), 0) == kCFCompareEqualTo ) + { + if( vlcSock == -1 ) + { + int peerSock; + + /* set-up data socket */ + peerSock = socket(AF_UNIX, SOCK_STREAM, 0); + if( peerSock != -1 ) + { + struct sockaddr_un peerAddr; + /* set-up connection address */ + memset(&peerAddr, 0, sizeof(peerAddr)); + peerAddr.sun_family = AF_UNIX; + strncpy(peerAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(peerAddr.sun_path)-1); + + /* connect */ + printf("data connect in progess...\n"); + if( connect(peerSock, (struct sockaddr *)&peerAddr, sizeof(struct sockaddr_un)) != -1 ) + { + printf("data sending switched on\n"); + vlcSock = peerSock; + } + else + printf("connect data socket failed (errno=%d)\n", errno ); + } + else + printf("create data socket failed (errno=%d)\n", errno ); + } + } + + /* VLC wants us to stop sending data */ + if( CFStringCompare( name, CFSTR( "VLCAccessStopDataSending" ), 0) == kCFCompareEqualTo ) + { + if( vlcSock != -1 ) + { + close( vlcSock ); + vlcSock = -1; + printf( "data sending switched off\n" ); + } + } +} + +/* called if a device is added */ +static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, EyeTVPluginDeviceType deviceType) +{ + printf("VLC media player Plug-In: Device with type %i and ID %i added\n", (int)deviceType, (int)deviceID); + + long result = 0; + + if( globals ) + { + ++i_deviceCount; + if( 1 == i_deviceCount ) + { + /* notify a potential VLC instance about the addition */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), + CFSTR("DeviceAdded"), + CFSTR(VLC_NOTIFICATION_OBJECT), + /*userInfo*/ NULL, + TRUE ); + } + } + return result; +} + +/* called if a device is removed */ +static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID) +{ + printf("VLC media player Plug-In: DeviceRemoved\n"); + + long result = 0; + + --i_deviceCount; + if( 0 == i_deviceCount ) + { + /* notify a potential VLC instance about the removal */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), + CFSTR("DeviceRemoved"), + CFSTR(VLC_NOTIFICATION_OBJECT), + /*userInfo*/ NULL, + TRUE ); + } + if( (vlcSock != -1) && (deviceID == globals->activeDeviceID) ) + { + close(vlcSock); + vlcSock = -1; + printf( "data sending switched off\n" ); + } + + return result; +} + +/* This function is called, whenever packets are received by EyeTV. For reasons of performance, + * the data is the original data, not a copy. That means, EyeTV waits until this method is + * finished. Therefore all in this method should be as fast as possible. */ +static long VLCEyeTVPluginPacketsArrived(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, long **packets, long packetsCount) +{ + if( globals ) + { + /* check if data connection is active */ + if( vlcSock != -1 ) + { + if( deviceID == globals->activeDeviceID ) + { + long pidCount = globals->activePIDsCount; + if( pidCount ) + { + while( packetsCount ) + { + /* apply PID filtering, only PIDs in active service for device are sent through */ + long pid = (ntohl(**packets) & 0x001FFF00L)>>8; + long i; + for( i=0; iactivePIDs[i].pid == pid ) + { + ssize_t sent = write(vlcSock, *packets, sizeof(TransportStreamPacket)); + if( sent != sizeof(TransportStreamPacket) ) + { + if( sent == -1 ) + printf("data sending failed (errno=%d)\n", errno); + else + printf("data sending incomplete (sent=%d)\n", sent); + close(vlcSock); + vlcSock = -1; + return 0; + } + ++(globals->seenPIDs[i]); +#if 0 + if( i > 0 ) + { + /* if we assume that consecutive packets should have the same PID, it would therefore + speed up filtering to reorder activePIDs list based on pid occurrences */ + EyeTVPluginPIDInfo swap = globals->activePIDs[i]; + memmove(globals->activePIDs+1, globals->activePIDs, sizeof(EyeTVPluginPIDInfo)*i); + globals->activePIDs[0] = swap; + } + + if( pid && filterPidInfo.pidType != kEyeTVPIDType_PMT ) + { + /* to save on CPU, prevent EyeTV from mirroring that program by blocking video & audio packets + by changing PID to NULL PID */ +#if defined(WORDS_BIGENDIAN) + **packets |= 0x001FFF00L; +#else + **packets |= 0x00FFF800L; +#endif + } +#endif + /* done filtering on this packet, move on to next packet */ + break; + } + } + if( i == pidCount ) + printf("unexpected PID %ld\n", pid); + } + --packetsCount; + ++packets; + } + } + } + } + return 0; +} + +/* VLCEyeTVPluginServiceChanged, + * + * - *globals : The plug-in Globals + * - deviceID : Identifies the active Device + * - headendID : The HeadendID, for e300 it's the orbital position of the satelite in + * tenth degrees east + * - transponderID : The Frequency in kHz + * - serviceID : original ServiceID from the DVB-Stream (e300, e400) + * - pidList : List of active PIDs + * + * Whenever a service changes, this function is called. Service-related plug-in data should be updated here. + */ +static long VLCEyeTVPluginServiceChanged(VLCEyeTVPluginGlobals_t *globals, + EyeTVPluginDeviceID deviceID, + long headendID, + long transponderID, + long serviceID, + EyeTVPluginPIDInfo *pidList, + long pidsCount) +{ + long result = 0; + int i; + + printf("\nVLC media player Plug-In: ServiceChanged:\n"); + printf( "=====================================\n"); + + if( globals ) + { + printf("DeviceID: %ld, ", deviceID); + printf("HeadendID: %ld, ", headendID); + printf("TransponderID: %ld, ", transponderID); + printf("ServiceID: %ld\n\n", serviceID); + + globals->activeDeviceID = deviceID; + globals->activePIDsCount = pidsCount; + + for( i = 0; i < pidsCount; i++ ) + { + globals->activePIDs[i] = pidList[i]; + globals->seenPIDs[i] = 0; + printf("Active PID: %ld, type: %ld\n", pidList[i].pid, pidList[i].pidType); + } + } + printf( "=====================================\n"); + + /* notify a potential VLC instance about the service change */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), + CFSTR("ServiceChanged"), + CFSTR(VLC_NOTIFICATION_OBJECT), + /*userInfo*/ NULL, + TRUE ); + + return result; +} + + +#pragma mark - +/* EyeTVPluginDispatcher, + * + * - selector : See 'EyeTVPluginDefs.h' + * - *refCon : The RefCon to the plug-in-related Data + * - deviceID : Identifies the Device + * - params : Parameters for functioncall + * + * This function is a part of the interface for the communication with EyeTV. If something happens, + * EyeTV thinks, we should know of, it calls this function with the corresponding selector. */ + +#pragma export on + +long EyeTVPluginDispatcher( EyeTVPluginParams* params ) +{ + long result = 0; + + switch( params->selector ) + { + case kEyeTVPluginSelector_Initialize: + result = VLCEyeTVPluginInitialize((VLCEyeTVPluginGlobals_t**)params->refCon, + params->initialize.apiVersion, params->initialize.callback); + break; + + case kEyeTVPluginSelector_Terminate: + result = VLCEyeTVPluginTerminate((VLCEyeTVPluginGlobals_t*)params->refCon); + break; + + case kEyeTVPluginSelector_GetInfo: + result = VLCEyeTVPluginGetInformation((VLCEyeTVPluginGlobals_t*)params->refCon, + params->info.pluginAPIVersion, params->info.pluginName, params->info.description); + break; + + case kEyeTVPluginSelector_DeviceAdded: + result = VLCEyeTVPluginDeviceAdded((VLCEyeTVPluginGlobals_t*)params->refCon, + params->deviceID, params->deviceAdded.deviceType); + break; + + case kEyeTVPluginSelector_DeviceRemoved: + result = VLCEyeTVPluginDeviceRemoved((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID); + break; + + case kEyeTVPluginSelector_PacketsArrived: + result = VLCEyeTVPluginPacketsArrived((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID, + params->packetsArrived.packets, params->packetsArrived.packetCount); + break; + + case kEyeTVPluginSelector_ServiceChanged: + result = VLCEyeTVPluginServiceChanged((VLCEyeTVPluginGlobals_t*)params->refCon, + params->deviceID, params->serviceChanged.headendID, + params->serviceChanged.transponderID, params->serviceChanged.serviceID, + params->serviceChanged.pidList, params->serviceChanged.pidCount); + break; + } + + return result; +} diff --git a/extras/MacOSX/eyetvplugin/eyetvplugin.h b/extras/MacOSX/eyetvplugin/eyetvplugin.h index 43db14702d..8c9c26447e 100644 --- a/extras/MacOSX/eyetvplugin/eyetvplugin.h +++ b/extras/MacOSX/eyetvplugin/eyetvplugin.h @@ -22,9 +22,6 @@ *****************************************************************************/ #include "EyeTVPluginDefs.h" -#include -#include -#include #include void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, diff --git a/extras/MacOSX/eyetvplugin/eyetvplugin.xcodeproj/project.pbxproj b/extras/MacOSX/eyetvplugin/eyetvplugin.xcodeproj/project.pbxproj index 50e0f91aad..6448826318 100644 --- a/extras/MacOSX/eyetvplugin/eyetvplugin.xcodeproj/project.pbxproj +++ b/extras/MacOSX/eyetvplugin/eyetvplugin.xcodeproj/project.pbxproj @@ -122,7 +122,6 @@ mainGroup = 089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */; projectDirPath = ""; projectRoot = ""; - shouldCheckCompatibility = 1; targets = ( 8D57630D048677EA00EA77CD /* VLC EyeTV Plug-In */, ); diff --git a/modules/access/Modules.am b/modules/access/Modules.am index 9c448b072e..ae506d6d62 100644 --- a/modules/access/Modules.am +++ b/modules/access/Modules.am @@ -1,3 +1,8 @@ +# Automake forgets to add a proper tag to libtool with Objective-C files. +# Moreocer Libtool should default tag to CC when none is specified but +# obviously does not. Here is a fix for that. +LIBTOOL=@LIBTOOL@ --tag=CC + SOURCES_access_file = file.c SOURCES_access_directory = directory.c SOURCES_access_dv = dv.c @@ -7,7 +12,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_access_eyetv = eyetv.m SOURCES_dvdnav = dvdnav.c SOURCES_dvdread = dvdread.c SOURCES_dc1394 = dc1394.c diff --git a/modules/access/eyetv.c b/modules/access/eyetv.c deleted file mode 100644 index 64df63d873..0000000000 --- a/modules/access/eyetv.c +++ /dev/null @@ -1,318 +0,0 @@ -/***************************************************************************** - * eyetv.c : Access module to connect to our plugin running within EyeTV - ***************************************************************************** - * Copyright (C) 2006-2007 the VideoLAN team - * $Id$ - * - * Author: Felix Kühne - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. - *****************************************************************************/ - -/***************************************************************************** - * Preamble - *****************************************************************************/ - -#include -#include - -#include - -/* TODO: - * watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */ - -/***************************************************************************** - * Module descriptior - *****************************************************************************/ -static int Open ( vlc_object_t * ); -static void Close( vlc_object_t * ); - -vlc_module_begin(); - set_shortname( "EyeTV" ); - set_description( _("EyeTV access module") ); - set_category( CAT_INPUT ); - set_subcategory( SUBCAT_INPUT_ACCESS ); - - set_capability( "access2", 0 ); - add_shortcut( "eyetv" ); - set_callbacks( Open, Close ); -vlc_module_end(); - -/***************************************************************************** - * Access: local prototypes - *****************************************************************************/ -typedef struct -{ - VLC_COMMON_MEMBERS - - vlc_mutex_t lock; - vlc_cond_t wait; - - CFMessagePortRef inputMessagePortFromEyeTV; -} eyetv_thread_t; - -struct access_sys_t -{ - eyetv_thread_t *p_thread; -}; - -CFDataRef dataFromEyetv; -int lastPacketId; -int lastForwardedPacketId; - -static ssize_t Read( access_t *, uint8_t *, size_t ); -static int Control( access_t *, int, va_list ); -static void Thread( vlc_object_t * ); -CFDataRef msgPortCallback( CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info ); - -/***************************************************************************** - * Open: sets up the module and its threads - *****************************************************************************/ -static int Open( vlc_object_t *p_this ) -{ - access_t *p_access = (access_t *)p_this; - access_sys_t *p_sys; - eyetv_thread_t *p_thread; - CFMessagePortContext context; - memset(&context, 0, sizeof(context)); - - /* Init p_access */ - access_InitFields( p_access ); \ - ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL ); \ - MALLOC_ERR( p_access->p_sys, access_sys_t ); \ - p_sys = p_access->p_sys; memset( p_sys, 0, sizeof( access_sys_t ) ); - - msg_Dbg( p_access, "coming up" ); - - /* create receiving thread which will keep the message port alive without blocking */ - p_sys->p_thread = p_thread = vlc_object_create( p_access, sizeof( eyetv_thread_t ) ); - vlc_object_attach( p_thread, p_this ); - vlc_mutex_init( p_access, &p_thread->lock ); - vlc_cond_init( p_access, &p_thread->wait ); - msg_Dbg( p_access, "thread created, msg port following now" ); - - /* set up our own msg port - * we may give the msgport such a generic name, because EyeTV may only run - * once per entire machine, so we can't interfere with other instances. - * we just trust the user no to launch multiple VLC instances trying to - * access EyeTV at the same time. If this happens, the latest launched - * instance will win. */ - p_sys->p_thread->inputMessagePortFromEyeTV = CFMessagePortCreateLocal( kCFAllocatorDefault, - CFSTR("VLCEyeTVMsgPort"), - &msgPortCallback, - &context, - /* no info to free */ NULL ); - if( p_sys->p_thread->inputMessagePortFromEyeTV == NULL ) - { - msg_Err( p_access, "opening local msg port failed" ); - free( p_sys->p_thread->inputMessagePortFromEyeTV ); - vlc_mutex_destroy( &p_thread->lock ); - vlc_cond_destroy( &p_thread->wait ); - vlc_object_detach( p_thread ); - vlc_object_destroy( p_thread ); - free( p_sys ); - return VLC_EGENERIC; - } - else - msg_Dbg( p_access, "remote msg port opened" ); - - /* let the thread run */ - if( vlc_thread_create( p_thread, "EyeTV Receiver Thread", Thread, - VLC_THREAD_PRIORITY_HIGHEST, VLC_FALSE ) ) - { - msg_Err( p_access, "couldn't launch eyetv receiver thread" ); - vlc_mutex_destroy( &p_thread->lock ); - vlc_cond_destroy( &p_thread->wait ); - vlc_object_detach( p_thread ); - vlc_object_destroy( p_thread ); - free( p_sys ); - return VLC_EGENERIC; - } - - msg_Dbg( p_access, "receiver thread created and launched" ); - - /* tell the EyeTV plugin to open up its msg port and start sending */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), - CFSTR("VLCAccessStartDataSending"), - CFSTR("VLCEyeTVSupport"), - /*userInfo*/ NULL, - TRUE ); - - msg_Dbg( p_access, "plugin notified" ); - - /* we don't need such a high priority */ - //vlc_thread_set_priority( p_access, VLC_THREAD_PRIORITY_LOW ); - - return VLC_SUCCESS; -} - -/***************************************************************************** - * Close: closes msg-port, free resources - *****************************************************************************/ -static void Close( vlc_object_t *p_this ) -{ - access_t *p_access = (access_t *)p_this; - access_sys_t *p_sys = p_access->p_sys; - - msg_Dbg( p_access, "closing" ); - - /* tell the EyeTV plugin to close its msg port and stop sending */ - CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), - CFSTR("VLCAccessStopDataSending"), - CFSTR("VLCEyeTVSupport"), - /*userInfo*/ NULL, - TRUE ); - - msg_Dbg( p_access, "plugin notified" ); - - /* stop receiver thread */ - vlc_object_kill( p_sys->p_thread ); - vlc_mutex_lock( &p_sys->p_thread->lock ); - vlc_cond_signal( &p_sys->p_thread->wait ); - vlc_mutex_unlock( &p_sys->p_thread->lock ); - vlc_thread_join( p_sys->p_thread ); - - /* close msg port */ - CFMessagePortInvalidate( p_sys->p_thread->inputMessagePortFromEyeTV ); - free( p_sys->p_thread->inputMessagePortFromEyeTV ); - msg_Dbg( p_access, "msg port closed and freed" ); - - /* free thread */ - vlc_mutex_destroy( &p_sys->p_thread->lock ); - vlc_cond_destroy( &p_sys->p_thread->wait ); - vlc_object_detach( p_sys->p_thread ); - vlc_object_destroy( p_sys->p_thread ); - - free( p_sys ); -} - -static void Thread( vlc_object_t *p_this ) -{ - eyetv_thread_t *p_thread= (eyetv_thread_t*)p_this; - CFRunLoopSourceRef runLoopSource; - - /* create our run loop source for the port and attach it to our current loop */ - runLoopSource = CFMessagePortCreateRunLoopSource( kCFAllocatorDefault, - p_thread->inputMessagePortFromEyeTV, - 0 ); - CFRunLoopAddSource( CFRunLoopGetCurrent(), - runLoopSource, - kCFRunLoopDefaultMode ); - - CFRunLoopRun(); -} - - -/***************************************************************************** -* msgPortCallback: receives data from the EyeTV plugin -*****************************************************************************/ -CFDataRef msgPortCallback( CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info ) -{ - extern CFDataRef dataFromEyetv; - extern int lastPacketId; - - /* copy callback data to module data */ - dataFromEyetv = CFDataCreateCopy( kCFAllocatorDefault, data ); -#if 0 - printf( "packet %i contained %i bytes, forwarding %i bytes\n", - (int)msgid, - (int)CFDataGetLength( data ), - (int)CFDataGetLength( dataFromEyetv ) ); -#endif - - lastPacketId = msgid; - - return NULL; /* we've got nothing to return */ -} - -/***************************************************************************** -* Read: forwarding data from EyeTV plugin which was received above -*****************************************************************************/ -static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len ) -{ - access_sys_t *p_sys = p_access->p_sys; - extern CFDataRef dataFromEyetv; - extern int lastPacketId; - extern int lastForwardedPacketId; - - /* wait for a new buffer before forwarding */ - while( lastPacketId == lastForwardedPacketId && !p_access->b_die ) - { - msleep( INPUT_ERROR_SLEEP ); - } - - /* read data here, copy it to p_buffer, fill i_len with respective length - * and return info with i_read; i_read = 0 == EOF */ - if( dataFromEyetv ) - { - CFDataGetBytes( dataFromEyetv, - CFRangeMake( 0, CFDataGetLength( dataFromEyetv ) ), - (uint8_t *)p_buffer ); - i_len = (int)CFDataGetLength( dataFromEyetv ); -#if 0 - msg_Dbg( p_access, "%i bytes with id %i received in read function, pushing to core", - (int)CFDataGetLength( dataFromEyetv ), lastPacketId ); -#endif - lastForwardedPacketId = lastPacketId; - if( i_len == 0) - { - msg_Err( p_access, "you looosed!" ); - return 0; - } - } - - if( p_access->b_die ) - return 0; - - return i_len; -} - -/***************************************************************************** - * Control: - *****************************************************************************/ -static int Control( access_t *p_access, int i_query, va_list args ) -{/* - vlc_bool_t *pb_bool; - int *pi_int; - int64_t *pi_64; - - switch( i_query ) - { - * * - case ACCESS_SET_PAUSE_STATE: - * Nothing to do * - break; - - case ACCESS_CAN_SEEK: - case ACCESS_CAN_FASTSEEK: - case ACCESS_CAN_PAUSE: - case ACCESS_CAN_CONTROL_PACE: - case ACCESS_GET_MTU: - case ACCESS_GET_PTS_DELAY: - case ACCESS_GET_TITLE_INFO: - case ACCESS_SET_TITLE: - case ACCESS_SET_SEEKPOINT: - case ACCESS_SET_PRIVATE_ID_STATE: - case ACCESS_GET_CONTENT_TYPE: - return VLC_EGENERIC; - - default: - msg_Warn( p_access, "unimplemented query in control" ); - return VLC_EGENERIC; - - } - return VLC_SUCCESS;*/ - return VLC_EGENERIC; -} diff --git a/modules/access/eyetv.m b/modules/access/eyetv.m new file mode 100644 index 0000000000..e7150c9c40 --- /dev/null +++ b/modules/access/eyetv.m @@ -0,0 +1,315 @@ +/***************************************************************************** + * eyetv.c : Access module to connect to our plugin running within EyeTV + ***************************************************************************** + * Copyright (C) 2006-2007 the VideoLAN team + * $Id: eyetv.c 23509 2007-12-09 17:39:28Z courmisch $ + * + * Author: Felix Kühne + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ + +#include +#include + +#include + +#include +#include +#include +#include + +#import + +/* TODO: + * watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */ + +/***************************************************************************** + * Module descriptior + *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +#define CHANNEL_TEXT N_("Channel number") +#define CHANNEL_LONGTEXT N_( \ + "EyeTV program number, or use 0 for last channel, " \ + "-1 for S-Video input, -2 for Composite input" ) +vlc_module_begin(); + set_shortname( "EyeTV" ); + set_description( _("EyeTV access module") ); + set_category( CAT_INPUT ); + set_subcategory( SUBCAT_INPUT_ACCESS ); + + add_integer( "eyetv-channel", 0, NULL, + CHANNEL_TEXT, CHANNEL_LONGTEXT, VLC_FALSE ); + + set_capability( "access2", 0 ); + add_shortcut( "eyetv" ); + set_callbacks( Open, Close ); +vlc_module_end(); + +/***************************************************************************** + * Access: local prototypes + *****************************************************************************/ +struct access_sys_t +{ + int eyetvSock; +}; + +static ssize_t Read( access_t *, uint8_t *, size_t ); +static int Control( access_t *, int, va_list ); + +static void selectChannel( vlc_object_t *p_this, int theChannelNum ) +{ + NSAppleScript *script; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + switch( theChannelNum ) + { + case -2: // Composite + script = [[NSAppleScript alloc] initWithSource: + @"tell application \"EyeTV\"\n" + " input_change input source composite video input\n" + " volume_change level 0\n" + " show player_window\n" + " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + "end tell"]; + break; + case -1: // S-Video + script = [[NSAppleScript alloc] initWithSource: + @"tell application \"EyeTV\"\n" + " input_change input source S video input\n" + " volume_change level 0\n" + " show player_window\n" + " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + "end tell"]; + break; + case 0: // Last + script = [[NSAppleScript alloc] initWithSource: + @"tell application \"EyeTV\"\n" + " volume_change level 0\n" + " show player_window\n" + " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + "end tell"]; + break; + default: + if( theChannelNum > 0 ) + { + NSString *channel_change = [NSString stringWithFormat: + @"tell application \"EyeTV\"\n" + " channel_change channel number %d\n" + " volume_change level 0\n" + " show player_window\n" + " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + "end tell", theChannelNum]; + script = [[NSAppleScript alloc] initWithSource:channel_change]; + } + else + return; + } + NSDictionary *errorDict; + NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&errorDict]; + if( nil == descriptor ) + { + NSString *errorString = [errorDict objectForKey:NSAppleScriptErrorMessage]; + msg_Err( p_this, "EyeTV source change failed with error status '%s'", [errorString UTF8String] ); + } + [script release]; + [pool release]; +} + +/***************************************************************************** + * Open: sets up the module and its threads + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + access_t *p_access = (access_t *)p_this; + access_sys_t *p_sys; + + struct sockaddr_un publicAddr, peerAddr; + int publicSock; + + vlc_value_t val; + + /* Init p_access */ + access_InitFields( p_access ); \ + ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL ); \ + MALLOC_ERR( p_access->p_sys, access_sys_t ); \ + p_sys = p_access->p_sys; memset( p_sys, 0, sizeof( access_sys_t ) ); + + var_Create( p_access, "eyetv-channel", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); + var_Get( p_access, "eyetv-channel", &val); + + msg_Dbg( p_access, "coming up" ); + + selectChannel(p_this, val.i_int); + + /* socket */ + memset(&publicAddr, 0, sizeof(publicAddr)); + publicAddr.sun_family = AF_UNIX; + strncpy(publicAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(publicAddr.sun_path)-1); + /* remove previous public path if it wasn't cleanly removed */ + if( (0 != unlink(publicAddr.sun_path)) && (ENOENT != errno) ) + { + msg_Err( p_access, "local socket path is not usable (errno=%d)", errno ); + free( p_sys ); + return VLC_EGENERIC; + } + + publicSock = socket(AF_UNIX, SOCK_STREAM, 0); + if( publicSock == -1 ) + { + msg_Err( p_access, "create local socket failed (errno=%d)", errno ); + free( p_sys ); + return VLC_EGENERIC; + } + + if( bind(publicSock, (struct sockaddr *)&publicAddr, sizeof(struct sockaddr_un)) == -1 ) + { + msg_Err( p_access, "bind local socket failed (errno=%d)", errno ); + close( publicSock ); + free( p_sys ); + return VLC_EGENERIC; + } + + /* we are not expecting more than one connection */ + if( listen(publicSock, 1) == -1 ) + { + msg_Err( p_access, "cannot accept connection (errno=%d)", errno ); + close( publicSock ); + free( p_sys ); + return VLC_EGENERIC; + } + else + { + socklen_t peerSockLen = sizeof(struct sockaddr_un); + int peerSock; + + /* tell the EyeTV plugin to open start sending */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), + CFSTR("VLCAccessStartDataSending"), + CFSTR("VLCEyeTVSupport"), + /*userInfo*/ NULL, + TRUE ); + + msg_Dbg( p_access, "plugin notified" ); + + peerSock = accept(publicSock, (struct sockaddr *)&peerAddr, &peerSockLen); + if( peerSock == -1 ) + { + msg_Err( p_access, "cannot wait for connection (errno=%d)", errno ); + close( publicSock ); + free( p_sys ); + return VLC_EGENERIC; + } + + msg_Dbg( p_access, "plugin connected" ); + + p_sys->eyetvSock = peerSock; + + /* remove public access */ + close(publicSock); + unlink(publicAddr.sun_path); + } + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: closes msg-port, free resources + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + access_t *p_access = (access_t *)p_this; + access_sys_t *p_sys = p_access->p_sys; + + msg_Dbg( p_access, "closing" ); + + /* tell the EyeTV plugin to close its msg port and stop sending */ + CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), + CFSTR("VLCAccessStopDataSending"), + CFSTR("VLCEyeTVSupport"), + /*userInfo*/ NULL, + TRUE ); + + msg_Dbg( p_access, "plugin notified" ); + + close(p_sys->eyetvSock); + + msg_Dbg( p_access, "msg port closed and freed" ); + + free( p_sys ); +} + +/***************************************************************************** +* Read: forwarding data from EyeTV plugin which was received above +*****************************************************************************/ +static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len ) +{ + access_sys_t *p_sys = p_access->p_sys; + int i_read; + + if( p_access->info.b_eof ) + return 0; + + i_read = net_Read( p_access, p_sys->eyetvSock, NULL, p_buffer, i_len, + VLC_FALSE ); + if( i_read == 0 ) + p_access->info.b_eof = VLC_TRUE; + else if( i_read > 0 ) + p_access->info.i_pos += i_read; + + return i_read; +} + +/***************************************************************************** + * Control: + *****************************************************************************/ +static int Control( access_t *p_access, int i_query, va_list args ) +{/* + vlc_bool_t *pb_bool; + int *pi_int; + int64_t *pi_64; + + switch( i_query ) + { + * * + case ACCESS_SET_PAUSE_STATE: + * Nothing to do * + break; + + case ACCESS_CAN_SEEK: + case ACCESS_CAN_FASTSEEK: + case ACCESS_CAN_PAUSE: + case ACCESS_CAN_CONTROL_PACE: + case ACCESS_GET_MTU: + case ACCESS_GET_PTS_DELAY: + case ACCESS_GET_TITLE_INFO: + case ACCESS_SET_TITLE: + case ACCESS_SET_SEEKPOINT: + case ACCESS_SET_PRIVATE_ID_STATE: + case ACCESS_GET_CONTENT_TYPE: + return VLC_EGENERIC; + + default: + msg_Warn( p_access, "unimplemented query in control" ); + return VLC_EGENERIC; + + } + return VLC_SUCCESS;*/ + return VLC_EGENERIC; +} diff --git a/modules/gui/macosx/eyetv.m b/modules/gui/macosx/eyetv.m index c6ad4c1d94..8220a7159a 100644 --- a/modules/gui/macosx/eyetv.m +++ b/modules/gui/macosx/eyetv.m @@ -132,8 +132,6 @@ static VLCEyeTVController *_o_sharedInstance = nil; script = [[NSAppleScript alloc] initWithSource: @"tell application \"EyeTV\"\n" "channel_up\n" - "volume_change level 0\n" - "tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" "get current channel\n" "end tell"]; msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel up" ); @@ -143,8 +141,6 @@ static VLCEyeTVController *_o_sharedInstance = nil; script = [[NSAppleScript alloc] initWithSource: @"tell application \"EyeTV\"\n" "channel_down\n" - "volume_change level 0\n" - "tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" "get current channel\n" "end tell"]; msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel down" ); @@ -172,25 +168,21 @@ static VLCEyeTVController *_o_sharedInstance = nil; case -2: // Composite script = [[NSAppleScript alloc] initWithSource: @"tell application \"EyeTV\"\n" - " input_change input source composite video input" - " volume_change level 0\n" - " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + " input_change input source composite video input\n" + " show player_window\n" "end tell"]; break; case -1: // S-Video script = [[NSAppleScript alloc] initWithSource: @"tell application \"EyeTV\"\n" - " input_change input source S video input" - " volume_change level 0\n" - " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + " input_change input source S video input\n" + " show player_window\n" "end tell"]; break; - case 0: // Tuner + case 0: // Last script = [[NSAppleScript alloc] initWithSource: @"tell application \"EyeTV\"\n" - " input_change input source tuner input" - " volume_change level 0\n" - " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + " show player_window\n" "end tell"]; break; default: @@ -198,9 +190,8 @@ static VLCEyeTVController *_o_sharedInstance = nil; { NSString *channel_change = [NSString stringWithFormat: @"tell application \"EyeTV\"\n" - @" channel_change channel number %d\n" - " volume_change level 0\n" - " tell application \"System Events\" to set visible of process \"EyeTV\" to false\n" + " channel_change channel number %d\n" + " show player_window\n" "end tell", theChannelNum]; script = [[NSAppleScript alloc] initWithSource:channel_change]; } diff --git a/modules/gui/macosx/open.m b/modules/gui/macosx/open.m index df3194495e..630331f08e 100644 --- a/modules/gui/macosx/open.m +++ b/modules/gui/macosx/open.m @@ -83,7 +83,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class ) p_list = [NSMutableArray arrayWithCapacity: 1]; next_media = IOIteratorNext( media_iterator ); - if( next_media != nil ) + if( next_media ) { char psz_buf[0x32]; size_t dev_path_length; @@ -116,7 +116,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class ) IOObjectRelease( next_media ); - } while( ( next_media = IOIteratorNext( media_iterator ) ) != nil ); + } while( ( next_media = IOIteratorNext( media_iterator ) ) ); } IOObjectRelease( media_iterator ); @@ -237,11 +237,14 @@ static VLCOpen *_o_sharedMainInstance = nil; /* wake up with the correct EyeTV GUI */ if( [[[VLCMain sharedInstance] getEyeTVController] isEyeTVrunning] == YES ) - [o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"]; - else if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES ) { - [o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"]; - [self setupChannelInfo]; + if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES ) + { + [o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"]; + [self setupChannelInfo]; + } + else + [o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"]; } else [o_eyetv_tabView selectTabViewItemWithIdentifier:@"noeyetv"]; @@ -411,6 +414,10 @@ static VLCOpen *_o_sharedMainInstance = nil; { [self openNetInfoChanged: nil]; } + else if( [o_label isEqualToString: _NS("EyeTV")] ) + { + [o_mrl setStringValue: @"eyetv://"]; + } } - (void)openFileGeneric @@ -797,12 +804,23 @@ static VLCOpen *_o_sharedMainInstance = nil; - (IBAction)eyetvSwitchChannel:(id)sender { if( sender == o_eyetv_nextProgram_btn ) - [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: YES]]; + { + int chanNum = [[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: YES]; + [o_eyetv_channels_pop selectItemWithTag:chanNum]; + [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]]; + } else if( sender == o_eyetv_previousProgram_btn ) - [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: NO]]; + { + int chanNum = [[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: NO]; + [o_eyetv_channels_pop selectItemWithTag:chanNum]; + [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]]; + } else if( sender == o_eyetv_channels_pop ) - [[[VLCMain sharedInstance] getEyeTVController] selectChannel: - [[sender selectedItem] tag]]; + { + int chanNum = [[sender selectedItem] tag]; + [[[VLCMain sharedInstance] getEyeTVController] selectChannel:chanNum]; + [o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]]; + } else msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" ); } @@ -865,9 +883,6 @@ static VLCOpen *_o_sharedMainInstance = nil; if( channels ) { NSString *channel; - [[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("Tuner") - action: nil - keyEquivalent: @""] setTag:x++]; [[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]]; while( channel = [channels nextObject] ) { @@ -875,7 +890,7 @@ static VLCOpen *_o_sharedMainInstance = nil; * additionally, we save a bit of time */ [[[o_eyetv_channels_pop menu] addItemWithTitle: channel action: nil - keyEquivalent: @""] setTag:x++]; + keyEquivalent: @""] setTag:++x]; } /* make Tuner the default */ [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] currentChannel]]; @@ -884,8 +899,6 @@ static VLCOpen *_o_sharedMainInstance = nil; /* clean up GUI */ [o_eyetv_chn_bgbar setHidden: YES]; [o_eyetv_chn_status_txt setHidden: YES]; - - [o_mrl setStringValue: @"eyetv:"]; } - (IBAction)subsChanged:(id)sender