]> git.sesse.net Git - vlc/blob - modules/access/mms/mms.c
* new dutch translation
[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.31 2003/03/30 18:14:35 gbazin 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/time.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <fcntl.h>
42
43 #include <vlc/vlc.h>
44 #include <vlc/input.h>
45
46 #ifdef HAVE_UNISTD_H
47 #   include <unistd.h>
48 #endif
49
50 #ifdef WIN32
51 #   include <winsock2.h>
52 #   include <ws2tcpip.h>
53 #   ifndef IN_MULTICAST
54 #       define IN_MULTICAST(a) IN_CLASSD(a)
55 #   endif
56 #else
57 #   include <sys/socket.h>
58 #   include <netinet/in.h>
59 #   if HAVE_ARPA_INET_H
60 #      include <arpa/inet.h>
61 #   elif defined( SYS_BEOS )
62 #      include <net/netdb.h>
63 #   endif
64 #endif
65
66 #include "network.h"
67 #include "asf.h"
68 #include "buffer.h"
69 #include "mms.h"
70
71 #undef MMS_DEBUG
72
73 /****************************************************************************
74  * NOTES:
75  *  MMSProtocole documentation found at http://get.to/sdp
76  ****************************************************************************/
77
78 /*****************************************************************************
79  * Local prototypes
80  *****************************************************************************/
81 static int  Open        ( vlc_object_t * );
82 static void Close       ( vlc_object_t * );
83
84 static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
85                           size_t i_len );
86 static void Seek        ( input_thread_t *, off_t );
87 static int  SetProgram  ( input_thread_t *, pgrm_descriptor_t * );
88
89
90 static int MMSOpen( input_thread_t  *, url_t *, int, char * );
91
92 static int MMSStart  ( input_thread_t  *, uint32_t );
93 static int MMSStop  ( input_thread_t  *p_input );
94
95 static int MMSClose  ( input_thread_t  * );
96
97
98 static int  mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 );
99 static int  mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t *, int );
100
101 static int  mms_HeaderMediaRead( input_thread_t *, int );
102
103 static int  mms_ReceivePacket( input_thread_t * );
104
105 static void mms_ParseURL( url_t *p_url, char *psz_url );
106
107
108
109 /*
110  * XXX DON'T FREE MY MEMORY !!! XXX
111  * non mais :P
112  */
113
114 /*
115  * Ok, ok, j'le ferai plus...
116  */
117 /*
118  * Merci :))
119  */
120 /*
121  * Vous pourriez signer vos commentaires (même si on voit bien qui peut
122  * écrire ce genre de trucs :p), et écrire en anglais, bordel de
123  * merde :p.
124  */
125
126 /*****************************************************************************
127  * Module descriptor
128  *****************************************************************************/
129 #define CACHING_TEXT N_("caching value in ms")
130 #define CACHING_LONGTEXT N_( \
131     "Allows you to modify the default caching value for mms streams. This " \
132     "value should be set in miliseconds units." )
133
134 vlc_module_begin();
135     set_description( _("Microsoft Media Server (MMS) input") );
136     set_capability( "access", 0 );
137     add_category_hint( "stream", NULL, VLC_TRUE );
138         add_integer( "mms-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
139                      CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
140
141         add_bool( "mms-all", 0, NULL,
142                   "force selection of all streams",
143                   "force selection of all streams", VLC_TRUE );
144
145         add_string( "mms-stream", NULL, NULL,
146                     "streams selection",
147                     "force this stream selection", VLC_TRUE );
148         add_integer( "mms-maxbitrate", 0, NULL,
149                      "max bitrate",
150                      "set max bitrate for auto streams selections", VLC_FALSE );
151     add_shortcut( "mms" );
152     add_shortcut( "mmsu" );
153     add_shortcut( "mmst" );
154     set_callbacks( Open, Close );
155 vlc_module_end();
156
157 #define BUF_SIZE 200000
158
159 static int Open( vlc_object_t *p_this )
160 {
161     access_t    *p_access;
162     int         i_proto;
163     char        *psz_network;
164     int         i_status;
165
166     input_thread_t  *p_input = (input_thread_t*)p_this;
167
168     /* *** allocate p_access_data *** */
169     p_input->p_access_data =
170         (void*)p_access = malloc( sizeof( access_t ) );
171     memset( p_access, 0, sizeof( access_t ) );
172
173
174     /* *** Parse URL and get server addr/port and path *** */
175     mms_ParseURL( &p_access->url, p_input->psz_name );
176     if( p_access->url.psz_server_addr == NULL ||
177         !( *p_access->url.psz_server_addr ) )
178     {
179         FREE( p_access->url.psz_private );
180         msg_Err( p_input, "invalid server name" );
181         return( -1 );
182     }
183     if( p_access->url.i_server_port == 0 )
184     {
185         p_access->url.i_server_port = 1755; /* default port */
186     }
187     if( p_access->url.i_bind_port == 0 )
188     {
189         p_access->url.i_bind_port = 7000;   /* default port */
190     }
191
192
193     /* *** connect to this server *** */
194     /* 1: look at  requested protocol (udp/tcp) */
195     i_proto = MMS_PROTO_AUTO;
196     if( *p_input->psz_access )
197     {
198         if( !strncmp( p_input->psz_access, "mmsu", 4 ) )
199         {
200             i_proto = MMS_PROTO_UDP;
201         }
202         else if( !strncmp( p_input->psz_access, "mmst", 4 ) )
203         {
204             i_proto = MMS_PROTO_TCP;
205         }
206     }
207     /* 2: look at ip version ipv4/ipv6 */
208     psz_network = "";
209     if( config_GetInt( p_input, "ipv4" ) )
210     {
211         psz_network = "ipv4";
212     }
213     else if( config_GetInt( p_input, "ipv6" ) )
214     {
215         psz_network = "ipv6";
216     }
217     /* 3: connect */
218     if( i_proto == MMS_PROTO_AUTO )
219     {   /* first try with TCP */
220         i_status =
221             MMSOpen( p_input, &p_access->url, MMS_PROTO_TCP, psz_network );
222         if( i_status < 0 )
223         {   /* then with UDP */
224             i_status =
225              MMSOpen( p_input, &p_access->url, MMS_PROTO_UDP, psz_network );
226         }
227     }
228     else
229     {
230
231         i_status =
232             MMSOpen( p_input, &p_access->url, i_proto, psz_network );
233     }
234
235     if( i_status < 0 )
236     {
237         msg_Err( p_input, "cannot connect to server" );
238         FREE( p_access->url.psz_private );
239         return( -1 );
240     }
241     msg_Dbg( p_input, "connected to %s", p_access->url.psz_server_addr );
242
243
244     /* *** set exported functions *** */
245     p_input->pf_read = Read;
246     p_input->pf_seek = Seek;
247     p_input->pf_set_program = SetProgram;
248     p_input->pf_set_area = NULL;
249
250     p_input->p_private = NULL;
251
252     /* *** finished to set some variable *** */
253     vlc_mutex_lock( &p_input->stream.stream_lock );
254     p_input->stream.b_pace_control = 0;
255     p_input->stream.p_selected_area->i_tell = 0;
256     /*
257      * i_flags_broadcast
258      *  yy xx ?? ??
259      *  broadcast    yy=0x02, xx= 0x00
260      *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video
261      */
262     if( p_access->i_packet_count <= 0 || ( p_access->i_flags_broadcast >> 24 ) == 0x02 )
263     {
264         p_input->stream.b_seekable = 0;
265         p_input->stream.p_selected_area->i_size = 0;
266     }
267     else
268     {
269         p_input->stream.b_seekable = 1;
270         p_input->stream.p_selected_area->i_size =
271             p_access->i_header +
272             p_access->i_packet_count * p_access->i_packet_length;
273     }
274
275     p_input->stream.i_method = INPUT_METHOD_NETWORK;
276     vlc_mutex_unlock( &p_input->stream.stream_lock );
277
278     /* *** Start stream *** */
279     if( MMSStart( p_input, 0xffffffff ) < 0 )
280     {
281         msg_Err( p_input, "cannot start stream" );
282         MMSClose( p_input );
283         FREE( p_access->url.psz_private );
284         return( -1 );
285     }
286
287     /* Update default_pts to a suitable value for mms access */
288     p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000;
289
290     return( 0 );
291 }
292
293 /*****************************************************************************
294  * Close: free unused data structures
295  *****************************************************************************/
296 static void Close( vlc_object_t *p_this )
297 {
298     input_thread_t *  p_input = (input_thread_t *)p_this;
299     access_t    *p_access = (access_t*)p_input->p_access_data;
300
301     /* close connection with server */
302     MMSClose( p_input );
303
304     /* free memory */
305     FREE( p_access->url.psz_private );
306
307     FREE( p_input->p_access_data );
308 }
309
310 /*****************************************************************************
311  * SetProgram: do nothing
312  *****************************************************************************/
313 static int SetProgram( input_thread_t * p_input,
314                        pgrm_descriptor_t * p_program )
315 {
316     return( 0 );
317 }
318
319 /*****************************************************************************
320  * Seek: try to go at the right place
321  *****************************************************************************/
322 static void Seek( input_thread_t * p_input, off_t i_pos )
323 {
324     access_t    *p_access = (access_t*)p_input->p_access_data;
325     uint32_t    i_packet;
326     uint32_t    i_offset;
327     var_buffer_t    buffer;
328
329     if( i_pos < 0 )
330     {
331         return;
332     }
333
334     vlc_mutex_lock( &p_input->stream.stream_lock );
335
336     if( i_pos < p_access->i_header)
337     {
338
339         if( p_access->i_pos < p_access->i_header )
340         {
341             /* no need to restart stream, it was already one
342              * or no stream was yet read */
343             p_access->i_pos = i_pos;
344             return;
345         }
346         else
347         {
348             i_packet = 0xffffffff;
349             i_offset = 0;
350         }
351     }
352     else
353     {
354         i_packet = ( i_pos - p_access->i_header ) / p_access->i_packet_length;
355         i_offset = ( i_pos - p_access->i_header ) % p_access->i_packet_length;
356     }
357     msg_Dbg( p_input, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );
358
359     MMSStop( p_input );
360     msg_Dbg( p_input, "stream stopped (seek)" );
361
362     /* *** restart stream *** */
363     var_buffer_initwrite( &buffer, 0 );
364     var_buffer_add64( &buffer, 0 ); /* seek point in second */
365     var_buffer_add32( &buffer, 0xffffffff );
366     var_buffer_add32( &buffer, i_packet ); // begin from start
367     var_buffer_add8( &buffer, 0xff ); // stream time limit
368     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
369     var_buffer_add8( &buffer, 0xff ); //
370     var_buffer_add8( &buffer, 0x00 ); // don't use limit
371     var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
372
373     mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
374                      buffer.p_data, buffer.i_data );
375
376     var_buffer_free( &buffer );
377
378
379     for( ;; )
380     {
381         mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
382         if( p_access->i_command == 0x1e )
383         {
384             msg_Dbg( p_input, "received 0x1e (seek)" );
385             break;
386         }
387     }
388
389     for( ;; )
390     {
391         mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
392         if( p_access->i_command == 0x05 )
393         {
394             msg_Dbg( p_input, "received 0x05 (seek)" );
395             break;
396         }
397     }
398
399     /* get a packet */
400     mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
401     msg_Dbg( p_input, "Streaming restarted" );
402
403     p_access->i_media_used += i_offset;
404     p_access->i_pos = i_pos;
405     p_input->stream.p_selected_area->i_tell = i_pos;
406     vlc_mutex_unlock( &p_input->stream.stream_lock );
407 }
408
409 static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
410                           size_t i_len )
411 {
412     access_t    *p_access = (access_t*)p_input->p_access_data;
413     size_t      i_data;
414     size_t      i_copy;
415
416     i_data = 0;
417
418     /* *** send header if needed ** */
419     if( p_access->i_pos < p_access->i_header )
420     {
421         i_copy = __MIN( i_len, p_access->i_header - p_access->i_pos );
422         if( i_copy > 0 )
423         {
424             memcpy( p_buffer,
425                     p_access->p_header + p_access->i_pos,
426                     i_copy );
427         }
428         i_data += i_copy;
429     }
430
431     /* *** now send data if needed *** */
432     while( i_data < i_len )
433     {
434         if( p_access->i_media_used < p_access->i_media )
435         {
436             i_copy = __MIN( i_len - i_data ,
437                             p_access->i_media - p_access->i_media_used );
438             memcpy( p_buffer + i_data,
439                     p_access->p_media + p_access->i_media_used,
440                     i_copy );
441             i_data += i_copy;
442             p_access->i_media_used += i_copy;
443         }
444         else if( p_access->p_media != NULL &&
445                  p_access->i_media_used < p_access->i_packet_length )
446         {
447             i_copy = __MIN( i_len - i_data,
448                             p_access->i_packet_length - p_access->i_media_used);
449             memset( p_buffer + i_data, 0, i_copy );
450
451             i_data += i_copy;
452             p_access->i_media_used += i_copy;
453         }
454         else
455         {
456             if( p_access->i_eos
457                  || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 )
458             {
459                 p_access->i_pos += i_data;
460                 return( i_data );
461             }
462         }
463     }
464
465     p_access->i_pos += i_data;
466     return( i_data );
467 }
468
469 static void asf_HeaderParse( mms_stream_t stream[128],
470                              uint8_t *p_header, int i_header )
471 {
472     var_buffer_t buffer;
473     guid_t      guid;
474     uint64_t    i_size;
475     int         i;
476
477     for( i = 0; i < 128; i++ )
478     {
479         stream[i].i_cat = MMS_STREAM_UNKNOWN;
480     }
481
482     //fprintf( stderr, " ---------------------header:%d\n", i_header );
483     var_buffer_initread( &buffer, p_header, i_header );
484
485     var_buffer_getguid( &buffer, &guid );
486
487     if( !CmpGuid( &guid, &asf_object_header_guid ) )
488     {
489 //        XXX Error
490 //        fprintf( stderr, " ---------------------ERROR------\n" );
491     }
492     var_buffer_getmemory( &buffer, NULL, 30 - 16 );
493
494     for( ;; )
495     {
496         //fprintf( stderr, " ---------------------data:%d\n", buffer.i_data );
497
498         var_buffer_getguid( &buffer, &guid );
499         i_size = var_buffer_get64( &buffer );
500
501         //fprintf( stderr, "  guid=0x%8.8x-0x%4.4x-0x%4.4x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x size=%lld\n",
502         //                  guid.v1,guid.v2, guid.v3,
503         //                  guid.v4[0],guid.v4[1],guid.v4[2],guid.v4[3],
504         //                  guid.v4[4],guid.v4[5],guid.v4[6],guid.v4[7],
505         //                  i_size );
506
507         if( CmpGuid( &guid, &asf_object_stream_properties_guid ) )
508         {
509             int     i_stream_id;
510             guid_t  stream_type;
511             //msg_Dbg( p_input, "found stream_properties" );
512
513             var_buffer_getguid( &buffer, &stream_type );
514             var_buffer_getmemory( &buffer, NULL, 32 );
515             i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
516
517             //fprintf( stderr, " 1---------------------skip:%lld\n", i_size - 24 - 32 - 16 - 1 );
518             var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1);
519
520             if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
521             {
522                 //fprintf( stderr, "\nvideo stream[%d] found\n", i_stream_id );
523                 //msg_Dbg( p_input, "video stream[%d] found", i_stream_id );
524                 stream[i_stream_id].i_cat = MMS_STREAM_VIDEO;
525             }
526             else if( CmpGuid( &stream_type, &asf_object_stream_type_audio ) )
527             {
528                 //fprintf( stderr, "\naudio stream[%d] found\n", i_stream_id );
529                 //msg_Dbg( p_input, "audio stream[%d] found", i_stream_id );
530                 stream[i_stream_id].i_cat = MMS_STREAM_AUDIO;
531             }
532             else
533             {
534 //                msg_Dbg( p_input, "unknown stream[%d] found", i_stream_id );
535                 stream[i_stream_id].i_cat = MMS_STREAM_UNKNOWN;
536             }
537         }
538         else if ( CmpGuid( &guid, &asf_object_bitrate_properties_guid ) )
539         {
540             int     i_count;
541             uint8_t i_stream_id;
542
543             i_count = var_buffer_get16( &buffer );
544             i_size -= 2;
545             while( i_count > 0 )
546             {
547                 i_stream_id = var_buffer_get16( &buffer )&0x7f;
548                 stream[i_stream_id].i_bitrate =  var_buffer_get32( &buffer );
549                 i_count--;
550                 i_size -= 6;
551             }
552             //fprintf( stderr, " 2---------------------skip:%lld\n", i_size - 24);
553             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
554         }
555         else
556         {
557             //fprintf( stderr, " 3---------------------skip:%lld\n", i_size - 24);
558             // skip unknown guid
559             var_buffer_getmemory( &buffer, NULL, i_size - 24 );
560         }
561
562         if( var_buffer_readempty( &buffer ) )
563         {
564             return;
565         }
566     }
567 }
568
569 static void mms_StreamSelect( input_thread_t * p_input,
570                               mms_stream_t stream[128] )
571 {
572     /* XXX FIXME use mututal eclusion information */
573     int i;
574     int i_audio, i_video;
575     int b_audio, b_video;
576     int i_bitrate_total;
577     int i_bitrate_max;
578     char *psz_stream;
579
580     i_audio = 0;
581     i_video = 0;
582     i_bitrate_total = 0;
583     i_bitrate_max = config_GetInt( p_input, "mms-maxbitrate" );
584     b_audio = config_GetInt( p_input, "audio" );
585     b_video = config_GetInt( p_input, "video" );
586     if( config_GetInt( p_input, "mms-all" ) )
587     {
588         /* select all valid stream */
589         for( i = 1; i < 128; i++ )
590         {
591             if( stream[i].i_cat != MMS_STREAM_UNKNOWN )
592             {
593                 stream[i].i_selected = 1;
594             }
595         }
596         return;
597     }
598     else
599     {
600         for( i = 0; i < 128; i++ )
601         {
602             stream[i].i_selected = 0; /* by default, not selected */
603         }
604     }
605     psz_stream = config_GetPsz( p_input, "mms-stream" );
606
607     if( psz_stream && *psz_stream )
608     {
609         char *psz_tmp = psz_stream;
610         while( *psz_tmp )
611         {
612             if( *psz_tmp == ',' )
613             {
614                 psz_tmp++;
615             }
616             else
617             {
618                 int i_stream;
619                 i_stream = atoi( psz_tmp );
620                 while( *psz_tmp != '\0' && *psz_tmp != ',' )
621                 {
622                     psz_tmp++;
623                 }
624
625                 if( i_stream > 0 && i_stream < 128 &&
626                     stream[i_stream].i_cat != MMS_STREAM_UNKNOWN )
627                 {
628                     stream[i_stream].i_selected = 1;
629                 }
630             }
631         }
632         FREE( psz_stream );
633         return;
634     }
635     FREE( psz_stream );
636
637     /* big test:
638      * select a stream if
639      *    - no audio nor video stream
640      *    - or:
641      *         - if i_bitrate_max not set keep the highest bitrate
642      *         - if i_bitrate_max is set, keep stream that make we used best
643      *           quality regarding i_bitrate_max
644      *
645      * XXX: little buggy:
646      *        - it doesn't use mutual exclusion info..
647      *        - when selecting a better stream we could select
648      *        something that make i_bitrate_total> i_bitrate_max
649      */
650     for( i = 1; i < 128; i++ )
651     {
652         if( stream[i].i_cat == MMS_STREAM_UNKNOWN )
653         {
654             continue;
655         }
656         else if( stream[i].i_cat == MMS_STREAM_AUDIO && b_audio &&
657                  ( i_audio <= 0 ||
658                     ( ( ( stream[i].i_bitrate > stream[i_audio].i_bitrate &&
659                           ( i_bitrate_total + stream[i].i_bitrate - stream[i_audio].i_bitrate
660                                             < i_bitrate_max || !i_bitrate_max) ) ||
661                         ( stream[i].i_bitrate < stream[i_audio].i_bitrate &&
662                               i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
663                       ) )  ) )
664         {
665             /* unselect old stream */
666             if( i_audio > 0 )
667             {
668                 stream[i_audio].i_selected = 0;
669                 if( stream[i_audio].i_bitrate> 0 )
670                 {
671                     i_bitrate_total -= stream[i_audio].i_bitrate;
672                 }
673             }
674
675             stream[i].i_selected = 1;
676             if( stream[i].i_bitrate> 0 )
677             {
678                 i_bitrate_total += stream[i].i_bitrate;
679             }
680             i_audio = i;
681         }
682         else if( stream[i].i_cat == MMS_STREAM_VIDEO && b_video &&
683                  ( i_video <= 0 ||
684                     (
685                         ( ( stream[i].i_bitrate > stream[i_video].i_bitrate &&
686                             ( i_bitrate_total + stream[i].i_bitrate - stream[i_video].i_bitrate
687                                             < i_bitrate_max || !i_bitrate_max) ) ||
688                           ( stream[i].i_bitrate < stream[i_video].i_bitrate &&
689                             i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
690                         ) ) )  )
691         {
692             /* unselect old stream */
693
694             stream[i_video].i_selected = 0;
695             if( stream[i_video].i_bitrate> 0 )
696             {
697                 i_bitrate_total -= stream[i_video].i_bitrate;
698             }
699
700             stream[i].i_selected = 1;
701             if( stream[i].i_bitrate> 0 )
702             {
703                 i_bitrate_total += stream[i].i_bitrate;
704             }
705             i_video = i;
706         }
707
708     }
709     if( i_bitrate_max > 0 )
710     {
711         msg_Dbg( p_input,
712                  "requested bitrate:%d real bitrate:%d",
713                  i_bitrate_max, i_bitrate_total );
714     }
715     else
716     {
717         msg_Dbg( p_input,
718                  "total bitrate:%d",
719                  i_bitrate_total );
720     }
721 }
722
723 /****************************************************************************
724  * MMSOpen : Open a connection with the server over mmst or mmsu(not yet)
725  ****************************************************************************/
726 static int MMSOpen( input_thread_t  *p_input,
727                        url_t *p_url,
728                        int  i_proto,
729                        char *psz_network ) /* "", "ipv4", "ipv6" */
730 {
731     module_t    *p_network;
732     access_t    *p_access = (access_t*)p_input->p_access_data;
733
734     network_socket_t    socket_desc;
735     int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
736
737     var_buffer_t buffer;
738     char         tmp[4096];
739     uint16_t     *p;
740     int          i_server_version;
741     int          i_tool_version;
742     int          i_update_player_url;
743     int          i_encryption_type;
744     int          i;
745     int          i_streams;
746     int          i_first;
747
748
749     /* *** Open a TCP connection with server *** */
750     msg_Dbg( p_input, "waiting for connection..." );
751     socket_desc.i_type = NETWORK_TCP;
752     socket_desc.psz_server_addr = p_url->psz_server_addr;
753     socket_desc.i_server_port   = p_url->i_server_port;
754     socket_desc.psz_bind_addr   = "";
755     socket_desc.i_bind_port     = 0;
756     p_input->p_private = (void*)&socket_desc;
757     if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
758     {
759         msg_Err( p_input, "failed to open a connection (tcp)" );
760         return( -1 );
761     }
762     module_Unneed( p_input, p_network );
763     p_access->socket_tcp.i_handle = socket_desc.i_handle;
764     p_input->i_mtu    = 0; /*socket_desc.i_mtu;*/
765     msg_Dbg( p_input,
766              "connection(tcp) with \"%s:%d\" successful",
767              p_url->psz_server_addr,
768              p_url->i_server_port );
769
770     /* *** Bind port if UDP protocol is selected *** */
771     if( b_udp )
772     {
773         if( !p_url->psz_bind_addr || !*p_url->psz_bind_addr )
774         {
775             struct sockaddr_in name;
776             socklen_t i_namelen = sizeof( struct sockaddr_in );
777
778             if( getsockname( p_access->socket_tcp.i_handle,
779                              (struct sockaddr*)&name, &i_namelen ) < 0 )
780             {
781
782                 msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );
783 #if defined( UNDER_CE )
784                 CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
785 #elif defined( WIN32 )
786                 closesocket( p_access->socket_tcp.i_handle );
787 #else
788                 close( p_access->socket_tcp.i_handle );
789 #endif
790                 return( -1 );
791             }
792             p_access->psz_bind_addr = inet_ntoa( name.sin_addr );
793         }
794         else
795         {
796             p_access->psz_bind_addr = strdup( p_url->psz_bind_addr );
797         }
798         socket_desc.i_type = NETWORK_UDP;
799         socket_desc.psz_server_addr = "";
800         socket_desc.i_server_port   = 0;
801         socket_desc.psz_bind_addr   = p_access->psz_bind_addr;
802         socket_desc.i_bind_port     = p_url->i_bind_port;
803         p_input->p_private = (void*)&socket_desc;
804         if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
805         {
806             msg_Err( p_input, "failed to open a connection (udp)" );
807 #if defined( UNDER_CE )
808             CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
809 #elif defined( WIN32 )
810             closesocket( p_access->socket_tcp.i_handle );
811 #else
812             close( p_access->socket_tcp.i_handle );
813 #endif
814             return( -1 );
815         }
816         module_Unneed( p_input, p_network );
817         p_access->socket_udp.i_handle = socket_desc.i_handle;
818         p_input->i_mtu    = 0;/*socket_desc.i_mtu;  FIXME */
819
820     }
821     else
822     {
823         p_access->psz_bind_addr = NULL;
824     }
825
826     /* *** Init context for mms prototcol *** */
827     GenerateGuid( &p_access->guid );    /* used to identify client by server */
828     msg_Dbg( p_input,
829              "generated guid: "GUID_FMT,
830              GUID_PRINT( p_access->guid ) );
831     p_access->i_command_level = 1;          /* updated after 0x1A command */
832     p_access->i_seq_num = 0;
833     p_access->i_media_packet_id_type  = 0x04;
834     p_access->i_header_packet_id_type = 0x02;
835     p_access->i_proto = i_proto;
836     p_access->i_packet_seq_num = 0;
837     p_access->p_header = NULL;
838     p_access->i_header = 0;
839     p_access->p_media = NULL;
840     p_access->i_media = 0;
841     p_access->i_media_used = 0;
842
843     p_access->i_pos = 0;
844     p_access->i_buffer_tcp = 0;
845     p_access->i_buffer_udp = 0;
846     p_access->p_cmd = NULL;
847     p_access->i_cmd = 0;
848     p_access->i_eos = 0;
849
850     /* *** send command 1 : connection request *** */
851     var_buffer_initwrite( &buffer, 0 );
852     var_buffer_add16( &buffer, 0x001c );
853     var_buffer_add16( &buffer, 0x0003 );
854     sprintf( tmp,
855              "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
856              GUID_PRINT( p_access->guid ),
857              p_url->psz_server_addr );
858     var_buffer_addUTF16( &buffer, tmp );
859
860     mms_CommandSend( p_input,
861                      0x01,          /* connexion request */
862                      0x00000000,    /* flags, FIXME */
863                      0x0004000b,    /* ???? */
864                      buffer.p_data,
865                      buffer.i_data );
866
867     if( mms_CommandRead( p_input, 0x01, 0 ) < 0 )
868     {
869         var_buffer_free( &buffer );
870         MMSClose( p_input );
871         return( -1 );
872     }
873
874     i_server_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 32 );
875     i_tool_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 36 );
876     i_update_player_url = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 40 );
877     i_encryption_type = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
878     p = (uint16_t*)( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
879 #define GETUTF16( psz, size ) \
880     { \
881         int i; \
882         psz = malloc( size + 1); \
883         for( i = 0; i < size; i++ ) \
884         { \
885             psz[i] = p[i]; \
886         } \
887         psz[size] = '\0'; \
888         p += 2 * ( size ); \
889     }
890     GETUTF16( p_access->psz_server_version, i_server_version );
891     GETUTF16( p_access->psz_tool_version, i_tool_version );
892     GETUTF16( p_access->psz_update_player_url, i_update_player_url );
893     GETUTF16( p_access->psz_encryption_type, i_encryption_type );
894 #undef GETUTF16
895     msg_Dbg( p_input,
896              "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
897              p_access->psz_server_version,
898              p_access->psz_tool_version,
899              p_access->psz_update_player_url,
900              p_access->psz_encryption_type );
901
902     /* *** should make an 18 command to make data timing *** */
903
904     /* *** send command 2 : transport protocol selection *** */
905     var_buffer_reinitwrite( &buffer, 0 );
906     var_buffer_add32( &buffer, 0x00000000 );
907     var_buffer_add32( &buffer, 0x000a0000 );
908     var_buffer_add32( &buffer, 0x00000002 );
909     if( b_udp )
910     {
911         sprintf( tmp,
912                  "\\\\%s\\UDP\\%d",
913                  p_access->psz_bind_addr,
914                  p_url->i_bind_port );
915     }
916     else
917     {
918         sprintf( tmp, "\\\\192.168.0.1\\TCP\\1242"  );
919     }
920     var_buffer_addUTF16( &buffer, tmp );
921     var_buffer_add16( &buffer, '0' );
922
923     mms_CommandSend( p_input,
924                      0x02,          /* connexion request */
925                      0x00000000,    /* flags, FIXME */
926                      0xffffffff,    /* ???? */
927                      buffer.p_data,
928                      buffer.i_data );
929
930     /* *** response from server, should be 0x02 or 0x03 *** */
931     mms_CommandRead( p_input, 0x02, 0x03 );
932     if( p_access->i_command == 0x03 )
933     {
934         msg_Err( p_input,
935                  "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
936         var_buffer_free( &buffer );
937         MMSClose( p_input );
938         return( -1 );
939     }
940     else if( p_access->i_command != 0x02 )
941     {
942         msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
943     }
944
945     /* *** send command 5 : media file name/path requested *** */
946     var_buffer_reinitwrite( &buffer, 0 );
947     var_buffer_add64( &buffer, 0 );
948     var_buffer_addUTF16( &buffer, p_url->psz_path );
949
950     mms_CommandSend( p_input,
951                      0x05,
952                      p_access->i_command_level,
953                      0xffffffff,
954                      buffer.p_data,
955                      buffer.i_data );
956
957     /* *** wait for reponse *** */
958     mms_CommandRead( p_input, 0x1a, 0x06 );
959
960     /* test if server send 0x1A answer */
961     if( p_access->i_command == 0x1A )
962     {
963         msg_Err( p_input, "id/password requested (not yet supported)" );
964         /*  FIXME */
965         var_buffer_free( &buffer );
966         MMSClose( p_input );
967         return( -1 );
968     }
969     if( p_access->i_command != 0x06 )
970     {
971         msg_Err( p_input,
972                  "unknown answer (0x%x instead of 0x06)",
973                  p_access->i_command );
974         var_buffer_free( &buffer );
975         MMSClose( p_input );
976         return( -1 );
977     }
978
979     /*  1 for file ok, 2 for authen ok */
980     switch( GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) )
981     {
982         case 0x0001:
983             msg_Dbg( p_input, "Media file name/path accepted" );
984             break;
985         case 0x0002:
986             msg_Dbg( p_input, "Authentication accepted" );
987             break;
988         case -1:
989         default:
990         msg_Err( p_input, "error while asking for file %d",
991                  GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) );
992         var_buffer_free( &buffer );
993         MMSClose( p_input );
994         return( -1 );
995     }
996
997     p_access->i_flags_broadcast =
998         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 12 );
999     p_access->i_media_length =
1000         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 24 );
1001     p_access->i_packet_length =
1002         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
1003     p_access->i_packet_count =
1004         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
1005     p_access->i_max_bit_rate =
1006         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 56 );
1007     p_access->i_header_size =
1008         GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 60 );
1009
1010     msg_Dbg( p_input,
1011              "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
1012              p_access->i_flags_broadcast,
1013              p_access->i_media_length,
1014              p_access->i_packet_length,
1015              p_access->i_packet_count,
1016              p_access->i_max_bit_rate,
1017              p_access->i_header_size );
1018
1019     /* XXX XXX dirty hack XXX XXX */
1020     p_input->i_mtu    = 3 * p_access->i_packet_length;
1021
1022     /* *** send command 15 *** */
1023
1024     var_buffer_reinitwrite( &buffer, 0 );
1025     var_buffer_add32( &buffer, 0 );
1026     var_buffer_add32( &buffer, 0x8000 );
1027     var_buffer_add32( &buffer, 0xffffffff );
1028     var_buffer_add32( &buffer, 0x00 );
1029     var_buffer_add32( &buffer, 0x00 );
1030     var_buffer_add32( &buffer, 0x00 );
1031     var_buffer_add64( &buffer, 0x40ac200000000000 );
1032     var_buffer_add32( &buffer, p_access->i_header_packet_id_type );
1033     mms_CommandSend( p_input, 0x15, p_access->i_command_level, 0x00,
1034                      buffer.p_data, buffer.i_data );
1035
1036     /* *** wait for reponse *** */
1037     mms_CommandRead( p_input, 0x11, 0 );
1038
1039     if( p_access->i_command != 0x11 )
1040     {
1041         msg_Err( p_input,
1042                  "unknown answer (0x%x instead of 0x11)",
1043                  p_access->i_command );
1044         var_buffer_free( &buffer );
1045         MMSClose( p_input );
1046         return( -1 );
1047     }
1048     /* *** now read header packet *** */
1049     /* XXX could be split over multiples packets */
1050     for( ;; )
1051     {
1052         if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
1053         {
1054             msg_Err( p_input, "cannot receive header" );
1055             var_buffer_free( &buffer );
1056             MMSClose( p_input );
1057             return( -1 );
1058         }
1059         if( p_access->i_header >= p_access->i_header_size )
1060         {
1061             msg_Dbg( p_input,
1062                      "header complete(%d)",
1063                      p_access->i_header );
1064             break;
1065         }
1066         msg_Dbg( p_input,
1067                  "header incomplete (%d/%d), reading more",
1068                  p_access->i_header,
1069                  p_access->i_header_size );
1070     }
1071
1072     /* *** parse header and get stream and their id *** */
1073     /* get all streams properties,
1074      *
1075      * TODO : stream bitrates properties(optional)
1076      *        and bitrate mutual exclusion(optional) */
1077     asf_HeaderParse( p_access->stream,
1078                      p_access->p_header, p_access->i_header );
1079     mms_StreamSelect( p_input, p_access->stream );
1080     /* *** now select stream we want to receive *** */
1081     /* TODO take care of stream bitrate TODO */
1082     i_streams = 0;
1083     i_first = -1;
1084     var_buffer_reinitwrite( &buffer, 0 );
1085     /* for now, select first audio and video stream */
1086     for( i = 1; i < 128; i++ )
1087     {
1088
1089         if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN )
1090         {
1091             i_streams++;
1092             if( i_first != -1 )
1093             {
1094                 var_buffer_add16( &buffer, 0xffff );
1095                 var_buffer_add16( &buffer, i );
1096             }
1097             else
1098             {
1099                 i_first = i;
1100             }
1101             if( p_access->stream[i].i_selected )
1102             {
1103                 var_buffer_add16( &buffer, 0x0000 );
1104                 msg_Info( p_input,
1105                           "selecting stream[0x%x] %s (%d kb/s)",
1106                           i,
1107                           ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ?
1108                                                   "audio" : "video" ,
1109                           p_access->stream[i].i_bitrate / 1024);
1110             }
1111             else
1112             {
1113                 var_buffer_add16( &buffer, 0x0002 );
1114                 msg_Info( p_input,
1115                           "ignoring stream[0x%x] %s (%d kb/s)",
1116                           i,
1117                           ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ?
1118                                     "audio" : "video" ,
1119                           p_access->stream[i].i_bitrate / 1024);
1120
1121             }
1122         }
1123     }
1124
1125     if( i_streams == 0 )
1126     {
1127         msg_Err( p_input, "cannot find any stream" );
1128         var_buffer_free( &buffer );
1129         MMSClose( p_input );
1130         return( -1 );
1131     }
1132     mms_CommandSend( p_input, 0x33,
1133                      i_streams,
1134                      0xffff | ( i_first << 16 ),
1135                      buffer.p_data, buffer.i_data );
1136
1137     mms_CommandRead( p_input, 0x21, 0 );
1138     if( p_access->i_command != 0x21 )
1139     {
1140         msg_Err( p_input,
1141                  "unknown answer (0x%x instead of 0x21)",
1142                  p_access->i_command );
1143         var_buffer_free( &buffer );
1144         MMSClose( p_input );
1145         return( -1 );
1146     }
1147
1148
1149     var_buffer_free( &buffer );
1150
1151     msg_Info( p_input, "connection sucessful" );
1152
1153     return( 0 );
1154 }
1155
1156 /****************************************************************************
1157  * MMSStart : Start streaming
1158  ****************************************************************************/
1159 static int MMSStart  ( input_thread_t  *p_input, uint32_t i_packet )
1160 {
1161     access_t        *p_access = (access_t*)p_input->p_access_data;
1162     var_buffer_t    buffer;
1163
1164     /* *** start stream from packet 0 *** */
1165     var_buffer_initwrite( &buffer, 0 );
1166     var_buffer_add64( &buffer, 0 ); /* seek point in second */
1167     var_buffer_add32( &buffer, 0xffffffff );
1168     var_buffer_add32( &buffer, i_packet ); // begin from start
1169     var_buffer_add8( &buffer, 0xff ); // stream time limit
1170     var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
1171     var_buffer_add8( &buffer, 0xff ); //
1172     var_buffer_add8( &buffer, 0x00 ); // don't use limit
1173     var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
1174
1175     mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
1176                      buffer.p_data, buffer.i_data );
1177
1178     var_buffer_free( &buffer );
1179
1180     mms_CommandRead( p_input, 0x05, 0 );
1181
1182     if( p_access->i_command != 0x05 )
1183     {
1184         msg_Err( p_input,
1185                  "unknown answer (0x%x instead of 0x05)",
1186                  p_access->i_command );
1187         return( -1 );
1188     }
1189     else
1190     {
1191         /* get a packet */
1192         mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
1193         msg_Dbg( p_input, "Streaming started" );
1194         return( 0 );
1195     }
1196 }
1197
1198 /****************************************************************************
1199  * MMSStop : Stop streaming
1200  ****************************************************************************/
1201 static int MMSStop  ( input_thread_t  *p_input )
1202 {
1203     access_t        *p_access = (access_t*)p_input->p_access_data;
1204
1205     /* *** stop stream but keep connection alive *** */
1206     mms_CommandSend( p_input,
1207                      0x09,
1208                      p_access->i_command_level,
1209                      0x001fffff,
1210                      NULL, 0 );
1211     return( 0 );
1212 }
1213
1214 /****************************************************************************
1215  * MMSClose : Close streaming and connection
1216  ****************************************************************************/
1217 static int MMSClose  ( input_thread_t  *p_input )
1218 {
1219     access_t        *p_access = (access_t*)p_input->p_access_data;
1220
1221     msg_Dbg( p_input, "Connection closed" );
1222
1223     /* *** tell server that we will disconnect *** */
1224     mms_CommandSend( p_input,
1225                      0x0d,
1226                      p_access->i_command_level,
1227                      0x00000001,
1228                      NULL, 0 );
1229     /* *** close sockets *** */
1230 #if defined( UNDER_CE )
1231     CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
1232 #elif defined( WIN32 )
1233     closesocket( p_access->socket_tcp.i_handle );
1234 #else
1235     close( p_access->socket_tcp.i_handle );
1236 #endif
1237
1238     if( p_access->i_proto == MMS_PROTO_UDP )
1239     {
1240 #if defined( UNDER_CE )
1241         CloseHandle( (HANDLE)p_access->socket_udp.i_handle );
1242 #elif defined( WIN32 )
1243         closesocket( p_access->socket_udp.i_handle );
1244 #else
1245         close( p_access->socket_udp.i_handle );
1246 #endif
1247     }
1248
1249     FREE( p_access->p_cmd );
1250     FREE( p_access->p_media );
1251     FREE( p_access->p_header );
1252
1253     FREE( p_access->psz_server_version );
1254     FREE( p_access->psz_tool_version );
1255     FREE( p_access->psz_update_player_url );
1256     FREE( p_access->psz_encryption_type );
1257
1258     return( 0 );
1259 }
1260
1261 /*****************************************************************************
1262  * mms_ParseURL : parse an url string and fill an url_t
1263  *****************************************************************************/
1264 static void mms_ParseURL( url_t *p_url, char *psz_url )
1265 {
1266     char *psz_parser;
1267     char *psz_server_port;
1268
1269     p_url->psz_private = strdup( psz_url );
1270
1271     psz_parser = p_url->psz_private;
1272
1273     while( *psz_parser == '/' )
1274     {
1275         psz_parser++;
1276     }
1277     p_url->psz_server_addr = psz_parser;
1278
1279     while( *psz_parser &&
1280            *psz_parser != ':' &&  *psz_parser != '/' && *psz_parser != '@' )
1281     {
1282         psz_parser++;
1283     }
1284
1285     if( *psz_parser == ':' )
1286     {
1287         *psz_parser = '\0';
1288         psz_parser++;
1289         psz_server_port = psz_parser;
1290
1291         while( *psz_parser && *psz_parser != '/' )
1292         {
1293             psz_parser++;
1294         }
1295     }
1296     else
1297     {
1298         psz_server_port = "";
1299     }
1300
1301     if( *psz_parser == '@' )
1302     {
1303         char *psz_bind_port;
1304
1305         *psz_parser = '\0';
1306         psz_parser++;
1307
1308         p_url->psz_bind_addr = psz_parser;
1309
1310         while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
1311         {
1312             psz_parser++;
1313         }
1314
1315         if( *psz_parser == ':' )
1316         {
1317             *psz_parser = '\0';
1318             psz_parser++;
1319             psz_bind_port = psz_parser;
1320
1321             while( *psz_parser && *psz_parser != '/' )
1322             {
1323                 psz_parser++;
1324             }
1325         }
1326         else
1327         {
1328             psz_bind_port = "";
1329         }
1330         if( *psz_bind_port )
1331         {
1332             p_url->i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
1333         }
1334         else
1335         {
1336             p_url->i_bind_port = 0;
1337         }
1338     }
1339     else
1340     {
1341         p_url->psz_bind_addr = "";
1342         p_url->i_bind_port = 0;
1343     }
1344
1345     if( *psz_parser == '/' )
1346     {
1347         *psz_parser = '\0';
1348         psz_parser++;
1349         p_url->psz_path = psz_parser;
1350     }
1351
1352     if( *psz_server_port )
1353     {
1354         p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 );
1355     }
1356     else
1357     {
1358         p_url->i_server_port = 0;
1359     }
1360 }
1361
1362 /****************************************************************************
1363  *
1364  * MMS specific functions
1365  *
1366  ****************************************************************************/
1367
1368 static int mms_CommandSend( input_thread_t *p_input,
1369                              int i_command,
1370                              uint32_t i_prefix1, uint32_t i_prefix2,
1371                              uint8_t *p_data, int i_data )
1372 {
1373     var_buffer_t buffer;
1374
1375     access_t    *p_access = (access_t*)p_input->p_access_data;
1376     int i_data_by8;
1377
1378     i_data_by8 = ( i_data + 7 ) / 8;
1379
1380     /* first init uffer */
1381     var_buffer_initwrite( &buffer, 0 );
1382
1383     var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
1384     var_buffer_add32( &buffer, 0xB00BFACE );
1385     /* size after protocol type */
1386     var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
1387     var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
1388     var_buffer_add32( &buffer, i_data_by8 + 4 );
1389     var_buffer_add32( &buffer, p_access->i_seq_num ); p_access->i_seq_num++;
1390     var_buffer_add64( &buffer, 0 );
1391     var_buffer_add32( &buffer, i_data_by8 + 2 );
1392     var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
1393     var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
1394     var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
1395
1396     /* specific command data */
1397     if( p_data && i_data > 0 )
1398     {
1399         var_buffer_addmemory( &buffer, p_data, i_data );
1400     }
1401
1402     /* send it */
1403     if( send( p_access->socket_tcp.i_handle,
1404               buffer.p_data,
1405               buffer.i_data,
1406               0 ) == -1 )
1407     {
1408         msg_Err( p_input, "failed to send command" );
1409         return( -1 );
1410     }
1411
1412     var_buffer_free( &buffer );
1413     return( 0 );
1414 }
1415
1416 static int  NetFillBuffer( input_thread_t *p_input )
1417 {
1418 #ifdef UNDER_CE
1419     return -1;
1420 #else
1421     access_t    *p_access = (access_t*)p_input->p_access_data;
1422     struct timeval  timeout;
1423     fd_set          fds;
1424     int             i_ret;
1425
1426     /* FIXME when using udp */
1427     ssize_t i_tcp, i_udp;
1428     ssize_t i_tcp_read, i_udp_read;
1429     int i_handle_max;
1430
1431     /* Initialize file descriptor set */
1432     FD_ZERO( &fds );
1433
1434     i_tcp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_tcp;
1435
1436     if( p_access->i_proto == MMS_PROTO_UDP )
1437     {
1438         i_udp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_udp;
1439     }
1440     else
1441     {
1442         i_udp = 0;  /* there isn't udp socket */
1443     }
1444
1445     i_handle_max = 0;
1446     if( i_tcp > 0 )
1447     {
1448         FD_SET( p_access->socket_tcp.i_handle, &fds );
1449         i_handle_max = __MAX( i_handle_max, p_access->socket_tcp.i_handle );
1450     }
1451     if( i_udp > 0 )
1452     {
1453         FD_SET( p_access->socket_udp.i_handle, &fds );
1454         i_handle_max = __MAX( i_handle_max, p_access->socket_udp.i_handle );
1455     }
1456
1457     if( i_handle_max == 0 )
1458     {
1459         msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
1460         return( 0 );
1461     }
1462     else
1463     {
1464 //        msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
1465     }
1466
1467     /* We'll wait 0.5 second if nothing happens */
1468     timeout.tv_sec = 0;
1469     timeout.tv_usec = 500000;
1470
1471     /* Find if some data is available */
1472     while( (i_ret = select( i_handle_max + 1, &fds,
1473                             NULL, NULL, &timeout )) == 0
1474            || (i_ret < 0 && errno == EINTR) )
1475     {
1476         FD_ZERO( &fds );
1477         if( i_tcp > 0 ) FD_SET( p_access->socket_tcp.i_handle, &fds );
1478         if( i_udp > 0 ) FD_SET( p_access->socket_udp.i_handle, &fds );
1479         timeout.tv_sec = 0;
1480         timeout.tv_usec = 500000;
1481
1482         if( p_input->b_die || p_input->b_error )
1483         {
1484             return 0;
1485         }
1486     }
1487
1488     if( i_ret < 0 )
1489     {
1490         msg_Err( p_input, "network select error (%s)", strerror(errno) );
1491         return -1;
1492     }
1493
1494     if( i_tcp > 0 && FD_ISSET( p_access->socket_tcp.i_handle, &fds ) )
1495     {
1496         i_tcp_read =
1497             recv( p_access->socket_tcp.i_handle,
1498                   p_access->buffer_tcp + p_access->i_buffer_tcp,
1499                   i_tcp + MMS_BUFFER_SIZE/2, 0 );
1500     }
1501     else
1502     {
1503         i_tcp_read = 0;
1504     }
1505
1506     if( i_udp > 0 && FD_ISSET( p_access->socket_udp.i_handle, &fds ) )
1507     {
1508         i_udp_read = recv( p_access->socket_udp.i_handle,
1509                            p_access->buffer_udp + p_access->i_buffer_udp,
1510                            i_udp + MMS_BUFFER_SIZE/2, 0 );
1511     }
1512     else
1513     {
1514         i_udp_read = 0;
1515     }
1516
1517 #if MMS_DEBUG
1518     if( p_access->i_proto == MMS_PROTO_UDP )
1519     {
1520         msg_Dbg( p_input,
1521                  "filling buffer TCP:%d+%d UDP:%d+%d",
1522                  p_access->i_buffer_tcp,
1523                  i_tcp_read,
1524                  p_access->i_buffer_udp,
1525                  i_udp_read );
1526     }
1527     else
1528     {
1529         msg_Dbg( p_input,
1530                  "filling buffer TCP:%d+%d",
1531                  p_access->i_buffer_tcp,
1532                  i_tcp_read );
1533     }
1534 #endif
1535     if( i_tcp_read > 0 )
1536     {
1537         p_access->i_buffer_tcp += i_tcp_read;
1538     }
1539     if( i_udp_read > 0 )
1540     {
1541         p_access->i_buffer_udp += i_udp_read;
1542     }
1543
1544     return( i_tcp_read + i_udp_read);
1545 #endif
1546 }
1547
1548 static int  mms_ParseCommand( input_thread_t *p_input,
1549                               uint8_t *p_data,
1550                               int i_data,
1551                               int *pi_used )
1552 {
1553  #define GET32( i_pos ) \
1554     ( p_access->p_cmd[i_pos] + ( p_access->p_cmd[i_pos +1] << 8 ) + \
1555       ( p_access->p_cmd[i_pos + 2] << 16 ) + \
1556       ( p_access->p_cmd[i_pos + 3] << 24 ) )
1557
1558     access_t    *p_access = (access_t*)p_input->p_access_data;
1559     int         i_length;
1560     uint32_t    i_id;
1561
1562     if( p_access->p_cmd )
1563     {
1564         free( p_access->p_cmd );
1565     }
1566     p_access->i_cmd = i_data;
1567     p_access->p_cmd = malloc( i_data );
1568     memcpy( p_access->p_cmd, p_data, i_data );
1569
1570     *pi_used = i_data; /* by default */
1571
1572     if( i_data < MMS_CMD_HEADERSIZE )
1573     {
1574         msg_Warn( p_input, "truncated command (header incomplete)" );
1575         p_access->i_command = 0;
1576         return( -1 );
1577     }
1578     i_id =  GetDWLE( p_data + 4 );
1579     i_length = GetDWLE( p_data + 8 ) + 16;
1580
1581     if( i_id != 0xb00bface )
1582     {
1583         msg_Err( p_input,
1584                  "incorrect command header (0x%x)", i_id );
1585         p_access->i_command = 0;
1586         return( -1 );
1587     }
1588
1589     if( i_length > p_access->i_cmd )
1590     {
1591         msg_Warn( p_input,
1592                   "truncated command (missing %d bytes)",
1593                    i_length - i_data  );
1594         p_access->i_command = 0;
1595         return( -1 );
1596     }
1597     else if( i_length < p_access->i_cmd )
1598     {
1599         p_access->i_cmd = i_length;
1600         *pi_used = i_length;
1601     }
1602
1603     msg_Dbg( p_input,
1604              "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",
1605              GET32( 0 ),
1606              GET32( 4 ),
1607              GET32( 8 ),
1608              /* 12: protocol type "MMS " */
1609              GET32( 16 ),
1610              GET32( 20 ),
1611              /* 24: unknown (0) */
1612              /* 28: unknown (0) */
1613              GET32( 32 ),
1614              GET32( 36 )
1615              /* 40: switches */
1616              /* 44: extra */ );
1617
1618     p_access->i_command = GET32( 36 ) & 0xffff;
1619
1620     return( MMS_PACKET_CMD );
1621 }
1622
1623 static int  mms_ParsePacket( input_thread_t *p_input,
1624                              uint8_t *p_data, size_t i_data,
1625                              int *pi_used )
1626 {
1627     access_t    *p_access = (access_t*)p_input->p_access_data;
1628     int i_packet_seq_num;
1629     size_t i_packet_length;
1630     uint32_t i_packet_id;
1631
1632     uint8_t  *p_packet;
1633
1634
1635     *pi_used = i_data; /* default */
1636     if( i_data <= 8 )
1637     {
1638         msg_Warn( p_input, "truncated packet (header incomplete)" );
1639         return( -1 );
1640     }
1641
1642     i_packet_id = p_data[4];
1643     i_packet_seq_num = GetDWLE( p_data );
1644     i_packet_length = GetWLE( p_data + 6 );
1645
1646     //msg_Warn( p_input, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
1647
1648     if( i_packet_length > i_data || i_packet_length <= 8)
1649     {
1650         msg_Dbg( p_input,
1651                  "truncated packet (missing %d bytes)",
1652                  i_packet_length - i_data  );
1653         *pi_used = 0;
1654         return( -1 );
1655     }
1656     else if( i_packet_length < i_data )
1657     {
1658         *pi_used = i_packet_length;
1659     }
1660
1661     if( i_packet_id == 0xff )
1662     {
1663         msg_Warn( p_input,
1664                   "receive MMS UDP pair timing" );
1665         return( MMS_PACKET_UDP_TIMING );
1666     }
1667
1668     if( i_packet_id != p_access->i_header_packet_id_type &&
1669         i_packet_id != p_access->i_media_packet_id_type )
1670     {
1671         msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
1672         return( -1 );
1673     }
1674
1675     /* we now have a media or a header packet */
1676     p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
1677     memcpy( p_packet, p_data + 8, i_packet_length - 8 );
1678
1679     if( i_packet_seq_num != p_access->i_packet_seq_num )
1680     {
1681         /* FIXME for udp could be just wrong order ? */
1682         msg_Warn( p_input,
1683                   "detected packet lost (%d != %d)",
1684                   i_packet_seq_num,
1685                   p_access->i_packet_seq_num );
1686         p_access->i_packet_seq_num = i_packet_seq_num;
1687     }
1688     p_access->i_packet_seq_num++;
1689
1690     if( i_packet_id == p_access->i_header_packet_id_type )
1691     {
1692         if( p_access->p_header )
1693         {
1694             p_access->p_header = realloc( p_access->p_header,
1695                                           p_access->i_header + i_packet_length - 8 );
1696             memcpy( &p_access->p_header[p_access->i_header],
1697                     p_packet,
1698                     i_packet_length - 8 );
1699             p_access->i_header += i_packet_length - 8;
1700
1701             free( p_packet );
1702         }
1703         else
1704         {
1705             p_access->p_header = p_packet;
1706             p_access->i_header = i_packet_length - 8;
1707         }
1708 /*        msg_Dbg( p_input,
1709                  "receive header packet (%d bytes)",
1710                  i_packet_length - 8 ); */
1711
1712         return( MMS_PACKET_HEADER );
1713     }
1714     else
1715     {
1716         FREE( p_access->p_media );
1717         p_access->p_media = p_packet;
1718         p_access->i_media = i_packet_length - 8;
1719         p_access->i_media_used = 0;
1720 /*        msg_Dbg( p_input,
1721                  "receive media packet (%d bytes)",
1722                  i_packet_length - 8 ); */
1723
1724         return( MMS_PACKET_MEDIA );
1725     }
1726 }
1727
1728 static int mms_ReceivePacket( input_thread_t *p_input )
1729 {
1730     access_t    *p_access = (access_t*)p_input->p_access_data;
1731     int i_packet_tcp_type;
1732     int i_packet_udp_type;
1733
1734     for( ;; )
1735     {
1736         if( NetFillBuffer( p_input ) < 0 )
1737         {
1738             msg_Warn( p_input, "cannot fill buffer" );
1739             continue;
1740         }
1741
1742         i_packet_tcp_type = -1;
1743         i_packet_udp_type = -1;
1744
1745         if( p_access->i_buffer_tcp > 0 )
1746         {
1747             int i_used;
1748
1749             if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface )
1750             {
1751                 i_packet_tcp_type =
1752                     mms_ParseCommand( p_input,
1753                                       p_access->buffer_tcp,
1754                                       p_access->i_buffer_tcp,
1755                                       &i_used );
1756
1757             }
1758             else
1759             {
1760                 i_packet_tcp_type =
1761                     mms_ParsePacket( p_input,
1762                                      p_access->buffer_tcp,
1763                                      p_access->i_buffer_tcp,
1764                                      &i_used );
1765             }
1766             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1767             {
1768                 memmove( p_access->buffer_tcp,
1769                          p_access->buffer_tcp + i_used,
1770                          MMS_BUFFER_SIZE - i_used );
1771             }
1772             p_access->i_buffer_tcp -= i_used;
1773         }
1774         else if( p_access->i_buffer_udp > 0 )
1775         {
1776             int i_used;
1777
1778             i_packet_udp_type =
1779                 mms_ParsePacket( p_input,
1780                                  p_access->buffer_udp,
1781                                  p_access->i_buffer_udp,
1782                                  &i_used );
1783
1784             if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
1785             {
1786                 memmove( p_access->buffer_udp,
1787                          p_access->buffer_udp + i_used,
1788                          MMS_BUFFER_SIZE - i_used );
1789             }
1790             p_access->i_buffer_udp -= i_used;
1791         }
1792
1793         if( i_packet_tcp_type == MMS_PACKET_CMD &&
1794                 p_access->i_command == 0x1b )
1795         {
1796             mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1797             i_packet_tcp_type = -1;
1798         }
1799
1800         if( i_packet_tcp_type != -1 )
1801         {
1802             return( i_packet_tcp_type );
1803         }
1804         else if( i_packet_udp_type != -1 )
1805         {
1806             return( i_packet_udp_type );
1807         }
1808
1809     }
1810 }
1811
1812 static int  mms_ReceiveCommand( input_thread_t *p_input )
1813 {
1814     access_t    *p_access = (access_t*)p_input->p_access_data;
1815
1816     for( ;; )
1817     {
1818         int i_used;
1819         int i_status;
1820
1821         if( NetFillBuffer( p_input ) < 0 )
1822         {
1823             msg_Warn( p_input, "cannot fill buffer" );
1824             continue;
1825         }
1826         if( p_access->i_buffer_tcp > 0 )
1827         {
1828             i_status = mms_ParseCommand( p_input,
1829                                   p_access->buffer_tcp,
1830                                   p_access->i_buffer_tcp,
1831                                   &i_used );
1832             if( i_used < MMS_BUFFER_SIZE )
1833             {
1834                 memmove( p_access->buffer_tcp,
1835                          p_access->buffer_tcp + i_used,
1836                          MMS_BUFFER_SIZE - i_used );
1837             }
1838             p_access->i_buffer_tcp -= i_used;
1839
1840             if( i_status < 0 )
1841             {
1842                 return( -1 );
1843             }
1844
1845             if( p_access->i_command == 0x1b )
1846             {
1847                 mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1848             }
1849             else
1850             {
1851                 break;
1852             }
1853         }
1854         else
1855         {
1856             return( -1 );
1857         }
1858     }
1859
1860     return( 0 );
1861 }
1862
1863 #define MMS_RETRY_MAX       10
1864 #define MMS_RETRY_SLEEP     50000
1865
1866 static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
1867 {
1868     access_t    *p_access = (access_t*)p_input->p_access_data;
1869     int i_count;
1870     int i_status;
1871
1872     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1873     {
1874
1875         i_status = mms_ReceiveCommand( p_input );
1876         if( i_status < 0 || p_access->i_command == 0 )
1877         {
1878             i_count++;
1879             msleep( MMS_RETRY_SLEEP );
1880         }
1881         else if( i_command1 == 0 && i_command2 == 0)
1882         {
1883             return( 0 );
1884         }
1885         else if( p_access->i_command == i_command1 || p_access->i_command == i_command2 )
1886         {
1887             return( 0 );
1888         }
1889         else
1890         {
1891             switch( p_access->i_command )
1892             {
1893                 case 0x03:
1894                     msg_Warn( p_input, "socket closed by server" );
1895                     p_access->i_eos = 1;
1896                     return( -1 );
1897                 case 0x1e:
1898                     msg_Warn( p_input, "end of media stream" );
1899                     p_access->i_eos = 1;
1900                     return( -1 );
1901                 default:
1902                     break;
1903             }
1904         }
1905     }
1906     msg_Warn( p_input, "failed to receive command (abording)" );
1907
1908     return( -1 );
1909 }
1910
1911
1912 static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
1913 {
1914     access_t    *p_access = (access_t*)p_input->p_access_data;
1915     int         i_count;
1916
1917     for( i_count = 0; i_count < MMS_RETRY_MAX; )
1918     {
1919         int i_status;
1920
1921         i_status = mms_ReceivePacket( p_input );
1922         if( i_status < 0 )
1923         {
1924             i_count++;
1925             msg_Warn( p_input,
1926                       "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
1927             msleep( MMS_RETRY_SLEEP );
1928         }
1929         else if( i_status == i_type || i_type == MMS_PACKET_ANY )
1930         {
1931             return( i_type );
1932         }
1933         else if( i_status == MMS_PACKET_CMD )
1934         {
1935             switch( p_access->i_command )
1936             {
1937                 case 0x03:
1938                     msg_Warn( p_input, "socket closed by server" );
1939                     p_access->i_eos = 1;
1940                     return( -1 );
1941                 case 0x1e:
1942                     msg_Warn( p_input, "end of media stream" );
1943                     p_access->i_eos = 1;
1944                     return( -1 );
1945                 case 0x20:
1946                     /* XXX not too dificult to be done EXCEPT that we
1947                      * need to restart demuxer... and I don't see how we
1948                      * could do that :p */
1949                     msg_Err( p_input,
1950                              "reinitialization needed --> unsupported" );
1951                     p_access->i_eos = 1;
1952                     return( -1 );
1953                 default:
1954                     break;
1955             }
1956         }
1957     }
1958     msg_Err( p_input,
1959              "cannot receive %s (abording)",
1960                ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
1961     return( -1 );
1962 }
1963