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

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * mms.c: MMS access plug-in
  3.  *****************************************************************************
  4.  * Copyright (C) 2001, 2002 the VideoLAN team
  5.  * $Id: 4a860fd889ddba5b01b2f0da5176c7e783c3518f $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  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_access.h>
  31. #include <errno.h>
  32. #include <assert.h>
  33. #ifdef HAVE_UNISTD_H
  34. #   include <unistd.h>
  35. #endif
  36. #ifdef HAVE_FCNTL_H
  37. #   include <fcntl.h>
  38. #endif
  39. #ifdef HAVE_SYS_TIME_H
  40. #   include <sys/time.h>
  41. #endif
  42. #ifdef HAVE_SYS_TYPES_H
  43. #   include <sys/types.h>
  44. #endif
  45. #ifdef HAVE_SYS_STAT_H
  46. #   include <sys/stat.h>
  47. #endif
  48. #ifdef HAVE_POLL
  49. #   include <poll.h>
  50. #endif
  51. #include <vlc_network.h>
  52. #include "vlc_url.h"
  53. #include "asf.h"
  54. #include "buffer.h"
  55. #include "mms.h"
  56. #include "mmstu.h"
  57. #undef MMS_DEBUG
  58. /****************************************************************************
  59.  * NOTES:
  60.  *  MMSProtocole documentation found at http://get.to/sdp
  61.  ****************************************************************************/
  62. /*****************************************************************************
  63.  * Local prototypes
  64.  *****************************************************************************/
  65. int   MMSTUOpen   ( access_t * );
  66. void  MMSTUClose  ( access_t * );
  67. static block_t *Block( access_t * );
  68. static int Seek( access_t *, int64_t );
  69. static int Control( access_t *, int, va_list );
  70. static int  MMSOpen ( access_t *, vlc_url_t *, int );
  71. static int  MMSStart( access_t *, uint32_t );
  72. static int  MMSStop ( access_t * );
  73. static void MMSClose( access_t * );
  74. static int  mms_CommandRead( access_t *p_access, int i_command1, int i_command2 );
  75. static int  mms_CommandSend( access_t *, int, uint32_t, uint32_t, uint8_t *, int );
  76. static int  mms_HeaderMediaRead( access_t *, int );
  77. static int  mms_ReceivePacket( access_t * );
  78. static void* KeepAliveThread( void * );
  79. int  MMSTUOpen( access_t *p_access )
  80. {
  81.     access_sys_t   *p_sys;
  82.     int             i_proto;
  83.     int             i_status;
  84.     /* Set up p_access */
  85.     access_InitFields( p_access );
  86.     p_access->pf_read = NULL;
  87.     p_access->pf_block = Block;
  88.     p_access->pf_control = Control;
  89.     p_access->pf_seek = Seek;
  90.     p_access->p_sys = p_sys = calloc( 1, sizeof( access_sys_t ) );
  91.     if( !p_sys ) return VLC_ENOMEM;
  92.     p_sys->i_timeout = var_CreateGetInteger( p_access, "mms-timeout" );
  93.     vlc_mutex_init( &p_sys->lock_netwrite );
  94.     /* *** Parse URL and get server addr/port and path *** */
  95.     vlc_UrlParse( &p_sys->url, p_access->psz_path, 0 );
  96.     if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '' )
  97.     {
  98.         msg_Err( p_access, "invalid server name" );
  99.         vlc_UrlClean( &p_sys->url );
  100.         vlc_mutex_destroy( &p_sys->lock_netwrite );
  101.         free( p_sys );
  102.         return VLC_EGENERIC;
  103.     }
  104.     if( p_sys->url.i_port <= 0 )
  105.     {
  106.         p_sys->url.i_port = 1755;
  107.     }
  108.     /* *** connect to this server *** */
  109.     /* look at  requested protocol (udp/tcp) */
  110.     i_proto = MMS_PROTO_AUTO;
  111.     if( *p_access->psz_access )
  112.     {
  113.         if( !strncmp( p_access->psz_access, "mmsu", 4 ) )
  114.         {
  115.             i_proto = MMS_PROTO_UDP;
  116.         }
  117.         else if( !strncmp( p_access->psz_access, "mmst", 4 ) )
  118.         {
  119.             i_proto = MMS_PROTO_TCP;
  120.         }
  121.     }
  122.     /* connect */
  123.     if( i_proto == MMS_PROTO_AUTO )
  124.     {   /* first try with TCP and then UDP*/
  125.         if( ( i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_TCP ) ) )
  126.         {
  127.             if( !p_access->b_die )
  128.                 i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_UDP );
  129.         }
  130.     }
  131.     else
  132.     {
  133.         i_status = MMSOpen( p_access, &p_sys->url, i_proto );
  134.     }
  135.     if( i_status )
  136.     {
  137.         msg_Err( p_access, "cannot connect to server" );
  138.         vlc_UrlClean( &p_sys->url );
  139.         vlc_mutex_destroy( &p_sys->lock_netwrite );
  140.         free( p_sys );
  141.         return VLC_EGENERIC;
  142.     }
  143.     msg_Dbg( p_access, "connected to %s:%d", p_sys->url.psz_host, p_sys->url.i_port );
  144.     /*
  145.      * i_flags_broadcast
  146.      *  yy xx ?? ??
  147.      *  broadcast    yy=0x02, xx= 0x00
  148.      *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video
  149.      */
  150.     if( p_sys->i_packet_count <= 0 && p_sys->asfh.i_data_packets_count > 0 )
  151.     {
  152.         p_sys->i_packet_count = p_sys->asfh.i_data_packets_count;
  153.     }
  154.     if( p_sys->i_packet_count <= 0 || ( p_sys->i_flags_broadcast >> 24 ) == 0x02 )
  155.     {
  156.         p_sys->b_seekable = false;
  157.     }
  158.     else
  159.     {
  160.         p_sys->b_seekable = true;
  161.         p_access->info.i_size =
  162.             (uint64_t)p_sys->i_header +
  163.             (uint64_t)p_sys->i_packet_count * (uint64_t)p_sys->i_packet_length;
  164.     }
  165.     /* *** Start stream *** */
  166.     if( MMSStart( p_access, 0xffffffff ) < 0 )
  167.     {
  168.         msg_Err( p_access, "cannot start stream" );
  169.         MMSTUClose ( p_access );
  170.         return VLC_EGENERIC;
  171.     }
  172.     /* Keep the connection alive when paused */
  173.     p_sys->p_keepalive = malloc( sizeof( mmstu_keepalive_t ) );
  174.     if( !p_sys->p_keepalive )
  175.     {
  176.         MMSTUClose ( p_access );
  177.         return VLC_ENOMEM;
  178.     }
  179.     p_sys->p_keepalive->p_access = p_access;
  180.     vlc_mutex_init( &p_sys->p_keepalive->lock );
  181.     vlc_cond_init( &p_sys->p_keepalive->wait );
  182.     p_sys->p_keepalive->b_paused = false;
  183.     if( vlc_clone( &p_sys->p_keepalive->handle, KeepAliveThread,
  184.                    p_sys->p_keepalive, VLC_THREAD_PRIORITY_LOW ) )
  185.     {
  186.         vlc_cond_destroy( &p_sys->p_keepalive->wait );
  187.         vlc_mutex_destroy( &p_sys->p_keepalive->lock );
  188.         free( p_sys->p_keepalive );
  189.         p_sys->p_keepalive = NULL;
  190.     }
  191.     return VLC_SUCCESS;
  192. }
  193. /*****************************************************************************
  194.  * Close: free unused data structures
  195.  *****************************************************************************/
  196. void MMSTUClose( access_t *p_access )
  197. {
  198.     access_sys_t *p_sys = p_access->p_sys;
  199.     if( p_sys->p_keepalive )
  200.     {
  201.         vlc_cancel( p_sys->p_keepalive->handle );
  202.         vlc_join( p_sys->p_keepalive->handle, NULL );
  203.         vlc_cond_destroy( &p_sys->p_keepalive->wait );
  204.         vlc_mutex_destroy( &p_sys->p_keepalive->lock );
  205.         free( p_sys->p_keepalive );
  206.     }
  207.     /* close connection with server */
  208.     MMSClose( p_access );
  209.     /* free memory */
  210.     vlc_UrlClean( &p_sys->url );
  211.     vlc_mutex_destroy( &p_sys->lock_netwrite );
  212.     free( p_sys );
  213. }
  214. /*****************************************************************************
  215.  * Control:
  216.  *****************************************************************************/
  217. static int Control( access_t *p_access, int i_query, va_list args )
  218. {
  219.     access_sys_t *p_sys = p_access->p_sys;
  220.     bool   *pb_bool;
  221.     bool    b_bool;
  222.     int64_t      *pi_64;
  223.     int           i_int;
  224.     switch( i_query )
  225.     {
  226.         /* */
  227.         case ACCESS_CAN_SEEK:
  228.             pb_bool = (bool*)va_arg( args, bool* );
  229.             *pb_bool = p_sys->b_seekable;
  230.             break;
  231.         case ACCESS_CAN_FASTSEEK:
  232.             pb_bool = (bool*)va_arg( args, bool* );
  233.             *pb_bool = false;
  234.             break;
  235.         case ACCESS_CAN_PAUSE:
  236.             pb_bool = (bool*)va_arg( args, bool* );
  237.             *pb_bool = true;
  238.             break;
  239.         case ACCESS_CAN_CONTROL_PACE:
  240.             pb_bool = (bool*)va_arg( args, bool* );
  241. #if 0       /* Disable for now until we have a clock synchro algo
  242.              * which works with something else than MPEG over UDP */
  243.             *pb_bool = false;
  244. #endif
  245.             *pb_bool = true;
  246.             break;
  247.         /* */
  248.         case ACCESS_GET_PTS_DELAY:
  249.             pi_64 = (int64_t*)va_arg( args, int64_t * );
  250.             *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * INT64_C(1000);
  251.             break;
  252.         case ACCESS_GET_PRIVATE_ID_STATE:
  253.             i_int = (int)va_arg( args, int );
  254.             pb_bool = (bool *)va_arg( args, bool * );
  255.             if( i_int < 0 || i_int > 127 )
  256.                 return VLC_EGENERIC;
  257.             *pb_bool =  p_sys->asfh.stream[i_int].i_selected ? true : false;
  258.             break;
  259.         /* */
  260.         case ACCESS_SET_PAUSE_STATE:
  261.             b_bool = (bool)va_arg( args, int );
  262.             if( b_bool )
  263.                 MMSStop( p_access );
  264.             else
  265.                 Seek( p_access, p_access->info.i_pos );
  266.             if( p_sys->p_keepalive )
  267.             {
  268.                 vlc_mutex_lock( &p_sys->p_keepalive->lock );
  269.                 p_sys->p_keepalive->b_paused = b_bool;
  270.                 if( b_bool )
  271.                     vlc_cond_signal( &p_sys->p_keepalive->wait );
  272.                 vlc_mutex_unlock( &p_sys->p_keepalive->lock );
  273.             }
  274.             break;
  275.         case ACCESS_GET_TITLE_INFO:
  276.         case ACCESS_SET_TITLE:
  277.         case ACCESS_SET_SEEKPOINT:
  278.         case ACCESS_SET_PRIVATE_ID_STATE:
  279.         case ACCESS_GET_CONTENT_TYPE:
  280.             return VLC_EGENERIC;
  281.         default:
  282.             msg_Warn( p_access, "unimplemented query in control" );
  283.             return VLC_EGENERIC;
  284.     }
  285.     return VLC_SUCCESS;
  286. }
  287. /*****************************************************************************
  288.  * Seek: try to go at the right place
  289.  *****************************************************************************/
  290. static int Seek( access_t * p_access, int64_t i_pos )
  291. {
  292.     access_sys_t *p_sys = p_access->p_sys;
  293.     uint32_t    i_packet;
  294.     uint32_t    i_offset;
  295.     var_buffer_t buffer;
  296.     if( i_pos < 0 )
  297.         return VLC_EGENERIC;
  298.     if( i_pos < p_sys->i_header)
  299.     {
  300.         if( p_access->info.i_pos < p_sys->i_header )
  301.         {
  302.             /* no need to restart stream, it was already one
  303.              * or no stream was yet read */
  304.             p_access->info.i_pos = i_pos;
  305.             return VLC_SUCCESS;
  306.         }
  307.         else
  308.         {
  309.             i_packet = 0xffffffff;
  310.             i_offset = 0;
  311.         }
  312.     }
  313.     else
  314.     {
  315.         i_packet = ( i_pos - p_sys->i_header ) / p_sys->i_packet_length;
  316.         i_offset = ( i_pos - p_sys->i_header ) % p_sys->i_packet_length;
  317.     }
  318.     if( p_sys->b_seekable && i_packet >= p_sys->i_packet_count )
  319.         return VLC_EGENERIC;
  320.     msg_Dbg( p_access, "seeking to %"PRId64 " (packet:%d)", i_pos, i_packet );
  321.     MMSStop( p_access );
  322.     msg_Dbg( p_access, "stream stopped (seek)" );
  323.     /* *** restart stream *** */
  324.     var_buffer_initwrite( &buffer, 0 );
  325.     var_buffer_add64( &buffer, 0 ); /* seek point in second */
  326.     var_buffer_add32( &buffer, 0xffffffff );
  327.     var_buffer_add32( &buffer, i_packet ); // begin from start
  328.     var_buffer_add8( &buffer, 0xff ); // stream time limit
  329.     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
  330.     var_buffer_add8( &buffer, 0xff ); //
  331.     var_buffer_add8( &buffer, 0x00 ); // don't use limit
  332.     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
  333.     mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff,
  334.                      buffer.p_data, buffer.i_data );
  335.     var_buffer_free( &buffer );
  336.     while( vlc_object_alive (p_access) )
  337.     {
  338.         if( mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ) < 0 )
  339.         {
  340.             p_access->info.b_eof = true;
  341.             return VLC_EGENERIC;
  342.         }
  343.         if( p_sys->i_command == 0x1e )
  344.         {
  345.             msg_Dbg( p_access, "received 0x1e (seek)" );
  346.             break;
  347.         }
  348.     }
  349.     while( vlc_object_alive (p_access) )
  350.     {
  351.         if( mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ) < 0 )
  352.         {
  353.             p_access->info.b_eof = true;
  354.             return VLC_EGENERIC;
  355.         }
  356.         if( p_sys->i_command == 0x05 )
  357.         {
  358.             msg_Dbg( p_access, "received 0x05 (seek)" );
  359.             break;
  360.         }
  361.     }
  362.     /* get a packet */
  363.     if( mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 )
  364.     {
  365.         p_access->info.b_eof = true;
  366.         return VLC_EGENERIC;
  367.     }
  368.     msg_Dbg( p_access, "Streaming restarted" );
  369.     p_sys->i_media_used += i_offset;
  370.     p_access->info.i_pos = i_pos;
  371.     p_access->info.b_eof = false;
  372.     return VLC_SUCCESS;
  373. }
  374. /*****************************************************************************
  375.  * Block:
  376.  *****************************************************************************/
  377. static block_t *Block( access_t *p_access )
  378. {
  379.     access_sys_t *p_sys = p_access->p_sys;
  380.     if( p_access->info.b_eof )
  381.         return NULL;
  382.     if( p_access->info.i_pos < p_sys->i_header )
  383.     {
  384.         const size_t i_copy = p_sys->i_header - p_access->info.i_pos;
  385.         block_t *p_block = block_New( p_access, i_copy );
  386.         if( !p_block )
  387.             return NULL;
  388.         memcpy( p_block->p_buffer, &p_sys->p_header[p_access->info.i_pos], i_copy );
  389.         p_access->info.i_pos += i_copy;
  390.         return p_block;
  391.     }
  392.     else if( p_sys->p_media && p_sys->i_media_used < __MAX( p_sys->i_media, p_sys->i_packet_length ) )
  393.     {
  394.         size_t i_copy = 0;
  395.         size_t i_padding = 0;
  396.         if( p_sys->i_media_used < p_sys->i_media )
  397.             i_copy = p_sys->i_media - p_sys->i_media_used;
  398.         if( __MAX( p_sys->i_media, p_sys->i_media_used ) < p_sys->i_packet_length )
  399.             i_padding = p_sys->i_packet_length - __MAX( p_sys->i_media, p_sys->i_media_used );
  400.         block_t *p_block = block_New( p_access, i_copy + i_padding );
  401.         if( !p_block )
  402.             return NULL;
  403.         if( i_copy > 0 )
  404.             memcpy( &p_block->p_buffer[0], &p_sys->p_media[p_sys->i_media_used], i_copy );
  405.         if( i_padding > 0 )
  406.             memset( &p_block->p_buffer[i_copy], 0, i_padding );
  407.         p_sys->i_media_used += i_copy + i_padding;
  408.         p_access->info.i_pos += i_copy + i_padding;
  409.         return p_block;
  410.     }
  411.     mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA );
  412.     return NULL;
  413. }
  414. /****************************************************************************
  415.  * MMSOpen : Open a connection with the server over mmst or mmsu
  416.  ****************************************************************************/
  417. static int MMSOpen( access_t  *p_access, vlc_url_t *p_url, int  i_proto )
  418. {
  419.     access_sys_t *p_sys = p_access->p_sys;
  420.     int           b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
  421.     var_buffer_t buffer;
  422.     char         tmp[4096];
  423.     uint16_t     *p;
  424.     int          i_server_version;
  425.     int          i_tool_version;
  426.     int          i_update_player_url;
  427.     int          i_encryption_type;
  428.     int          i;
  429.     int          i_streams;
  430.     int          i_first;
  431.     char         *mediapath;
  432.     /* *** Open a TCP connection with server *** */
  433.     msg_Dbg( p_access, "waiting for connection..." );
  434.     p_sys->i_handle_tcp = net_ConnectTCP( p_access, p_url->psz_host, p_url->i_port );
  435.     if( p_sys->i_handle_tcp < 0 )
  436.     {
  437.         msg_Err( p_access, "failed to open a connection (tcp)" );
  438.         return VLC_EGENERIC;
  439.     }
  440.     msg_Dbg( p_access,
  441.              "connection(tcp) with "%s:%d" successful",
  442.              p_url->psz_host,
  443.              p_url->i_port );
  444.     /* *** Bind port if UDP protocol is selected *** */
  445.     if( b_udp )
  446.     {
  447.         if( net_GetSockAddress( p_sys->i_handle_tcp, p_sys->sz_bind_addr,
  448.                                 NULL ) )
  449.         {
  450.             net_Close( p_sys->i_handle_tcp );
  451.             return VLC_EGENERIC;
  452.         }
  453.         p_sys->i_handle_udp = net_ListenUDP1( (vlc_object_t *)p_access, p_sys->sz_bind_addr,
  454.                                               7000 );
  455.         if( p_sys->i_handle_udp < 0 )
  456.         {
  457.             msg_Err( p_access, "failed to open a connection (udp)" );
  458.             net_Close( p_sys->i_handle_tcp );
  459.             return VLC_EGENERIC;
  460.         }
  461.         msg_Dbg( p_access,
  462.                  "connection(udp) at "%s:%d" successful",
  463.                  p_sys->sz_bind_addr, 7000 );
  464.     }
  465.     /* *** Init context for mms prototcol *** */
  466.      GenerateGuid ( &p_sys->guid );    /* used to identify client by server */
  467.     msg_Dbg( p_access,
  468.              "generated guid: "GUID_FMT,
  469.              GUID_PRINT( p_sys->guid ) );
  470.     p_sys->i_command_level = 1;          /* updated after 0x1A command */
  471.     p_sys->i_seq_num = 0;
  472.     p_sys->i_media_packet_id_type  = 0x04;
  473.     p_sys->i_header_packet_id_type = 0x02;
  474.     p_sys->i_proto = i_proto;
  475.     p_sys->i_packet_seq_num = 0;
  476.     p_sys->p_header = NULL;
  477.     p_sys->i_header = 0;
  478.     p_sys->p_media = NULL;
  479.     p_sys->i_media = 0;
  480.     p_sys->i_media_used = 0;
  481.     p_access->info.i_pos = 0;
  482.     p_sys->i_buffer_tcp = 0;
  483.     p_sys->i_buffer_udp = 0;
  484.     p_sys->p_cmd = NULL;
  485.     p_sys->i_cmd = 0;
  486.     p_access->info.b_eof = false;
  487.     /* *** send command 1 : connection request *** */
  488.     var_buffer_initwrite( &buffer, 0 );
  489.     var_buffer_add16( &buffer, 0x001c );
  490.     var_buffer_add16( &buffer, 0x0003 );
  491.     sprintf( tmp,
  492.              "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
  493.              GUID_PRINT( p_sys->guid ),
  494.              p_url->psz_host );
  495.     var_buffer_addUTF16( &buffer, tmp );
  496.     mms_CommandSend( p_access,
  497.                      0x01,          /* connexion request */
  498.                      0x00000000,    /* flags, FIXME */
  499.                      0x0004000b,    /* ???? */
  500.                      buffer.p_data,
  501.                      buffer.i_data );
  502.     if( mms_CommandRead( p_access, 0x01, 0 ) < 0 )
  503.     {
  504.         var_buffer_free( &buffer );
  505.         MMSClose( p_access );
  506.         return VLC_EGENERIC;
  507.     }
  508.     i_server_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 32 );
  509.     i_tool_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 36 );
  510.     i_update_player_url = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 40 );
  511.     i_encryption_type = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
  512.     p = (uint16_t*)( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
  513. #define GETUTF16( psz, size ) 
  514.     { 
  515.         int i; 
  516.         psz = malloc( size + 1); 
  517.         for( i = 0; i < size; i++ ) 
  518.         { 
  519.             psz[i] = p[i]; 
  520.         } 
  521.         psz[size] = ''; 
  522.         p += ( size ); 
  523.     }
  524.     GETUTF16( p_sys->psz_server_version, i_server_version );
  525.     GETUTF16( p_sys->psz_tool_version, i_tool_version );
  526.     GETUTF16( p_sys->psz_update_player_url, i_update_player_url );
  527.     GETUTF16( p_sys->psz_encryption_type, i_encryption_type );
  528. #undef GETUTF16
  529.     msg_Dbg( p_access,
  530.              "0x01 --> server_version:"%s" tool_version:"%s" update_player_url:"%s" encryption_type:"%s"",
  531.              p_sys->psz_server_version,
  532.              p_sys->psz_tool_version,
  533.              p_sys->psz_update_player_url,
  534.              p_sys->psz_encryption_type );
  535.     /* *** should make an 18 command to make data timing *** */
  536.     /* *** send command 2 : transport protocol selection *** */
  537.     var_buffer_reinitwrite( &buffer, 0 );
  538.     var_buffer_add32( &buffer, 0x00000000 );
  539.     var_buffer_add32( &buffer, 0x000a0000 );
  540.     var_buffer_add32( &buffer, 0x00000002 );
  541.     if( b_udp )
  542.     {
  543.         sprintf( tmp,
  544.                  "\\%s\UDP\%d",
  545.                  p_sys->sz_bind_addr,
  546.                  7000 ); // FIXME
  547.     }
  548.     else
  549.     {
  550.         sprintf( tmp, "\\192.168.0.1\TCP\1242"  );
  551.     }
  552.     var_buffer_addUTF16( &buffer, tmp );
  553.     var_buffer_add16( &buffer, '0' );
  554.     mms_CommandSend( p_access,
  555.                      0x02,          /* connexion request */
  556.                      0x00000000,    /* flags, FIXME */
  557.                      0xffffffff,    /* ???? */
  558.                      buffer.p_data,
  559.                      buffer.i_data );
  560.     /* *** response from server, should be 0x02 or 0x03 *** */
  561.     mms_CommandRead( p_access, 0x02, 0x03 );
  562.     if( p_sys->i_command == 0x03 )
  563.     {
  564.         msg_Err( p_access,
  565.                  "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
  566.         var_buffer_free( &buffer );
  567.         MMSClose( p_access );
  568.         return VLC_EGENERIC;
  569.     }
  570.     else if( p_sys->i_command != 0x02 )
  571.     {
  572.         msg_Warn( p_access, "received command isn't 0x02 in reponse to 0x02" );
  573.     }
  574.     /* *** send command 5 : media file name/path requested *** */
  575.     var_buffer_reinitwrite( &buffer, 0 );
  576.     var_buffer_add64( &buffer, 0 );
  577.     /* media file path shouldn't start with / character */
  578.     mediapath = p_url->psz_path;
  579.     if ( *mediapath == '/' )
  580.     {
  581.         mediapath++;
  582.     }
  583.     var_buffer_addUTF16( &buffer, mediapath );
  584.     mms_CommandSend( p_access,
  585.                      0x05,
  586.                      p_sys->i_command_level,
  587.                      0xffffffff,
  588.                      buffer.p_data,
  589.                      buffer.i_data );
  590.     /* *** wait for reponse *** */
  591.     mms_CommandRead( p_access, 0x1a, 0x06 );
  592.     /* test if server send 0x1A answer */
  593.     if( p_sys->i_command == 0x1A )
  594.     {
  595.         msg_Err( p_access, "id/password requested (not yet supported)" );
  596.         /*  FIXME */
  597.         var_buffer_free( &buffer );
  598.         MMSClose( p_access );
  599.         return VLC_EGENERIC;
  600.     }
  601.     if( p_sys->i_command != 0x06 )
  602.     {
  603.         msg_Err( p_access,
  604.                  "unknown answer (0x%x instead of 0x06)",
  605.                  p_sys->i_command );
  606.         var_buffer_free( &buffer );
  607.         MMSClose( p_access );
  608.         return( -1 );
  609.     }
  610.     /*  1 for file ok, 2 for authen ok */
  611.     switch( GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) )
  612.     {
  613.         case 0x0001:
  614.             msg_Dbg( p_access, "media file name/path accepted" );
  615.             break;
  616.         case 0x0002:
  617.             msg_Dbg( p_access, "authentication accepted" );
  618.             break;
  619.         case -1:
  620.         default:
  621.         msg_Err( p_access, "error while asking for file %d",
  622.                  GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) );
  623.         var_buffer_free( &buffer );
  624.         MMSClose( p_access );
  625.         return VLC_EGENERIC;
  626.     }
  627.     p_sys->i_flags_broadcast =
  628.         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 12 );
  629.     p_sys->i_media_length =
  630.         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 24 );
  631.     p_sys->i_packet_length =
  632.         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
  633.     p_sys->i_packet_count =
  634.         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
  635.     p_sys->i_max_bit_rate =
  636.         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 56 );
  637.     p_sys->i_header_size =
  638.         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 60 );
  639.     msg_Dbg( p_access,
  640.              "answer 0x06 flags:0x%8.8"PRIx32" media_length:%"PRIu32"s "
  641.              "packet_length:%u packet_count:%"PRId32" max_bit_rate:%d "
  642.              "header_size:%zu",
  643.              p_sys->i_flags_broadcast,
  644.              p_sys->i_media_length,
  645.              (unsigned)p_sys->i_packet_length,
  646.              p_sys->i_packet_count,
  647.              p_sys->i_max_bit_rate,
  648.              p_sys->i_header_size );
  649.     /* *** send command 15 *** */
  650.     var_buffer_reinitwrite( &buffer, 0 );
  651.     var_buffer_add32( &buffer, 0 );
  652.     var_buffer_add32( &buffer, 0x8000 );
  653.     var_buffer_add32( &buffer, 0xffffffff );
  654.     var_buffer_add32( &buffer, 0x00 );
  655.     var_buffer_add32( &buffer, 0x00 );
  656.     var_buffer_add32( &buffer, 0x00 );
  657.     var_buffer_add64( &buffer, (((uint64_t)0x40ac2000)<<32) );
  658.     var_buffer_add32( &buffer, p_sys->i_header_packet_id_type );
  659.     var_buffer_add32( &buffer, 0x00 );
  660.     mms_CommandSend( p_access, 0x15, p_sys->i_command_level, 0x00,
  661.                      buffer.p_data, buffer.i_data );
  662.     /* *** wait for reponse *** */
  663.     /* Commented out because it fails on some stream (no 0x11 answer) */
  664. #if 0
  665.     mms_CommandRead( p_access, 0x11, 0 );
  666.     if( p_sys->i_command != 0x11 )
  667.     {
  668.         msg_Err( p_access,
  669.                  "unknown answer (0x%x instead of 0x11)",
  670.                  p_sys->i_command );
  671.         var_buffer_free( &buffer );
  672.         MMSClose( p_access );
  673.         return( -1 );
  674.     }
  675. #endif
  676.     /* *** now read header packet *** */
  677.     /* XXX could be split over multiples packets */
  678.     msg_Dbg( p_access, "reading header" );
  679.     for( ;; )
  680.     {
  681.         if( mms_HeaderMediaRead( p_access, MMS_PACKET_HEADER ) < 0 )
  682.         {
  683.             msg_Err( p_access, "cannot receive header" );
  684.             var_buffer_free( &buffer );
  685.             MMSClose( p_access );
  686.             return VLC_EGENERIC;
  687.         }
  688.         if( p_sys->i_header >= p_sys->i_header_size )
  689.         {
  690.             msg_Dbg( p_access,
  691.                      "header complete(%zu)",
  692.                      p_sys->i_header );
  693.             break;
  694.         }
  695.         msg_Dbg( p_access,
  696.                  "header incomplete (%zu/%zu), reading more",
  697.                  p_sys->i_header,
  698.                  p_sys->i_header_size );
  699.     }
  700.     /* *** parse header and get stream and their id *** */
  701.     /* get all streams properties,
  702.      *
  703.      * TODO : stream bitrates properties(optional)
  704.      *        and bitrate mutual exclusion(optional) */
  705.      asf_HeaderParse ( &p_sys->asfh,
  706.                            p_sys->p_header, p_sys->i_header );
  707.      asf_StreamSelect( &p_sys->asfh,
  708.                            var_CreateGetInteger( p_access, "mms-maxbitrate" ),
  709.                            var_CreateGetInteger( p_access, "mms-all" ),
  710.                            var_CreateGetInteger( p_access, "audio" ),
  711.                            var_CreateGetInteger( p_access, "video" ) );
  712.     /* *** now select stream we want to receive *** */
  713.     /* TODO take care of stream bitrate TODO */
  714.     i_streams = 0;
  715.     i_first = -1;
  716.     var_buffer_reinitwrite( &buffer, 0 );
  717.     /* for now, select first audio and video stream */
  718.     for( i = 1; i < 128; i++ )
  719.     {
  720.         if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN )
  721.         {
  722.             i_streams++;
  723.             if( i_first != -1 )
  724.             {
  725.                 var_buffer_add16( &buffer, 0xffff );
  726.                 var_buffer_add16( &buffer, i );
  727.             }
  728.             else
  729.             {
  730.                 i_first = i;
  731.             }
  732.             if( p_sys->asfh.stream[i].i_selected )
  733.             {
  734.                 var_buffer_add16( &buffer, 0x0000 );
  735.                 msg_Info( p_access,
  736.                           "selecting stream[0x%x] %s (%d kb/s)",
  737.                           i,
  738.                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
  739.                                                   "audio" : "video" ,
  740.                           p_sys->asfh.stream[i].i_bitrate / 1024);
  741.             }
  742.             else
  743.             {
  744.                 var_buffer_add16( &buffer, 0x0002 );
  745.                 msg_Info( p_access,
  746.                           "ignoring stream[0x%x] %s (%d kb/s)",
  747.                           i,
  748.                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
  749.                                     "audio" : "video" ,
  750.                           p_sys->asfh.stream[i].i_bitrate / 1024);
  751.             }
  752.         }
  753.     }
  754.     if( i_streams == 0 )
  755.     {
  756.         msg_Err( p_access, "cannot find any stream" );
  757.         var_buffer_free( &buffer );
  758.         MMSClose( p_access );
  759.         return VLC_EGENERIC;
  760.     }
  761.     mms_CommandSend( p_access, 0x33,
  762.                      i_streams,
  763.                      0xffff | ( i_first << 16 ),
  764.                      buffer.p_data, buffer.i_data );
  765.     mms_CommandRead( p_access, 0x21, 0 );
  766.     if( p_sys->i_command != 0x21 )
  767.     {
  768.         msg_Err( p_access,
  769.                  "unknown answer (0x%x instead of 0x21)",
  770.                  p_sys->i_command );
  771.         var_buffer_free( &buffer );
  772.         MMSClose( p_access );
  773.         return VLC_EGENERIC;
  774.     }
  775.     var_buffer_free( &buffer );
  776.     msg_Info( p_access, "connection successful" );
  777.     return VLC_SUCCESS;
  778. }
  779. /****************************************************************************
  780.  * MMSStart : Start streaming
  781.  ****************************************************************************/
  782. static int MMSStart( access_t  *p_access, uint32_t i_packet )
  783. {
  784.     access_sys_t        *p_sys = p_access->p_sys;
  785.     var_buffer_t    buffer;
  786.     /* *** start stream from packet 0 *** */
  787.     var_buffer_initwrite( &buffer, 0 );
  788.     var_buffer_add64( &buffer, 0 ); /* seek point in second */
  789.     var_buffer_add32( &buffer, 0xffffffff );
  790.     var_buffer_add32( &buffer, i_packet ); // begin from start
  791.     var_buffer_add8( &buffer, 0xff ); // stream time limit
  792.     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
  793.     var_buffer_add8( &buffer, 0xff ); //
  794.     var_buffer_add8( &buffer, 0x00 ); // don't use limit
  795.     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
  796.     mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff,
  797.                      buffer.p_data, buffer.i_data );
  798.     var_buffer_free( &buffer );
  799.     mms_CommandRead( p_access, 0x05, 0 );
  800.     if( p_sys->i_command != 0x05 )
  801.     {
  802.         msg_Err( p_access,
  803.                  "unknown answer (0x%x instead of 0x05)",
  804.                  p_sys->i_command );
  805.         return -1;
  806.     }
  807.     else
  808.     {
  809.         /* get a packet */
  810.         if( mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 )
  811.             return -1;
  812.         msg_Dbg( p_access, "streaming started" );
  813.         return 0;
  814.     }
  815. }
  816. /****************************************************************************
  817.  * MMSStop : Stop streaming
  818.  ****************************************************************************/
  819. static int MMSStop( access_t  *p_access )
  820. {
  821.     access_sys_t *p_sys = p_access->p_sys;
  822.     /* *** stop stream but keep connection alive *** */
  823.     mms_CommandSend( p_access,
  824.                      0x09,
  825.                      p_sys->i_command_level,
  826.                      0x001fffff,
  827.                      NULL, 0 );
  828.     return( 0 );
  829. }
  830. /****************************************************************************
  831.  * MMSClose : Close streaming and connection
  832.  ****************************************************************************/
  833. static void MMSClose( access_t  *p_access )
  834. {
  835.     access_sys_t        *p_sys = p_access->p_sys;
  836.     msg_Dbg( p_access, "Connection closed" );
  837.     /* *** tell server that we will disconnect *** */
  838.     mms_CommandSend( p_access,
  839.                      0x0d,
  840.                      p_sys->i_command_level,
  841.                      0x00000001,
  842.                      NULL, 0 );
  843.     /* *** close sockets *** */
  844.     net_Close( p_sys->i_handle_tcp );
  845.     if( p_sys->i_proto == MMS_PROTO_UDP )
  846.     {
  847.         net_Close( p_sys->i_handle_udp );
  848.     }
  849.     FREENULL( p_sys->p_cmd );
  850.     FREENULL( p_sys->p_media );
  851.     FREENULL( p_sys->p_header );
  852.     FREENULL( p_sys->psz_server_version );
  853.     FREENULL( p_sys->psz_tool_version );
  854.     FREENULL( p_sys->psz_update_player_url );
  855.     FREENULL( p_sys->psz_encryption_type );
  856. }
  857. /****************************************************************************
  858.  *
  859.  * MMS specific functions
  860.  *
  861.  ****************************************************************************/
  862. static int mms_CommandSend( access_t *p_access, int i_command,
  863.                             uint32_t i_prefix1, uint32_t i_prefix2,
  864.                             uint8_t *p_data, int i_data_old )
  865. {
  866.     var_buffer_t buffer;
  867.     access_sys_t *p_sys = p_access->p_sys;
  868.     int i_data_by8, i_ret;
  869.     int i_data = i_data_old;
  870.     while( i_data & 0x7 ) i_data++;
  871.     i_data_by8 = i_data >> 3;
  872.     /* first init buffer */
  873.     var_buffer_initwrite( &buffer, 0 );
  874.     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
  875.     var_buffer_add32( &buffer, 0xB00BFACE );
  876.     /* size after protocol type */
  877.     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
  878.     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
  879.     var_buffer_add32( &buffer, i_data_by8 + 4 );
  880.     var_buffer_add32( &buffer, p_sys->i_seq_num ); p_sys->i_seq_num++;
  881.     var_buffer_add64( &buffer, 0 );
  882.     var_buffer_add32( &buffer, i_data_by8 + 2 );
  883.     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
  884.     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
  885.     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
  886.     /* specific command data */
  887.     if( p_data && i_data > 0 )
  888.     {
  889.         var_buffer_addmemory( &buffer, p_data, i_data_old );
  890.     }
  891.     /* Append padding to the command data */
  892.     var_buffer_add64( &buffer, 0 );
  893.     /* send it */
  894.     vlc_mutex_lock( &p_sys->lock_netwrite );
  895.     i_ret = net_Write( p_access, p_sys->i_handle_tcp, NULL, buffer.p_data,
  896.                        buffer.i_data - ( 8 - ( i_data - i_data_old ) ) );
  897.     vlc_mutex_unlock( &p_sys->lock_netwrite );
  898.     if( i_ret != buffer.i_data - ( 8 - ( i_data - i_data_old ) ) )
  899.     {
  900.         var_buffer_free( &buffer );
  901.         msg_Err( p_access, "failed to send command" );
  902.         return VLC_EGENERIC;
  903.     }
  904.     var_buffer_free( &buffer );
  905.     return VLC_SUCCESS;
  906. }
  907. static int NetFillBuffer( access_t *p_access )
  908. {
  909. #ifdef UNDER_CE
  910.     return -1;
  911. #else
  912.     access_sys_t    *p_sys = p_access->p_sys;
  913.     int             i_ret;
  914.     struct pollfd   ufd[2];
  915.     unsigned        timeout, nfd;
  916.     /* FIXME when using udp */
  917.     ssize_t i_tcp, i_udp;
  918.     ssize_t i_tcp_read, i_udp_read;
  919.     int i_try = 0;
  920.     i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp;
  921.     if( p_sys->i_proto == MMS_PROTO_UDP )
  922.     {
  923.         i_udp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_udp;
  924.     }
  925.     else
  926.     {
  927.         i_udp = 0;  /* there isn't udp socket */
  928.     }
  929.     if( ( i_udp <= 0 ) && ( i_tcp <= 0 ) )
  930.     {
  931.         msg_Warn( p_access, "nothing to read %d:%d", (int)i_tcp, (int)i_udp );
  932.         return 0;
  933.     }
  934.     else
  935.     {
  936.         /* msg_Warn( p_access, "ask for tcp:%d udp:%d", i_tcp, i_udp ); */
  937.     }
  938.     /* Find if some data is available */
  939.     do
  940.     {
  941.         i_try++;
  942.         /* Initialize file descriptor set */
  943.         memset (ufd, 0, sizeof (ufd));
  944.         nfd = 0;
  945.         if( i_tcp > 0 )
  946.         {
  947.             ufd[nfd].fd = p_sys->i_handle_tcp;
  948.             ufd[nfd].events = POLLIN;
  949.             nfd++;
  950.         }
  951.         if( i_udp > 0 )
  952.         {
  953.             ufd[nfd].fd = p_sys->i_handle_udp;
  954.             ufd[nfd].events = POLLIN;
  955.             nfd++;
  956.         }
  957.         /* We'll wait 0.5 second if nothing happens */
  958.         timeout = __MIN( 500, p_sys->i_timeout );
  959.         if( i_try * timeout > p_sys->i_timeout )
  960.         {
  961.             msg_Err(p_access, "no data received");
  962.             return -1;
  963.         }
  964.         if( i_try > 3 && (p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0) )
  965.         {
  966.             return -1;
  967.         }
  968.         if( !vlc_object_alive (p_access) || p_access->b_error )
  969.             return -1;
  970.         //msg_Dbg( p_access, "NetFillBuffer: trying again (select)" );
  971.     } while( !(i_ret = poll( ufd, nfd, timeout)) ||
  972.              (i_ret < 0 && errno == EINTR) );
  973.     if( i_ret < 0 )
  974.     {
  975.         msg_Err( p_access, "network poll error (%m)" );
  976.         return -1;
  977.     }
  978.     i_tcp_read = i_udp_read = 0;
  979.     if( ( i_tcp > 0 ) && ufd[0].revents )
  980.     {
  981.         i_tcp_read =
  982.             recv( p_sys->i_handle_tcp,
  983.                   p_sys->buffer_tcp + p_sys->i_buffer_tcp,
  984.                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
  985.     }
  986.     if( i_udp > 0 && ufd[i_tcp > 0].revents )
  987.     {
  988.         i_udp_read = recv( p_sys->i_handle_udp,
  989.                            p_sys->buffer_udp + p_sys->i_buffer_udp,
  990.                            i_udp + MMS_BUFFER_SIZE/2, 0 );
  991.     }
  992. #ifdef MMS_DEBUG
  993.     if( p_sys->i_proto == MMS_PROTO_UDP )
  994.     {
  995.         msg_Dbg( p_access, "filling buffer TCP:%d+%d UDP:%d+%d",
  996.                  p_sys->i_buffer_tcp, i_tcp_read,
  997.                  p_sys->i_buffer_udp, i_udp_read );
  998.     }
  999.     else
  1000.     {
  1001.         msg_Dbg( p_access, "filling buffer TCP:%d+%d",
  1002.                  p_sys->i_buffer_tcp, i_tcp_read );
  1003.     }
  1004. #endif
  1005.     if( i_tcp_read > 0 ) p_sys->i_buffer_tcp += i_tcp_read;
  1006.     if( i_udp_read > 0 ) p_sys->i_buffer_udp += i_udp_read;
  1007.     return i_tcp_read + i_udp_read;
  1008. #endif
  1009. }
  1010. static int  mms_ParseCommand( access_t *p_access,
  1011.                               uint8_t *p_data,
  1012.                               size_t i_data,
  1013.                               int *pi_used )
  1014. {
  1015.  #define GET32( i_pos ) 
  1016.     ( p_sys->p_cmd[i_pos] + ( p_sys->p_cmd[i_pos +1] << 8 ) + 
  1017.       ( p_sys->p_cmd[i_pos + 2] << 16 ) + 
  1018.       ( p_sys->p_cmd[i_pos + 3] << 24 ) )
  1019.     access_sys_t        *p_sys = p_access->p_sys;
  1020.     uint32_t    i_length;
  1021.     uint32_t    i_id;
  1022.     free( p_sys->p_cmd );
  1023.     p_sys->i_cmd = i_data;
  1024.     p_sys->p_cmd = malloc( i_data );
  1025.     memcpy( p_sys->p_cmd, p_data, i_data );
  1026.     *pi_used = i_data; /* by default */
  1027.     if( i_data < MMS_CMD_HEADERSIZE )
  1028.     {
  1029.         msg_Warn( p_access, "truncated command (header incomplete)" );
  1030.         p_sys->i_command = 0;
  1031.         return -1;
  1032.     }
  1033.     i_id =  GetDWLE( p_data + 4 );
  1034.     i_length = GetDWLE( p_data + 8 ) + 16;
  1035.     if( i_id != 0xb00bface || i_length < 16 )
  1036.     {
  1037.         msg_Err( p_access,
  1038.                  "incorrect command header (0x%"PRIx32")", i_id );
  1039.         p_sys->i_command = 0;
  1040.         return -1;
  1041.     }
  1042.     if( i_length > p_sys->i_cmd )
  1043.     {
  1044.         msg_Warn( p_access,
  1045.                   "truncated command (missing %zu bytes)",
  1046.                    (size_t)i_length - i_data  );
  1047.         p_sys->i_command = 0;
  1048.         return -1;
  1049.     }
  1050.     else if( i_length < p_sys->i_cmd )
  1051.     {
  1052.         p_sys->i_cmd = i_length;
  1053.         *pi_used = i_length;
  1054.     }
  1055.     msg_Dbg( p_access,
  1056.              "recv command start_sequence:0x%8.8x command_id:0x%8.8x length:%d len8:%d sequence 0x%8.8x len8_II:%d dir_comm:0x%8.8x",
  1057.              GET32( 0 ),
  1058.              GET32( 4 ),
  1059.              GET32( 8 ),
  1060.              /* 12: protocol type "MMS " */
  1061.              GET32( 16 ),
  1062.              GET32( 20 ),
  1063.              /* 24: unknown (0) */
  1064.              /* 28: unknown (0) */
  1065.              GET32( 32 ),
  1066.              GET32( 36 )
  1067.              /* 40: switches */
  1068.              /* 44: extra */ );
  1069.     p_sys->i_command = GET32( 36 ) & 0xffff;
  1070. #undef GET32
  1071.     return MMS_PACKET_CMD;
  1072. }
  1073. static int  mms_ParsePacket( access_t *p_access,
  1074.                              uint8_t *p_data, size_t i_data,
  1075.                              int *pi_used )
  1076. {
  1077.     access_sys_t        *p_sys = p_access->p_sys;
  1078.     int i_packet_seq_num;
  1079.     size_t i_packet_length;
  1080.     uint32_t i_packet_id;
  1081.     *pi_used = i_data; /* default */
  1082.     if( i_data <= 8 )
  1083.     {
  1084.         msg_Warn( p_access, "truncated packet (header incomplete)" );
  1085.         return -1;
  1086.     }
  1087.     i_packet_id = p_data[4];
  1088.     i_packet_seq_num = GetDWLE( p_data );
  1089.     i_packet_length = GetWLE( p_data + 6 );
  1090.     //msg_Warn( p_access, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
  1091.     if( i_packet_length > i_data || i_packet_length <= 8)
  1092.     {
  1093.      /*   msg_Dbg( p_access,
  1094.                  "truncated packet (Declared %d bytes, Actual %d bytes)",
  1095.                  i_packet_length, i_data  ); */
  1096.         *pi_used = 0;
  1097.         return -1;
  1098.     }
  1099.     else if( i_packet_length < i_data )
  1100.     {
  1101.         *pi_used = i_packet_length;
  1102.     }
  1103.     if( i_packet_id == 0xff )
  1104.     {
  1105.         msg_Warn( p_access,
  1106.                   "receive MMS UDP pair timing" );
  1107.         return( MMS_PACKET_UDP_TIMING );
  1108.     }
  1109.     if( i_packet_id != p_sys->i_header_packet_id_type &&
  1110.         i_packet_id != p_sys->i_media_packet_id_type )
  1111.     {
  1112.         msg_Warn( p_access, "incorrect Packet Id Type (0x%x)", i_packet_id );
  1113.         return -1;
  1114.     }
  1115.     /* we now have a media or a header packet */
  1116.     if( i_packet_seq_num != p_sys->i_packet_seq_num )
  1117.     {
  1118. #if 0
  1119.         /* FIXME for udp could be just wrong order ? */
  1120.         msg_Warn( p_access,
  1121.                   "detected packet lost (%d != %d)",
  1122.                   i_packet_seq_num,
  1123.                   p_sys->i_packet_seq_num );
  1124. #endif
  1125.     }
  1126.     p_sys->i_packet_seq_num = i_packet_seq_num + 1;
  1127.     if( i_packet_id == p_sys->i_header_packet_id_type )
  1128.     {
  1129.         if( p_sys->p_header )
  1130.         {
  1131.             p_sys->p_header = realloc( p_sys->p_header,
  1132.                                           p_sys->i_header + i_packet_length - 8 );
  1133.             memcpy( &p_sys->p_header[p_sys->i_header],
  1134.                     p_data + 8, i_packet_length - 8 );
  1135.             p_sys->i_header += i_packet_length - 8;
  1136.         }
  1137.         else
  1138.         {
  1139.             uint8_t* p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
  1140.             memcpy( p_packet, p_data + 8, i_packet_length - 8 );
  1141.             p_sys->p_header = p_packet;
  1142.             p_sys->i_header = i_packet_length - 8;
  1143.         }
  1144. /*        msg_Dbg( p_access,
  1145.                  "receive header packet (%d bytes)",
  1146.                  i_packet_length - 8 ); */
  1147.         return MMS_PACKET_HEADER;
  1148.     }
  1149.     else
  1150.     {
  1151.         uint8_t* p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
  1152.         memcpy( p_packet, p_data + 8, i_packet_length - 8 );
  1153.         FREENULL( p_sys->p_media );
  1154.         p_sys->p_media = p_packet;
  1155.         p_sys->i_media = i_packet_length - 8;
  1156.         p_sys->i_media_used = 0;
  1157. /*        msg_Dbg( p_access,
  1158.                  "receive media packet (%d bytes)",
  1159.                  i_packet_length - 8 ); */
  1160.         return MMS_PACKET_MEDIA;
  1161.     }
  1162. }
  1163. static int mms_ReceivePacket( access_t *p_access )
  1164. {
  1165.     access_sys_t *p_sys = p_access->p_sys;
  1166.     int i_packet_tcp_type;
  1167.     int i_packet_udp_type;
  1168.     for( ;; )
  1169.     {
  1170.         bool b_refill = true;
  1171.         /* first if we need to refill buffer */
  1172.         if( p_sys->i_buffer_tcp >= MMS_CMD_HEADERSIZE )
  1173.         {
  1174.             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface  )
  1175.             {
  1176.                 if( GetDWLE( p_sys->buffer_tcp + 8 ) + 16 <=
  1177.                     (uint32_t)p_sys->i_buffer_tcp )
  1178.                 {
  1179.                     b_refill = false;
  1180.                 }
  1181.             }
  1182.             else if( GetWLE( p_sys->buffer_tcp + 6 ) <= p_sys->i_buffer_tcp )
  1183.             {
  1184.                 b_refill = false;
  1185.             }
  1186.         }
  1187.         if( p_sys->i_proto == MMS_PROTO_UDP && p_sys->i_buffer_udp >= 8 &&
  1188.             GetWLE( p_sys->buffer_udp + 6 ) <= p_sys->i_buffer_udp )
  1189.         {
  1190.             b_refill = false;
  1191.         }
  1192.         if( b_refill && NetFillBuffer( p_access ) < 0 )
  1193.         {
  1194.             msg_Warn( p_access, "cannot fill buffer" );
  1195.             return -1;
  1196.         }
  1197.         i_packet_tcp_type = -1;
  1198.         i_packet_udp_type = -1;
  1199.         if( p_sys->i_buffer_tcp > 0 )
  1200.         {
  1201.             int i_used;
  1202.             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface )
  1203.             {
  1204.                 i_packet_tcp_type =
  1205.                     mms_ParseCommand( p_access, p_sys->buffer_tcp,
  1206.                                       p_sys->i_buffer_tcp, &i_used );
  1207.             }
  1208.             else
  1209.             {
  1210.                 i_packet_tcp_type =
  1211.                     mms_ParsePacket( p_access, p_sys->buffer_tcp,
  1212.                                      p_sys->i_buffer_tcp, &i_used );
  1213.             }
  1214.             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
  1215.             {
  1216.                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
  1217.                          MMS_BUFFER_SIZE - i_used );
  1218.             }
  1219.             p_sys->i_buffer_tcp -= i_used;
  1220.         }
  1221.         else if( p_sys->i_buffer_udp > 0 )
  1222.         {
  1223.             int i_used;
  1224.             i_packet_udp_type =
  1225.                 mms_ParsePacket( p_access, p_sys->buffer_udp,
  1226.                                  p_sys->i_buffer_udp, &i_used );
  1227.             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
  1228.             {
  1229.                 memmove( p_sys->buffer_udp, p_sys->buffer_udp + i_used,
  1230.                          MMS_BUFFER_SIZE - i_used );
  1231.             }
  1232.             p_sys->i_buffer_udp -= i_used;
  1233.         }
  1234.         if( i_packet_tcp_type == MMS_PACKET_CMD && p_sys->i_command == 0x1b )
  1235.         {
  1236.             mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
  1237.             i_packet_tcp_type = -1;
  1238.         }
  1239.         if( i_packet_tcp_type != -1 )
  1240.         {
  1241.             return i_packet_tcp_type;
  1242.         }
  1243.         else if( i_packet_udp_type != -1 )
  1244.         {
  1245.             return i_packet_udp_type;
  1246.         }
  1247.     }
  1248. }
  1249. static int mms_ReceiveCommand( access_t *p_access )
  1250. {
  1251.     access_sys_t *p_sys = p_access->p_sys;
  1252.     for( ;; )
  1253.     {
  1254.         int i_used;
  1255.         int i_status;
  1256.         if( NetFillBuffer( p_access ) < 0 )
  1257.         {
  1258.             msg_Warn( p_access, "cannot fill buffer" );
  1259.             return VLC_EGENERIC;
  1260.         }
  1261.         if( p_sys->i_buffer_tcp > 0 )
  1262.         {
  1263.             i_status = mms_ParseCommand( p_access, p_sys->buffer_tcp,
  1264.                                          p_sys->i_buffer_tcp, &i_used );
  1265.             if( i_used < MMS_BUFFER_SIZE )
  1266.             {
  1267.                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
  1268.                          MMS_BUFFER_SIZE - i_used );
  1269.             }
  1270.             p_sys->i_buffer_tcp -= i_used;
  1271.             if( i_status < 0 )
  1272.             {
  1273.                 return VLC_EGENERIC;
  1274.             }
  1275.             if( p_sys->i_command == 0x1b )
  1276.             {
  1277.                 mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
  1278.             }
  1279.             else
  1280.             {
  1281.                 break;
  1282.             }
  1283.         }
  1284.         else
  1285.         {
  1286.             return VLC_EGENERIC;
  1287.         }
  1288.     }
  1289.     return VLC_SUCCESS;
  1290. }
  1291. #define MMS_RETRY_MAX       10
  1292. #define MMS_RETRY_SLEEP     50000
  1293. static int mms_CommandRead( access_t *p_access, int i_command1,
  1294.                             int i_command2 )
  1295. {
  1296.     access_sys_t *p_sys = p_access->p_sys;
  1297.     int i_count;
  1298.     int i_status;
  1299.     for( i_count = 0; i_count < MMS_RETRY_MAX; )
  1300.     {
  1301.         i_status = mms_ReceiveCommand( p_access );
  1302.         if( i_status < 0 || p_sys->i_command == 0 )
  1303.         {
  1304.             i_count++;
  1305.             msleep( MMS_RETRY_SLEEP );
  1306.         }
  1307.         else if( i_command1 == 0 && i_command2 == 0)
  1308.         {
  1309.             return VLC_SUCCESS;
  1310.         }
  1311.         else if( p_sys->i_command == i_command1 ||
  1312.                  p_sys->i_command == i_command2 )
  1313.         {
  1314.             return VLC_SUCCESS;
  1315.         }
  1316.         else
  1317.         {
  1318.             switch( p_sys->i_command )
  1319.             {
  1320.                 case 0x03:
  1321.                     msg_Warn( p_access, "socket closed by server" );
  1322.                     p_access->info.b_eof = true;
  1323.                     return VLC_EGENERIC;
  1324.                 case 0x1e:
  1325.                     msg_Warn( p_access, "end of media stream" );
  1326.                     p_access->info.b_eof = true;
  1327.                     return VLC_EGENERIC;
  1328.                 default:
  1329.                     break;
  1330.             }
  1331.         }
  1332.     }
  1333.     p_access->info.b_eof = true;
  1334.     msg_Warn( p_access, "failed to receive command (aborting)" );
  1335.     return VLC_EGENERIC;
  1336. }
  1337. static int mms_HeaderMediaRead( access_t *p_access, int i_type )
  1338. {
  1339.     access_sys_t *p_sys = p_access->p_sys;
  1340.     int          i_count;
  1341.     for( i_count = 0; i_count < MMS_RETRY_MAX; )
  1342.     {
  1343.         int i_status;
  1344.         if( !vlc_object_alive (p_access) )
  1345.             return -1;
  1346.         i_status = mms_ReceivePacket( p_access );
  1347.         if( i_status < 0 )
  1348.         {
  1349.             i_count++;
  1350.             msg_Warn( p_access, "cannot receive header (%d/%d)",
  1351.                       i_count, MMS_RETRY_MAX );
  1352.             msleep( MMS_RETRY_SLEEP );
  1353.         }
  1354.         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
  1355.         {
  1356.             return i_type;
  1357.         }
  1358.         else if( i_status == MMS_PACKET_CMD )
  1359.         {
  1360.             switch( p_sys->i_command )
  1361.             {
  1362.                 case 0x03:
  1363.                     msg_Warn( p_access, "socket closed by server" );
  1364.                     p_access->info.b_eof = true;
  1365.                     return -1;
  1366.                 case 0x1e:
  1367.                     msg_Warn( p_access, "end of media stream" );
  1368.                     p_access->info.b_eof = true;
  1369.                     return -1;
  1370.                 case 0x20:
  1371.                     /* XXX not too dificult to be done EXCEPT that we
  1372.                      * need to restart demuxer... and I don't see how we
  1373.                      * could do that :p */
  1374.                     msg_Err( p_access,
  1375.                              "reinitialization needed --> unsupported" );
  1376.                     p_access->info.b_eof = true;
  1377.                     return -1;
  1378.                 default:
  1379.                     break;
  1380.             }
  1381.         }
  1382.     }
  1383.     msg_Err( p_access, "cannot receive %s (aborting)",
  1384.              ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
  1385.     p_access->info.b_eof = true;
  1386.     return -1;
  1387. }
  1388. static void* KeepAliveThread( void *p_data )
  1389. {
  1390.     mmstu_keepalive_t *p_thread = (mmstu_keepalive_t *) p_data;
  1391.     access_t *p_access = p_thread->p_access;
  1392.     vlc_mutex_lock( &p_thread->lock );
  1393.     mutex_cleanup_push( &p_thread->lock );
  1394.     for( ;; )
  1395.     {
  1396.         /* Do nothing until paused (if ever) */
  1397.         while( !p_thread->b_paused )
  1398.             vlc_cond_wait( &p_thread->wait, &p_thread->lock );
  1399.         do
  1400.         {
  1401.             int canc;
  1402.             /* Send keep-alive every ten seconds */
  1403.             vlc_mutex_unlock( &p_thread->lock );
  1404.             canc = vlc_savecancel();
  1405.             mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
  1406.             vlc_restorecancel( canc );
  1407.             vlc_mutex_lock( &p_thread->lock );
  1408.             msleep( 10 * CLOCK_FREQ );
  1409.         }
  1410.         while( p_thread->b_paused );
  1411.     }
  1412.     vlc_cleanup_pop();
  1413.     assert(0);
  1414. }