eyetvplugin.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:20k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2. * eyetvplugin.c: Plug-In for the EyeTV software to connect to VLC
  3. *****************************************************************************
  4. * Copyright (C) 2006-2007 the VideoLAN team
  5. * $Id: 3f190a6ed624040b740d9f0738f343deef437dfa $
  6. *
  7. * Authors: Felix Kühne <fkuehne at videolan dot org>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 2 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22. *****************************************************************************/
  23. #include "eyetvplugin.h"
  24. #include <sys/types.h>
  25. #include <sys/socket.h>
  26. #include <sys/un.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29. #define MAX_PIDS            256
  30. #define MAX_ACTIVE_PIDS     256
  31. #define MAX_DEVICES         16
  32. #define VLC_NOTIFICATION_OBJECT "VLCEyeTVSupport"
  33. #pragma push
  34. #pragma pack(1)
  35. /* Structure for TS-Packets */
  36. typedef struct 
  37. {
  38.     uint32_t    sync_byte : 8,
  39.                 transport_error_indicator : 1,
  40.                 payload_unit_start_indicator : 1,
  41.                 transport_priority : 1,
  42.                 PID : 13,
  43.                 transport_scrambling_control : 2,
  44.                 adaptation_field_control : 2,
  45.                 continuity_counter : 4;
  46.     uint8_t     payload[184];
  47. } TransportStreamPacket;
  48. #pragma pop
  49. /* Structure to hold global data to communicate with EyeTV */
  50. typedef struct 
  51. {
  52.     EyeTVPluginCallbackProc     callback;
  53.     /* Structure to hold current active service */
  54.     EyeTVPluginDeviceID         activeDeviceID;
  55.     long                        activePIDsCount; 
  56.     EyeTVPluginPIDInfo          activePIDs[MAX_ACTIVE_PIDS];
  57. } VLCEyeTVPluginGlobals_t;
  58. /* following globals limits us to one VLC instance using EyeTV */
  59. static int i_deviceCount;
  60. static int i_vlcSock;
  61. #pragma mark -
  62. /* initialise the plug-in */
  63. static long VLCEyeTVPluginInitialize(VLCEyeTVPluginGlobals_t** globals, long apiVersion, EyeTVPluginCallbackProc callback)
  64. {
  65.     printf("VLC media player Plug-In: Initializen");
  66.     long result = 0;
  67.     
  68.     /* init our own storage */
  69.     i_deviceCount = 0;
  70.     i_vlcSock = -1;
  71.     
  72.     /* notify a potential VLC instance about our initialisation */
  73.     CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
  74.                                           CFSTR("PluginInit"), 
  75.                                           CFSTR(VLC_NOTIFICATION_OBJECT), 
  76.                                           /*userInfo*/ NULL, 
  77.                                           TRUE );
  78.     
  79.     /* init our notification support */
  80.     CFNotificationCenterAddObserver( CFNotificationCenterGetDistributedCenter(),
  81.                                      /* observer */ NULL, 
  82.                                      /* callBack */ VLCEyeTVPluginGlobalNotificationReceived,
  83.                                      /* name, NULL==all */ NULL,
  84.                                      CFSTR(VLC_NOTIFICATION_OBJECT), 
  85.                                      CFNotificationSuspensionBehaviorDeliverImmediately );
  86.     
  87.     *globals = (VLCEyeTVPluginGlobals_t *) calloc(1, sizeof( VLCEyeTVPluginGlobals_t ) );
  88.     ( *globals )->callback = callback;
  89.         
  90.     return result;
  91. }
  92. /* we will be terminated soon, clean up */
  93. static long VLCEyeTVPluginTerminate(VLCEyeTVPluginGlobals_t *globals)
  94. {
  95.     long result = 0;
  96.     
  97.     printf("VLC media player Plug-In: Terminaten");
  98.     
  99.     /* notify a potential VLC instance about our termination */
  100.     CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
  101.                                           CFSTR("PluginQuit"), 
  102.                                           CFSTR(VLC_NOTIFICATION_OBJECT), 
  103.                                           /*userInfo*/ NULL, 
  104.                                           TRUE );
  105.     
  106.     /* remove us from the global notification centre */
  107.     CFNotificationCenterRemoveEveryObserver( CFNotificationCenterGetDistributedCenter(),
  108.                                              (void *)VLCEyeTVPluginGlobalNotificationReceived );
  109.     
  110.     /* close data connection */
  111.     if( i_vlcSock != -1 )
  112.     {
  113.         close( i_vlcSock );
  114.         i_vlcSock = -1;
  115.     }
  116.     
  117.     free( globals );
  118.     return result;
  119. }
  120. /* called when EyeTV asks various stuff about us */
  121. static long VLCEyeTVPluginGetInformation(VLCEyeTVPluginGlobals_t *globals, long* outAPIVersion, char* outName, char *outDescription)
  122. {
  123.     printf("VLC media player Plug-In: GetInfon");
  124.     long result = 0;
  125.     
  126.     if( globals ) 
  127.     {
  128.         if( outAPIVersion )
  129.         {
  130.             *outAPIVersion = EYETV_PLUGIN_API_VERSION;
  131.         }
  132.         
  133.         if( outName )
  134.         {
  135.             strcpy( outName, "VLC media player Plug-In");
  136.         }
  137.         
  138.         if( outDescription )
  139.         {
  140.             strcpy( outDescription, "This Plug-In connects EyeTV to the VLC media player for streaming purposes.");
  141.         }
  142.     }
  143.     
  144.     return result;
  145. }
  146. /* called if we received a global notification */
  147. void VLCEyeTVPluginGlobalNotificationReceived( CFNotificationCenterRef center, 
  148.                                               void *observer, 
  149.                                               CFStringRef name, 
  150.                                               const void *object, 
  151.                                               CFDictionaryRef userInfo )
  152. {
  153.     /* when VLC launches after us, we need to inform it about our existance and the current state of available devices */
  154.     if( CFStringCompare( name, CFSTR( "VLCOSXGUIInit" ), 0) == kCFCompareEqualTo )
  155.     {
  156.         /* we're here */
  157.         CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
  158.                                               CFSTR("PluginInit"), 
  159.                                               CFSTR(VLC_NOTIFICATION_OBJECT), 
  160.                                               /*userInfo*/ NULL, 
  161.                                               TRUE );
  162.         if( i_deviceCount > 0 )
  163.         {
  164.             /* at least one device is apparently connected */
  165.             CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter (),
  166.                                                   CFSTR("DeviceAdded"), 
  167.                                                   CFSTR(VLC_NOTIFICATION_OBJECT), 
  168.                                                   /*userInfo*/ NULL, 
  169.                                                   TRUE );
  170.         }
  171.     }
  172.     
  173.     /* VLC wants us to start sending data */
  174.     if( CFStringCompare( name, CFSTR( "VLCAccessStartDataSending" ), 0) == kCFCompareEqualTo )
  175.     {
  176.         if( i_vlcSock == -1 )
  177.         {
  178.             int peerSock;
  179.          
  180.             /* set-up data socket */
  181.             peerSock = socket(AF_UNIX, SOCK_STREAM, 0);
  182.             if( peerSock != -1 )
  183.             {
  184.                 struct sockaddr_un peerAddr;
  185.                 /* set-up connection address */
  186.                 memset(&peerAddr, 0, sizeof(peerAddr));
  187.                 peerAddr.sun_family = AF_UNIX;
  188.                 strncpy(peerAddr.sun_path, "/tmp/.vlc-eyetv-bridge", sizeof(peerAddr.sun_path)-1);
  189.                 
  190.                 /* connect */
  191.                 printf("data connect in progess...n");
  192.                 if( connect(peerSock, (struct sockaddr *)&peerAddr, sizeof(struct sockaddr_un)) != -1 )
  193.                 {
  194.                     printf("data sending switched onn");
  195.                     i_vlcSock = peerSock;
  196.                 }
  197.                 else
  198.                     printf("connect data socket failed (errno=%d)n", errno );
  199.             }
  200.             else
  201.                 printf("create data socket failed (errno=%d)n", errno );
  202.         }
  203.     }
  204.     
  205.     /* VLC wants us to stop sending data */
  206.     if( CFStringCompare( name, CFSTR( "VLCAccessStopDataSending" ), 0) == kCFCompareEqualTo )
  207.     {
  208.         if( i_vlcSock != -1 )
  209.         {
  210.             close( i_vlcSock );
  211.             i_vlcSock = -1;
  212.             printf( "data sending switched offn" );
  213.         }
  214.     }
  215. }
  216. /* called if a device is added */
  217. static long VLCEyeTVPluginDeviceAdded(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, EyeTVPluginDeviceType deviceType)
  218. {
  219.     printf("VLC media player Plug-In: Device with type %i and ID %i addedn", (int)deviceType, (int)deviceID);
  220.     
  221.     long result = 0;
  222.     
  223.     if( globals ) 
  224.     {
  225.         ++i_deviceCount;
  226.         if( 1 == i_deviceCount )
  227.         {                
  228.             /* notify a potential VLC instance about the addition */
  229.             CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
  230.                                                   CFSTR("DeviceAdded"), 
  231.                                                   CFSTR(VLC_NOTIFICATION_OBJECT), 
  232.                                                   /*userInfo*/ NULL, 
  233.                                                   TRUE );
  234.         }
  235.     }
  236.     return result;
  237. }
  238. /* called if a device is removed */
  239. static long VLCEyeTVPluginDeviceRemoved(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID)
  240. {
  241.     printf("VLC media player Plug-In: DeviceRemovedn");
  242.     
  243.     long result = 0;
  244.         
  245.     --i_deviceCount;
  246.     if( 0 == i_deviceCount )
  247.     {                
  248.         /* notify a potential VLC instance about the removal */
  249.         CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
  250.                                               CFSTR("DeviceRemoved"), 
  251.                                               CFSTR(VLC_NOTIFICATION_OBJECT), 
  252.                                               /*userInfo*/ NULL, 
  253.                                               TRUE );
  254.     }
  255.     if( (i_vlcSock != -1) && (deviceID == globals->activeDeviceID) )
  256.     {
  257.         close(i_vlcSock);
  258.         i_vlcSock = -1;
  259.         printf( "data sending switched offn" );
  260.     }
  261.     
  262.     return result;
  263. }
  264. /* This function is called, whenever packets are received by EyeTV. For reasons of performance,
  265.  * the data is the original data, not a copy. That means, EyeTV waits until this method is 
  266.  * finished. Therefore all in this method should be as fast as possible. */
  267. static long VLCEyeTVPluginPacketsArrived(VLCEyeTVPluginGlobals_t *globals, EyeTVPluginDeviceID deviceID, long **packets, long packetsCount)
  268. {
  269.     if( globals ) 
  270.     {
  271.         /* check if data connection is active */
  272.         if( i_vlcSock != -1 )
  273.         {
  274.             if( deviceID == globals->activeDeviceID ) 
  275.             {
  276.                 long pidCount = globals->activePIDsCount;
  277.                 if( pidCount )
  278.                 {
  279.                     uint8_t packetBuffer[sizeof(TransportStreamPacket)*20];
  280.                     int packetBufferSize = 0;
  281.                     while( packetsCount )
  282.                     {
  283.                         /* apply PID filtering, only PIDs in active service for device are sent through */
  284.                         long pid = ntohl(**packets)>>8 & 0x1FFFL;
  285.                         /* ignore NULL packets */
  286.                         if( 0x1FFFL != pid )
  287.                         {
  288.                             long i;
  289.                             for( i=0; i<pidCount; ++i )
  290.                             {
  291.                                 if( globals->activePIDs[i].pid == pid )
  292.                                 {
  293.                                     if( packetBufferSize <= (sizeof(packetBuffer)-sizeof(TransportStreamPacket)) )
  294.                                     {
  295.                                         /* copy packet in our buffer */
  296.                                         memcpy(packetBuffer+packetBufferSize, *packets, sizeof(TransportStreamPacket));
  297.                                         packetBufferSize += sizeof(TransportStreamPacket);
  298.                                     }
  299.                                     else
  300.                                     {
  301.                                         /* flush buffer to VLC */
  302.                                         ssize_t sent = write(i_vlcSock, packetBuffer, packetBufferSize);
  303.                                         if( sent != packetBufferSize )
  304.                                         {
  305.                                             if( sent == -1 )
  306.                                                 printf("data sending failed (errno=%d)n", errno);
  307.                                             else
  308.                                                 printf("data sending incomplete (sent=%d)n", sent);
  309.                                             close(i_vlcSock);
  310.                                             i_vlcSock = -1;
  311.                                             return 0;
  312.                                         }
  313.                                         packetBufferSize = 0;
  314.                                     }
  315.                                     if( i > 0 )
  316.                                     {
  317.                                        /* if we assume that consecutive packets would have the same PID in most cases,
  318.                                           it would therefore speed up filtering to reorder activePIDs list based on pid
  319.                                           occurrences */
  320.                                         EyeTVPluginPIDInfo swap = globals->activePIDs[i];
  321.                                         do
  322.                                         {
  323.                                             register int c = i--;
  324.                                             globals->activePIDs[c] = globals->activePIDs[i];
  325.                                         }
  326.                                         while( i );
  327.                                         globals->activePIDs[i] = swap;
  328.                                     }
  329.                                     if( pid && globals->activePIDs[0].pidType != kEyeTVPIDType_PMT )
  330.                                     {
  331.                                         /* to save on CPU, prevent EyeTV from mirroring that program by blocking video & audio packets
  332.                                            by changing all packets but PAT and PMT to NULL PID */
  333. #if defined(WORDS_BIGENDIAN)
  334.                                         **packets |= 0x001FFF00L;
  335. #else
  336.                                         **packets |= 0x00FFF800L;
  337. #endif
  338.                                     }
  339.                                     /* done filtering on this packet, move on to next packet */
  340.                                     break;
  341.                                 }
  342.                             }
  343.                         }
  344.                         --packetsCount;
  345.                         ++packets;
  346.                     }
  347.                     if( packetBufferSize )
  348.                     {
  349.                         /* flush buffer to VLC */
  350.                         ssize_t sent = write(i_vlcSock, packetBuffer, packetBufferSize);
  351.                         if( sent != packetBufferSize )
  352.                         {
  353.                             if( sent == -1 )
  354.                                 printf("data sending failed (errno=%d)n", errno);
  355.                             else
  356.                                 printf("data sending incomplete (sent=%d)n", sent);
  357.                             close(i_vlcSock);
  358.                             i_vlcSock = -1;
  359.                             return 0;
  360.                         }
  361.                     }
  362.                 }
  363.             }
  364.         }
  365.     }
  366.     return 0;
  367. }
  368. /*  VLCEyeTVPluginServiceChanged,
  369.  *
  370.  *  - *globals      : The plug-in Globals
  371.  *  - deviceID      : Identifies the active Device
  372.  *   - headendID        : The HeadendID, for e300 it's the orbital position of the satelite in 
  373.  *                    tenth degrees east
  374.  *   - transponderID : The Frequency in kHz
  375.  *   - serviceID        : original ServiceID from the DVB-Stream (e300, e400)
  376.  *  - pidList       : List of active PIDs   
  377.  *
  378.  *  Whenever a service changes, this function is called. Service-related plug-in data should be updated here.
  379.  */
  380. static long VLCEyeTVPluginServiceChanged(VLCEyeTVPluginGlobals_t *globals, 
  381.                                             EyeTVPluginDeviceID deviceID, 
  382.                                             long headendID, 
  383.                                             long transponderID, 
  384.                                             long serviceID, 
  385.                                             EyeTVPluginPIDInfo *pidList, 
  386.                                             long pidsCount)
  387. {
  388.     long result = 0;
  389.     int i;
  390.     
  391.     printf("nVLC media player Plug-In: ServiceChanged:n");
  392.     printf(  "=====================================n");
  393.     
  394.     if( globals ) 
  395.     {
  396.         printf("DeviceID: %ld, ", deviceID);
  397.         printf("HeadendID: %ld, ", headendID);
  398.         printf("TransponderID: %ld, ", transponderID);
  399.         printf("ServiceID: %ldnn", serviceID);
  400.         
  401.         globals->activeDeviceID = deviceID;
  402.         globals->activePIDsCount = pidsCount;
  403.         /* need active PIDs for packet filtering */
  404.         for( i = 0; i < pidsCount; i++ )
  405.         {
  406.             globals->activePIDs[i] = pidList[i];
  407.             printf("Active PID: %ld, type: %ldn", pidList[i].pid, pidList[i].pidType);
  408.         }
  409.     }
  410.     printf(  "=====================================n");
  411.     
  412.     /* notify a potential VLC instance about the service change */
  413.     CFNotificationCenterPostNotification( CFNotificationCenterGetDistributedCenter(),
  414.                                           CFSTR("ServiceChanged"), 
  415.                                           CFSTR(VLC_NOTIFICATION_OBJECT), 
  416.                                           /*userInfo*/ NULL, 
  417.                                           TRUE );
  418.     
  419.     return result;
  420. }
  421. #pragma mark -
  422. /* EyeTVPluginDispatcher,
  423.  *
  424.  *  - selector : See 'EyeTVPluginDefs.h'
  425.  *  - *refCon :  The RefCon to the plug-in-related Data
  426.  *  - deviceID : Identifies the Device
  427.  *  - params : Parameters for functioncall
  428.  *
  429.  * This function is a part of the interface for the communication with EyeTV. If something happens,
  430.  * EyeTV thinks, we should know of, it calls this function with the corresponding selector. */
  431. #pragma export on
  432. long EyeTVPluginDispatcher( EyeTVPluginParams* params )
  433. {
  434.     long result = 0;
  435.     switch( params->selector ) 
  436.     {
  437.         case kEyeTVPluginSelector_Initialize:
  438.             result = VLCEyeTVPluginInitialize((VLCEyeTVPluginGlobals_t**)params->refCon, 
  439.                                     params->initialize.apiVersion, params->initialize.callback);
  440.             break;
  441.             
  442.         case kEyeTVPluginSelector_Terminate:
  443.             result = VLCEyeTVPluginTerminate((VLCEyeTVPluginGlobals_t*)params->refCon);
  444.             break;
  445.         case kEyeTVPluginSelector_GetInfo:
  446.             result = VLCEyeTVPluginGetInformation((VLCEyeTVPluginGlobals_t*)params->refCon, 
  447.                                     params->info.pluginAPIVersion, params->info.pluginName, params->info.description);
  448.             break;
  449.         case kEyeTVPluginSelector_DeviceAdded:
  450.             result = VLCEyeTVPluginDeviceAdded((VLCEyeTVPluginGlobals_t*)params->refCon, 
  451.                                     params->deviceID, params->deviceAdded.deviceType);
  452.             break;
  453.         
  454.         case kEyeTVPluginSelector_DeviceRemoved:
  455.             result = VLCEyeTVPluginDeviceRemoved((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID);
  456.             break;
  457.         case kEyeTVPluginSelector_PacketsArrived:
  458.             result = VLCEyeTVPluginPacketsArrived((VLCEyeTVPluginGlobals_t*)params->refCon, params->deviceID, 
  459.                                     params->packetsArrived.packets, params->packetsArrived.packetCount);
  460.             break;
  461.         case kEyeTVPluginSelector_ServiceChanged:
  462.             result = VLCEyeTVPluginServiceChanged((VLCEyeTVPluginGlobals_t*)params->refCon, 
  463.                                     params->deviceID, params->serviceChanged.headendID, 
  464.                                     params->serviceChanged.transponderID, params->serviceChanged.serviceID, 
  465.                                     params->serviceChanged.pidList, params->serviceChanged.pidCount);
  466.             break;
  467.     }
  468.     return result;
  469. }