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