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

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

parent 5266ede1
......@@ -23,6 +23,11 @@
#include "eyetvplugin.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define MAX_PIDS 256
#define MAX_ACTIVE_PIDS 256
#define MAX_DEVICES 16
......@@ -31,11 +36,9 @@
#pragma push
#pragma pack(1)
/* Structure for TS-Packets */
typedef struct
{
unsigned long sync_byte : 8,
uint32_t sync_byte : 8,
transport_error_indicator : 1,
payload_unit_start_indicator : 1,
transport_priority : 1,
......@@ -43,73 +46,32 @@ typedef struct
transport_scrambling_control : 2,
adaptation_field_control : 2,
continuity_counter : 4;
} TransportStreamHeader;
unsigned char data[188-4];
} TransportStreamPacket;
#pragma pop
/* Structure to hold Information on devices */
/* Structure for TS-Packets */
typedef struct
{
EyeTVPluginDeviceID deviceID;
EyeTVPluginDeviceType deviceType;
long headendID;
long transponderID;
long serviceID;
long pidsCount;
long pids[MAX_PIDS];
TransportStreamHeader header;
uint8_t payload[184];
EyeTVPluginPIDInfo activePIDs[MAX_ACTIVE_PIDS];
long activePIDsCount;
} TransportStreamPacket;
} DeviceInfo;
#pragma pop
/* Structure to hold global data to communicate with EyeTV */
typedef struct
{
EyeTVPluginCallbackProc callback;
long deviceCount;
DeviceInfo devices[MAX_DEVICES];
long long packetCount;
/* Structure to hold current active service */
EyeTVPluginDeviceID activeDeviceID;
long activePIDsCount;
EyeTVPluginPIDInfo activePIDs[MAX_ACTIVE_PIDS];
long seenPIDs[MAX_ACTIVE_PIDS];
} 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;
}
static int i_deviceCount;
static int vlcSock;
#pragma mark -
......@@ -120,8 +82,8 @@ static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long api
long result = 0;
/* init our own storage */
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;
nativeGlobals = malloc( sizeof( VLCEyeTVPluginOwnGlobals_t ) );
i_deviceCount = 0;
vlcSock = -1;
/* notify a potential VLC instance about our initialisation */
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
......@@ -147,12 +109,10 @@ static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long api
/* we will be terminated soon, clean up */
static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals)
{
extern VLCEyeTVPluginOwnGlobals_t *nativeGlobals;
long result = 0;
printf("VLC media player Plug-In: Terminate\n");
long result = 0;
/* notify a potential VLC instance about our termination */
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
CFSTR("PluginQuit"),
......@@ -164,24 +124,23 @@ static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals)
CFNotificationCenterRemoveEveryObserver( CFNotificationCenterGetDistributedCenter(),
(void *)VLCEyeTVPluginGlobalNotificationReceived );
/* invalidate and free msg port */
if( nativeGlobals->messagePortToVLC )
/* close data connection */
if( vlcSock != -1 )
{
CFMessagePortInvalidate( nativeGlobals->messagePortToVLC );
free( nativeGlobals->messagePortToVLC );
printf( "msgport invalidated and freed\n" );
close( vlcSock );
vlcSock = -1;
}
else
printf( "no msgport to free\n" );
if( globals )
{
long i;
for( i=0; i<globals->activePIDsCount; ++i )
{
printf("activePID: %ld, count=%ld\n", globals->activePIDs[i].pid, globals->seenPIDs[i] );
}
free( globals );
}
if( nativeGlobals )
free( nativeGlobals );
return result;
}
......@@ -200,14 +159,12 @@ static long VLCEyeTVPluginGetInformation(VLCEyeTVPluginGlobals_t *globals, long*
if( outName )
{
char* name = "VLC media player Plug-In";
strcpy( &outName[0], name);
strcpy( outName, "VLC media player Plug-In");
}
if( outDescription )
{
char* desc = "This Plug-In connects EyeTV to the VLC media player for streaming purposes.";
strcpy( &outDescription[0], desc);
strcpy( outDescription, "This Plug-In connects EyeTV to the VLC media player for streaming purposes.");
}
}
......@@ -221,27 +178,6 @@ void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center,
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 )
{
......@@ -251,7 +187,7 @@ void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center,
CFSTR(VLC_NOTIFICATION_OBJECT),
/*userInfo*/ NULL,
TRUE );
if( nativeGlobals && ( nativeGlobals->i_deviceCount > 0 ) )
if( i_deviceCount > 0 )
{
/* at least one device is apparently connected */
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
......@@ -265,23 +201,45 @@ void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center,
/* 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
if( vlcSock == -1 )
{
int peerSock;
/* set-up data socket */
peerSock = socket(AF_UNIX, SOCK_STREAM, 0);
if( peerSock != -1 )
{
nativeGlobals->b_msgPortOpen = TRUE;
printf( "msg port opened / data sending switched on\n" );
struct sockaddr_un peerAddr;
/* set-up connection address */
memset(&peerAddr, 0, sizeof(peerAddr));
peerAddr.sun_family = AF_UNIX;
strncpy(peerAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(peerAddr.sun_path)-1);
/* connect */
printf("data connect in progess...\n");
if( connect(peerSock, (struct sockaddr *)&peerAddr, sizeof(struct sockaddr_un)) != -1 )
{
printf("data sending switched on\n");
vlcSock = peerSock;
}
else
printf("connect data socket failed (errno=%d)\n", errno );
}
else
printf("create data socket failed (errno=%d)\n", errno );
}
}
/* VLC wants us to stop sending data */
if( CFStringCompare( name, CFSTR( "VLCAccessStopDataSending" ), 0) == kCFCompareEqualTo )
{
nativeGlobals->b_msgPortOpen = FALSE;
if( vlcSock != -1 )
{
close( vlcSock );
vlcSock = -1;
printf( "data sending switched off\n" );
}
}
}
/* called if a device is added */
......@@ -290,25 +248,12 @@ static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPlu
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 )
++i_deviceCount;
if( 1 == i_deviceCount )
{
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"),
......@@ -317,7 +262,6 @@ static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPlu
TRUE );
}
}
return result;
}
......@@ -326,26 +270,11 @@ static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVP
{
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++ )
--i_deviceCount;
if( 0 == i_deviceCount )
{
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"),
......@@ -353,7 +282,11 @@ static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVP
/*userInfo*/ NULL,
TRUE );
}
}
if( (vlcSock != -1) && (deviceID == globals->activeDeviceID) )
{
close(vlcSock);
vlcSock = -1;
printf( "data sending switched off\n" );
}
return result;
......@@ -362,147 +295,74 @@ static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVP
/* 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 )
if( globals )
{
DeviceInfo *deviceInfo = GetDeviceInfo(globals, deviceID);
if( deviceInfo )
/* check if data connection is active */
if( vlcSock != -1 )
{
/* alloc the buffer if wanted */
if( nativeGlobals->b_msgPortOpen == TRUE )
theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) );
for( i = 0; i < packetsCount; i++ )
if( deviceID == globals->activeDeviceID )
{
packet = ( TransportStreamPacket* )packets[i];
isNewPID = 1;
/* search for PID */
for( j = 0; j < deviceInfo->pidsCount; j++ )
long pidCount = globals->activePIDsCount;
if( pidCount )
{
if( packet->PID == deviceInfo->pids[j] )
while( packetsCount )
{
isNewPID = 0;
break;
}
}
/* add new PIDs to the DeviceInfo */
if( isNewPID )
/* apply PID filtering, only PIDs in active service for device are sent through */
long pid = (ntohl(**packets) & 0x001FFF00L)>>8;
long i;
for( i=0; i<pidCount; ++i )
{
printf ("VLC media player Plug-In: SamplePacketsArrived, newPID = %6d\n", packet->PID);
if( deviceInfo->pidsCount < MAX_PIDS )
if( globals->activePIDs[i].pid == pid )
{
deviceInfo->pids[deviceInfo->pidsCount++] = packet->PID;
}
}
else
ssize_t sent = write(vlcSock, *packets, sizeof(TransportStreamPacket));
if( sent != sizeof(TransportStreamPacket) )
{
/* 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( sent == -1 )
printf("data sending failed (errno=%d)\n", errno);
else
printf("data sending incomplete (sent=%d)\n", sent);
close(vlcSock);
vlcSock = -1;
return 0;
}
++(globals->seenPIDs[i]);
#if 0
if( i > 0 )
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;
{
/* if we assume that consecutive packets should have the same PID, it would therefore
speed up filtering to reorder activePIDs list based on pid occurrences */
EyeTVPluginPIDInfo swap = globals->activePIDs[i];
memmove(globals->activePIDs+1, globals->activePIDs, sizeof(EyeTVPluginPIDInfo)*i);
globals->activePIDs[0] = swap;
}
if( pid && filterPidInfo.pidType != kEyeTVPIDType_PMT )
{
/* to save on CPU, prevent EyeTV from mirroring that program by blocking video & audio packets
by changing PID to NULL PID */
#if defined(WORDS_BIGENDIAN)
**packets |= 0x001FFF00L;
#else
**packets |= 0x00FFF800L;
#endif
}
#endif
/* done filtering on this packet, move on to next packet */
break;
}
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;
if( i == pidCount )
printf("unexpected PID %ld\n", pid);
}
else if( i_returnValue == kCFMessagePortTransportError )
printf( "transport error while sending!\n" );
else
{
//printf( "success, freeing resources\n" );
free( theMutableRef );
theMutableRef = CFDataCreateMutable( kCFAllocatorDefault, (188) );
--packetsCount;
++packets;
}
}
}
}
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;
return 0;
}
/* VLCEyeTVPluginServiceChanged,
......@@ -533,29 +393,20 @@ static long VLCEyeTVPluginServiceChanged(VLCEyeTVPluginGlobals_t *globals,
if( globals )
{
DeviceInfo *deviceInfo = GetDeviceInfo( globals, deviceID );
if( deviceInfo )
{
deviceInfo->headendID = headendID;
printf("DeviceID: %ld, ", deviceID);
printf("HeadendID: %ld, ", headendID);
deviceInfo->transponderID = transponderID;
printf("TransponderID: %ld, ", transponderID);
deviceInfo->serviceID = serviceID;
printf("ServiceID: %ld\n\n", serviceID);
deviceInfo->activePIDsCount = pidsCount;
globals->activeDeviceID = deviceID;
globals->activePIDsCount = pidsCount;
for( i = 0; i < pidsCount; i++ )
{
deviceInfo->activePIDs[i] = pidList[i];
globals->activePIDs[i] = pidList[i];
globals->seenPIDs[i] = 0;
printf("Active PID: %ld, type: %ld\n", pidList[i].pid, pidList[i].pidType);
}
deviceInfo->pidsCount = 0;
}
}
printf( "=====================================\n");
......
......@@ -22,9 +22,6 @@
*****************************************************************************/
#include "EyeTVPluginDefs.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center,
......
......@@ -122,7 +122,6 @@
mainGroup = 089C166AFE841209C02AAC07 /* VLC EyeTV Plug-In */;
projectDirPath = "";
projectRoot = "";
shouldCheckCompatibility = 1;
targets = (
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_directory = directory.c
SOURCES_access_dv = dv.c
......@@ -7,7 +12,7 @@ SOURCES_access_http = http.c
SOURCES_access_ftp = ftp.c
SOURCES_access_smb = smb.c
SOURCES_access_gnomevfs = gnomevfs.c
SOURCES_access_eyetv = eyetv.c
SOURCES_access_eyetv = eyetv.m
SOURCES_dvdnav = dvdnav.c
SOURCES_dvdread = dvdread.c
SOURCES_dc1394 = dc1394.c
......
......@@ -2,7 +2,7 @@
* eyetv.c : Access module to connect to our plugin running within EyeTV
*****************************************************************************
* 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>
*
......@@ -28,7 +28,14 @@
#include <vlc/vlc.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:
* watch for PluginQuit or DeviceRemoved to stop output to VLC's core then */
......@@ -39,12 +46,19 @@
static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
#define CHANNEL_TEXT N_("Channel number")
#define CHANNEL_LONGTEXT N_( \
"EyeTV program number, or use 0 for last channel, " \
"-1 for S-Video input, -2 for Composite input" )
vlc_module_begin();
set_shortname( "EyeTV" );
set_description( _("EyeTV access module") );
set_category( CAT_INPUT );
set_subcategory( SUBCAT_INPUT_ACCESS );
add_integer( "eyetv-channel", 0, NULL,
CHANNEL_TEXT, CHANNEL_LONGTEXT, VLC_FALSE );
set_capability( "access2", 0 );
add_shortcut( "eyetv" );
set_callbacks( Open, Close );
......@@ -53,29 +67,71 @@ 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;
int eyetvSock;
};
CFDataRef dataFromEyetv;
int lastPacketId;
int lastForwardedPacketId;
static ssize_t Read( access_t *, uint8_t *, size_t );
static int Control( access_t *, int, va_list );
static void Thread( vlc_object_t * );
CFDataRef msgPortCallback( CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info );
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
......@@ -84,9 +140,11 @@ 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));
struct sockaddr_un publicAddr, peerAddr;
int publicSock;
vlc_value_t val;
/* Init p_access */
access_InitFields( p_access ); \
......@@ -94,56 +152,55 @@ static int Open( vlc_object_t *p_this )
MALLOC_ERR( p_access->p_sys, access_sys_t ); \
p_sys = p_access->p_sys; memset( p_sys, 0, sizeof( access_sys_t ) );
var_Create( p_access, "eyetv-channel", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Get( p_access, "eyetv-channel", &val);
msg_Dbg( p_access, "coming up" );
/* 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 )
selectChannel(p_this, val.i_int);
/* socket */
memset(&publicAddr, 0, sizeof(publicAddr));
publicAddr.sun_family = AF_UNIX;
strncpy(publicAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(publicAddr.sun_path)-1);
/* remove previous public path if it wasn't cleanly removed */
if( (0 != unlink(publicAddr.sun_path)) && (ENOENT != errno) )
{
msg_Err( p_access, "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 );
msg_Err( p_access, "local socket path is not usable (errno=%d)", errno );
free( p_sys );
return VLC_EGENERIC;
}
publicSock = socket(AF_UNIX, SOCK_STREAM, 0);
if( publicSock == -1 )
{
msg_Err( p_access, "create local socket failed (errno=%d)", errno );
free( p_sys );
return VLC_EGENERIC;
}
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 ) )
if( bind(publicSock, (struct sockaddr *)&publicAddr, sizeof(struct sockaddr_un)) == -1 )
{
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 );
msg_Err( p_access, "bind local socket failed (errno=%d)", errno );
close( publicSock );
free( p_sys );
return VLC_EGENERIC;
}
msg_Dbg( p_access, "receiver thread created and launched" );
/* we are not expecting more than one connection */
if( listen(publicSock, 1) == -1 )
{
msg_Err( p_access, "cannot accept connection (errno=%d)", errno );
close( publicSock );
free( p_sys );
return VLC_EGENERIC;
}
else
{
socklen_t peerSockLen = sizeof(struct sockaddr_un);
int peerSock;
/* tell the EyeTV plugin to open up its msg port and start sending */
/* tell the EyeTV plugin to open start sending */
CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
CFSTR("VLCAccessStartDataSending"),
CFSTR("VLCEyeTVSupport"),
......@@ -152,9 +209,23 @@ static int Open( vlc_object_t *p_this )
msg_Dbg( p_access, "plugin notified" );
/* we don't need such a high priority */
//vlc_thread_set_priority( p_access, VLC_THREAD_PRIORITY_LOW );
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;
}
......@@ -177,106 +248,32 @@ static void Close( vlc_object_t *p_this )
msg_Dbg( p_access, "plugin notified" );
/* stop receiver thread */
vlc_object_kill( p_sys->p_thread );
vlc_mutex_lock( &p_sys->p_thread->lock );
vlc_cond_signal( &p_sys->p_thread->wait );
vlc_mutex_unlock( &p_sys->p_thread->lock );
vlc_thread_join( p_sys->p_thread );
close(p_sys->eyetvSock);
/* close msg port */
CFMessagePortInvalidate( p_sys->p_thread->inputMessagePortFromEyeTV );
free( p_sys->p_thread->inputMessagePortFromEyeTV );
msg_Dbg( p_access, "msg port closed and freed" );
/* free thread */
vlc_mutex_destroy( &p_sys->p_thread->lock );
vlc_cond_destroy( &p_sys->p_thread->wait );
vlc_object_detach( p_sys->p_thread );
vlc_object_destroy( p_sys->p_thread );
free( p_sys );
}
static void Thread( vlc_object_t *p_this )
{
eyetv_thread_t *p_thread= (eyetv_thread_t*)p_this;
CFRunLoopSourceRef runLoopSource;
/* create our run loop source for the port and attach it to our current loop */
runLoopSource = CFMessagePortCreateRunLoopSource( kCFAllocatorDefault,
p_thread->inputMessagePortFromEyeTV,
0 );
CFRunLoopAddSource( CFRunLoopGetCurrent(),
runLoopSource,
kCFRunLoopDefaultMode );
CFRunLoopRun();
}
/*****************************************************************************
* msgPortCallback: receives data from the EyeTV plugin
*****************************************************************************/
CFDataRef msgPortCallback( CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info )
{
extern CFDataRef dataFromEyetv;
extern int lastPacketId;
/* copy callback data to module data */
dataFromEyetv = CFDataCreateCopy( kCFAllocatorDefault, data );
#if 0
printf( "packet %i contained %i bytes, forwarding %i bytes\n",
(int)msgid,
(int)CFDataGetLength( data ),
(int)CFDataGetLength( dataFromEyetv ) );
#endif
lastPacketId = msgid;
return NULL; /* we've got nothing to return */
}
/*****************************************************************************
* Read: forwarding data from EyeTV plugin which was received above
*****************************************************************************/
static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len )
{
access_sys_t *p_sys = p_access->p_sys;
extern CFDataRef dataFromEyetv;
extern int lastPacketId;
extern int lastForwardedPacketId;
int i_read;
/* 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!" );
if( p_access->info.b_eof )
return 0;
}
}
if( p_access->b_die )
return 0;
i_read = net_Read( p_access, p_sys->eyetvSock, NULL, p_buffer, i_len,
VLC_FALSE );
if( i_read == 0 )
p_access->info.b_eof = VLC_TRUE;
else if( i_read > 0 )
p_access->info.i_pos += i_read;
return i_len;
return i_read;
}
/*****************************************************************************
......
......@@ -132,8 +132,6 @@ static VLCEyeTVController *_o_sharedInstance = nil;
script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n"
"channel_up\n"
"volume_change level 0\n"
"tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
"get current channel\n"
"end tell"];
msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel up" );
......@@ -143,8 +141,6 @@ static VLCEyeTVController *_o_sharedInstance = nil;
script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n"
"channel_down\n"
"volume_change level 0\n"
"tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
"get current channel\n"
"end tell"];
msg_Dbg( VLCIntf, "telling eyetv to switch 1 channel down" );
......@@ -172,25 +168,21 @@ static VLCEyeTVController *_o_sharedInstance = nil;
case -2: // Composite
script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n"
" input_change input source composite video input"
" volume_change level 0\n"
" tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
" input_change input source composite video input\n"
" show player_window\n"
"end tell"];
break;
case -1: // S-Video
script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n"
" input_change input source S video input"
" volume_change level 0\n"
" tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
" input_change input source S video input\n"
" show player_window\n"
"end tell"];
break;
case 0: // Tuner
case 0: // Last
script = [[NSAppleScript alloc] initWithSource:
@"tell application \"EyeTV\"\n"
" input_change input source tuner input"
" volume_change level 0\n"
" tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
" show player_window\n"
"end tell"];
break;
default:
......@@ -198,9 +190,8 @@ static VLCEyeTVController *_o_sharedInstance = nil;
{
NSString *channel_change = [NSString stringWithFormat:
@"tell application \"EyeTV\"\n"
@" channel_change channel number %d\n"
" volume_change level 0\n"
" tell application \"System Events\" to set visible of process \"EyeTV\" to false\n"
" channel_change channel number %d\n"
" show player_window\n"
"end tell", theChannelNum];
script = [[NSAppleScript alloc] initWithSource:channel_change];
}
......
......@@ -83,7 +83,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class )
p_list = [NSMutableArray arrayWithCapacity: 1];
next_media = IOIteratorNext( media_iterator );
if( next_media != nil )
if( next_media )
{
char psz_buf[0x32];
size_t dev_path_length;
......@@ -116,7 +116,7 @@ NSArray *GetEjectableMediaOfClass( const char *psz_class )
IOObjectRelease( next_media );
} while( ( next_media = IOIteratorNext( media_iterator ) ) != nil );
} while( ( next_media = IOIteratorNext( media_iterator ) ) );
}
IOObjectRelease( media_iterator );
......@@ -237,12 +237,15 @@ static VLCOpen *_o_sharedMainInstance = nil;
/* wake up with the correct EyeTV GUI */
if( [[[VLCMain sharedInstance] getEyeTVController] isEyeTVrunning] == YES )
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
else if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES )
{
if( [[[VLCMain sharedInstance] getEyeTVController] isDeviceConnected] == YES )
{
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"eyetvup"];
[self setupChannelInfo];
}
else
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"nodevice"];
}
else
[o_eyetv_tabView selectTabViewItemWithIdentifier:@"noeyetv"];
......@@ -411,6 +414,10 @@ static VLCOpen *_o_sharedMainInstance = nil;
{
[self openNetInfoChanged: nil];
}
else if( [o_label isEqualToString: _NS("EyeTV")] )
{
[o_mrl setStringValue: @"eyetv://"];
}
}
- (void)openFileGeneric
......@@ -797,12 +804,23 @@ static VLCOpen *_o_sharedMainInstance = nil;
- (IBAction)eyetvSwitchChannel:(id)sender
{
if( sender == o_eyetv_nextProgram_btn )
[o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: YES]];
{
int chanNum = [[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: YES];
[o_eyetv_channels_pop selectItemWithTag:chanNum];
[o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
}
else if( sender == o_eyetv_previousProgram_btn )
[o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: NO]];
{
int chanNum = [[[VLCMain sharedInstance] getEyeTVController] switchChannelUp: NO];
[o_eyetv_channels_pop selectItemWithTag:chanNum];
[o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
}
else if( sender == o_eyetv_channels_pop )
[[[VLCMain sharedInstance] getEyeTVController] selectChannel:
[[sender selectedItem] tag]];
{
int chanNum = [[sender selectedItem] tag];
[[[VLCMain sharedInstance] getEyeTVController] selectChannel:chanNum];
[o_mrl setStringValue: [NSString stringWithFormat:@"eyetv:// :eyetv-channel=%d", chanNum]];
}
else
msg_Err( VLCIntf, "eyetvSwitchChannel sent by unknown object" );
}
......@@ -865,9 +883,6 @@ static VLCOpen *_o_sharedMainInstance = nil;
if( channels )
{
NSString *channel;
[[[o_eyetv_channels_pop menu] addItemWithTitle: _NS("Tuner")
action: nil
keyEquivalent: @""] setTag:x++];
[[o_eyetv_channels_pop menu] addItem: [NSMenuItem separatorItem]];
while( channel = [channels nextObject] )
{
......@@ -875,7 +890,7 @@ static VLCOpen *_o_sharedMainInstance = nil;
* additionally, we save a bit of time */
[[[o_eyetv_channels_pop menu] addItemWithTitle: channel
action: nil
keyEquivalent: @""] setTag:x++];
keyEquivalent: @""] setTag:++x];
}
/* make Tuner the default */
[o_eyetv_channels_pop selectItemWithTag:[[[VLCMain sharedInstance] getEyeTVController] currentChannel]];
......@@ -884,8 +899,6 @@ static VLCOpen *_o_sharedMainInstance = nil;
/* clean up GUI */
[o_eyetv_chn_bgbar setHidden: YES];
[o_eyetv_chn_status_txt setHidden: YES];
[o_mrl setStringValue: @"eyetv:"];
}
- (IBAction)subsChanged:(id)sender
......
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