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