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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * netsync.c: synchronisation between several network clients.
  3.  *****************************************************************************
  4.  * Copyright (C) 2004 the VideoLAN team
  5.  * $Id: e6950464b1ce3ae4c411949e08927e862961b8cc $
  6.  *
  7.  * Authors: Gildas Bazin <gbazin@videolan.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. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifdef HAVE_CONFIG_H
  27. # include "config.h"
  28. #endif
  29. #include <vlc_common.h>
  30. #include <vlc_plugin.h>
  31. #include <vlc_interface.h>
  32. #include <vlc_input.h>
  33. #include <vlc_es_out.h>
  34. #ifdef HAVE_UNISTD_H
  35. #    include <unistd.h>
  36. #endif
  37. #ifdef HAVE_SYS_TIME_H
  38. #    include <sys/time.h>
  39. #endif
  40. #ifdef HAVE_SYS_TYPES_H
  41. #   include <sys/types.h>
  42. #endif
  43. #ifdef HAVE_POLL
  44. #   include <poll.h>
  45. #endif
  46. #include <vlc_network.h>
  47. #define NETSYNC_PORT 9875
  48. /* FIXME: UGLY UGLY !! Netsync should be totally reworked */
  49. #include "../../src/input/input_internal.h"
  50. /*****************************************************************************
  51.  * Module descriptor
  52.  *****************************************************************************/
  53. static int  Activate( vlc_object_t * );
  54. static void Close   ( vlc_object_t * );
  55. static mtime_t GetClockRef( intf_thread_t *, mtime_t );
  56. /// bug [String] This string is BAD.
  57. #define NETSYNC_TEXT N_( "Act as master" )
  58. #define NETSYNC_LONGTEXT N_( "Should " 
  59.   "act as the master client for the network synchronisation?" )
  60. /// bug [String] This string is BAD.
  61. #define MIP_TEXT N_( "Master client ip address" )
  62. #define MIP_LONGTEXT N_( "IP address of " 
  63.   "the master client used for the network synchronisation." )
  64. vlc_module_begin ()
  65.     set_shortname( N_("Network Sync"))
  66.     set_description( N_("Network synchronisation") )
  67.     set_category( CAT_ADVANCED )
  68.     set_subcategory( SUBCAT_ADVANCED_MISC )
  69.     add_bool( "netsync-master", 0, NULL,
  70.               NETSYNC_TEXT, NETSYNC_LONGTEXT, true )
  71.     add_string( "netsync-master-ip", NULL, NULL, MIP_TEXT, MIP_LONGTEXT,
  72.                 true )
  73.     set_capability( "interface", 0 )
  74.     set_callbacks( Activate, Close )
  75. vlc_module_end ()
  76. /*****************************************************************************
  77.  * Local prototypes
  78.  *****************************************************************************/
  79. static void Run( intf_thread_t *p_intf );
  80. /*****************************************************************************
  81.  * Activate: initialize and create stuff
  82.  *****************************************************************************/
  83. static int Activate( vlc_object_t *p_this )
  84. {
  85.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  86.     int fd;
  87.     if( config_GetInt( p_intf, "netsync-master" ) <= 0 )
  88.     {
  89.         char *psz_master = config_GetPsz( p_intf, "netsync-master-ip" );
  90.         if( psz_master == NULL )
  91.         {
  92.             msg_Err( p_intf, "master address not specified" );
  93.             return VLC_EGENERIC;
  94.         }
  95.         fd = net_ConnectUDP( VLC_OBJECT(p_intf), psz_master, NETSYNC_PORT, -1 );
  96.         free( psz_master );
  97.     }
  98.     else
  99.         fd = net_ListenUDP1( VLC_OBJECT(p_intf), NULL, NETSYNC_PORT );
  100.     if( fd == -1 )
  101.     {
  102.         msg_Err( p_intf, "Netsync socket failure" );
  103.         return VLC_EGENERIC;
  104.     }
  105.     p_intf->p_sys = (void *)(intptr_t)fd;
  106.     p_intf->pf_run = Run;
  107.     return VLC_SUCCESS;
  108. }
  109. /*****************************************************************************
  110.  * Close: destroy interface
  111.  *****************************************************************************/
  112. void Close( vlc_object_t *p_this )
  113. {
  114.     intf_thread_t *p_intf = (intf_thread_t*)p_this;
  115.     net_Close( (intptr_t)p_intf->p_sys );
  116. }
  117. /*****************************************************************************
  118.  * Run: interface thread
  119.  *****************************************************************************/
  120. static void Run( intf_thread_t *p_intf )
  121. {
  122. #define MAX_MSG_LENGTH (2 * sizeof(int64_t))
  123.     input_thread_t *p_input = NULL;
  124.     char p_data[MAX_MSG_LENGTH];
  125.     int i_socket;
  126.     int canc = vlc_savecancel();
  127.     /* High priority thread */
  128.     vlc_thread_set_priority( p_intf, VLC_THREAD_PRIORITY_INPUT );
  129.     while( vlc_object_alive( p_intf ) )
  130.     {
  131.         /* Update the input */
  132.         if( p_input == NULL )
  133.             p_input =
  134.                 (input_thread_t *)vlc_object_find( p_intf, VLC_OBJECT_INPUT,
  135.                                                    FIND_ANYWHERE );
  136.         else if( p_input->b_dead )
  137.         {
  138.             vlc_object_release( p_input );
  139.             p_input = NULL;
  140.         }
  141.         if( p_input == NULL )
  142.         {
  143.             /* Wait a bit */
  144.             msleep( INTF_IDLE_SLEEP );
  145.             continue;
  146.         }
  147.         /*
  148.          * We now have an input
  149.          */
  150.         /* Initialize file descriptor set and timeout (0.5s) */
  151.         /* FIXME: arbitrary tick */
  152.         struct pollfd ufd = { .fd = i_socket, .events = POLLIN, };
  153.         if( b_master )
  154.         {
  155.             struct sockaddr_storage from;
  156.             mtime_t i_date, i_clockref, i_master_clockref;
  157.             int i_struct_size, i_read, i_ret;
  158.             /* Don't block */
  159.             i_ret = poll( &ufd, 1, 500 );
  160.             if( i_ret == 0 ) continue;
  161.             if( i_ret < 0 )
  162.             {
  163.                 /* Wait a bit */
  164.                 msleep( INTF_IDLE_SLEEP );
  165.                 continue;
  166.             }
  167.             /* We received something */
  168.             i_struct_size = sizeof( from );
  169.             i_read = recvfrom( i_socket, p_data, MAX_MSG_LENGTH, 0,
  170.                                (struct sockaddr*)&from,
  171.                                (unsigned int *)&i_struct_size );
  172.             i_clockref = ntoh64(*(int64_t *)p_data);
  173.             i_date = mdate();
  174.             *(int64_t *)p_data = hton64( i_date );
  175.             i_master_clockref = GetClockRef( p_intf, i_clockref );
  176.             *(((int64_t *)p_data)+1) = hton64( i_master_clockref );
  177.             /* Reply to the sender */
  178.             sendto( i_socket, p_data, 2 * sizeof(int64_t), 0,
  179.                     (struct sockaddr *)&from, i_struct_size );
  180. #if 0
  181.             msg_Dbg( p_intf, "Master clockref: %"PRId64" -> %"PRId64", from %s "
  182.                      "(date: %"PRId64")", i_clockref, i_master_clockref,
  183.                      from.ss_family == AF_INET
  184.                      ? inet_ntoa(((struct sockaddr_in *)&from)->sin_addr)
  185.                      : "non-IPv4", i_date );
  186. #endif
  187.         }
  188.         else
  189.         {
  190.             mtime_t i_send_date, i_receive_date, i_master_date, i_diff_date;
  191.             mtime_t i_master_clockref, i_client_clockref, i_drift;
  192.             mtime_t i_clockref = 0;
  193.             int i_sent, i_read, i_ret;
  194.             /* Send clock request to the master */
  195.             *(int64_t *)p_data = hton64( i_clockref );
  196.             i_send_date = mdate();
  197.             i_sent = send( i_socket, p_data, sizeof(int64_t), 0 );
  198.             if( i_sent <= 0 )
  199.             {
  200.                 /* Wait a bit */
  201.                 msleep( INTF_IDLE_SLEEP );
  202.                 continue;
  203.             }
  204.             /* Don't block */
  205.             i_ret = poll( &ufd, 1, 500 );
  206.             if( i_ret == 0 ) continue;
  207.             if( i_ret < 0 )
  208.             {
  209.                 /* Wait a bit */
  210.                 msleep( INTF_IDLE_SLEEP );
  211.                 continue;
  212.             }
  213.             i_receive_date = mdate();
  214.             i_read = recv( i_socket, p_data, MAX_MSG_LENGTH, 0 );
  215.             if( i_read <= 0 )
  216.             {
  217.                 /* Wait a bit */
  218.                 msleep( INTF_IDLE_SLEEP );
  219.                 continue;
  220.             }
  221.             i_master_date = ntoh64(*(int64_t *)p_data);
  222.             i_master_clockref = ntoh64(*(((int64_t *)p_data)+1));
  223.             i_diff_date = i_receive_date -
  224.                           ((i_receive_date - i_send_date) / 2 + i_master_date);
  225.             i_client_clockref = i_drift = 0;
  226.             if( p_input && i_master_clockref )
  227.             {
  228.                 i_client_clockref = GetClockRef( p_intf, i_clockref );
  229.                 i_drift = i_client_clockref - i_master_clockref - i_diff_date;
  230.                 /* Update our clock to match the master's one */
  231.                 if( i_client_clockref )
  232.                     p_input->i_pts_delay -= i_drift;
  233.             }
  234. #if 0
  235.             msg_Dbg( p_intf, "Slave clockref: %"PRId64" -> %"PRId64" -> %"PRId64", "
  236.                      "clock diff: %"PRId64" drift: %"PRId64,
  237.                      i_clockref, i_master_clockref,
  238.                      i_client_clockref, i_diff_date, i_drift );
  239. #endif
  240.             /* Wait a bit */
  241.             msleep( INTF_IDLE_SLEEP );
  242.         }
  243.     }
  244.     if( p_input ) vlc_object_release( p_input );
  245.     vlc_restorecancel( canc );
  246. }
  247. static mtime_t GetClockRef( intf_thread_t *p_intf, mtime_t i_pts )
  248. {
  249.     input_thread_t *p_input = p_intf->p_sys->p_input;
  250.     mtime_t i_ts;
  251.     if( !p_input || !p_input->p->p_es_out ) return 0;
  252.     if( es_out_Control( p_input->p->p_es_out, ES_OUT_GET_TS, i_pts, &i_ts ) ==
  253.         VLC_SUCCESS )
  254.     {
  255.         return i_ts;
  256.     }
  257.     return 0;
  258. }