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