Commit 10649df7 authored by Felix Paul Kühne's avatar Felix Paul Kühne

* forward-port of all eyetv relates sources in my branch

    - this stuff is highly unfinished; needs much more work and testing
    - don't be surprised if you don't see anything when trying it out, this port is basically a big reminder for me to keep working on it ;-)
    - the access module is probably going to be ported from CoreFoundation-driven C to Cocoa-based Obj-C
    - everything will be 10.4-only, since EyeTV is only available this way as well
    - the plugin to put into EyeTV is compiled in UB-mode by default and incorporates Public Domain code provided by Elgato Systems GmbH
parent 906a3bfe
......@@ -5030,13 +5030,16 @@ AC_ARG_ENABLE(macosx,
[ --enable-macosx MacOS X support (default enabled on MacOS X)],
[if test "${enable_macosx}" = "yes"
then
VLC_ADD_BUILTINS([macosx])
VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL])
VLC_ADD_PLUGINS([access_eyetv])
VLC_ADD_LDFLAGS([access_eyetv], [-framework CoreFoundation])
VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL -framework QTKit])
VLC_ADD_OBJCFLAGS( [macosx],[-fobjc-exceptions] )
fi],
[AC_CHECK_HEADERS(Cocoa/Cocoa.h,
VLC_ADD_PLUGINS([access_eyetv])
VLC_ADD_LDFLAGS([access_eyetv], [-framework CoreFoundation])
VLC_ADD_BUILTINS([macosx])
VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL])
VLC_ADD_LDFLAGS([macosx],[-framework IOKit -framework Cocoa -framework Carbon -framework QuickTime -lobjc -ObjC -framework OpenGL -framework AGL -framework QTKit])
VLC_ADD_OBJCFLAGS( [macosx],[-fobjc-exceptions] )
)])
CFLAGS=$ORIGCFLAGS
......
B/* Localized versions of Info.plist keys */
/* This is public domain code developed by Elgato Systems GmbH. No GPL-covered
* changes were added to this file by any members of the VideoLAN team. If you
* want to do so, add a modified GPL header here, but keep a message emphasising
* the non-licensed parts of this header file.
* Ideally, VideoLAN-related changes should only go to eyetvplugin.h.
*
* $Id$
*/
#pragma once
/*
The EyeTV Plugin API
====================
The EyeTV Software gives third parties access to the incoming MPEG-2 transport stream.
At this time the API is available for the following products:
- EyeTV 200 (analog)
- EyeTV 300 (DVB-S)
- EyeTV 400 (DVB-T)
A plugin receives device plugged/unplugged notifications, it can request or release
individual PIDs and most importantly it has access to transport stream packets in
real time, as they arrive from the device. Note that the plugin is called before EyeTV
itself looks at the packets, so it is even possible to modify the data.
Plugins currently live in EyeTV.app/Contens/Plugins/
A plugin is packaged as a bundle with a single entry point:
long EyeTVPluginDispatcher(EyeTVPluginSelector selector,
void *refCon,
EyeTVPluginDeviceID deviceID,
long param1,
long param2,
long param3,
long param4);
PID Filtering
=============
EyeTV employs both hardware and software PID filtering. A plugin's dispatch routine
is called with the kEyeTVPluginSelector_PacketsArrived selector after the hardware
PID filter (naturally) but prior to the software PID filter, so the plugin has access
to all packets that are delivered by the hardware.
A plugin can request PIDs that are not needed by EyeTV from the hardware PID filter by
means of a callback routine, see eyeTVPluginSelector_SetCallback.
Note that hardware PID filtering is on for single processor machines (to reduce the CPU
load), but off for multi-processor machines (to improve channel switch times).
This behaviour is controlled by the "hardware PID filter" key in com.elgato.eyetv.plist,
which defaults to "Auto" ("Off" on MP machines, "On" on single-processor machines). EyeTV
does not offer GUI to change this setting. A plugin hence needs to be prepared to handle
both an entire transponder or multiplex and to request PIDs it might need.
Note that the plugin is called on the real-time thread that receives the transport stream
packets and that the packet buffers passed to the plugin are the actual hardware DMA buffers.
Please return as quickly as possible from the kEyeTVPluginSelector_PacketsArrived call and
avoid blocking the calling thread.
Revision History:
02/27/2004: Initial Release.
*/
#define EYETV_PLUGIN_API_VERSION 0x04021901
#define EYETV_PLUGIN_API_MIN_VERSION 0x04021901
typedef long long EyeTVPluginDeviceID;
typedef long EyeTVPluginDeviceType;
typedef long EyeTVPluginSelector;
enum {
kEyeTVPIDType_Video = 0,
kEyeTVPIDType_MPEGAudio = 1,
kEyeTVPIDType_VBI = 2, /* teletext */
kEyeTVPIDType_PCR = 3,
kEyeTVPIDType_PMT = 4,
kEyeTVPIDType_Unknown = 5,
kEyeTVPIDType_AC3Audio = 6
};
typedef struct EyeTVPluginPIDInfo EyeTVPluginPIDInfo;
struct EyeTVPluginPIDInfo {
long pid;
long pidType;
};
/***********************************************************************************
*
* EyeTVPluginCallbackParams,
*
***********************************************************************************/
enum {
kEyeTVPluginCallbackSelector_RetainPIDs = 0,
kEyeTVPluginCallbackSelector_ReleasePIDs = 1
};
typedef struct EyeTVPluginCallbackParams EyeTVPluginCallbackParams;
struct EyeTVPluginCallbackParams {
EyeTVPluginDeviceID deviceID; // the deviceID
long selector; // callback selector, see above
long *pids; // list of pids to release/retain
long pidsCount; // count of pids
};
/***********************************************************************************
*
* typedef for the callback function,
*
***********************************************************************************/
typedef long(* EyeTVPluginCallbackProc)(EyeTVPluginCallbackParams *params);
/***********************************************************************************
*
* EyeTVPluginParamStructs
*
***********************************************************************************/
typedef struct EyeTVPluginInitializeParams EyeTVPluginInitializeParams;
struct EyeTVPluginInitializeParams {
long apiVersion; // version of the EyeTV_PLUGIN_API
EyeTVPluginCallbackProc callback; // the callback
}; /* 8 bytes */
typedef struct EyeTVPluginGetInfoParams EyeTVPluginGetInfoParams;
struct EyeTVPluginGetInfoParams {
long *pluginAPIVersion; // <- EYETV_PLUGIN_API_VERSION
char *pluginName; // <- points to a 128-byte buffer, the plugin is expected to fill the buffer with
// a UTF-8 encoded string.
char *description; // <- points to a 1024-byte buffer, the plugin is expected to fill the buffer with
// a UTF-8 encoded string describing the plugin.
}; /* 12 bytes */
enum {
kEyeTVPluginDeviceType_Unknown = 0,
kEyeTVPluginDeviceType_e200 = 1,
kEyeTVPluginDeviceType_e300 = 2,
kEyeTVPluginDeviceType_e400 = 3
} ;
typedef struct EyeTVPluginDeviceAddedParams EyeTVPluginDeviceAddedParams;
struct EyeTVPluginDeviceAddedParams {
EyeTVPluginDeviceType deviceType;
}; /* 4 bytes */
typedef struct EyeTVPluginPacketsArrivedParams EyeTVPluginPacketsArrivedParams;
struct EyeTVPluginPacketsArrivedParams {
long **packets; // points to an array of packets
long packetCount;
}; /* 8 bytes */
typedef struct EyeTVPluginServiceChangedParams EyeTVPluginServiceChangedParams;
struct EyeTVPluginServiceChangedParams {
long headendID; // new headend ID. For E300 it's the orbital position of the satellite
// in tenth of a degree
long transponderID; // new transponder ID (The Frequency in kHz)
long serviceID; // new service ID (the ID of the used service as included in the DVB Stream)
EyeTVPluginPIDInfo *pidList; // points to the list of active PIDs;
long pidCount; // the length of pidList
}; /* 20 bytes */
/***********************************************************************************
*
* EyeTVPluginParams
*
***********************************************************************************/
typedef struct EyeTVPluginParams EyeTVPluginParams;
struct EyeTVPluginParams {
EyeTVPluginDeviceID deviceID; // ID of the device
EyeTVPluginSelector selector; // selector
void *refCon; // refCon
union {
EyeTVPluginInitializeParams initialize; // kEyeTVPluginSelector_Initialize
// kEyeTVPluginSelector_Terminate, no additional parameters
EyeTVPluginGetInfoParams info; // kEyeTVPluginSelector_GetInfo
EyeTVPluginDeviceAddedParams deviceAdded; // kEyeTVPluginSelector_DeviceAdded
// kEyeTVPluginSelector_DeviceRemoved, no additional parameters
EyeTVPluginPacketsArrivedParams packetsArrived; // kEyeTVPluginSelector_PacketsArrived
EyeTVPluginServiceChangedParams serviceChanged; // kEyeTVPluginSelector_ServiceChanged
};
};
enum { // EyeTVPluginSelector
kEyeTVPluginSelector_Initialize = 0,
kEyeTVPluginSelector_Terminate = 1,
kEyeTVPluginSelector_GetInfo = 2,
kEyeTVPluginSelector_DeviceAdded = 3,
kEyeTVPluginSelector_DeviceRemoved = 4,
kEyeTVPluginSelector_PacketsArrived = 5,
kEyeTVPluginSelector_ServiceChanged = 6
};
/***********************************************************************************
*
* EyeTVPluginEntryProc
*
***********************************************************************************/
typedef long(* EyeTVPluginEntryProc)(EyeTVPluginParams *params);
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundleIconFile</key>
<string></string>
<key>CFBundleIdentifier</key>
<string>org.videolan.vlceyetvplugin</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CFPlugInDynamicRegisterFunction</key>
<string></string>
<key>CFPlugInDynamicRegistration</key>
<string>NO</string>
<key>CFPlugInFactories</key>
<dict>
<key>00000000-0000-0000-0000-000000000000</key>
<string>MyFactoryFunction</string>
</dict>
<key>CFPlugInTypes</key>
<dict>
<key>00000000-0000-0000-0000-000000000000</key>
<array>
<string>00000000-0000-0000-0000-000000000000</string>
</array>
</dict>
<key>CFPlugInUnloadFunction</key>
<string></string>
</dict>
</plist>
/*****************************************************************************
* eyetvplugin.c: Plug-In for the EyeTV software to connect to VLC
*****************************************************************************
* Copyright (C) 2006-2007 the VideoLAN team
* $Id$
*
* Authors: Felix Kühne <fkuehne at videolan dot org>
*
* 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; i<globals->deviceCount; 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( i<globals->deviceCount )
{
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.h: Plug-In for the EyeTV software to connect to VLC
*****************************************************************************
* Copyright (C) 2006-2007 the VideoLAN team
* $Id$
*
* Authors: Felix Kühne <fkuehne at videolan dot org>
*
* 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 "EyeTVPluginDefs.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo );
\ No newline at end of file
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 42;
objects = {
/* Begin PBXBuildFile section */
8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */; };
8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; };
CC09359B0AE11E6A00647FD0 /* eyetvplugin.c in Sources */ = {isa = PBXBuildFile; fileRef = CC09359A0AE11E6A00647FD0 /* eyetvplugin.c */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
8D576316048677EA00EA77CD /* VLC EyeTV Plug-In.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "VLC EyeTV Plug-In.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
8D576317048677EA00EA77CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
CC09359A0AE11E6A00647FD0 /* eyetvplugin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eyetvplugin.c; sourceTree = "<group>"; };
CC09359C0AE11E7900647FD0 /* EyeTVPluginDefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EyeTVPluginDefs.h; sourceTree = "<group>"; };
CC3AE2920AE2E4EE00ACC87C /* eyetvplugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eyetvplugin.h; sourceTree = "<group>"; };
CC74BC500AE2714300AD738B /* eyetv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = eyetv.c; path = ../../../modules/access/eyetv.c; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8D576313048677EA00EA77CD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */ = {
isa = PBXGroup;
children = (
CC74BC530AE2715100AD738B /* access module */,
08FB77AFFE84173DC02AAC07 /* Source */,
089C167CFE841241C02AAC07 /* Resources */,
089C1671FE841209C02AAC07 /* External Frameworks and Libraries */,
19C28FB6FE9D52B211CA2CBB /* Products */,
);
name = "VLC EyeTV Plug-In";
sourceTree = "<group>";
};
089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = {
isa = PBXGroup;
children = (
0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */,
);
name = "External Frameworks and Libraries";
sourceTree = "<group>";
};
089C167CFE841241C02AAC07 /* Resources */ = {
isa = PBXGroup;
children = (
8D576317048677EA00EA77CD /* Info.plist */,
8D5B49A704867FD3000E48DA /* InfoPlist.strings */,
);
name = Resources;
sourceTree = "<group>";
};
08FB77AFFE84173DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
CC3AE2920AE2E4EE00ACC87C /* eyetvplugin.h */,
CC09359A0AE11E6A00647FD0 /* eyetvplugin.c */,
CC09359C0AE11E7900647FD0 /* EyeTVPluginDefs.h */,
);
name = Source;
sourceTree = "<group>";
};
19C28FB6FE9D52B211CA2CBB /* Products */ = {
isa = PBXGroup;
children = (
8D576316048677EA00EA77CD /* VLC EyeTV Plug-In.bundle */,
);
name = Products;
sourceTree = "<group>";
};
CC74BC530AE2715100AD738B /* access module */ = {
isa = PBXGroup;
children = (
CC74BC500AE2714300AD738B /* eyetv.c */,
);
name = "access module";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
8D57630D048677EA00EA77CD /* VLC EyeTV Plug-In */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget "VLC EyeTV Plug-In" */;
buildPhases = (
8D57630F048677EA00EA77CD /* Resources */,
8D576311048677EA00EA77CD /* Sources */,
8D576313048677EA00EA77CD /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = "VLC EyeTV Plug-In";
productInstallPath = "$(HOME)/Library/Bundles";
productName = "VLC EyeTV Plug-In";
productReference = 8D576316048677EA00EA77CD /* VLC EyeTV Plug-In.bundle */;
productType = "com.apple.product-type.bundle";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
089C1669FE841209C02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB911E08733D790010E9CD /* Build configuration list for PBXProject "eyetvplugin" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */;
projectDirPath = "";
projectRoot = "";
shouldCheckCompatibility = 1;
targets = (
8D57630D048677EA00EA77CD /* VLC EyeTV Plug-In */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8D57630F048677EA00EA77CD /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8D576311048677EA00EA77CD /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CC09359B0AE11E6A00647FD0 /* eyetvplugin.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
089C167EFE841241C02AAC07 /* English */,
);
name = InfoPlist.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
1DEB911B08733D790010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_C_LANGUAGE_STANDARD = "compiler-default";
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Library/Bundles";
PRODUCT_NAME = "VLC EyeTV Plug-In";
WRAPPER_EXTENSION = bundle;
ZERO_LINK = YES;
};
name = Debug;
};
1DEB911C08733D790010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = (
ppc,
i386,
);
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G5;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Library/Bundles";
PRODUCT_NAME = "VLC EyeTV Plug-In";
WRAPPER_EXTENSION = bundle;
};
name = Release;
};
1DEB911F08733D790010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
};
name = Debug;
};
1DEB912008733D790010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB911A08733D790010E9CD /* Build configuration list for PBXNativeTarget "VLC EyeTV Plug-In" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB911B08733D790010E9CD /* Debug */,
1DEB911C08733D790010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB911E08733D790010E9CD /* Build configuration list for PBXProject "eyetvplugin" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB911F08733D790010E9CD /* Debug */,
1DEB912008733D790010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 089C1669FE841209C02AAC07 /* Project object */;
}
......@@ -7,6 +7,7 @@ SOURCES_access_http = http.c
SOURCES_access_ftp = ftp.c
SOURCES_access_smb = smb.c
SOURCES_access_gnomevfs = gnomevfs.c
SOURCES_access_eyetv = eyetv.c
SOURCES_dvdnav = dvdnav.c
SOURCES_dvdread = dvdread.c
SOURCES_dc1394 = dc1394.c
......
/*****************************************************************************
* eyetv.c : Access module to connect to our plugin running within EyeTV
*****************************************************************************
* Copyright (C) 2006-2007 the VideoLAN team
* $Id$
*
* Author: Felix Kühne <fkuehne at videolan dot org>
*
* 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 <stdlib.h>
#include <vlc/vlc.h>
#include <vlc_access.h>
#include <CoreFoundation/CoreFoundation.h>
/* 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 int Read( access_t *, uint8_t *, int );
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 */
p_sys->p_thread->b_die = VLC_TRUE;
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 int Read( access_t *p_access, uint8_t *p_buffer, int 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:
return VLC_EGENERIC;
default:
msg_Warn( p_access, "unimplemented query in control" );
return VLC_EGENERIC;
}
return VLC_SUCCESS;*/
return VLC_EGENERIC;
}
......@@ -46,5 +46,7 @@ SOURCES_macosx = \
fspanel.h \
update.h \
update.m \
eyetv.h \
eyetv.m \
$(NULL)
/*****************************************************************************
* eyetv.h: small class to control the notification parts of the EyeTV plugin
*****************************************************************************
* Copyright (C) 2006-2007 the VideoLAN team
* $Id$
*
* Authors: Felix Kühne <fkuehne at videolan dot org>
*
* 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.
*****************************************************************************/
#import <Cocoa/Cocoa.h>
@interface VLCEyeTVController : NSObject
{
BOOL b_eyeTVactive;
BOOL b_deviceConnected;
}
- (void)globalNotificationReceived: (NSNotification *)theNotification;
- (BOOL)isEyeTVrunning;
- (BOOL)isDeviceConnected;
- (void)launchEyeTV;
- (void)switchChannelUp:(BOOL)b_yesOrNo;
- (void)selectChannel:(int)theChannelNum;
- (int)getNumberOfChannels;
- (NSString *)getNameOfChannel:(int)theChannelNum;
@end
/*****************************************************************************
* eyetv.m: small class to control the notification parts of the EyeTV plugin
*****************************************************************************
* Copyright (C) 2006-2007 the VideoLAN team
* $Id$
*
* Authors: Felix Kühne <fkuehne at videolan dot org>
*
* 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.
*****************************************************************************/
#import "eyetv.h"
/* for apple event interaction [carbon] */
#import <ApplicationServices/ApplicationServices.h>
/* for various VLC core related calls */
#import "intf.h"
@implementation VLCEyeTVController
static VLCEyeTVController *_o_sharedInstance = nil;
+ (VLCEyeTVController *)sharedInstance
{
return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
}
- (id)init
{
if (_o_sharedInstance) {
[self dealloc];
} else {
_o_sharedInstance = [super init];
[[NSDistributedNotificationCenter defaultCenter]
addObserver: self
selector: @selector(globalNotificationReceived:)
name: NULL
object: @"VLCEyeTVSupport"
suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
}
return _o_sharedInstance;
}
- (void)globalNotificationReceived: (NSNotification *)theNotification
{
msg_Dbg( VLCIntf, "notification received in VLC with name %s and object %s",
[[theNotification name] UTF8String], [[theNotification object] UTF8String] );
/* update our info on the used device */
if( [[theNotification name] isEqualToString: @"DeviceAdded"] )
b_deviceConnected = YES;
if( [[theNotification name] isEqualToString: @"DeviceRemoved"] )
b_deviceConnected = NO;
/* is eyetv running? */
if( [[theNotification name] isEqualToString: @"PluginInit"] )
b_eyeTVactive = YES;
if( [[theNotification name] isEqualToString: @"PluginQuit"] )
b_eyeTVactive = NO;
}
- (BOOL)isEyeTVrunning
{
return b_eyeTVactive;
}
- (BOOL)isDeviceConnected
{
return b_deviceConnected;
}
- (void)launchEyeTV
{
OSStatus stat;
FSRef eyetvPath;
stat = LSFindApplicationForInfo ( 'EyTV',
CFSTR("com.elgato.eyetv"),
NULL,
&eyetvPath,
NULL );
if( stat != noErr )
msg_Err( VLCIntf, "finding EyeTV failed with error code %i", (int)stat );
stat = LSOpenFSRef( &eyetvPath, NULL );
if( stat != noErr )
msg_Err( VLCIntf, "opening EyeTV failed with error code %i", (int)stat );
}
- (void)switchChannelUp:(BOOL)b_yesOrNo
{
OSErr err;
AppleEvent ourAE = {typeNull, nil};
AEBuildError theBuildError;
const OSType eyetvSignature = 'EyTV'; /* carbon FOURCC style */
OSType eyetvCommand;
if( b_yesOrNo == YES )
{
eyetvCommand = 'Chup'; /* same style */
msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel up" );
}
else
{
eyetvCommand = 'Chdn'; /* same style again */
msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel down" );
}
err = AEBuildAppleEvent(
/* EyeTV script suite */ eyetvSignature,
/* command */ eyetvCommand,
/* signature type */ typeApplSignature,
/* signature */ &eyetvSignature,
/* signature size */ sizeof(eyetvSignature),
/* basic return id */ kAutoGenerateReturnID,
/* generic transaction id */ kAnyTransactionID,
/* to-be-created AE */ &ourAE,
/* get some possible errors */ &theBuildError,
/* got no params for now */ "" );
if( err != aeBuildSyntaxNoErr )
{
msg_Err( VLCIntf, "Error %i encountered while trying to the build the AE to launch eyetv.\n" \
"additionally, the following info was returned: AEBuildErrorCode:%i at pos:%i",
(int)err, theBuildError.fError, theBuildError.fErrorPos);
return;
}
else
msg_Dbg( VLCIntf, "AE created successfully, trying to send now" );
err = AESendMessage(
/* our AE */ &ourAE,
/* no need for a response-AE */ NULL,
/* we neither want a response nor user interaction */ kAENoReply | kAENeverInteract,
/* we don't need a special time-out */ kAEDefaultTimeout );
if( err != noErr )
msg_Err( VLCIntf, "Error %i encountered while trying to tell EyeTV to switch channel", (int)err );
err = AEDisposeDesc(&ourAE);
}
- (void)selectChannel: (int)theChannelNum
{
}
- (int)getNumberOfChannels
{
return 2;
}
- (NSString *)getNameOfChannel: (int)theChannelNum
{
return @"dummy name";
}
@end
......@@ -105,6 +105,7 @@ struct intf_sys_t
id o_interaction_list; /* VLCInteractionList*/
id o_sfilters; /* VLCsFilters */
id o_update; /* VLCUpdate */
id o_eyetv; /* VLCEyeTVController */
BOOL nib_main_loaded; /* reference to the main-nib */
BOOL nib_open_loaded; /* reference to the open-nib */
BOOL nib_about_loaded; /* reference to the about-nib */
......@@ -307,6 +308,7 @@ struct intf_sys_t
- (id)getMainIntfPgbar;
- (id)getControllerWindow;
- (id)getVoutMenu;
- (id)getEyeTVController;
- (void)applicationWillTerminate:(NSNotification *)notification;
- (NSString *)localizedString:(char *)psz;
- (char *)delocalizeString:(NSString *)psz;
......
......@@ -48,6 +48,7 @@
#import "embeddedwindow.h"
#import "update.h"
#import "AppleRemote.h"
#import "eyetv.h"
#import <vlc_input.h>
......@@ -359,6 +360,14 @@ static VLCMain *_o_sharedMainInstance = nil;
[o_remote setClickCountEnabledButtons: kRemoteButtonPlay];
[o_remote setDelegate: _o_sharedMainInstance];
o_eyetv = [[VLCEyeTVController alloc] init];
/* announce our launch to a potential eyetv plugin */
[[NSDistributedNotificationCenter defaultCenter] postNotificationName: @"VLCOSXGUIInit"
object: @"VLCEyeTVSupport"
userInfo: NULL
deliverImmediately: YES];
return _o_sharedMainInstance;
}
......@@ -1017,6 +1026,13 @@ static VLCMain *_o_sharedMainInstance = nil;
return o_vout_menu;
}
- (id)getEyeTVController
{
if( o_eyetv )
return o_eyetv;
return nil;
}
- (void)manage
{
playlist_t * p_playlist;
......@@ -1621,6 +1637,9 @@ static VLCMain *_o_sharedMainInstance = nil;
if( o_interaction_list != nil )
[o_interaction_list release];
if( o_eyetv != nil )
[o_eyetv release];
if( o_img_pause_pressed != nil )
{
[o_img_pause_pressed release];
......
......@@ -42,10 +42,15 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
IBOutlet id o_btn_ok;
IBOutlet id o_btn_cancel;
IBOutlet id o_output_ckbox;
IBOutlet id o_sout_options;
/* open file */
IBOutlet id o_file_path;
IBOutlet id o_file_btn_browse;
IBOutlet id o_file_stream;
/* open disc */
IBOutlet id o_disc_type;
IBOutlet id o_disc_device;
IBOutlet id o_disc_device_lbl;
......@@ -59,6 +64,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
IBOutlet id o_disc_videots_btn_browse;
IBOutlet id o_disc_dvd_menus;
/* open network */
IBOutlet id o_net_mode;
IBOutlet id o_net_udp_port;
IBOutlet id o_net_udp_port_lbl;
......@@ -72,6 +78,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
IBOutlet id o_net_http_url_lbl;
IBOutlet id o_net_timeshift_ckbox;
/* open subtitle file */
IBOutlet id o_file_sub_ckbox;
IBOutlet id o_file_sub_btn_settings;
IBOutlet id o_file_sub_sheet;
......@@ -94,8 +101,19 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
IBOutlet id o_file_sub_font_box;
IBOutlet id o_file_sub_file_box;
IBOutlet id o_output_ckbox;
IBOutlet id o_sout_options;
/* open eyetv support */
IBOutlet id o_eyetv_tabView;
IBOutlet id o_eyetv_channels_pop;
IBOutlet id o_eyetv_currentChannel_lbl;
IBOutlet id o_eyetv_chn_status_txt;
IBOutlet id o_eyetv_chn_bgbar;
IBOutlet id o_eyetv_launchEyeTV_btn;
IBOutlet id o_eyetv_nextProgram_btn;
IBOutlet id o_eyetv_noDevice_lbl;
IBOutlet id o_eyetv_noDeviceLong_lbl;
IBOutlet id o_eyetv_noEyeTV_lbl;
IBOutlet id o_eyetv_noEyeTVLong_lbl;
IBOutlet id o_eyetv_previousProgram_btn;
BOOL b_autoplay;
}
......@@ -125,6 +143,11 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class );
- (IBAction)openNetStepperChanged:(id)sender;
- (void)openNetInfoChanged:(NSNotification *)o_notification;
- (IBAction)eyetvSwitchChannel:(id)sender;
- (IBAction)eyetvLaunch:(id)sender;
- (void)eyetvChanged:(NSNotification *)o_notification;
- (void)setupChannelInfo;
- (IBAction)subsChanged:(id)sender;
- (IBAction)subSettings:(id)sender;
- (IBAction)subFileBrowse:(id)sender;
......
/*****************************************************************************
* open.m: MacOS X module for vlc
*****************************************************************************
* Copyright (C) 2002-2006 the VideoLAN team
* Copyright (C) 2002-2007 the VideoLAN team
* $Id$
*
* Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
......@@ -39,11 +39,11 @@
#include <IOKit/storage/IOCDMedia.h>
#include <IOKit/storage/IODVDMedia.h>
#include "intf.h"
#include "playlist.h"
#include "open.h"
#include "output.h"
#import <vlc_interface.h>
#import "intf.h"
#import "playlist.h"
#import "open.h"
#import "output.h"
#import "eyetv.h"
/*****************************************************************************
* GetEjectableMediaOfClass
......@@ -189,7 +189,10 @@ static VLCOpen *_o_sharedMainInstance = nil;
[o_net_udp_port setIntValue: config_GetInt( p_intf, "server-port" )];
[o_net_udp_port_stp setIntValue: config_GetInt( p_intf, "server-port" )];
[o_eyetv_chn_bgbar setUsesThreadedAnimation: YES];
/* FIXME: implement EyeTV l10n here */
[self setSubPanel];
......@@ -231,6 +234,21 @@ static VLCOpen *_o_sharedMainInstance = nil;
selector: @selector(openNetInfoChanged:)
name: NSControlTextDidChangeNotification
object: o_net_http_url];
/* wake up with the correct GUI */
if( [[[VLCMain sharedInstance] getEyeTVController] isEyeTVrunning] == YES )
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES )
{
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"];
[self setupChannelInfo];
}
[[NSDistributedNotificationCenter defaultCenter] addObserver: self
selector: @selector(eyetvChanged:)
name: NULL
object: @"VLCEyeTVSupport"
suspensionBehavior: NSNotificationSuspensionBehaviorDeliverImmediately];
/* register clicks on text fields */
[[NSNotificationCenter defaultCenter] addObserver: self
......@@ -779,6 +797,83 @@ static VLCOpen *_o_sharedMainInstance = nil;
}
}
- (IBAction)eyetvSwitchChannel:(id)sender
{
if( sender == o_eyetv_nextProgram_btn )
[[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: YES];
else if( sender == o_eyetv_previousProgram_btn )
[[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: NO];
else if( sender == o_eyetv_channels_pop )
[[[VLCMain sharedInstance] getEyeTVController] selectChannel:
[sender indexOfSelectedItem]];
else
msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
}
- (IBAction)eyetvLaunch:(id)sender
{
[[[VLCMain sharedInstance] getEyeTVController] launchEyeTV];
}
- (void)eyetvChanged:(NSNotification *)o_notification
{
if( [[o_notification name] isEqualToString: @"DeviceAdded"] )
{
msg_Dbg( VLCIntf, "eyetv device was added" );
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"];
[self setupChannelInfo];
}
else if( [[o_notification name] isEqualToString: @"DeviceRemoved"] )
{
/* leave the channel selection like that,
* switch to our "no device" tab */
msg_Dbg( VLCIntf, "eyetv device was removed" );
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
}
else if( [[o_notification name] isEqualToString: @"PluginQuit"] )
{
/* switch to the "launch eyetv" tab */
msg_Dbg( VLCIntf, "eyetv was terminated" );
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"noeyetv"];
}
else if( [[o_notification name] isEqualToString: @"PluginInit"] )
{
/* we got no device yet */
msg_Dbg( VLCIntf, "eyetv was launched, no device yet" );
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
}
else
msg_Warn( VLCIntf, "unknown external notify '%s' received", [[o_notification name] UTF8String] );
}
/* little helper method, since this code needs to be run by multiple objects */
- (void)setupChannelInfo
{
/* set up channel selection */
[o_eyetv_channels_pop removeAllItems];
[o_eyetv_chn_bgbar setHidden: NO];
[o_eyetv_chn_bgbar animate: self];
[o_eyetv_chn_status_txt setStringValue: _NS("Retrieving Channel Info...")];
[o_eyetv_chn_status_txt setHidden: NO];
/* retrieve info */
int x = 0;
int channelCount = ( [[[VLCMain sharedInstance] getEyeTVController] getNumberOfChannels] + 1 );
while( x != channelCount )
{
/* we have to add items this way, because we accept duplicates
* additionally, we save a bit of time */
[[o_eyetv_channels_pop menu] addItemWithTitle: [[[VLCMain sharedInstance] getEyeTVController] getNameOfChannel: x]
action: nil
keyEquivalent: @""];
x += 1;
}
/* clean up GUI */
[o_eyetv_chn_bgbar setHidden: YES];
[o_eyetv_chn_status_txt setHidden: YES];
}
- (IBAction)subsChanged:(id)sender
{
if ([o_file_sub_ckbox state] == NSOnState)
......
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