Commit 36868ee9 authored by Damien Fouilleul's avatar Damien Fouilleul

eyetv: latest version of EyeTV capture plugin, needs lotta testing

parent 5266ede1
/***************************************************************************** /*****************************************************************************
* eyetvplugin.c: Plug-In for the EyeTV software to connect to VLC * eyetvplugin.c: Plug-In for the EyeTV software to connect to VLC
***************************************************************************** *****************************************************************************
* Copyright (C) 2006-2007 the VideoLAN team * Copyright (C) 2006-2007 the VideoLAN team
* $Id$ * $Id$
* *
* Authors: Felix Kühne <fkuehne at videolan dot org> * Authors: Felix Kühne <fkuehne at videolan dot org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/ *****************************************************************************/
#include "eyetvplugin.h" #include "eyetvplugin.h"
#define MAX_PIDS 256 #include <sys/types.h>
#define MAX_ACTIVE_PIDS 256 #include <sys/socket.h>
#define MAX_DEVICES 16 #include <sys/un.h>
#define VLC_NOTIFICATION_OBJECT "VLCEyeTVSupport" #include <unistd.h>
#pragma push #define MAX_PIDS 256
#pragma pack(1) #define MAX_ACTIVE_PIDS 256
#define MAX_DEVICES 16
#define VLC_NOTIFICATION_OBJECT "VLCEyeTVSupport"
/* Structure for TS-Packets */
typedef struct #pragma push
{ #pragma pack(1)
unsigned long sync_byte : 8,
transport_error_indicator : 1, typedef struct
payload_unit_start_indicator : 1, {
transport_priority : 1, uint32_t sync_byte : 8,
PID : 13, transport_error_indicator : 1,
transport_scrambling_control : 2, payload_unit_start_indicator : 1,
adaptation_field_control : 2, transport_priority : 1,
continuity_counter : 4; PID : 13,
transport_scrambling_control : 2,
unsigned char data[188-4]; adaptation_field_control : 2,
continuity_counter : 4;
} TransportStreamPacket; } TransportStreamHeader;
#pragma pop /* Structure for TS-Packets */
typedef struct
{
/* Structure to hold Information on devices */ TransportStreamHeader header;
typedef struct uint8_t payload[184];
{
EyeTVPluginDeviceID deviceID; } TransportStreamPacket;
EyeTVPluginDeviceType deviceType;
#pragma pop
long headendID;
long transponderID;
long serviceID; /* Structure to hold global data to communicate with EyeTV */
typedef struct
long pidsCount; {
long pids[MAX_PIDS]; EyeTVPluginCallbackProc callback;
/* Structure to hold current active service */
EyeTVPluginPIDInfo activePIDs[MAX_ACTIVE_PIDS]; EyeTVPluginDeviceID activeDeviceID;
long activePIDsCount; long activePIDsCount;
EyeTVPluginPIDInfo activePIDs[MAX_ACTIVE_PIDS];
} DeviceInfo; long seenPIDs[MAX_ACTIVE_PIDS];
} VLCEyeTVPluginGlobals_t;
/* Structure to hold global data to communicate with EyeTV */ static int i_deviceCount;
typedef struct static int vlcSock;
{
EyeTVPluginCallbackProc callback; #pragma mark -
long deviceCount;
DeviceInfo devices[MAX_DEVICES]; /* initialise the plug-in */
long long packetCount; static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long apiVersion, EyeTVPluginCallbackProc callback)
{
} VLCEyeTVPluginGlobals_t; printf("VLC media player Plug-In: Initialize\n");
long result = 0;
/* 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 */ /* init our own storage */
typedef struct i_deviceCount = 0;
{ vlcSock = -1;
int i_deviceCount;
CFMessagePortRef messagePortToVLC; /* notify a potential VLC instance about our initialisation */
bool b_msgPortOpen; CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
} VLCEyeTVPluginOwnGlobals_t; CFSTR("PluginInit"),
CFSTR(VLC_NOTIFICATION_OBJECT),
VLCEyeTVPluginOwnGlobals_t *nativeGlobals; /*userInfo*/ NULL,
TRUE );
/* return the DeviceInfo with ID deviceID */ /* init our notification support */
static DeviceInfo *GetDeviceInfo(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID) CFNotificationCenterAddObserver( CFNotificationCenterGetDistributedCenter(),
{ /* observer */ NULL,
int i; /* callBack */ VLCEyeTVPluginGlobalNotificationReceived,
/* name, NULL==all */ NULL,
if( globals ) CFSTR(VLC_NOTIFICATION_OBJECT),
{ CFNotificationSuspensionBehaviorDeliverImmediately );
for( i=0; i<globals->deviceCount; i++)
{ *globals = (VLCEyeTVPluginGlobals_t *) calloc(1, sizeof( VLCEyeTVPluginGlobals_t ) );
if( globals->devices[i].deviceID == deviceID ) ( *globals )->callback = callback;
{
return &globals->devices[i]; return result;
} }
}
} /* we will be terminated soon, clean up */
static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals)
return NULL; {
} long result = 0;
#pragma mark - printf("VLC media player Plug-In: Terminate\n");
/* initialise the plug-in */ /* notify a potential VLC instance about our termination */
static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long apiVersion, EyeTVPluginCallbackProc callback) CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
{ CFSTR("PluginQuit"),
printf("VLC media player Plug-In: Initialize\n"); CFSTR(VLC_NOTIFICATION_OBJECT),
long result = 0; /*userInfo*/ NULL,
TRUE );
/* init our own storage */
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; /* remove us from the global notification centre */
nativeGlobals = malloc( sizeof( VLCEyeTVPluginOwnGlobals_t ) ); CFNotificationCenterRemoveEveryObserver( CFNotificationCenterGetDistributedCenter(),
(void *)VLCEyeTVPluginGlobalNotificationReceived );
/* notify a potential VLC instance about our initialisation */
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), /* close data connection */
CFSTR("PluginInit"), if( vlcSock != -1 )
CFSTR(VLC_NOTIFICATION_OBJECT), {
/*userInfo*/ NULL, close( vlcSock );
TRUE ); vlcSock = -1;
}
/* init our notification support */
CFNotificationCenterAddObserver( CFNotificationCenterGetDistributedCenter(), if( globals )
/* observer */ NULL, {
/* callBack */ VLCEyeTVPluginGlobalNotificationReceived, long i;
/* name, NULL==all */ NULL, for( i=0; i<globals->activePIDsCount; ++i )
CFSTR(VLC_NOTIFICATION_OBJECT), {
CFNotificationSuspensionBehaviorDeliverImmediately ); printf("activePID: %ld, count=%ld\n", globals->activePIDs[i].pid, globals->seenPIDs[i] );
}
*globals = (VLCEyeTVPluginGlobals_t *) calloc(1, sizeof( VLCEyeTVPluginGlobals_t ) ); free( globals );
( *globals )->callback = callback; }
return result; return result;
} }
/* we will be terminated soon, clean up */ /* called when EyeTV asks various stuff about us */
static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals) static long VLCEyeTVPluginGetInformation(VLCEyeTVPluginGlobals_t *globals, long* outAPIVersion, char* outName, char *outDescription)
{ {
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; printf("VLC media player Plug-In: GetInfo\n");
long result = 0;
printf("VLC media player Plug-In: Terminate\n");
if( globals )
long result = 0; {
if( outAPIVersion )
/* notify a potential VLC instance about our termination */ {
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), *outAPIVersion = EYETV_PLUGIN_API_VERSION;
CFSTR("PluginQuit"), }
CFSTR(VLC_NOTIFICATION_OBJECT),
/*userInfo*/ NULL, if( outName )
TRUE ); {
strcpy( outName, "VLC media player Plug-In");
/* remove us from the global notification centre */ }
CFNotificationCenterRemoveEveryObserver( CFNotificationCenterGetDistributedCenter(),
(void *)VLCEyeTVPluginGlobalNotificationReceived ); if( outDescription )
{
/* invalidate and free msg port */ strcpy( outDescription, "This Plug-In connects EyeTV to the VLC media player for streaming purposes.");
if( nativeGlobals->messagePortToVLC ) }
{ }
CFMessagePortInvalidate( nativeGlobals->messagePortToVLC );
free( nativeGlobals->messagePortToVLC ); return result;
printf( "msgport invalidated and freed\n" ); }
}
else /* called if we received a global notification */
printf( "no msgport to free\n" ); void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center,
void *observer,
if( globals ) CFStringRef name,
{ const void *object,
free( globals ); CFDictionaryRef userInfo )
} {
/* when VLC launches after us, we need to inform it about our existance and the current state of available devices */
if( nativeGlobals ) if( CFStringCompare( name, CFSTR( "VLCOSXGUIInit" ), 0) == kCFCompareEqualTo )
free( nativeGlobals ); {
/* we're here */
return result; CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
} CFSTR("PluginInit"),
CFSTR(VLC_NOTIFICATION_OBJECT),
/* called when EyeTV asks various stuff about us */ /*userInfo*/ NULL,
static long VLCEyeTVPluginGetInformation(VLCEyeTVPluginGlobals_t *globals, long* outAPIVersion, char* outName, char *outDescription) TRUE );
{ if( i_deviceCount > 0 )
printf("VLC media player Plug-In: GetInfo\n"); {
long result = 0; /* at least one device is apparently connected */
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
if( globals ) CFSTR("DeviceAdded"),
{ CFSTR(VLC_NOTIFICATION_OBJECT),
if( outAPIVersion ) /*userInfo*/ NULL,
{ TRUE );
*outAPIVersion = EYETV_PLUGIN_API_VERSION; }
} }
if( outName ) /* VLC wants us to start sending data */
{ if( CFStringCompare( name, CFSTR( "VLCAccessStartDataSending" ), 0) == kCFCompareEqualTo )
char* name = "VLC media player Plug-In"; {
strcpy( &outName[0], name); if( vlcSock == -1 )
} {
int peerSock;
if( outDescription )
{ /* set-up data socket */
char* desc = "This Plug-In connects EyeTV to the VLC media player for streaming purposes."; peerSock = socket(AF_UNIX, SOCK_STREAM, 0);
strcpy( &outDescription[0], desc); if( peerSock != -1 )
} {
} struct sockaddr_un peerAddr;
/* set-up connection address */
return result; memset(&peerAddr, 0, sizeof(peerAddr));
} peerAddr.sun_family = AF_UNIX;
strncpy(peerAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(peerAddr.sun_path)-1);
/* called if we received a global notification */
void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, /* connect */
void *observer, printf("data connect in progess...\n");
CFStringRef name, if( connect(peerSock, (struct sockaddr *)&peerAddr, sizeof(struct sockaddr_un)) != -1 )
const void *object, {
CFDictionaryRef userInfo ) printf("data sending switched on\n");
{ vlcSock = peerSock;
CFIndex maxlen; }
char *theName, *theObject; else
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; printf("connect data socket failed (errno=%d)\n", errno );
}
maxlen = CFStringGetMaximumSizeForEncoding( CFStringGetLength( name ), else
kCFStringEncodingUTF8) + 1; printf("create data socket failed (errno=%d)\n", errno );
theName = malloc(maxlen); }
CFStringGetCString( name, }
theName,
maxlen, /* VLC wants us to stop sending data */
kCFStringEncodingUTF8); if( CFStringCompare( name, CFSTR( "VLCAccessStopDataSending" ), 0) == kCFCompareEqualTo )
{
maxlen = CFStringGetMaximumSizeForEncoding( CFStringGetLength( name ), if( vlcSock != -1 )
kCFStringEncodingUTF8) + 1; {
theObject = malloc(maxlen); close( vlcSock );
CFStringGetCString( object, vlcSock = -1;
theObject, printf( "data sending switched off\n" );
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 */ /* called if a device is added */
if( CFStringCompare( name, CFSTR( "VLCOSXGUIInit" ), 0) == kCFCompareEqualTo ) static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, EyeTVPluginDeviceType deviceType)
{ {
/* we're here */ printf("VLC media player Plug-In: Device with type %i and ID %i added\n", (int)deviceType, (int)deviceID);
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
CFSTR("PluginInit"), long result = 0;
CFSTR(VLC_NOTIFICATION_OBJECT),
/*userInfo*/ NULL, if( globals )
TRUE ); {
if( nativeGlobals && ( nativeGlobals->i_deviceCount > 0 ) ) ++i_deviceCount;
{ if( 1 == i_deviceCount )
/* at least one device is apparently connected */ {
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), /* notify a potential VLC instance about the addition */
CFSTR("DeviceAdded"), CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
CFSTR(VLC_NOTIFICATION_OBJECT), CFSTR("DeviceAdded"),
/*userInfo*/ NULL, CFSTR(VLC_NOTIFICATION_OBJECT),
TRUE ); /*userInfo*/ NULL,
} TRUE );
} }
}
/* VLC wants us to start sending data */ return result;
if( CFStringCompare( name, CFSTR( "VLCAccessStartDataSending" ), 0) == kCFCompareEqualTo ) }
{
nativeGlobals->messagePortToVLC = CFMessagePortCreateRemote( kCFAllocatorDefault, /* called if a device is removed */
CFSTR("VLCEyeTVMsgPort") ); static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID)
if( nativeGlobals->messagePortToVLC == NULL ) {
printf( "getting messagePortToVLC failed!\n" ); printf("VLC media player Plug-In: DeviceRemoved\n");
else
{ long result = 0;
nativeGlobals->b_msgPortOpen = TRUE;
printf( "msg port opened / data sending switched on\n" ); --i_deviceCount;
} if( 0 == i_deviceCount )
} {
/* notify a potential VLC instance about the removal */
/* VLC wants us to stop sending data */ CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
if( CFStringCompare( name, CFSTR( "VLCAccessStopDataSending" ), 0) == kCFCompareEqualTo ) CFSTR("DeviceRemoved"),
{ CFSTR(VLC_NOTIFICATION_OBJECT),
nativeGlobals->b_msgPortOpen = FALSE; /*userInfo*/ NULL,
printf( "data sending switched off\n" ); TRUE );
} }
} if( (vlcSock != -1) && (deviceID == globals->activeDeviceID) )
{
/* called if a device is added */ close(vlcSock);
static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, EyeTVPluginDeviceType deviceType) vlcSock = -1;
{ printf( "data sending switched off\n" );
printf("VLC media player Plug-In: Device with type %i and ID %i added\n", (int)deviceType, (int)deviceID); }
long result = 0; return result;
DeviceInfo *deviceInfo; }
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;
/* 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
if( globals ) * 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->deviceCount < MAX_DEVICES ) {
{ if( globals )
deviceInfo = &( globals->devices[globals->deviceCount] ); {
memset(deviceInfo, 0, sizeof(DeviceInfo)); /* check if data connection is active */
if( vlcSock != -1 )
deviceInfo->deviceID = deviceID; {
deviceInfo->deviceType = deviceType; if( deviceID == globals->activeDeviceID )
{
globals->deviceCount++; long pidCount = globals->activePIDsCount;
if( pidCount )
if( nativeGlobals ) {
nativeGlobals->i_deviceCount = globals->deviceCount; while( packetsCount )
{
/* notify a potential VLC instance about the addition */ /* apply PID filtering, only PIDs in active service for device are sent through */
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), long pid = (ntohl(**packets) & 0x001FFF00L)>>8;
CFSTR("DeviceAdded"), long i;
CFSTR(VLC_NOTIFICATION_OBJECT), for( i=0; i<pidCount; ++i )
/*userInfo*/ NULL, {
TRUE ); if( globals->activePIDs[i].pid == pid )
} {
} ssize_t sent = write(vlcSock, *packets, sizeof(TransportStreamPacket));
if( sent != sizeof(TransportStreamPacket) )
return result; {
} if( sent == -1 )
printf("data sending failed (errno=%d)\n", errno);
/* called if a device is removed */ else
static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID) printf("data sending incomplete (sent=%d)\n", sent);
{ close(vlcSock);
printf("VLC media player Plug-In: DeviceRemoved\n"); vlcSock = -1;
return 0;
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; }
long result = 0; ++(globals->seenPIDs[i]);
int i; #if 0
if( i > 0 )
if( globals ) {
{ /* if we assume that consecutive packets should have the same PID, it would therefore
for( i = 0; i < globals->deviceCount; i++ ) speed up filtering to reorder activePIDs list based on pid occurrences */
{ EyeTVPluginPIDInfo swap = globals->activePIDs[i];
if ( globals->devices[i].deviceID == deviceID ) memmove(globals->activePIDs+1, globals->activePIDs, sizeof(EyeTVPluginPIDInfo)*i);
{ globals->activePIDs[0] = swap;
globals->deviceCount--; }
if( i<globals->deviceCount ) if( pid && filterPidInfo.pidType != kEyeTVPIDType_PMT )
{ {
globals->devices[i] = globals->devices[globals->deviceCount]; /* 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)
if( nativeGlobals ) **packets |= 0x001FFF00L;
nativeGlobals->i_deviceCount = globals->deviceCount; #else
**packets |= 0x00FFF800L;
/* notify a potential VLC instance about the removal */ #endif
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(), }
CFSTR("DeviceRemoved"), #endif
CFSTR(VLC_NOTIFICATION_OBJECT), /* done filtering on this packet, move on to next packet */
/*userInfo*/ NULL, break;
TRUE ); }
} }
} if( i == pidCount )
} printf("unexpected PID %ld\n", pid);
}
return result; --packetsCount;
} ++packets;
}
/* 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; return 0;
static long VLCEyeTVPluginPacketsArrived(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, long **packets, long packetsCount) }
{
long result = 0; /* VLCEyeTVPluginServiceChanged,
int i, j, isNewPID; *
TransportStreamPacket *packet; * - *globals : The plug-in Globals
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals; * - deviceID : Identifies the active Device
SInt32 i_returnValue; * - headendID : The HeadendID, for e300 it's the orbital position of the satelite in
CFMutableDataRef theMutableRef; * tenth degrees east
uint8_t *p_bufferForSending = malloc(4); * - transponderID : The Frequency in kHz
bool b_nonSendData; * - serviceID : original ServiceID from the DVB-Stream (e300, e400)
int i_lastSentPacket; * - pidList : List of active PIDs
*
if( globals && nativeGlobals ) * Whenever a service changes, this function is called. Service-related plug-in data should be updated here.
{ */
DeviceInfo *deviceInfo = GetDeviceInfo(globals, deviceID); static long VLCEyeTVPluginServiceChanged(VLCEyeTVPluginGlobals_t *globals,
EyeTVPluginDeviceID deviceID,
if( deviceInfo ) long headendID,
{ long transponderID,
/* alloc the buffer if wanted */ long serviceID,
if( nativeGlobals->b_msgPortOpen == TRUE ) EyeTVPluginPIDInfo *pidList,
theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) ); long pidsCount)
{
for( i = 0; i < packetsCount; i++ ) long result = 0;
{ int i;
packet = ( TransportStreamPacket* )packets[i];
isNewPID = 1; printf("\nVLC media player Plug-In: ServiceChanged:\n");
printf( "=====================================\n");
/* search for PID */
for( j = 0; j < deviceInfo->pidsCount; j++ ) if( globals )
{ {
if( packet->PID == deviceInfo->pids[j] ) printf("DeviceID: %ld, ", deviceID);
{ printf("HeadendID: %ld, ", headendID);
isNewPID = 0; printf("TransponderID: %ld, ", transponderID);
break; printf("ServiceID: %ld\n\n", serviceID);
}
} globals->activeDeviceID = deviceID;
globals->activePIDsCount = pidsCount;
/* add new PIDs to the DeviceInfo */
if( isNewPID ) for( i = 0; i < pidsCount; i++ )
{ {
printf ("VLC media player Plug-In: SamplePacketsArrived, newPID = %6d\n", packet->PID); globals->activePIDs[i] = pidList[i];
globals->seenPIDs[i] = 0;
if( deviceInfo->pidsCount < MAX_PIDS ) printf("Active PID: %ld, type: %ld\n", pidList[i].pid, pidList[i].pidType);
{ }
deviceInfo->pids[deviceInfo->pidsCount++] = packet->PID; }
} printf( "=====================================\n");
}
else /* notify a potential VLC instance about the service change */
{ CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
/* forward data to VLC if wanted */ CFSTR("ServiceChanged"),
/* FIXME: we only receive ARD for now */ CFSTR(VLC_NOTIFICATION_OBJECT),
if( nativeGlobals->b_msgPortOpen == TRUE && ( /*userInfo*/ NULL,
packet->PID == 1401 || TRUE );
packet->PID == 1402 ||
packet->PID == 1400 || return result;
packet->PID == 1404 || }
packet->PID == 3070 ||
packet->PID == 3072 ||
packet->PID == 3074 || #pragma mark -
packet->PID == 5074 || /* EyeTVPluginDispatcher,
packet->PID == 0 || *
packet->PID == 17 || * - selector : See 'EyeTVPluginDefs.h'
packet->PID == 19 || * - *refCon : The RefCon to the plug-in-related Data
packet->PID == 20 ) ) * - deviceID : Identifies the Device
{ * - params : Parameters for functioncall
/* in a good world, this wouldn't be necessary */ *
if( theMutableRef == NULL ) * This function is a part of the interface for the communication with EyeTV. If something happens,
theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) ); * EyeTV thinks, we should know of, it calls this function with the corresponding selector. */
/* collect data to send larger packets */ #pragma export on
/* enlarge buffer if necessary */ long EyeTVPluginDispatcher( EyeTVPluginParams* params )
if( i > 0 ) {
CFDataIncreaseLength( theMutableRef, 188 ); long result = 0;
/* add missing header */ switch( params->selector )
memcpy( p_bufferForSending, packet, 4 ); {
CFDataAppendBytes( theMutableRef, p_bufferForSending, sizeof(p_bufferForSending) ); case kEyeTVPluginSelector_Initialize:
result = VLCEyeTVPluginInitialize((VLCEyeTVPluginGlobals_t**)params->refCon,
free( p_bufferForSending ); params->initialize.apiVersion, params->initialize.callback);
p_bufferForSending = malloc(4); break;
/* add payload */ case kEyeTVPluginSelector_Terminate:
CFDataAppendBytes( theMutableRef, packet->data, sizeof(packet->data) ); result = VLCEyeTVPluginTerminate((VLCEyeTVPluginGlobals_t*)params->refCon);
break;
b_nonSendData = TRUE;
case kEyeTVPluginSelector_GetInfo:
} result = VLCEyeTVPluginGetInformation((VLCEyeTVPluginGlobals_t*)params->refCon,
} params->info.pluginAPIVersion, params->info.pluginName, params->info.description);
break;
globals->packetCount++;
case kEyeTVPluginSelector_DeviceAdded:
if( globals->packetCount%10000 == 0 ) result = VLCEyeTVPluginDeviceAdded((VLCEyeTVPluginGlobals_t*)params->refCon,
printf("-> %lld Packets received so far...\n",globals->packetCount); params->deviceID, params->deviceAdded.deviceType);
} break;
if( nativeGlobals->b_msgPortOpen == TRUE ) case kEyeTVPluginSelector_DeviceRemoved:
{ result = VLCEyeTVPluginDeviceRemoved((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID);
printf( "sending %i bytes of data\n", CFDataGetLength( theMutableRef ) ); break;
i_returnValue = CFMessagePortSendRequest( nativeGlobals->messagePortToVLC,
/* arbitrary int val */ globals->packetCount, case kEyeTVPluginSelector_PacketsArrived:
/* the data */ theMutableRef, result = VLCEyeTVPluginPacketsArrived((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID,
/* no timeout for sending */ 0, params->packetsArrived.packets, params->packetsArrived.packetCount);
/* no timeout for resp */ 0, break;
/* no resp. wanted */ NULL,
NULL ); case kEyeTVPluginSelector_ServiceChanged:
b_nonSendData = FALSE; result = VLCEyeTVPluginServiceChanged((VLCEyeTVPluginGlobals_t*)params->refCon,
i_lastSentPacket = globals->packetCount; params->deviceID, params->serviceChanged.headendID,
if( i_returnValue == kCFMessagePortSendTimeout ) params->serviceChanged.transponderID, params->serviceChanged.serviceID,
printf( "time out while sending\n" ); params->serviceChanged.pidList, params->serviceChanged.pidCount);
else if( i_returnValue == kCFMessagePortReceiveTimeout ) break;
printf( "time out while waiting for resp\n" ); }
else if( i_returnValue == kCFMessagePortIsInvalid )
{ return result;
/* 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;
}
...@@ -22,9 +22,6 @@ ...@@ -22,9 +22,6 @@
*****************************************************************************/ *****************************************************************************/
#include "EyeTVPluginDefs.h" #include "EyeTVPluginDefs.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center,
......
...@@ -122,7 +122,6 @@ ...@@ -122,7 +122,6 @@
mainGroup = 089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */; mainGroup = 089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
shouldCheckCompatibility = 1;
targets = ( targets = (
8D57630D048677EA00EA77CD /* VLC EyeTV Plug-In */, 8D57630D048677EA00EA77CD /* VLC EyeTV Plug-In */,
); );
......
# 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_file = file.c
SOURCES_access_directory = directory.c SOURCES_access_directory = directory.c
SOURCES_access_dv = dv.c SOURCES_access_dv = dv.c
...@@ -7,7 +12,7 @@ SOURCES_access_http = http.c ...@@ -7,7 +12,7 @@ SOURCES_access_http = http.c
SOURCES_access_ftp = ftp.c SOURCES_access_ftp = ftp.c
SOURCES_access_smb = smb.c SOURCES_access_smb = smb.c
SOURCES_access_gnomevfs = gnomevfs.c SOURCES_access_gnomevfs = gnomevfs.c
SOURCES_access_eyetv = eyetv.c SOURCES_access_eyetv = eyetv.m
SOURCES_dvdnav = dvdnav.c SOURCES_dvdnav = dvdnav.c
SOURCES_dvdread = dvdread.c SOURCES_dvdread = dvdread.c
SOURCES_dc1394 = dc1394.c SOURCES_dc1394 = dc1394.c
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* eyetv.c : Access module to connect to our plugin running within EyeTV * eyetv.c : Access module to connect to our plugin running within EyeTV
***************************************************************************** *****************************************************************************
* Copyright (C) 2006-2007 the VideoLAN team * Copyright (C) 2006-2007 the VideoLAN team
* $Id$ * $Id: eyetv.c 23509 2007-12-09 17:39:28Z courmisch $
* *
* Author: Felix Kühne <fkuehne at videolan dot org> * Author: Felix Kühne <fkuehne at videolan dot org>
* *
...@@ -28,7 +28,14 @@ ...@@ -28,7 +28,14 @@
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <vlc_access.h> #include <vlc_access.h>
#include <CoreFoundation/CoreFoundation.h> #include <vlc_network.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#import <Foundation/Foundation.h>
/* TODO: /* TODO:
* watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */ * watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */
...@@ -39,12 +46,19 @@ ...@@ -39,12 +46,19 @@
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void Close( 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(); vlc_module_begin();
set_shortname( "EyeTV" ); set_shortname( "EyeTV" );
set_description( _("EyeTV access module") ); set_description( _("EyeTV access module") );
set_category( CAT_INPUT ); set_category( CAT_INPUT );
set_subcategory( SUBCAT_INPUT_ACCESS ); set_subcategory( SUBCAT_INPUT_ACCESS );
add_integer( "eyetv-channel", 0, NULL,
CHANNEL_TEXT, CHANNEL_LONGTEXT, VLC_FALSE );
set_capability( "access2", 0 ); set_capability( "access2", 0 );
add_shortcut( "eyetv" ); add_shortcut( "eyetv" );
set_callbacks( Open, Close ); set_callbacks( Open, Close );
...@@ -53,29 +67,71 @@ vlc_module_end(); ...@@ -53,29 +67,71 @@ vlc_module_end();
/***************************************************************************** /*****************************************************************************
* Access: local prototypes * 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 struct access_sys_t
{ {
eyetv_thread_t *p_thread; int eyetvSock;
}; };
CFDataRef dataFromEyetv;
int lastPacketId;
int lastForwardedPacketId;
static ssize_t Read( access_t *, uint8_t *, size_t ); static ssize_t Read( access_t *, uint8_t *, size_t );
static int Control( access_t *, int, va_list ); static int Control( access_t *, int, va_list );
static void Thread( vlc_object_t * );
CFDataRef msgPortCallback( CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info ); 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 * Open: sets up the module and its threads
...@@ -84,77 +140,92 @@ static int Open( vlc_object_t *p_this ) ...@@ -84,77 +140,92 @@ static int Open( vlc_object_t *p_this )
{ {
access_t *p_access = (access_t *)p_this; access_t *p_access = (access_t *)p_this;
access_sys_t *p_sys; access_sys_t *p_sys;
eyetv_thread_t *p_thread;
CFMessagePortContext context; struct sockaddr_un publicAddr, peerAddr;
memset(&context, 0, sizeof(context)); int publicSock;
vlc_value_t val;
/* Init p_access */ /* Init p_access */
access_InitFields( p_access ); \ access_InitFields( p_access ); \
ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL ); \ ACCESS_SET_CALLBACKS( Read, NULL, Control, NULL ); \
MALLOC_ERR( p_access->p_sys, access_sys_t ); \ MALLOC_ERR( p_access->p_sys, access_sys_t ); \
p_sys = p_access->p_sys; memset( p_sys, 0, sizeof( 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" ); msg_Dbg( p_access, "coming up" );
/* create receiving thread which will keep the message port alive without blocking */ selectChannel(p_this, val.i_int);
p_sys->p_thread = p_thread = vlc_object_create( p_access, sizeof( eyetv_thread_t ) );
vlc_object_attach( p_thread, p_this ); /* socket */
vlc_mutex_init( p_access, &p_thread->lock ); memset(&publicAddr, 0, sizeof(publicAddr));
vlc_cond_init( p_access, &p_thread->wait ); publicAddr.sun_family = AF_UNIX;
msg_Dbg( p_access, "thread created, msg port following now" ); strncpy(publicAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(publicAddr.sun_path)-1);
/* remove previous public path if it wasn't cleanly removed */
/* set up our own msg port if( (0 != unlink(publicAddr.sun_path)) && (ENOENT != errno) )
* 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" ); msg_Err( p_access, "local socket path is not usable (errno=%d)", errno );
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 ); free( p_sys );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
else
msg_Dbg( p_access, "remote msg port opened" ); publicSock = socket(AF_UNIX, SOCK_STREAM, 0);
if( publicSock == -1 )
/* 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" ); msg_Err( p_access, "create local socket failed (errno=%d)", errno );
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 ); free( p_sys );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
msg_Dbg( p_access, "receiver thread created and launched" ); if( bind(publicSock, (struct sockaddr *)&publicAddr, sizeof(struct sockaddr_un)) == -1 )
{
/* tell the EyeTV plugin to open up its msg port and start sending */ msg_Err( p_access, "bind local socket failed (errno=%d)", errno );
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (), close( publicSock );
CFSTR("VLCAccessStartDataSending"), free( p_sys );
CFSTR("VLCEyeTVSupport"), return VLC_EGENERIC;
/*userInfo*/ NULL, }
TRUE );
/* we are not expecting more than one connection */
msg_Dbg( p_access, "plugin notified" ); if( listen(publicSock, 1) == -1 )
{
/* we don't need such a high priority */ msg_Err( p_access, "cannot accept connection (errno=%d)", errno );
//vlc_thread_set_priority( p_access, VLC_THREAD_PRIORITY_LOW ); 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; return VLC_SUCCESS;
} }
...@@ -176,107 +247,33 @@ static void Close( vlc_object_t *p_this ) ...@@ -176,107 +247,33 @@ static void Close( vlc_object_t *p_this )
TRUE ); TRUE );
msg_Dbg( p_access, "plugin notified" ); msg_Dbg( p_access, "plugin notified" );
close(p_sys->eyetvSock);
/* 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" ); 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 ); 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 * 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 ) 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; access_sys_t *p_sys = p_access->p_sys;
extern CFDataRef dataFromEyetv; int i_read;
extern int lastPacketId;
extern int lastForwardedPacketId; if( p_access->info.b_eof )
/* 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 0;
return i_len; 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;
} }
/***************************************************************************** /*****************************************************************************
......
...@@ -132,8 +132,6 @@ static VLCEyeTVController *_o_sharedInstance = nil; ...@@ -132,8 +132,6 @@ static VLCEyeTVController *_o_sharedInstance = nil;
script = [[NSAppleScript alloc] initWithSource: script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n" @"tell application \"EyeTV\"\n"
"channel_up\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" "get current channel\n"
"end tell"]; "end tell"];
msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel up" ); msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel up" );
...@@ -143,8 +141,6 @@ static VLCEyeTVController *_o_sharedInstance = nil; ...@@ -143,8 +141,6 @@ static VLCEyeTVController *_o_sharedInstance = nil;
script = [[NSAppleScript alloc] initWithSource: script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n" @"tell application \"EyeTV\"\n"
"channel_down\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" "get current channel\n"
"end tell"]; "end tell"];
msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel down" ); msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel down" );
...@@ -172,25 +168,21 @@ static VLCEyeTVController *_o_sharedInstance = nil; ...@@ -172,25 +168,21 @@ static VLCEyeTVController *_o_sharedInstance = nil;
case -2: // Composite case -2: // Composite
script = [[NSAppleScript alloc] initWithSource: script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n" @"tell application \"EyeTV\"\n"
" input_change input source composite video input" " 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"]; "end tell"];
break; break;
case -1: // S-Video case -1: // S-Video
script = [[NSAppleScript alloc] initWithSource: script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n" @"tell application \"EyeTV\"\n"
" input_change input source S video input" " 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"]; "end tell"];
break; break;
case 0: // Tuner case 0: // Last
script = [[NSAppleScript alloc] initWithSource: script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n" @"tell application \"EyeTV\"\n"
" input_change input source tuner input" " show player_window\n"
" volume_change level 0\n"
" tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
"end tell"]; "end tell"];
break; break;
default: default:
...@@ -198,9 +190,8 @@ static VLCEyeTVController *_o_sharedInstance = nil; ...@@ -198,9 +190,8 @@ static VLCEyeTVController *_o_sharedInstance = nil;
{ {
NSString *channel_change = [NSString stringWithFormat: NSString *channel_change = [NSString stringWithFormat:
@"tell application \"EyeTV\"\n" @"tell application \"EyeTV\"\n"
@" channel_change channel number %d\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]; "end tell", theChannelNum];
script = [[NSAppleScript alloc] initWithSource:channel_change]; script = [[NSAppleScript alloc] initWithSource:channel_change];
} }
......
...@@ -83,7 +83,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class ) ...@@ -83,7 +83,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class )
p_list = [NSMutableArray arrayWithCapacity: 1]; p_list = [NSMutableArray arrayWithCapacity: 1];
next_media = IOIteratorNext( media_iterator ); next_media = IOIteratorNext( media_iterator );
if( next_media != nil ) if( next_media )
{ {
char psz_buf[0x32]; char psz_buf[0x32];
size_t dev_path_length; size_t dev_path_length;
...@@ -116,7 +116,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class ) ...@@ -116,7 +116,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class )
IOObjectRelease( next_media ); IOObjectRelease( next_media );
} while( ( next_media = IOIteratorNext( media_iterator ) ) != nil ); } while( ( next_media = IOIteratorNext( media_iterator ) ) );
} }
IOObjectRelease( media_iterator ); IOObjectRelease( media_iterator );
...@@ -237,11 +237,14 @@ static VLCOpen *_o_sharedMainInstance = nil; ...@@ -237,11 +237,14 @@ static VLCOpen *_o_sharedMainInstance = nil;
/* wake up with the correct EyeTV GUI */ /* wake up with the correct EyeTV GUI */
if( [[[VLCMain sharedInstance] getEyeTVController] isEyeTVrunning] == YES ) if( [[[VLCMain sharedInstance] getEyeTVController] isEyeTVrunning] == YES )
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
else if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES )
{ {
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"]; if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES )
[self setupChannelInfo]; {
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"];
[self setupChannelInfo];
}
else
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
} }
else else
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"noeyetv"]; [o_eyetv_tabView selectTabViewItemWithIdentifier:@"noeyetv"];
...@@ -411,6 +414,10 @@ static VLCOpen *_o_sharedMainInstance = nil; ...@@ -411,6 +414,10 @@ static VLCOpen *_o_sharedMainInstance = nil;
{ {
[self openNetInfoChanged: nil]; [self openNetInfoChanged: nil];
} }
else if( [o_label isEqualToString: _NS("EyeTV")] )
{
[o_mrl setStringValue: @"eyetv://"];
}
} }
- (void)openFileGeneric - (void)openFileGeneric
...@@ -797,12 +804,23 @@ static VLCOpen *_o_sharedMainInstance = nil; ...@@ -797,12 +804,23 @@ static VLCOpen *_o_sharedMainInstance = nil;
- (IBAction)eyetvSwitchChannel:(id)sender - (IBAction)eyetvSwitchChannel:(id)sender
{ {
if( sender == o_eyetv_nextProgram_btn ) 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 ) 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 ) 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 else
msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" ); msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
} }
...@@ -865,9 +883,6 @@ static VLCOpen *_o_sharedMainInstance = nil; ...@@ -865,9 +883,6 @@ static VLCOpen *_o_sharedMainInstance = nil;
if( channels ) if( channels )
{ {
NSString *channel; NSString *channel;
[[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("Tuner")
action: nil
keyEquivalent: @""] setTag:x++];
[[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]]; [[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]];
while( channel = [channels nextObject] ) while( channel = [channels nextObject] )
{ {
...@@ -875,7 +890,7 @@ static VLCOpen *_o_sharedMainInstance = nil; ...@@ -875,7 +890,7 @@ static VLCOpen *_o_sharedMainInstance = nil;
* additionally, we save a bit of time */ * additionally, we save a bit of time */
[[[o_eyetv_channels_pop menu] addItemWithTitle: channel [[[o_eyetv_channels_pop menu] addItemWithTitle: channel
action: nil action: nil
keyEquivalent: @""] setTag:x++]; keyEquivalent: @""] setTag:++x];
} }
/* make Tuner the default */ /* make Tuner the default */
[o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] currentChannel]]; [o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] currentChannel]];
...@@ -884,8 +899,6 @@ static VLCOpen *_o_sharedMainInstance = nil; ...@@ -884,8 +899,6 @@ static VLCOpen *_o_sharedMainInstance = nil;
/* clean up GUI */ /* clean up GUI */
[o_eyetv_chn_bgbar setHidden: YES]; [o_eyetv_chn_bgbar setHidden: YES];
[o_eyetv_chn_status_txt setHidden: YES]; [o_eyetv_chn_status_txt setHidden: YES];
[o_mrl setStringValue: @"eyetv:"];
} }
- (IBAction)subsChanged:(id)sender - (IBAction)subsChanged:(id)sender
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment