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