Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

mmstu.c

00001 /*****************************************************************************
00002  * mms.c: MMS access plug-in
00003  *****************************************************************************
00004  * Copyright (C) 2001, 2002 the VideoLAN team
00005  * $Id: mmstu.c 12651 2005-09-22 20:48:59Z gbazin $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <stdlib.h>
00029 #include <vlc/vlc.h>
00030 #include <string.h>
00031 #include <vlc/input.h>
00032 #include <errno.h>
00033 
00034 #ifdef HAVE_UNISTD_H
00035 #   include <unistd.h>
00036 #endif
00037 #ifdef HAVE_FCNTL_H
00038 #   include <fcntl.h>
00039 #endif
00040 #ifdef HAVE_SYS_TIME_H
00041 #   include <sys/time.h>
00042 #endif
00043 #ifdef HAVE_SYS_TYPES_H 
00044 #   include <sys/types.h>
00045 #endif
00046 #ifdef HAVE_SYS_STAT_H
00047 #   include <sys/stat.h>
00048 #endif
00049 
00050 #include "network.h"
00051 #include "asf.h"
00052 #include "buffer.h"
00053 
00054 #include "mms.h"
00055 #include "mmstu.h"
00056 
00057 #undef MMS_DEBUG
00058 
00059 /****************************************************************************
00060  * NOTES:
00061  *  MMSProtocole documentation found at http://get.to/sdp
00062  ****************************************************************************/
00063 
00064 /*****************************************************************************
00065  * Local prototypes
00066  *****************************************************************************/
00067 int  E_( MMSTUOpen )  ( access_t * );
00068 void E_( MMSTUClose ) ( access_t * );
00069 
00070 
00071 static int Read( access_t *, uint8_t *, int );
00072 static int Seek( access_t *, int64_t );
00073 static int Control( access_t *, int, va_list );
00074 
00075 static int  MMSOpen ( access_t *, vlc_url_t *, int );
00076 static int  MMSStart( access_t *, uint32_t );
00077 static int  MMSStop ( access_t * );
00078 static void MMSClose( access_t * );
00079 
00080 
00081 static int  mms_CommandRead( access_t *p_access, int i_command1, int i_command2 );
00082 static int  mms_CommandSend( access_t *, int, uint32_t, uint32_t, uint8_t *, int );
00083 
00084 static int  mms_HeaderMediaRead( access_t *, int );
00085 
00086 static int  mms_ReceivePacket( access_t * );
00087 
00088 
00089 /*
00090  * XXX DON'T FREE MY MEMORY !!! XXX
00091  * non mais :P
00092  */
00093 /*
00094  * Ok, ok, j'le ferai plus...
00095  */
00096 /*
00097  * Merci :))
00098  */
00099 /*
00100  * Vous pourriez signer vos commentaires (m�e si on voit bien qui peut
00101  * �rire ce genre de trucs :p), et �rire en anglais, bordel de
00102  * merde :p.
00103  */
00104 /*
00105  * Alors la ouai �est fou les gens qui �rivent des commentaires sans les
00106  * signer. Ca m�iterait un coup de pied dans le cul � :)
00107  */
00108 
00109 int  E_(MMSTUOpen)( access_t *p_access )
00110 {
00111     access_sys_t   *p_sys;
00112     int             i_proto;
00113     int             i_status;
00114 
00115     /* Set up p_access */
00116     p_access->pf_read = Read;
00117     p_access->pf_block = NULL;
00118     p_access->pf_control = Control;
00119     p_access->pf_seek = Seek;
00120     p_access->info.i_update = 0;
00121     p_access->info.i_size = 0;
00122     p_access->info.i_pos = 0;
00123     p_access->info.b_eof = VLC_FALSE;
00124     p_access->info.i_title = 0;
00125     p_access->info.i_seekpoint = 0;
00126     p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
00127     memset( p_sys, 0, sizeof( access_sys_t ) );
00128 
00129     /* *** Parse URL and get server addr/port and path *** */
00130     vlc_UrlParse( &p_sys->url, p_access->psz_path, 0 );
00131     if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '\0' )
00132     {
00133         msg_Err( p_access, "invalid server name" );
00134         vlc_UrlClean( &p_sys->url );
00135         return VLC_EGENERIC;
00136     }
00137     if( p_sys->url.i_port <= 0 )
00138     {
00139         p_sys->url.i_port = 1755;
00140     }
00141 
00142     /* *** connect to this server *** */
00143     /* look at  requested protocol (udp/tcp) */
00144     i_proto = MMS_PROTO_AUTO;
00145     if( *p_access->psz_access )
00146     {
00147         if( !strncmp( p_access->psz_access, "mmsu", 4 ) )
00148         {
00149             i_proto = MMS_PROTO_UDP;
00150         }
00151         else if( !strncmp( p_access->psz_access, "mmst", 4 ) )
00152         {
00153             i_proto = MMS_PROTO_TCP;
00154         }
00155     }
00156 
00157     /* connect */
00158     if( i_proto == MMS_PROTO_AUTO )
00159     {   /* first try with TCP and then UDP*/
00160         if( ( i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_TCP ) ) )
00161         {
00162             i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_UDP );
00163         }
00164     }
00165     else
00166     {
00167         i_status = MMSOpen( p_access, &p_sys->url, i_proto );
00168     }
00169 
00170     if( i_status )
00171     {
00172         msg_Err( p_access, "cannot connect to server" );
00173         vlc_UrlClean( &p_sys->url );
00174         return VLC_EGENERIC;
00175     }
00176 
00177     msg_Dbg( p_access, "connected to %s:%d", p_sys->url.psz_host, p_sys->url.i_port );
00178     /*
00179      * i_flags_broadcast
00180      *  yy xx ?? ??
00181      *  broadcast    yy=0x02, xx= 0x00
00182      *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video
00183      */
00184     if( p_sys->i_packet_count <= 0 && p_sys->asfh.i_data_packets_count > 0 )
00185     {
00186         p_sys->i_packet_count = p_sys->asfh.i_data_packets_count;
00187     }
00188     if( p_sys->i_packet_count <= 0 || ( p_sys->i_flags_broadcast >> 24 ) == 0x02 )
00189     {
00190         p_sys->b_seekable = VLC_FALSE;
00191     }
00192     else
00193     {
00194         p_sys->b_seekable = VLC_TRUE;
00195         p_access->info.i_size =
00196             (uint64_t)p_sys->i_header +
00197             (uint64_t)p_sys->i_packet_count * (uint64_t)p_sys->i_packet_length;
00198     }
00199 
00200     /* *** Start stream *** */
00201     if( MMSStart( p_access, 0xffffffff ) < 0 )
00202     {
00203         msg_Err( p_access, "cannot start stream" );
00204         MMSClose( p_access );
00205         vlc_UrlClean( &p_sys->url );
00206         return VLC_EGENERIC;
00207     }
00208     return VLC_SUCCESS;
00209 }
00210 
00211 /*****************************************************************************
00212  * Close: free unused data structures
00213  *****************************************************************************/
00214 void E_(MMSTUClose)( access_t *p_access )
00215 {
00216     access_sys_t *p_sys = p_access->p_sys;
00217 
00218     /* close connection with server */
00219     MMSClose( p_access );
00220 
00221     /* free memory */
00222     vlc_UrlClean( &p_sys->url );
00223 
00224     free( p_sys );
00225 }
00226 
00227 /*****************************************************************************
00228  * Control:
00229  *****************************************************************************/
00230 static int Control( access_t *p_access, int i_query, va_list args )
00231 {
00232     access_sys_t *p_sys = p_access->p_sys;
00233     vlc_bool_t   *pb_bool;
00234     int          *pi_int;
00235     int64_t      *pi_64;
00236     int           i_int;
00237     vlc_value_t  val;
00238 
00239     switch( i_query )
00240     {
00241         /* */
00242         case ACCESS_CAN_SEEK:
00243             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00244             *pb_bool = p_sys->b_seekable;
00245             break;
00246 
00247         case ACCESS_CAN_FASTSEEK:
00248         case ACCESS_CAN_PAUSE:
00249             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00250             *pb_bool = VLC_FALSE;
00251             break;
00252 
00253         case ACCESS_CAN_CONTROL_PACE:
00254             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
00255 
00256 #if 0       /* Disable for now until we have a clock synchro algo
00257              * which works with something else than MPEG over UDP */
00258             *pb_bool = VLC_FALSE;
00259 #endif
00260             *pb_bool = VLC_TRUE;
00261             break;
00262 
00263         /* */
00264         case ACCESS_GET_MTU:
00265             pi_int = (int*)va_arg( args, int * );
00266             *pi_int = 3 * p_sys->i_packet_length;
00267             break;
00268 
00269         case ACCESS_GET_PTS_DELAY:
00270             pi_64 = (int64_t*)va_arg( args, int64_t * );
00271             var_Get( p_access, "mms-caching", &val );
00272             *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * I64C(1000);
00273             break;
00274 
00275         case ACCESS_GET_PRIVATE_ID_STATE:
00276             i_int = (int)va_arg( args, int );
00277             pb_bool = (vlc_bool_t *)va_arg( args, vlc_bool_t * );
00278 
00279             if( i_int < 0 || i_int > 127 )
00280                 return VLC_EGENERIC;
00281             *pb_bool =  p_sys->asfh.stream[i_int].i_selected ? VLC_TRUE : VLC_FALSE;
00282             break;
00283 
00284         /* */
00285         case ACCESS_SET_PAUSE_STATE:
00286         case ACCESS_GET_TITLE_INFO:
00287         case ACCESS_SET_TITLE:
00288         case ACCESS_SET_SEEKPOINT:
00289         case ACCESS_SET_PRIVATE_ID_STATE:
00290             return VLC_EGENERIC;
00291 
00292 
00293         default:
00294             msg_Warn( p_access, "unimplemented query in control" );
00295             return VLC_EGENERIC;
00296 
00297     }
00298     return VLC_SUCCESS;
00299 }
00300 
00301 /*****************************************************************************
00302  * Seek: try to go at the right place
00303  *****************************************************************************/
00304 static int Seek( access_t * p_access, int64_t i_pos )
00305 {
00306     access_sys_t *p_sys = p_access->p_sys;
00307     uint32_t    i_packet;
00308     uint32_t    i_offset;
00309     var_buffer_t buffer;
00310 
00311     if( i_pos < 0 )
00312         return VLC_EGENERIC;
00313 
00314     if( i_pos < p_sys->i_header)
00315     {
00316 
00317         if( p_access->info.i_pos < p_sys->i_header )
00318         {
00319             /* no need to restart stream, it was already one
00320              * or no stream was yet read */
00321             p_access->info.i_pos = i_pos;
00322             return VLC_SUCCESS;
00323         }
00324         else
00325         {
00326             i_packet = 0xffffffff;
00327             i_offset = 0;
00328         }
00329     }
00330     else
00331     {
00332         i_packet = ( i_pos - p_sys->i_header ) / p_sys->i_packet_length;
00333         i_offset = ( i_pos - p_sys->i_header ) % p_sys->i_packet_length;
00334     }
00335     msg_Dbg( p_access, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );
00336 
00337     MMSStop( p_access );
00338     msg_Dbg( p_access, "stream stopped (seek)" );
00339 
00340     /* *** restart stream *** */
00341     var_buffer_initwrite( &buffer, 0 );
00342     var_buffer_add64( &buffer, 0 ); /* seek point in second */
00343     var_buffer_add32( &buffer, 0xffffffff );
00344     var_buffer_add32( &buffer, i_packet ); // begin from start
00345     var_buffer_add8( &buffer, 0xff ); // stream time limit
00346     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
00347     var_buffer_add8( &buffer, 0xff ); //
00348     var_buffer_add8( &buffer, 0x00 ); // don't use limit
00349     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
00350 
00351     mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff,
00352                      buffer.p_data, buffer.i_data );
00353 
00354     var_buffer_free( &buffer );
00355 
00356 
00357     while( !p_access->b_die )
00358     {
00359         mms_HeaderMediaRead( p_access, MMS_PACKET_CMD );
00360         if( p_sys->i_command == 0x1e )
00361         {
00362             msg_Dbg( p_access, "received 0x1e (seek)" );
00363             break;
00364         }
00365     }
00366 
00367     while( !p_access->b_die )
00368     {
00369         mms_HeaderMediaRead( p_access, MMS_PACKET_CMD );
00370         if( p_sys->i_command == 0x05 )
00371         {
00372             msg_Dbg( p_access, "received 0x05 (seek)" );
00373             break;
00374         }
00375     }
00376 
00377     /* get a packet */
00378     mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA );
00379     msg_Dbg( p_access, "Streaming restarted" );
00380 
00381     p_sys->i_media_used += i_offset;
00382     p_access->info.i_pos = i_pos;
00383     p_access->info.b_eof = VLC_FALSE;
00384 
00385     return VLC_SUCCESS;
00386 }
00387 
00388 /*****************************************************************************
00389  * Read:
00390  *****************************************************************************/
00391 static int Read( access_t *p_access, uint8_t *p_buffer, int i_len )
00392 {
00393     access_sys_t *p_sys = p_access->p_sys;
00394     size_t      i_data;
00395     size_t      i_copy;
00396 
00397     i_data = 0;
00398 
00399     /* *** now send data if needed *** */
00400     while( i_data < (size_t)i_len )
00401     {
00402         if( p_access->info.i_pos < p_sys->i_header )
00403         {
00404             i_copy = __MIN( i_len, p_sys->i_header - p_access->info.i_pos );
00405             memcpy( &p_buffer[i_data], &p_sys->p_header[p_access->info.i_pos], i_copy );
00406             i_data += i_copy;
00407             p_access->info.i_pos += i_copy;
00408         }
00409         else if( p_sys->i_media_used < p_sys->i_media )
00410         {
00411             i_copy = __MIN( i_len - i_data ,
00412                             p_sys->i_media - p_sys->i_media_used );
00413             memcpy( &p_buffer[i_data], &p_sys->p_media[p_sys->i_media_used], i_copy );
00414             i_data += i_copy;
00415             p_sys->i_media_used += i_copy;
00416             p_access->info.i_pos += i_copy;
00417         }
00418         else if( p_sys->p_media != NULL &&
00419                  p_sys->i_media_used < p_sys->i_packet_length )
00420         {
00421             i_copy = __MIN( i_len - i_data,
00422                             p_sys->i_packet_length - p_sys->i_media_used);
00423             memset( &p_buffer[i_data], 0, i_copy );
00424 
00425             i_data += i_copy;
00426             p_sys->i_media_used += i_copy;
00427             p_access->info.i_pos += i_copy;
00428         }
00429         else if( p_access->info.b_eof ||
00430                  mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 )
00431         {
00432             break;
00433         }
00434     }
00435 
00436     return i_data;
00437 }
00438 
00439 /****************************************************************************
00440  * MMSOpen : Open a connection with the server over mmst or mmsu
00441  ****************************************************************************/
00442 static int MMSOpen( access_t  *p_access, vlc_url_t *p_url, int  i_proto )
00443 {
00444     access_sys_t *p_sys = p_access->p_sys;
00445     int           b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
00446 
00447     var_buffer_t buffer;
00448     char         tmp[4096];
00449     uint16_t     *p;
00450     int          i_server_version;
00451     int          i_tool_version;
00452     int          i_update_player_url;
00453     int          i_encryption_type;
00454     int          i;
00455     int          i_streams;
00456     int          i_first;
00457 
00458 
00459     /* *** Open a TCP connection with server *** */
00460     msg_Dbg( p_access, "waiting for connection..." );
00461     p_sys->i_handle_tcp = net_OpenTCP( p_access, p_url->psz_host, p_url->i_port );
00462     if( p_sys->i_handle_tcp < 0 )
00463     {
00464         msg_Err( p_access, "failed to open a connection (tcp)" );
00465         return VLC_EGENERIC;
00466     }
00467     msg_Dbg( p_access,
00468              "connection(tcp) with \"%s:%d\" successful",
00469              p_url->psz_host,
00470              p_url->i_port );
00471 
00472     /* *** Bind port if UDP protocol is selected *** */
00473     if( b_udp )
00474     {
00475         if( net_GetSockAddress( p_sys->i_handle_tcp, p_sys->sz_bind_addr,
00476                                 NULL ) )
00477         {
00478             net_Close( p_sys->i_handle_tcp );
00479             return VLC_EGENERIC;
00480         }
00481 
00482         p_sys->i_handle_udp = net_OpenUDP( p_access, p_sys->sz_bind_addr,
00483                                            7000, "", 0 );
00484         if( p_sys->i_handle_udp < 0 )
00485         {
00486             msg_Err( p_access, "failed to open a connection (udp)" );
00487             net_Close( p_sys->i_handle_tcp );
00488             return VLC_EGENERIC;
00489         }
00490         msg_Dbg( p_access,
00491                  "connection(udp) at \"%s:%d\" successful",
00492                  p_sys->sz_bind_addr, 7000 );
00493     }
00494 
00495     /* *** Init context for mms prototcol *** */
00496     E_( GenerateGuid )( &p_sys->guid );    /* used to identify client by server */
00497     msg_Dbg( p_access,
00498              "generated guid: "GUID_FMT,
00499              GUID_PRINT( p_sys->guid ) );
00500     p_sys->i_command_level = 1;          /* updated after 0x1A command */
00501     p_sys->i_seq_num = 0;
00502     p_sys->i_media_packet_id_type  = 0x04;
00503     p_sys->i_header_packet_id_type = 0x02;
00504     p_sys->i_proto = i_proto;
00505     p_sys->i_packet_seq_num = 0;
00506     p_sys->p_header = NULL;
00507     p_sys->i_header = 0;
00508     p_sys->p_media = NULL;
00509     p_sys->i_media = 0;
00510     p_sys->i_media_used = 0;
00511 
00512     p_access->info.i_pos = 0;
00513     p_sys->i_buffer_tcp = 0;
00514     p_sys->i_buffer_udp = 0;
00515     p_sys->p_cmd = NULL;
00516     p_sys->i_cmd = 0;
00517     p_access->info.b_eof = 0;
00518 
00519     /* *** send command 1 : connection request *** */
00520     var_buffer_initwrite( &buffer, 0 );
00521     var_buffer_add16( &buffer, 0x001c );
00522     var_buffer_add16( &buffer, 0x0003 );
00523     sprintf( tmp,
00524              "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
00525              GUID_PRINT( p_sys->guid ),
00526              p_url->psz_host );
00527     var_buffer_addUTF16( &buffer, tmp );
00528 
00529     mms_CommandSend( p_access,
00530                      0x01,          /* connexion request */
00531                      0x00000000,    /* flags, FIXME */
00532                      0x0004000b,    /* ???? */
00533                      buffer.p_data,
00534                      buffer.i_data );
00535 
00536     if( mms_CommandRead( p_access, 0x01, 0 ) < 0 )
00537     {
00538         var_buffer_free( &buffer );
00539         MMSClose( p_access );
00540         return VLC_EGENERIC;
00541     }
00542 
00543     i_server_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 32 );
00544     i_tool_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 36 );
00545     i_update_player_url = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 40 );
00546     i_encryption_type = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
00547     p = (uint16_t*)( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
00548 #define GETUTF16( psz, size ) \
00549     { \
00550         int i; \
00551         psz = malloc( size + 1); \
00552         for( i = 0; i < size; i++ ) \
00553         { \
00554             psz[i] = p[i]; \
00555         } \
00556         psz[size] = '\0'; \
00557         p += ( size ); \
00558     }
00559     GETUTF16( p_sys->psz_server_version, i_server_version );
00560     GETUTF16( p_sys->psz_tool_version, i_tool_version );
00561     GETUTF16( p_sys->psz_update_player_url, i_update_player_url );
00562     GETUTF16( p_sys->psz_encryption_type, i_encryption_type );
00563 #undef GETUTF16
00564     msg_Dbg( p_access,
00565              "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
00566              p_sys->psz_server_version,
00567              p_sys->psz_tool_version,
00568              p_sys->psz_update_player_url,
00569              p_sys->psz_encryption_type );
00570 
00571     /* *** should make an 18 command to make data timing *** */
00572 
00573     /* *** send command 2 : transport protocol selection *** */
00574     var_buffer_reinitwrite( &buffer, 0 );
00575     var_buffer_add32( &buffer, 0x00000000 );
00576     var_buffer_add32( &buffer, 0x000a0000 );
00577     var_buffer_add32( &buffer, 0x00000002 );
00578     if( b_udp )
00579     {
00580         sprintf( tmp,
00581                  "\\\\%s\\UDP\\%d",
00582                  p_sys->sz_bind_addr,
00583                  7000 ); // FIXME
00584     }
00585     else
00586     {
00587         sprintf( tmp, "\\\\192.168.0.1\\TCP\\1242"  );
00588     }
00589     var_buffer_addUTF16( &buffer, tmp );
00590     var_buffer_add16( &buffer, '0' );
00591 
00592     mms_CommandSend( p_access,
00593                      0x02,          /* connexion request */
00594                      0x00000000,    /* flags, FIXME */
00595                      0xffffffff,    /* ???? */
00596                      buffer.p_data,
00597                      buffer.i_data );
00598 
00599     /* *** response from server, should be 0x02 or 0x03 *** */
00600     mms_CommandRead( p_access, 0x02, 0x03 );
00601     if( p_sys->i_command == 0x03 )
00602     {
00603         msg_Err( p_access,
00604                  "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
00605         var_buffer_free( &buffer );
00606         MMSClose( p_access );
00607         return VLC_EGENERIC;
00608     }
00609     else if( p_sys->i_command != 0x02 )
00610     {
00611         msg_Warn( p_access, "received command isn't 0x02 in reponse to 0x02" );
00612     }
00613 
00614     /* *** send command 5 : media file name/path requested *** */
00615     var_buffer_reinitwrite( &buffer, 0 );
00616     var_buffer_add64( &buffer, 0 );
00617     var_buffer_addUTF16( &buffer, p_url->psz_path );
00618 
00619     mms_CommandSend( p_access,
00620                      0x05,
00621                      p_sys->i_command_level,
00622                      0xffffffff,
00623                      buffer.p_data,
00624                      buffer.i_data );
00625 
00626     /* *** wait for reponse *** */
00627     mms_CommandRead( p_access, 0x1a, 0x06 );
00628 
00629     /* test if server send 0x1A answer */
00630     if( p_sys->i_command == 0x1A )
00631     {
00632         msg_Err( p_access, "id/password requested (not yet supported)" );
00633         /*  FIXME */
00634         var_buffer_free( &buffer );
00635         MMSClose( p_access );
00636         return VLC_EGENERIC;
00637     }
00638     if( p_sys->i_command != 0x06 )
00639     {
00640         msg_Err( p_access,
00641                  "unknown answer (0x%x instead of 0x06)",
00642                  p_sys->i_command );
00643         var_buffer_free( &buffer );
00644         MMSClose( p_access );
00645         return( -1 );
00646     }
00647 
00648     /*  1 for file ok, 2 for authen ok */
00649     switch( GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) )
00650     {
00651         case 0x0001:
00652             msg_Dbg( p_access, "Media file name/path accepted" );
00653             break;
00654         case 0x0002:
00655             msg_Dbg( p_access, "Authentication accepted" );
00656             break;
00657         case -1:
00658         default:
00659         msg_Err( p_access, "error while asking for file %d",
00660                  GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) );
00661         var_buffer_free( &buffer );
00662         MMSClose( p_access );
00663         return VLC_EGENERIC;
00664     }
00665 
00666     p_sys->i_flags_broadcast =
00667         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 12 );
00668     p_sys->i_media_length =
00669         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 24 );
00670     p_sys->i_packet_length =
00671         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
00672     p_sys->i_packet_count =
00673         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
00674     p_sys->i_max_bit_rate =
00675         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 56 );
00676     p_sys->i_header_size =
00677         GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 60 );
00678 
00679     msg_Dbg( p_access,
00680              "answer 0x06 flags:0x%8.8x media_length:%us packet_length:%u packet_count:%u max_bit_rate:%d header_size:%d",
00681              p_sys->i_flags_broadcast,
00682              p_sys->i_media_length,
00683              p_sys->i_packet_length,
00684              p_sys->i_packet_count,
00685              p_sys->i_max_bit_rate,
00686              p_sys->i_header_size );
00687 
00688     /* *** send command 15 *** */
00689 
00690     var_buffer_reinitwrite( &buffer, 0 );
00691     var_buffer_add32( &buffer, 0 );
00692     var_buffer_add32( &buffer, 0x8000 );
00693     var_buffer_add32( &buffer, 0xffffffff );
00694     var_buffer_add32( &buffer, 0x00 );
00695     var_buffer_add32( &buffer, 0x00 );
00696     var_buffer_add32( &buffer, 0x00 );
00697     var_buffer_add64( &buffer, (((uint64_t)0x40ac2000)<<32) );
00698     var_buffer_add32( &buffer, p_sys->i_header_packet_id_type );
00699     var_buffer_add32( &buffer, 0x00 );
00700     mms_CommandSend( p_access, 0x15, p_sys->i_command_level, 0x00,
00701                      buffer.p_data, buffer.i_data );
00702 
00703     /* *** wait for reponse *** */
00704     /* Commented out because it fails on some stream (no 0x11 answer) */
00705 #if 0
00706     mms_CommandRead( p_access, 0x11, 0 );
00707 
00708     if( p_sys->i_command != 0x11 )
00709     {
00710         msg_Err( p_access,
00711                  "unknown answer (0x%x instead of 0x11)",
00712                  p_sys->i_command );
00713         var_buffer_free( &buffer );
00714         MMSClose( p_access );
00715         return( -1 );
00716     }
00717 #endif
00718 
00719     /* *** now read header packet *** */
00720     /* XXX could be split over multiples packets */
00721     msg_Dbg( p_access, "reading header" );
00722     for( ;; )
00723     {
00724         if( mms_HeaderMediaRead( p_access, MMS_PACKET_HEADER ) < 0 )
00725         {
00726             msg_Err( p_access, "cannot receive header" );
00727             var_buffer_free( &buffer );
00728             MMSClose( p_access );
00729             return VLC_EGENERIC;
00730         }
00731         if( p_sys->i_header >= p_sys->i_header_size )
00732         {
00733             msg_Dbg( p_access,
00734                      "header complete(%d)",
00735                      p_sys->i_header );
00736             break;
00737         }
00738         msg_Dbg( p_access,
00739                  "header incomplete (%d/%d), reading more",
00740                  p_sys->i_header,
00741                  p_sys->i_header_size );
00742     }
00743 
00744     /* *** parse header and get stream and their id *** */
00745     /* get all streams properties,
00746      *
00747      * TODO : stream bitrates properties(optional)
00748      *        and bitrate mutual exclusion(optional) */
00749     E_( asf_HeaderParse )( &p_sys->asfh,
00750                            p_sys->p_header, p_sys->i_header );
00751     E_( asf_StreamSelect)( &p_sys->asfh,
00752                            var_CreateGetInteger( p_access, "mms-maxbitrate" ),
00753                            var_CreateGetInteger( p_access, "mms-all" ),
00754                            var_CreateGetInteger( p_access, "audio" ),
00755                            var_CreateGetInteger( p_access, "video" ) );
00756 
00757     /* *** now select stream we want to receive *** */
00758     /* TODO take care of stream bitrate TODO */
00759     i_streams = 0;
00760     i_first = -1;
00761     var_buffer_reinitwrite( &buffer, 0 );
00762     /* for now, select first audio and video stream */
00763     for( i = 1; i < 128; i++ )
00764     {
00765 
00766         if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN )
00767         {
00768             i_streams++;
00769             if( i_first != -1 )
00770             {
00771                 var_buffer_add16( &buffer, 0xffff );
00772                 var_buffer_add16( &buffer, i );
00773             }
00774             else
00775             {
00776                 i_first = i;
00777             }
00778             if( p_sys->asfh.stream[i].i_selected )
00779             {
00780                 var_buffer_add16( &buffer, 0x0000 );
00781                 msg_Info( p_access,
00782                           "selecting stream[0x%x] %s (%d kb/s)",
00783                           i,
00784                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
00785                                                   "audio" : "video" ,
00786                           p_sys->asfh.stream[i].i_bitrate / 1024);
00787             }
00788             else
00789             {
00790                 var_buffer_add16( &buffer, 0x0002 );
00791                 msg_Info( p_access,
00792                           "ignoring stream[0x%x] %s (%d kb/s)",
00793                           i,
00794                           ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
00795                                     "audio" : "video" ,
00796                           p_sys->asfh.stream[i].i_bitrate / 1024);
00797 
00798             }
00799         }
00800     }
00801 
00802     if( i_streams == 0 )
00803     {
00804         msg_Err( p_access, "cannot find any stream" );
00805         var_buffer_free( &buffer );
00806         MMSClose( p_access );
00807         return VLC_EGENERIC;
00808     }
00809     mms_CommandSend( p_access, 0x33,
00810                      i_streams,
00811                      0xffff | ( i_first << 16 ),
00812                      buffer.p_data, buffer.i_data );
00813 
00814     mms_CommandRead( p_access, 0x21, 0 );
00815     if( p_sys->i_command != 0x21 )
00816     {
00817         msg_Err( p_access,
00818                  "unknown answer (0x%x instead of 0x21)",
00819                  p_sys->i_command );
00820         var_buffer_free( &buffer );
00821         MMSClose( p_access );
00822         return VLC_EGENERIC;
00823     }
00824 
00825 
00826     var_buffer_free( &buffer );
00827 
00828     msg_Info( p_access, "connection successful" );
00829 
00830     return VLC_SUCCESS;
00831 }
00832 
00833 /****************************************************************************
00834  * MMSStart : Start streaming
00835  ****************************************************************************/
00836 static int MMSStart( access_t  *p_access, uint32_t i_packet )
00837 {
00838     access_sys_t        *p_sys = p_access->p_sys;
00839     var_buffer_t    buffer;
00840 
00841     /* *** start stream from packet 0 *** */
00842     var_buffer_initwrite( &buffer, 0 );
00843     var_buffer_add64( &buffer, 0 ); /* seek point in second */
00844     var_buffer_add32( &buffer, 0xffffffff );
00845     var_buffer_add32( &buffer, i_packet ); // begin from start
00846     var_buffer_add8( &buffer, 0xff ); // stream time limit
00847     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
00848     var_buffer_add8( &buffer, 0xff ); //
00849     var_buffer_add8( &buffer, 0x00 ); // don't use limit
00850     var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
00851 
00852     mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff,
00853                      buffer.p_data, buffer.i_data );
00854 
00855     var_buffer_free( &buffer );
00856 
00857     mms_CommandRead( p_access, 0x05, 0 );
00858 
00859     if( p_sys->i_command != 0x05 )
00860     {
00861         msg_Err( p_access,
00862                  "unknown answer (0x%x instead of 0x05)",
00863                  p_sys->i_command );
00864         return( -1 );
00865     }
00866     else
00867     {
00868         /* get a packet */
00869         mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA );
00870         msg_Dbg( p_access, "Streaming started" );
00871         return( 0 );
00872     }
00873 }
00874 
00875 /****************************************************************************
00876  * MMSStop : Stop streaming
00877  ****************************************************************************/
00878 static int MMSStop( access_t  *p_access )
00879 {
00880     access_sys_t *p_sys = p_access->p_sys;
00881 
00882     /* *** stop stream but keep connection alive *** */
00883     mms_CommandSend( p_access,
00884                      0x09,
00885                      p_sys->i_command_level,
00886                      0x001fffff,
00887                      NULL, 0 );
00888     return( 0 );
00889 }
00890 
00891 /****************************************************************************
00892  * MMSClose : Close streaming and connection
00893  ****************************************************************************/
00894 static void MMSClose( access_t  *p_access )
00895 {
00896     access_sys_t        *p_sys = p_access->p_sys;
00897 
00898     msg_Dbg( p_access, "Connection closed" );
00899 
00900     /* *** tell server that we will disconnect *** */
00901     mms_CommandSend( p_access,
00902                      0x0d,
00903                      p_sys->i_command_level,
00904                      0x00000001,
00905                      NULL, 0 );
00906 
00907     /* *** close sockets *** */
00908     net_Close( p_sys->i_handle_tcp );
00909     if( p_sys->i_proto == MMS_PROTO_UDP )
00910     {
00911         net_Close( p_sys->i_handle_udp );
00912     }
00913 
00914     FREE( p_sys->p_cmd );
00915     FREE( p_sys->p_media );
00916     FREE( p_sys->p_header );
00917 
00918     FREE( p_sys->psz_server_version );
00919     FREE( p_sys->psz_tool_version );
00920     FREE( p_sys->psz_update_player_url );
00921     FREE( p_sys->psz_encryption_type );
00922 }
00923 
00924 /****************************************************************************
00925  *
00926  * MMS specific functions
00927  *
00928  ****************************************************************************/
00929 static int mms_CommandSend( access_t *p_access, int i_command,
00930                             uint32_t i_prefix1, uint32_t i_prefix2,
00931                             uint8_t *p_data, int i_data_old )
00932 {
00933     var_buffer_t buffer;
00934     access_sys_t *p_sys = p_access->p_sys;
00935     int i_data_by8, i_ret;
00936     int i_data = i_data_old;
00937 
00938     while( i_data & 0x7 ) i_data++;
00939     i_data_by8 = i_data >> 3;
00940 
00941     /* first init buffer */
00942     var_buffer_initwrite( &buffer, 0 );
00943 
00944     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
00945     var_buffer_add32( &buffer, 0xB00BFACE );
00946     /* size after protocol type */
00947     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
00948     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
00949     var_buffer_add32( &buffer, i_data_by8 + 4 );
00950     var_buffer_add32( &buffer, p_sys->i_seq_num ); p_sys->i_seq_num++;
00951     var_buffer_add64( &buffer, 0 );
00952     var_buffer_add32( &buffer, i_data_by8 + 2 );
00953     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
00954     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
00955     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
00956 
00957     /* specific command data */
00958     if( p_data && i_data > 0 )
00959     {
00960         var_buffer_addmemory( &buffer, p_data, i_data_old );
00961     }
00962 
00963     /* Append padding to the command data */
00964     var_buffer_add64( &buffer, 0 );
00965 
00966     /* send it */
00967     i_ret = net_Write( p_access, p_sys->i_handle_tcp, NULL, buffer.p_data,
00968                        buffer.i_data - ( 8 - ( i_data - i_data_old ) ) );
00969     if( i_ret != buffer.i_data - ( 8 - ( i_data - i_data_old ) ) )
00970     {
00971         msg_Err( p_access, "failed to send command" );
00972         return VLC_EGENERIC;
00973     }
00974 
00975     var_buffer_free( &buffer );
00976     return VLC_SUCCESS;
00977 }
00978 
00979 static int NetFillBuffer( access_t *p_access )
00980 {
00981 #ifdef UNDER_CE
00982     return -1;
00983 
00984 #else
00985     access_sys_t    *p_sys = p_access->p_sys;
00986     struct timeval  timeout;
00987     fd_set          fds_r, fds_e;
00988     int             i_ret;
00989 
00990     /* FIXME when using udp */
00991     ssize_t i_tcp, i_udp;
00992     ssize_t i_tcp_read, i_udp_read;
00993     int i_handle_max;
00994     int i_try = 0;
00995 
00996     i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp;
00997 
00998     if( p_sys->i_proto == MMS_PROTO_UDP )
00999     {
01000         i_udp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_udp;
01001     }
01002     else
01003     {
01004         i_udp = 0;  /* there isn't udp socket */
01005     }
01006 
01007     i_handle_max = 0;
01008 
01009     if( i_tcp > 0 )
01010         i_handle_max = __MAX( i_handle_max, p_sys->i_handle_tcp );
01011     if( i_udp > 0 )
01012         i_handle_max = __MAX( i_handle_max, p_sys->i_handle_udp );
01013 
01014     if( i_handle_max == 0 )
01015     {
01016         msg_Warn( p_access, "nothing to read %d:%d", (int)i_tcp, (int)i_udp );
01017         return 0;
01018     }
01019     else
01020     {
01021         /* msg_Warn( p_access, "ask for tcp:%d udp:%d", i_tcp, i_udp ); */
01022     }
01023 
01024     /* Find if some data is available */
01025     do
01026     {
01027         i_try++;
01028 
01029         /* Initialize file descriptor set */
01030         FD_ZERO( &fds_r );
01031         FD_ZERO( &fds_e );
01032 
01033         if( i_tcp > 0 )
01034         {
01035             FD_SET( p_sys->i_handle_tcp, &fds_r );
01036             FD_SET( p_sys->i_handle_tcp, &fds_e );
01037         }
01038         if( i_udp > 0 )
01039         {
01040             FD_SET( p_sys->i_handle_udp, &fds_r );
01041             FD_SET( p_sys->i_handle_udp, &fds_e );
01042         }
01043 
01044         /* We'll wait 0.5 second if nothing happens */
01045         timeout.tv_sec = 0;
01046         timeout.tv_usec = 500000;
01047 
01048         if( i_try > 3 && (p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0) )
01049         {
01050             return -1;
01051         }
01052 
01053         if( p_access->b_die || p_access->b_error ) return -1;
01054 
01055         //msg_Dbg( p_access, "NetFillBuffer: trying again (select)" );
01056 
01057     } while( !(i_ret = select(i_handle_max +1, &fds_r, 0, &fds_e, &timeout)) ||
01058              (i_ret < 0 && errno == EINTR) );
01059 
01060     if( i_ret < 0 )
01061     {
01062         msg_Err( p_access, "network select error (%s)", strerror(errno) );
01063         return -1;
01064     }
01065 
01066     i_tcp_read = i_udp_read = 0;
01067 
01068     if( i_tcp > 0 && FD_ISSET( p_sys->i_handle_tcp, &fds_r ) )
01069     {
01070         i_tcp_read =
01071             recv( p_sys->i_handle_tcp,
01072                   p_sys->buffer_tcp + p_sys->i_buffer_tcp,
01073                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
01074     }
01075 
01076     if( i_udp > 0 && FD_ISSET( p_sys->i_handle_udp, &fds_r ) )
01077     {
01078         i_udp_read = recv( p_sys->i_handle_udp,
01079                            p_sys->buffer_udp + p_sys->i_buffer_udp,
01080                            i_udp + MMS_BUFFER_SIZE/2, 0 );
01081     }
01082 
01083 #if MMS_DEBUG
01084     if( p_sys->i_proto == MMS_PROTO_UDP )
01085     {
01086         msg_Dbg( p_access, "filling buffer TCP:%d+%d UDP:%d+%d",
01087                  p_sys->i_buffer_tcp, i_tcp_read,
01088                  p_sys->i_buffer_udp, i_udp_read );
01089     }
01090     else
01091     {
01092         msg_Dbg( p_access, "filling buffer TCP:%d+%d",
01093                  p_sys->i_buffer_tcp, i_tcp_read );
01094     }
01095 #endif
01096 
01097     if( i_tcp_read > 0 ) p_sys->i_buffer_tcp += i_tcp_read;
01098     if( i_udp_read > 0 ) p_sys->i_buffer_udp += i_udp_read;
01099 
01100     return i_tcp_read + i_udp_read;
01101 #endif
01102 }
01103 
01104 static int  mms_ParseCommand( access_t *p_access,
01105                               uint8_t *p_data,
01106                               int i_data,
01107                               int *pi_used )
01108 {
01109  #define GET32( i_pos ) \
01110     ( p_sys->p_cmd[i_pos] + ( p_sys->p_cmd[i_pos +1] << 8 ) + \
01111       ( p_sys->p_cmd[i_pos + 2] << 16 ) + \
01112       ( p_sys->p_cmd[i_pos + 3] << 24 ) )
01113 
01114     access_sys_t        *p_sys = p_access->p_sys;
01115     int         i_length;
01116     uint32_t    i_id;
01117 
01118     if( p_sys->p_cmd )
01119     {
01120         free( p_sys->p_cmd );
01121     }
01122     p_sys->i_cmd = i_data;
01123     p_sys->p_cmd = malloc( i_data );
01124     memcpy( p_sys->p_cmd, p_data, i_data );
01125 
01126     *pi_used = i_data; /* by default */
01127 
01128     if( i_data < MMS_CMD_HEADERSIZE )
01129     {
01130         msg_Warn( p_access, "truncated command (header incomplete)" );
01131         p_sys->i_command = 0;
01132         return -1;
01133     }
01134     i_id =  GetDWLE( p_data + 4 );
01135     i_length = GetDWLE( p_data + 8 ) + 16;
01136 
01137     if( i_id != 0xb00bface )
01138     {
01139         msg_Err( p_access,
01140                  "incorrect command header (0x%x)", i_id );
01141         p_sys->i_command = 0;
01142         return -1;
01143     }
01144 
01145     if( i_length > p_sys->i_cmd )
01146     {
01147         msg_Warn( p_access,
01148                   "truncated command (missing %d bytes)",
01149                    i_length - i_data  );
01150         p_sys->i_command = 0;
01151         return -1;
01152     }
01153     else if( i_length < p_sys->i_cmd )
01154     {
01155         p_sys->i_cmd = i_length;
01156         *pi_used = i_length;
01157     }
01158 
01159     msg_Dbg( p_access,
01160              "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",
01161              GET32( 0 ),
01162              GET32( 4 ),
01163              GET32( 8 ),
01164              /* 12: protocol type "MMS " */
01165              GET32( 16 ),
01166              GET32( 20 ),
01167              /* 24: unknown (0) */
01168              /* 28: unknown (0) */
01169              GET32( 32 ),
01170              GET32( 36 )
01171              /* 40: switches */
01172              /* 44: extra */ );
01173 
01174     p_sys->i_command = GET32( 36 ) & 0xffff;
01175 #undef GET32
01176 
01177     return MMS_PACKET_CMD;
01178 }
01179 
01180 static int  mms_ParsePacket( access_t *p_access,
01181                              uint8_t *p_data, size_t i_data,
01182                              int *pi_used )
01183 {
01184     access_sys_t        *p_sys = p_access->p_sys;
01185     int i_packet_seq_num;
01186     size_t i_packet_length;
01187     uint32_t i_packet_id;
01188 
01189     uint8_t  *p_packet;
01190 
01191 
01192     *pi_used = i_data; /* default */
01193     if( i_data <= 8 )
01194     {
01195         msg_Warn( p_access, "truncated packet (header incomplete)" );
01196         return -1;
01197     }
01198 
01199     i_packet_id = p_data[4];
01200     i_packet_seq_num = GetDWLE( p_data );
01201     i_packet_length = GetWLE( p_data + 6 );
01202 
01203     //msg_Warn( p_access, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
01204 
01205     if( i_packet_length > i_data || i_packet_length <= 8)
01206     {
01207      /*   msg_Dbg( p_access,
01208                  "truncated packet (Declared %d bytes, Actual %d bytes)",
01209                  i_packet_length, i_data  ); */
01210         *pi_used = 0;
01211         return -1;
01212     }
01213     else if( i_packet_length < i_data )
01214     {
01215         *pi_used = i_packet_length;
01216     }
01217 
01218     if( i_packet_id == 0xff )
01219     {
01220         msg_Warn( p_access,
01221                   "receive MMS UDP pair timing" );
01222         return( MMS_PACKET_UDP_TIMING );
01223     }
01224 
01225     if( i_packet_id != p_sys->i_header_packet_id_type &&
01226         i_packet_id != p_sys->i_media_packet_id_type )
01227     {
01228         msg_Warn( p_access, "incorrect Packet Id Type (0x%x)", i_packet_id );
01229         return -1;
01230     }
01231 
01232     /* we now have a media or a header packet */
01233     p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
01234     memcpy( p_packet, p_data + 8, i_packet_length - 8 );
01235 
01236     if( i_packet_seq_num != p_sys->i_packet_seq_num )
01237     {
01238         /* FIXME for udp could be just wrong order ? */
01239         msg_Warn( p_access,
01240                   "detected packet lost (%d != %d)",
01241                   i_packet_seq_num,
01242                   p_sys->i_packet_seq_num );
01243         p_sys->i_packet_seq_num = i_packet_seq_num;
01244     }
01245     p_sys->i_packet_seq_num++;
01246 
01247     if( i_packet_id == p_sys->i_header_packet_id_type )
01248     {
01249         if( p_sys->p_header )
01250         {
01251             p_sys->p_header = realloc( p_sys->p_header,
01252                                           p_sys->i_header + i_packet_length - 8 );
01253             memcpy( &p_sys->p_header[p_sys->i_header],
01254                     p_packet,
01255                     i_packet_length - 8 );
01256             p_sys->i_header += i_packet_length - 8;
01257 
01258             free( p_packet );
01259         }
01260         else
01261         {
01262             p_sys->p_header = p_packet;
01263             p_sys->i_header = i_packet_length - 8;
01264         }
01265 /*        msg_Dbg( p_access,
01266                  "receive header packet (%d bytes)",
01267                  i_packet_length - 8 ); */
01268 
01269         return MMS_PACKET_HEADER;
01270     }
01271     else
01272     {
01273         FREE( p_sys->p_media );
01274         p_sys->p_media = p_packet;
01275         p_sys->i_media = i_packet_length - 8;
01276         p_sys->i_media_used = 0;
01277 /*        msg_Dbg( p_access,
01278                  "receive media packet (%d bytes)",
01279                  i_packet_length - 8 ); */
01280 
01281         return MMS_PACKET_MEDIA;
01282     }
01283 }
01284 
01285 static int mms_ReceivePacket( access_t *p_access )
01286 {
01287     access_sys_t *p_sys = p_access->p_sys;
01288     int i_packet_tcp_type;
01289     int i_packet_udp_type;
01290 
01291     for( ;; )
01292     {
01293         vlc_bool_t b_refill = VLC_TRUE;
01294 
01295         /* first if we need to refill buffer */
01296         if( p_sys->i_buffer_tcp >= MMS_CMD_HEADERSIZE )
01297         {
01298             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface  )
01299             {
01300                 if( GetDWLE( p_sys->buffer_tcp + 8 ) + 16 <=
01301                     (uint32_t)p_sys->i_buffer_tcp )
01302                 {
01303                     b_refill = VLC_FALSE;
01304                 }
01305             }
01306             else if( GetWLE( p_sys->buffer_tcp + 6 ) <= p_sys->i_buffer_tcp )
01307             {
01308                 b_refill = VLC_FALSE;
01309             }
01310         }
01311         if( p_sys->i_proto == MMS_PROTO_UDP && p_sys->i_buffer_udp >= 8 &&
01312             GetWLE( p_sys->buffer_udp + 6 ) <= p_sys->i_buffer_udp )
01313         {
01314             b_refill = VLC_FALSE;
01315         }
01316 
01317         if( b_refill && NetFillBuffer( p_access ) < 0 )
01318         {
01319             msg_Warn( p_access, "cannot fill buffer" );
01320             return -1;
01321         }
01322 
01323         i_packet_tcp_type = -1;
01324         i_packet_udp_type = -1;
01325 
01326         if( p_sys->i_buffer_tcp > 0 )
01327         {
01328             int i_used;
01329 
01330             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface )
01331             {
01332                 i_packet_tcp_type =
01333                     mms_ParseCommand( p_access, p_sys->buffer_tcp,
01334                                       p_sys->i_buffer_tcp, &i_used );
01335 
01336             }
01337             else
01338             {
01339                 i_packet_tcp_type =
01340                     mms_ParsePacket( p_access, p_sys->buffer_tcp,
01341                                      p_sys->i_buffer_tcp, &i_used );
01342             }
01343             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
01344             {
01345                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
01346                          MMS_BUFFER_SIZE - i_used );
01347             }
01348             p_sys->i_buffer_tcp -= i_used;
01349         }
01350         else if( p_sys->i_buffer_udp > 0 )
01351         {
01352             int i_used;
01353 
01354             i_packet_udp_type =
01355                 mms_ParsePacket( p_access, p_sys->buffer_udp,
01356                                  p_sys->i_buffer_udp, &i_used );
01357 
01358             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
01359             {
01360                 memmove( p_sys->buffer_udp, p_sys->buffer_udp + i_used,
01361                          MMS_BUFFER_SIZE - i_used );
01362             }
01363             p_sys->i_buffer_udp -= i_used;
01364         }
01365 
01366         if( i_packet_tcp_type == MMS_PACKET_CMD && p_sys->i_command == 0x1b )
01367         {
01368             mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
01369             i_packet_tcp_type = -1;
01370         }
01371 
01372         if( i_packet_tcp_type != -1 )
01373         {
01374             return i_packet_tcp_type;
01375         }
01376         else if( i_packet_udp_type != -1 )
01377         {
01378             return i_packet_udp_type;
01379         }
01380     }
01381 }
01382 
01383 static int mms_ReceiveCommand( access_t *p_access )
01384 {
01385     access_sys_t *p_sys = p_access->p_sys;
01386 
01387     for( ;; )
01388     {
01389         int i_used;
01390         int i_status;
01391 
01392         if( NetFillBuffer( p_access ) < 0 )
01393         {
01394             msg_Warn( p_access, "cannot fill buffer" );
01395             return VLC_EGENERIC;
01396         }
01397         if( p_sys->i_buffer_tcp > 0 )
01398         {
01399             i_status = mms_ParseCommand( p_access, p_sys->buffer_tcp,
01400                                          p_sys->i_buffer_tcp, &i_used );
01401             if( i_used < MMS_BUFFER_SIZE )
01402             {
01403                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
01404                          MMS_BUFFER_SIZE - i_used );
01405             }
01406             p_sys->i_buffer_tcp -= i_used;
01407 
01408             if( i_status < 0 )
01409             {
01410                 return VLC_EGENERIC;
01411             }
01412 
01413             if( p_sys->i_command == 0x1b )
01414             {
01415                 mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
01416             }
01417             else
01418             {
01419                 break;
01420             }
01421         }
01422         else
01423         {
01424             return VLC_EGENERIC;
01425         }
01426     }
01427 
01428     return VLC_SUCCESS;
01429 }
01430 
01431 #define MMS_RETRY_MAX       10
01432 #define MMS_RETRY_SLEEP     50000
01433 
01434 static int mms_CommandRead( access_t *p_access, int i_command1,
01435                             int i_command2 )
01436 {
01437     access_sys_t *p_sys = p_access->p_sys;
01438     int i_count;
01439     int i_status;
01440 
01441     for( i_count = 0; i_count < MMS_RETRY_MAX; )
01442     {
01443         i_status = mms_ReceiveCommand( p_access );
01444         if( i_status < 0 || p_sys->i_command == 0 )
01445         {
01446             i_count++;
01447             msleep( MMS_RETRY_SLEEP );
01448         }
01449         else if( i_command1 == 0 && i_command2 == 0)
01450         {
01451             return VLC_SUCCESS;
01452         }
01453         else if( p_sys->i_command == i_command1 ||
01454                  p_sys->i_command == i_command2 )
01455         {
01456             return VLC_SUCCESS;
01457         }
01458         else
01459         {
01460             switch( p_sys->i_command )
01461             {
01462                 case 0x03:
01463                     msg_Warn( p_access, "socket closed by server" );
01464                     p_access->info.b_eof = 1;
01465                     return VLC_EGENERIC;
01466                 case 0x1e:
01467                     msg_Warn( p_access, "end of media stream" );
01468                     p_access->info.b_eof = 1;
01469                     return VLC_EGENERIC;
01470                 default:
01471                     break;
01472             }
01473         }
01474     }
01475     msg_Warn( p_access, "failed to receive command (aborting)" );
01476 
01477     return VLC_EGENERIC;
01478 }
01479 
01480 
01481 static int mms_HeaderMediaRead( access_t *p_access, int i_type )
01482 {
01483     access_sys_t *p_sys = p_access->p_sys;
01484     int          i_count;
01485 
01486     for( i_count = 0; i_count < MMS_RETRY_MAX; )
01487     {
01488         int i_status;
01489 
01490         if( p_access->b_die )
01491             return -1;
01492 
01493         i_status = mms_ReceivePacket( p_access );
01494         if( i_status < 0 )
01495         {
01496             i_count++;
01497             msg_Warn( p_access, "cannot receive header (%d/%d)",
01498                       i_count, MMS_RETRY_MAX );
01499             msleep( MMS_RETRY_SLEEP );
01500         }
01501         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
01502         {
01503             return i_type;
01504         }
01505         else if( i_status == MMS_PACKET_CMD )
01506         {
01507             switch( p_sys->i_command )
01508             {
01509                 case 0x03:
01510                     msg_Warn( p_access, "socket closed by server" );
01511                     p_access->info.b_eof = 1;
01512                     return -1;
01513                 case 0x1e:
01514                     msg_Warn( p_access, "end of media stream" );
01515                     p_access->info.b_eof = 1;
01516                     return -1;
01517                 case 0x20:
01518                     /* XXX not too dificult to be done EXCEPT that we
01519                      * need to restart demuxer... and I don't see how we
01520                      * could do that :p */
01521                     msg_Err( p_access,
01522                              "reinitialization needed --> unsupported" );
01523                     p_access->info.b_eof = VLC_TRUE;
01524                     return -1;
01525                 default:
01526                     break;
01527             }
01528         }
01529     }
01530 
01531     msg_Err( p_access, "cannot receive %s (aborting)",
01532              ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
01533     return -1;
01534 }
01535 

Generated on Tue Dec 20 10:14:26 2005 for vlc-0.8.4a by  doxygen 1.4.2