]> git.sesse.net Git - vlc/blob - modules/access/mms/mmstu.c
7b69ee1ae6aba7e955fd0d4100b92ad85f397383
[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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, 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�e si on voit bien qui peut
101  * �rire ce genre de trucs :p), et �rire en anglais, bordel de
102  * merde :p.
103  */
104 /*
105  * Alors la ouai �est fou les gens qui �rivent des commentaires sans les
106  * signer. Ca m�iterait un coup de pied dans le cul � :)
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_ConnectTCP( 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:%us packet_length:%u packet_count:%u 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, int i_command,
930                             uint32_t i_prefix1, uint32_t i_prefix2,
931                             uint8_t *p_data, int i_data_old )
932 {
933     var_buffer_t buffer;
934     access_sys_t *p_sys = p_access->p_sys;
935     int i_data_by8, i_ret;
936     int i_data = i_data_old;
937
938     while( i_data & 0x7 ) i_data++;
939     i_data_by8 = i_data >> 3;
940
941     /* first init buffer */
942     var_buffer_initwrite( &buffer, 0 );
943
944     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
945     var_buffer_add32( &buffer, 0xB00BFACE );
946     /* size after protocol type */
947     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
948     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
949     var_buffer_add32( &buffer, i_data_by8 + 4 );
950     var_buffer_add32( &buffer, p_sys->i_seq_num ); p_sys->i_seq_num++;
951     var_buffer_add64( &buffer, 0 );
952     var_buffer_add32( &buffer, i_data_by8 + 2 );
953     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
954     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
955     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
956
957     /* specific command data */
958     if( p_data && i_data > 0 )
959     {
960         var_buffer_addmemory( &buffer, p_data, i_data_old );
961     }
962
963     /* Append padding to the command data */
964     var_buffer_add64( &buffer, 0 );
965
966     /* send it */
967     i_ret = net_Write( p_access, p_sys->i_handle_tcp, NULL, buffer.p_data,
968                        buffer.i_data - ( 8 - ( i_data - i_data_old ) ) );
969     if( i_ret != buffer.i_data - ( 8 - ( i_data - i_data_old ) ) )
970     {
971         msg_Err( p_access, "failed to send command" );
972         return VLC_EGENERIC;
973     }
974
975     var_buffer_free( &buffer );
976     return VLC_SUCCESS;
977 }
978
979 static int NetFillBuffer( access_t *p_access )
980 {
981 #ifdef UNDER_CE
982     return -1;
983
984 #else
985     access_sys_t    *p_sys = p_access->p_sys;
986     struct timeval  timeout;
987     fd_set          fds_r, fds_e;
988     int             i_ret;
989
990     /* FIXME when using udp */
991     ssize_t i_tcp, i_udp;
992     ssize_t i_tcp_read, i_udp_read;
993     int i_handle_max;
994     int i_try = 0;
995
996     i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp;
997
998     if( p_sys->i_proto == MMS_PROTO_UDP )
999     {
1000         i_udp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_udp;
1001     }
1002     else
1003     {
1004         i_udp = 0;  /* there isn't udp socket */
1005     }
1006
1007     i_handle_max = 0;
1008
1009     if( i_tcp > 0 )
1010         i_handle_max = __MAX( i_handle_max, p_sys->i_handle_tcp );
1011     if( i_udp > 0 )
1012         i_handle_max = __MAX( i_handle_max, p_sys->i_handle_udp );
1013
1014     if( i_handle_max == 0 )
1015     {
1016         msg_Warn( p_access, "nothing to read %d:%d", (int)i_tcp, (int)i_udp );
1017         return 0;
1018     }
1019     else
1020     {
1021         /* msg_Warn( p_access, "ask for tcp:%d udp:%d", i_tcp, i_udp ); */
1022     }
1023
1024     /* Find if some data is available */
1025     do
1026     {
1027         i_try++;
1028
1029         /* Initialize file descriptor set */
1030         FD_ZERO( &fds_r );
1031         FD_ZERO( &fds_e );
1032
1033         if( i_tcp > 0 )
1034         {
1035             FD_SET( p_sys->i_handle_tcp, &fds_r );
1036             FD_SET( p_sys->i_handle_tcp, &fds_e );
1037         }
1038         if( i_udp > 0 )
1039         {
1040             FD_SET( p_sys->i_handle_udp, &fds_r );
1041             FD_SET( p_sys->i_handle_udp, &fds_e );
1042         }
1043
1044         /* We'll wait 0.5 second if nothing happens */
1045         timeout.tv_sec = 0;
1046         timeout.tv_usec = 500000;
1047
1048         if( i_try > 3 && (p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0) )
1049         {
1050             return -1;
1051         }
1052
1053         if( p_access->b_die || p_access->b_error ) return -1;
1054
1055         //msg_Dbg( p_access, "NetFillBuffer: trying again (select)" );
1056
1057     } while( !(i_ret = select(i_handle_max +1, &fds_r, 0, &fds_e, &timeout)) ||
1058              (i_ret < 0 && errno == EINTR) );
1059
1060     if( i_ret < 0 )
1061     {
1062         msg_Err( p_access, "network select error (%s)", strerror(errno) );
1063         return -1;
1064     }
1065
1066     i_tcp_read = i_udp_read = 0;
1067
1068     if( i_tcp > 0 && FD_ISSET( p_sys->i_handle_tcp, &fds_r ) )
1069     {
1070         i_tcp_read =
1071             recv( p_sys->i_handle_tcp,
1072                   p_sys->buffer_tcp + p_sys->i_buffer_tcp,
1073                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
1074     }
1075
1076     if( i_udp > 0 && FD_ISSET( p_sys->i_handle_udp, &fds_r ) )
1077     {
1078         i_udp_read = recv( p_sys->i_handle_udp,
1079                            p_sys->buffer_udp + p_sys->i_buffer_udp,
1080                            i_udp + MMS_BUFFER_SIZE/2, 0 );
1081     }
1082
1083 #if MMS_DEBUG
1084     if( p_sys->i_proto == MMS_PROTO_UDP )
1085     {
1086         msg_Dbg( p_access, "filling buffer TCP:%d+%d UDP:%d+%d",
1087                  p_sys->i_buffer_tcp, i_tcp_read,
1088                  p_sys->i_buffer_udp, i_udp_read );
1089     }
1090     else
1091     {
1092         msg_Dbg( p_access, "filling buffer TCP:%d+%d",
1093                  p_sys->i_buffer_tcp, i_tcp_read );
1094     }
1095 #endif
1096
1097     if( i_tcp_read > 0 ) p_sys->i_buffer_tcp += i_tcp_read;
1098     if( i_udp_read > 0 ) p_sys->i_buffer_udp += i_udp_read;
1099
1100     return i_tcp_read + i_udp_read;
1101 #endif
1102 }
1103
1104 static int  mms_ParseCommand( access_t *p_access,
1105                               uint8_t *p_data,
1106                               int i_data,
1107                               int *pi_used )
1108 {
1109  #define GET32( i_pos ) \
1110     ( p_sys->p_cmd[i_pos] + ( p_sys->p_cmd[i_pos +1] << 8 ) + \
1111       ( p_sys->p_cmd[i_pos + 2] << 16 ) + \
1112       ( p_sys->p_cmd[i_pos + 3] << 24 ) )
1113
1114     access_sys_t        *p_sys = p_access->p_sys;
1115     int         i_length;
1116     uint32_t    i_id;
1117
1118     if( p_sys->p_cmd )
1119     {
1120         free( p_sys->p_cmd );
1121     }
1122     p_sys->i_cmd = i_data;
1123     p_sys->p_cmd = malloc( i_data );
1124     memcpy( p_sys->p_cmd, p_data, i_data );
1125
1126     *pi_used = i_data; /* by default */
1127
1128     if( i_data < MMS_CMD_HEADERSIZE )
1129     {
1130         msg_Warn( p_access, "truncated command (header incomplete)" );
1131         p_sys->i_command = 0;
1132         return -1;
1133     }
1134     i_id =  GetDWLE( p_data + 4 );
1135     i_length = GetDWLE( p_data + 8 ) + 16;
1136
1137     if( i_id != 0xb00bface )
1138     {
1139         msg_Err( p_access,
1140                  "incorrect command header (0x%x)", i_id );
1141         p_sys->i_command = 0;
1142         return -1;
1143     }
1144
1145     if( i_length > p_sys->i_cmd )
1146     {
1147         msg_Warn( p_access,
1148                   "truncated command (missing %d bytes)",
1149                    i_length - i_data  );
1150         p_sys->i_command = 0;
1151         return -1;
1152     }
1153     else if( i_length < p_sys->i_cmd )
1154     {
1155         p_sys->i_cmd = i_length;
1156         *pi_used = i_length;
1157     }
1158
1159     msg_Dbg( p_access,
1160              "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",
1161              GET32( 0 ),
1162              GET32( 4 ),
1163              GET32( 8 ),
1164              /* 12: protocol type "MMS " */
1165              GET32( 16 ),
1166              GET32( 20 ),
1167              /* 24: unknown (0) */
1168              /* 28: unknown (0) */
1169              GET32( 32 ),
1170              GET32( 36 )
1171              /* 40: switches */
1172              /* 44: extra */ );
1173
1174     p_sys->i_command = GET32( 36 ) & 0xffff;
1175 #undef GET32
1176
1177     return MMS_PACKET_CMD;
1178 }
1179
1180 static int  mms_ParsePacket( access_t *p_access,
1181                              uint8_t *p_data, size_t i_data,
1182                              int *pi_used )
1183 {
1184     access_sys_t        *p_sys = p_access->p_sys;
1185     int i_packet_seq_num;
1186     size_t i_packet_length;
1187     uint32_t i_packet_id;
1188
1189     uint8_t  *p_packet;
1190
1191
1192     *pi_used = i_data; /* default */
1193     if( i_data <= 8 )
1194     {
1195         msg_Warn( p_access, "truncated packet (header incomplete)" );
1196         return -1;
1197     }
1198
1199     i_packet_id = p_data[4];
1200     i_packet_seq_num = GetDWLE( p_data );
1201     i_packet_length = GetWLE( p_data + 6 );
1202
1203     //msg_Warn( p_access, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
1204
1205     if( i_packet_length > i_data || i_packet_length <= 8)
1206     {
1207      /*   msg_Dbg( p_access,
1208                  "truncated packet (Declared %d bytes, Actual %d bytes)",
1209                  i_packet_length, i_data  ); */
1210         *pi_used = 0;
1211         return -1;
1212     }
1213     else if( i_packet_length < i_data )
1214     {
1215         *pi_used = i_packet_length;
1216     }
1217
1218     if( i_packet_id == 0xff )
1219     {
1220         msg_Warn( p_access,
1221                   "receive MMS UDP pair timing" );
1222         return( MMS_PACKET_UDP_TIMING );
1223     }
1224
1225     if( i_packet_id != p_sys->i_header_packet_id_type &&
1226         i_packet_id != p_sys->i_media_packet_id_type )
1227     {
1228         msg_Warn( p_access, "incorrect Packet Id Type (0x%x)", i_packet_id );
1229         return -1;
1230     }
1231
1232     /* we now have a media or a header packet */
1233     p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
1234     memcpy( p_packet, p_data + 8, i_packet_length - 8 );
1235
1236     if( i_packet_seq_num != p_sys->i_packet_seq_num )
1237     {
1238         /* FIXME for udp could be just wrong order ? */
1239         msg_Warn( p_access,
1240                   "detected packet lost (%d != %d)",
1241                   i_packet_seq_num,
1242                   p_sys->i_packet_seq_num );
1243         p_sys->i_packet_seq_num = i_packet_seq_num;
1244     }
1245     p_sys->i_packet_seq_num++;
1246
1247     if( i_packet_id == p_sys->i_header_packet_id_type )
1248     {
1249         if( p_sys->p_header )
1250         {
1251             p_sys->p_header = realloc( p_sys->p_header,
1252                                           p_sys->i_header + i_packet_length - 8 );
1253             memcpy( &p_sys->p_header[p_sys->i_header],
1254                     p_packet,
1255                     i_packet_length - 8 );
1256             p_sys->i_header += i_packet_length - 8;
1257
1258             free( p_packet );
1259         }
1260         else
1261         {
1262             p_sys->p_header = p_packet;
1263             p_sys->i_header = i_packet_length - 8;
1264         }
1265 /*        msg_Dbg( p_access,
1266                  "receive header packet (%d bytes)",
1267                  i_packet_length - 8 ); */
1268
1269         return MMS_PACKET_HEADER;
1270     }
1271     else
1272     {
1273         FREE( p_sys->p_media );
1274         p_sys->p_media = p_packet;
1275         p_sys->i_media = i_packet_length - 8;
1276         p_sys->i_media_used = 0;
1277 /*        msg_Dbg( p_access,
1278                  "receive media packet (%d bytes)",
1279                  i_packet_length - 8 ); */
1280
1281         return MMS_PACKET_MEDIA;
1282     }
1283 }
1284
1285 static int mms_ReceivePacket( access_t *p_access )
1286 {
1287     access_sys_t *p_sys = p_access->p_sys;
1288     int i_packet_tcp_type;
1289     int i_packet_udp_type;
1290
1291     for( ;; )
1292     {
1293         vlc_bool_t b_refill = VLC_TRUE;
1294
1295         /* first if we need to refill buffer */
1296         if( p_sys->i_buffer_tcp >= MMS_CMD_HEADERSIZE )
1297         {
1298             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface  )
1299             {
1300                 if( GetDWLE( p_sys->buffer_tcp + 8 ) + 16 <=
1301                     (uint32_t)p_sys->i_buffer_tcp )
1302                 {
1303                     b_refill = VLC_FALSE;
1304                 }
1305             }
1306             else if( GetWLE( p_sys->buffer_tcp + 6 ) <= p_sys->i_buffer_tcp )
1307             {
1308                 b_refill = VLC_FALSE;
1309             }
1310         }
1311         if( p_sys->i_proto == MMS_PROTO_UDP && p_sys->i_buffer_udp >= 8 &&
1312             GetWLE( p_sys->buffer_udp + 6 ) <= p_sys->i_buffer_udp )
1313         {
1314             b_refill = VLC_FALSE;
1315         }
1316
1317         if( b_refill && NetFillBuffer( p_access ) < 0 )
1318         {
1319             msg_Warn( p_access, "cannot fill buffer" );
1320             return -1;
1321         }
1322
1323         i_packet_tcp_type = -1;
1324         i_packet_udp_type = -1;
1325
1326         if( p_sys->i_buffer_tcp > 0 )
1327         {
1328             int i_used;
1329
1330             if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface )
1331             {
1332                 i_packet_tcp_type =
1333                     mms_ParseCommand( p_access, p_sys->buffer_tcp,
1334                                       p_sys->i_buffer_tcp, &i_used );
1335
1336             }
1337             else
1338             {
1339                 i_packet_tcp_type =
1340                     mms_ParsePacket( p_access, p_sys->buffer_tcp,
1341                                      p_sys->i_buffer_tcp, &i_used );
1342             }
1343             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1344             {
1345                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
1346                          MMS_BUFFER_SIZE - i_used );
1347             }
1348             p_sys->i_buffer_tcp -= i_used;
1349         }
1350         else if( p_sys->i_buffer_udp > 0 )
1351         {
1352             int i_used;
1353
1354             i_packet_udp_type =
1355                 mms_ParsePacket( p_access, p_sys->buffer_udp,
1356                                  p_sys->i_buffer_udp, &i_used );
1357
1358             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1359             {
1360                 memmove( p_sys->buffer_udp, p_sys->buffer_udp + i_used,
1361                          MMS_BUFFER_SIZE - i_used );
1362             }
1363             p_sys->i_buffer_udp -= i_used;
1364         }
1365
1366         if( i_packet_tcp_type == MMS_PACKET_CMD && p_sys->i_command == 0x1b )
1367         {
1368             mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
1369             i_packet_tcp_type = -1;
1370         }
1371
1372         if( i_packet_tcp_type != -1 )
1373         {
1374             return i_packet_tcp_type;
1375         }
1376         else if( i_packet_udp_type != -1 )
1377         {
1378             return i_packet_udp_type;
1379         }
1380     }
1381 }
1382
1383 static int mms_ReceiveCommand( access_t *p_access )
1384 {
1385     access_sys_t *p_sys = p_access->p_sys;
1386
1387     for( ;; )
1388     {
1389         int i_used;
1390         int i_status;
1391
1392         if( NetFillBuffer( p_access ) < 0 )
1393         {
1394             msg_Warn( p_access, "cannot fill buffer" );
1395             return VLC_EGENERIC;
1396         }
1397         if( p_sys->i_buffer_tcp > 0 )
1398         {
1399             i_status = mms_ParseCommand( p_access, p_sys->buffer_tcp,
1400                                          p_sys->i_buffer_tcp, &i_used );
1401             if( i_used < MMS_BUFFER_SIZE )
1402             {
1403                 memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used,
1404                          MMS_BUFFER_SIZE - i_used );
1405             }
1406             p_sys->i_buffer_tcp -= i_used;
1407
1408             if( i_status < 0 )
1409             {
1410                 return VLC_EGENERIC;
1411             }
1412
1413             if( p_sys->i_command == 0x1b )
1414             {
1415                 mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 );
1416             }
1417             else
1418             {
1419                 break;
1420             }
1421         }
1422         else
1423         {
1424             return VLC_EGENERIC;
1425         }
1426     }
1427
1428     return VLC_SUCCESS;
1429 }
1430
1431 #define MMS_RETRY_MAX       10
1432 #define MMS_RETRY_SLEEP     50000
1433
1434 static int mms_CommandRead( access_t *p_access, int i_command1,
1435                             int i_command2 )
1436 {
1437     access_sys_t *p_sys = p_access->p_sys;
1438     int i_count;
1439     int i_status;
1440
1441     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1442     {
1443         i_status = mms_ReceiveCommand( p_access );
1444         if( i_status < 0 || p_sys->i_command == 0 )
1445         {
1446             i_count++;
1447             msleep( MMS_RETRY_SLEEP );
1448         }
1449         else if( i_command1 == 0 && i_command2 == 0)
1450         {
1451             return VLC_SUCCESS;
1452         }
1453         else if( p_sys->i_command == i_command1 ||
1454                  p_sys->i_command == i_command2 )
1455         {
1456             return VLC_SUCCESS;
1457         }
1458         else
1459         {
1460             switch( p_sys->i_command )
1461             {
1462                 case 0x03:
1463                     msg_Warn( p_access, "socket closed by server" );
1464                     p_access->info.b_eof = 1;
1465                     return VLC_EGENERIC;
1466                 case 0x1e:
1467                     msg_Warn( p_access, "end of media stream" );
1468                     p_access->info.b_eof = 1;
1469                     return VLC_EGENERIC;
1470                 default:
1471                     break;
1472             }
1473         }
1474     }
1475     msg_Warn( p_access, "failed to receive command (aborting)" );
1476
1477     return VLC_EGENERIC;
1478 }
1479
1480
1481 static int mms_HeaderMediaRead( access_t *p_access, int i_type )
1482 {
1483     access_sys_t *p_sys = p_access->p_sys;
1484     int          i_count;
1485
1486     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1487     {
1488         int i_status;
1489
1490         if( p_access->b_die )
1491             return -1;
1492
1493         i_status = mms_ReceivePacket( p_access );
1494         if( i_status < 0 )
1495         {
1496             i_count++;
1497             msg_Warn( p_access, "cannot receive header (%d/%d)",
1498                       i_count, MMS_RETRY_MAX );
1499             msleep( MMS_RETRY_SLEEP );
1500         }
1501         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
1502         {
1503             return i_type;
1504         }
1505         else if( i_status == MMS_PACKET_CMD )
1506         {
1507             switch( p_sys->i_command )
1508             {
1509                 case 0x03:
1510                     msg_Warn( p_access, "socket closed by server" );
1511                     p_access->info.b_eof = 1;
1512                     return -1;
1513                 case 0x1e:
1514                     msg_Warn( p_access, "end of media stream" );
1515                     p_access->info.b_eof = 1;
1516                     return -1;
1517                 case 0x20:
1518                     /* XXX not too dificult to be done EXCEPT that we
1519                      * need to restart demuxer... and I don't see how we
1520                      * could do that :p */
1521                     msg_Err( p_access,
1522                              "reinitialization needed --> unsupported" );
1523                     p_access->info.b_eof = VLC_TRUE;
1524                     return -1;
1525                 default:
1526                     break;
1527             }
1528         }
1529     }
1530
1531     msg_Err( p_access, "cannot receive %s (aborting)",
1532              ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
1533     return -1;
1534 }
1535