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