1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_access.h>
34 #include <vlc_strings.h>
35 #include <vlc_input.h>
37 #include <vlc_network.h>
39 #include <vlc_memstream.h>
51 /*****************************************************************************
53 *****************************************************************************/
54 int MMSHOpen ( stream_t
* );
55 void MMSHClose ( stream_t
* );
57 static block_t
*Block( stream_t
*p_access
, bool * );
58 static int Seek( stream_t
*, uint64_t );
59 static int Control( stream_t
*, int, va_list );
61 static int Describe( stream_t
*, char **ppsz_location
);
62 static int Start( stream_t
*, uint64_t );
63 static void Stop( stream_t
* );
65 static int GetPacket( stream_t
*, chunk_t
* );
66 static void GetHeader( stream_t
*p_access
, int i_content_length
);
68 static int Restart( stream_t
* );
69 static int Reset( stream_t
* );
71 //#define MMSH_USER_AGENT "NSPlayer/4.1.0.3856"
72 #define MMSH_USER_AGENT "NSPlayer/7.10.0.3059"
74 /****************************************************************************
75 * Open: connect to ftp server and ask for file
76 ****************************************************************************/
77 int MMSHOpen( stream_t
*p_access
)
79 access_sys_t
*p_sys
= calloc( 1, sizeof( *p_sys
) );
80 char *psz_location
= NULL
;
82 if( unlikely(p_sys
== NULL
) )
85 p_access
->p_sys
= p_sys
;
86 p_sys
->i_proto
= MMS_PROTO_HTTP
;
88 p_sys
->i_position
= 0;
91 p_sys
->b_proxy
= false;
94 char *psz_proxy
= vlc_getProxyUrl( p_access
->psz_url
);
95 if( psz_proxy
!= NULL
)
97 p_sys
->b_proxy
= true;
98 vlc_UrlParse( &p_sys
->proxy
, psz_proxy
);
101 if( ( p_sys
->proxy
.psz_host
== NULL
) ||
102 ( *p_sys
->proxy
.psz_host
== '\0' ) )
104 msg_Warn( p_access
, "invalid proxy host" );
105 vlc_UrlClean( &p_sys
->proxy
);
110 if( p_sys
->proxy
.i_port
<= 0 )
111 p_sys
->proxy
.i_port
= 80;
112 msg_Dbg( p_access
, "Using http proxy %s:%d",
113 p_sys
->proxy
.psz_host
, p_sys
->proxy
.i_port
);
116 /* open a tcp connection */
117 vlc_UrlParse( &p_sys
->url
, p_access
->psz_url
);
118 if( ( p_sys
->url
.psz_host
== NULL
) ||
119 ( *p_sys
->url
.psz_host
== '\0' ) )
121 msg_Err( p_access
, "invalid host" );
124 if( p_sys
->url
.i_port
<= 0 )
125 p_sys
->url
.i_port
= 80;
127 if( Describe( p_access
, &psz_location
) )
130 /* Handle redirection */
131 if( psz_location
!= NULL
)
133 msg_Dbg( p_access
, "redirection to %s", psz_location
);
134 p_access
->psz_url
= psz_location
;
136 vlc_UrlClean( &p_sys
->url
);
137 vlc_UrlClean( &p_sys
->proxy
);
139 return VLC_ACCESS_REDIRECT
;
143 if( Start( p_access
, 0 ) )
145 msg_Err( p_access
, "cannot start stream" );
146 free( p_sys
->p_header
);
150 ACCESS_SET_CALLBACKS( NULL
, Block
, Control
, Seek
);
155 vlc_UrlClean( &p_sys
->proxy
);
156 vlc_UrlClean( &p_sys
->url
);
161 /*****************************************************************************
162 * Close: free unused data structures
163 *****************************************************************************/
164 void MMSHClose ( stream_t
*p_access
)
166 access_sys_t
*p_sys
= p_access
->p_sys
;
170 free( p_sys
->p_header
);
173 vlc_UrlClean( &p_sys
->proxy
);
174 vlc_UrlClean( &p_sys
->url
);
178 /*****************************************************************************
180 *****************************************************************************/
181 static int Control( stream_t
*p_access
, int i_query
, va_list args
)
183 access_sys_t
*p_sys
= p_access
->p_sys
;
191 case STREAM_CAN_SEEK
:
192 pb_bool
= va_arg( args
, bool * );
193 *pb_bool
= !p_sys
->b_broadcast
;
196 case STREAM_CAN_FASTSEEK
:
197 pb_bool
= va_arg( args
, bool * );
201 case STREAM_CAN_PAUSE
:
202 case STREAM_CAN_CONTROL_PACE
:
203 pb_bool
= va_arg( args
, bool * );
207 case STREAM_GET_SIZE
:
209 uint64_t *s
= va_arg( args
, uint64_t * );
210 if (p_sys
->b_broadcast
)
212 *s
= p_sys
->asfh
.i_file_size
;
216 case STREAM_GET_PTS_DELAY
:
217 pi_64
= va_arg( args
, int64_t * );
218 *pi_64
= INT64_C(1000)
219 * var_InheritInteger( p_access
, "network-caching" );
222 case STREAM_GET_PRIVATE_ID_STATE
:
223 i_int
= va_arg( args
, int );
224 pb_bool
= va_arg( args
, bool * );
226 if( (i_int
< 0) || (i_int
> 127) )
228 *pb_bool
= p_sys
->asfh
.stream
[i_int
].i_selected
? true : false;
231 case STREAM_SET_PRIVATE_ID_STATE
:
233 i_int
= va_arg( args
, int );
234 b_bool
= (bool)va_arg( args
, int );
238 else if ( i_int
< 0 )
240 /* Deselecting all ES in this category */
243 if ( i_cat
> ES_CATEGORY_COUNT
)
248 /* Chose another ES */
250 i_cat
= p_sys
->asfh
.stream
[i_int
].i_cat
;
253 for ( int i
=0; i
< 128; i
++ )
255 /* First unselect all streams from the same cat */
256 if ( i_cat
== p_sys
->asfh
.stream
[i
].i_cat
)
257 p_sys
->asfh
.stream
[i
].i_selected
= false;
261 p_sys
->asfh
.stream
[i_int
].i_selected
= true;
264 Seek( p_access
, p_sys
->i_position
);
268 case STREAM_SET_PAUSE_STATE
:
269 b_bool
= (bool)va_arg( args
, int );
273 Seek( p_access
, p_sys
->i_position
);
282 /*****************************************************************************
283 * Seek: try to go at the right place
284 *****************************************************************************/
285 static int Seek( stream_t
*p_access
, uint64_t i_pos
)
287 access_sys_t
*p_sys
= p_access
->p_sys
;
292 msg_Dbg( p_access
, "seeking to %"PRId64
, i_pos
);
294 i_packet
= ( i_pos
- p_sys
->i_header
) / p_sys
->asfh
.i_min_data_packet_size
;
295 i_offset
= ( i_pos
- p_sys
->i_header
) % p_sys
->asfh
.i_min_data_packet_size
;
298 Start( p_access
, i_packet
* p_sys
->asfh
.i_min_data_packet_size
);
302 if( GetPacket( p_access
, &ck
) )
306 if( ck
.i_type
!= 0x4824 )
309 msg_Warn( p_access
, "skipping header" );
312 p_sys
->i_position
= i_pos
;
313 p_sys
->i_packet_used
+= i_offset
;
318 /*****************************************************************************
320 *****************************************************************************/
321 static block_t
*Block( stream_t
*p_access
, bool *restrict eof
)
323 access_sys_t
*p_sys
= p_access
->p_sys
;
324 const unsigned i_packet_min
= p_sys
->asfh
.i_min_data_packet_size
;
326 if( p_sys
->i_position
< p_sys
->i_start
+ p_sys
->i_header
)
328 const size_t i_offset
= p_sys
->i_position
- p_sys
->i_start
;
329 const size_t i_copy
= p_sys
->i_header
- i_offset
;
331 block_t
*p_block
= block_Alloc( i_copy
);
335 memcpy( p_block
->p_buffer
, &p_sys
->p_header
[i_offset
], i_copy
);
336 p_sys
->i_position
+= i_copy
;
339 else if( p_sys
->i_packet_length
> 0 &&
340 p_sys
->i_packet_used
< __MAX( p_sys
->i_packet_length
, i_packet_min
) )
343 size_t i_padding
= 0;
345 if( p_sys
->i_packet_used
< p_sys
->i_packet_length
)
346 i_copy
= p_sys
->i_packet_length
- p_sys
->i_packet_used
;
347 if( __MAX( p_sys
->i_packet_used
, p_sys
->i_packet_length
) < i_packet_min
)
348 i_padding
= i_packet_min
- __MAX( p_sys
->i_packet_used
, p_sys
->i_packet_length
);
350 block_t
*p_block
= block_Alloc( i_copy
+ i_padding
);
355 memcpy( &p_block
->p_buffer
[0], &p_sys
->p_packet
[p_sys
->i_packet_used
], i_copy
);
357 memset( &p_block
->p_buffer
[i_copy
], 0, i_padding
);
359 p_sys
->i_packet_used
+= i_copy
+ i_padding
;
360 p_sys
->i_position
+= i_copy
+ i_padding
;
366 if( GetPacket( p_access
, &ck
) )
369 if( p_sys
->b_broadcast
)
371 if( (ck
.i_type
== 0x4524) && (ck
.i_sequence
!= 0) )
372 i_ret
= Restart( p_access
);
373 else if( ck
.i_type
== 0x4324 )
374 i_ret
= Reset( p_access
);
382 if( ck
.i_type
!= 0x4424 )
384 p_sys
->i_packet_used
= 0;
385 p_sys
->i_packet_length
= 0;
392 static int Restart( stream_t
*p_access
)
394 access_sys_t
*p_sys
= p_access
->p_sys
;
395 char *psz_location
= NULL
;
397 msg_Dbg( p_access
, "Restart the stream" );
398 p_sys
->i_start
= p_sys
->i_position
;
401 msg_Dbg( p_access
, "stopping the stream" );
405 msg_Dbg( p_access
, "describe the stream" );
406 if( Describe( p_access
, &psz_location
) )
408 msg_Err( p_access
, "describe failed" );
411 free( psz_location
);
414 if( Start( p_access
, 0 ) )
416 msg_Err( p_access
, "Start failed" );
421 static int Reset( stream_t
*p_access
)
423 access_sys_t
*p_sys
= p_access
->p_sys
;
424 asf_header_t old_asfh
= p_sys
->asfh
;
427 msg_Dbg( p_access
, "Reset the stream" );
428 p_sys
->i_start
= p_sys
->i_position
;
431 p_sys
->i_packet_sequence
= 0;
432 p_sys
->i_packet_used
= 0;
433 p_sys
->i_packet_length
= 0;
434 p_sys
->p_packet
= NULL
;
436 /* Get the next header FIXME memory loss ? */
437 GetHeader( p_access
, -1 );
438 if( p_sys
->i_header
<= 0 )
441 asf_HeaderParse ( &p_sys
->asfh
,
442 p_sys
->p_header
, p_sys
->i_header
);
443 msg_Dbg( p_access
, "packet count=%"PRId64
" packet size=%d",
444 p_sys
->asfh
.i_data_packets_count
,
445 p_sys
->asfh
.i_min_data_packet_size
);
447 asf_StreamSelect( &p_sys
->asfh
,
448 var_InheritInteger( p_access
, "mms-maxbitrate" ),
449 var_InheritBool( p_access
, "mms-all" ),
450 var_InheritBool( p_access
, "audio" ),
451 var_InheritBool( p_access
, "video" ) );
453 /* Check we have comptible asfh */
454 for( i
= 1; i
< 128; i
++ )
456 asf_stream_t
*p_old
= &old_asfh
.stream
[i
];
457 asf_stream_t
*p_new
= &p_sys
->asfh
.stream
[i
];
459 if( p_old
->i_cat
!= p_new
->i_cat
|| p_old
->i_selected
!= p_new
->i_selected
)
464 msg_Warn( p_access
, "incompatible asf header, restart" );
465 return Restart( p_access
);
469 p_sys
->i_packet_used
= 0;
470 p_sys
->i_packet_length
= 0;
474 static void WriteRequestLine( const access_sys_t
*sys
,
475 struct vlc_memstream
*restrict stream
)
477 vlc_memstream_open( stream
);
479 vlc_memstream_puts( stream
, "GET " );
481 vlc_memstream_printf( stream
, "http://%s:%d", sys
->url
.psz_host
,
483 if( (sys
->url
.psz_path
== NULL
) || (sys
->url
.psz_path
[0] == '\0') )
484 vlc_memstream_putc( stream
, '/' );
486 vlc_memstream_puts( stream
, sys
->url
.psz_path
);
487 if( sys
->url
.psz_option
!= NULL
)
488 vlc_memstream_printf( stream
, "?%s", sys
->url
.psz_option
);
489 vlc_memstream_puts( stream
, " HTTP/1.0\r\n" );
491 vlc_memstream_printf( stream
, "Host: %s:%d\r\n", sys
->url
.psz_host
,
494 /* Proxy Authentication */
495 const vlc_url_t
*proxy
= &sys
->proxy
;
497 if( sys
->b_proxy
&& proxy
->psz_username
!= NULL
)
499 const char *pw
= proxy
->psz_password
? proxy
->psz_password
: "";
502 if( asprintf( &buf
, "%s:%s", proxy
->psz_username
, pw
) != -1 )
504 char *b64
= vlc_b64_encode( buf
);
508 vlc_memstream_printf( stream
, "Proxy-Authorization: "
509 "Basic %s\r\n", b64
);
515 vlc_memstream_puts( stream
, "Accept: */*\r\n" );
516 vlc_memstream_printf( stream
, "User-Agent: %s\r\n", MMSH_USER_AGENT
);
519 static int OpenConnection( stream_t
*p_access
,
520 struct vlc_memstream
*restrict stream
)
522 access_sys_t
*p_sys
= p_access
->p_sys
;
523 const vlc_url_t
*srv
= p_sys
->b_proxy
? &p_sys
->proxy
: &p_sys
->url
;
525 /* XXX: This is useless: HTTP/1.0 closes connection by default */
526 vlc_memstream_puts( stream
, "Connection: Close\r\n" );
528 vlc_memstream_puts( stream
, "\r\n" ); /* end of HTTP request header */
530 if( vlc_memstream_close( stream
) )
533 int fd
= net_ConnectTCP( p_access
, srv
->psz_host
, srv
->i_port
);
540 msg_Dbg( p_access
, "sending request:\n%s", stream
->ptr
);
542 ssize_t val
= net_Write( p_access
, fd
, stream
->ptr
, stream
->length
);
544 if( val
< (ssize_t
)stream
->length
)
546 msg_Err( p_access
, "failed to send request" );
552 return (fd
>= 0) ? VLC_SUCCESS
: VLC_EGENERIC
;
555 /*****************************************************************************
557 *****************************************************************************/
558 static int Describe( stream_t
*p_access
, char **ppsz_location
)
560 access_sys_t
*p_sys
= p_access
->p_sys
;
561 char *psz_location
= NULL
;
562 int i_content_length
= -1;
563 bool b_keepalive
= false;
565 struct vlc_memstream stream
;
568 p_sys
->b_broadcast
= true;
569 p_sys
->i_request_context
= 1;
570 p_sys
->i_packet_sequence
= 0;
571 p_sys
->i_packet_used
= 0;
572 p_sys
->i_packet_length
= 0;
573 p_sys
->p_packet
= NULL
;
575 GenerateGuid ( &p_sys
->guid
);
577 WriteRequestLine( p_sys
, &stream
);
579 vlc_memstream_printf( &stream
, "Pragma: no-cache,rate=1.000000,"
580 "stream-time=0,stream-offset=0:0,"
581 "request-context=%d,max-duration=0\r\n",
582 p_sys
->i_request_context
++ );
583 vlc_memstream_printf( &stream
, "Pragma: xClientGUID={"GUID_FMT
"}\r\n",
584 GUID_PRINT(p_sys
->guid
) );
586 if( OpenConnection( p_access
, &stream
) )
589 /* Receive the http header */
590 char *psz
= net_Gets( p_access
, p_sys
->fd
);
593 msg_Err( p_access
, "failed to read answer" );
597 if( strncmp( psz
, "HTTP/1.", 7 ) )
599 msg_Err( p_access
, "invalid HTTP reply '%s'", psz
);
603 i_code
= atoi( &psz
[9] );
606 msg_Err( p_access
, "error: %s", psz
);
611 msg_Dbg( p_access
, "HTTP reply '%s'", psz
);
615 psz
= net_Gets( p_access
, p_sys
->fd
);
619 msg_Err( p_access
, "failed to read answer" );
620 free( psz_location
);
630 char *p
= strchr( psz
, ':' );
633 msg_Err( p_access
, "malformed header line: %s", psz
);
635 free( psz_location
);
639 while( *p
== ' ' ) p
++;
641 /* FIXME FIXME test Content-Type to see if it's a plain stream or an
643 if( !strcasecmp( psz
, "Pragma" ) )
645 if( strstr( p
, "features" ) )
647 /* FIXME, it is a bit badly done here ..... */
648 if( strstr( p
, "broadcast" ) )
650 msg_Dbg( p_access
, "stream type = broadcast" );
651 p_sys
->b_broadcast
= true;
653 else if( strstr( p
, "seekable" ) )
655 msg_Dbg( p_access
, "stream type = seekable" );
656 p_sys
->b_broadcast
= false;
660 msg_Warn( p_access
, "unknown stream types (%s)", p
);
661 p_sys
->b_broadcast
= false;
665 else if( !strcasecmp( psz
, "Location" ) )
667 free( psz_location
);
668 psz_location
= vlc_uri_resolve( p_access
->psz_url
, p
);
670 else if( !strcasecmp( psz
, "Content-Length" ) )
672 i_content_length
= atoi( p
);
673 msg_Dbg( p_access
, "content-length = %d", i_content_length
);
675 else if( !strcasecmp( psz
, "Connection" ) )
677 if( strcasestr( p
, "Keep-Alive" ) )
679 msg_Dbg( p_access
, "Keep-Alive header found" );
688 /* Handle the redirection */
689 if( ( (i_code
== 301) || (i_code
== 302) ||
690 (i_code
== 303) || (i_code
== 307) ) &&
693 msg_Dbg( p_access
, "redirection to %s", psz_location
);
694 net_Close( p_sys
->fd
); p_sys
->fd
= -1;
696 *ppsz_location
= psz_location
;
699 free( psz_location
);
701 /* Read the asf header */
702 GetHeader( p_access
, b_keepalive
? i_content_length
: -1);
703 if( p_sys
->i_header
<= 0 )
705 msg_Err( p_access
, "header size == 0" );
708 /* close this connection */
709 net_Close( p_sys
->fd
);
712 /* *** parse header and get stream and their id *** */
713 /* get all streams properties,
715 * TODO : stream bitrates properties(optional)
716 * and bitrate mutual exclusion(optional) */
717 asf_HeaderParse ( &p_sys
->asfh
,
718 p_sys
->p_header
, p_sys
->i_header
);
719 msg_Dbg( p_access
, "packet count=%"PRId64
" packet size=%d",
720 p_sys
->asfh
.i_data_packets_count
,
721 p_sys
->asfh
.i_min_data_packet_size
);
723 if( p_sys
->asfh
.i_min_data_packet_size
<= 0 )
726 asf_StreamSelect( &p_sys
->asfh
,
727 var_InheritInteger( p_access
, "mms-maxbitrate" ),
728 var_InheritBool( p_access
, "mms-all" ),
729 var_InheritBool( p_access
, "audio" ),
730 var_InheritBool( p_access
, "video" ) );
736 net_Close( p_sys
->fd
);
742 static void GetHeader( stream_t
*p_access
, int i_content_length
)
744 access_sys_t
*p_sys
= p_access
->p_sys
;
745 int i_read_content
= 0;
747 /* Read the asf header */
749 free( p_sys
->p_header
);
750 p_sys
->p_header
= NULL
;
754 if( (i_content_length
>= 0 && i_read_content
>= i_content_length
) || GetPacket( p_access
, &ck
) || ck
.i_type
!= 0x4824 )
757 i_read_content
+= (4+ck
.i_size
);
761 p_sys
->i_header
+= ck
.i_data
;
762 p_sys
->p_header
= xrealloc( p_sys
->p_header
, p_sys
->i_header
);
763 memcpy( &p_sys
->p_header
[p_sys
->i_header
- ck
.i_data
],
764 ck
.p_data
, ck
.i_data
);
767 msg_Dbg( p_access
, "complete header size=%d", p_sys
->i_header
);
771 /*****************************************************************************
773 ****************************************************************************/
774 static int Start( stream_t
*p_access
, uint64_t i_pos
)
776 access_sys_t
*p_sys
= p_access
->p_sys
;
778 int i_streams_selected
= 0;
779 struct vlc_memstream stream
;
781 msg_Dbg( p_access
, "starting stream" );
783 for( unsigned i
= 1; i
< 128; i
++ )
785 if( p_sys
->asfh
.stream
[i
].i_cat
== ASF_CODEC_TYPE_UNKNOWN
)
788 if( p_sys
->asfh
.stream
[i
].i_selected
)
789 i_streams_selected
++;
791 if( i_streams_selected
<= 0 )
793 msg_Err( p_access
, "no stream selected" );
797 WriteRequestLine( p_sys
, &stream
);
799 vlc_memstream_puts( &stream
, "Pragma: no-cache,rate=1.000000" );
800 if( !p_sys
->b_broadcast
)
801 vlc_memstream_printf( &stream
, ",stream-time=0,stream-offset="
802 "%"PRIu32
":%"PRIu32
, (uint32_t)(i_pos
>> 32),
804 vlc_memstream_printf( &stream
, ",request-context=%d",
805 p_sys
->i_request_context
++ );
806 if( !p_sys
->b_broadcast
)
807 vlc_memstream_puts( &stream
, ",max-duration=0" );
808 vlc_memstream_puts( &stream
, "\r\n" );
810 vlc_memstream_puts( &stream
, "Pragma: xPlayStrm=1\r\n" );
811 vlc_memstream_printf( &stream
, "Pragma: xClientGUID={"GUID_FMT
"}\r\n",
812 GUID_PRINT(p_sys
->guid
) );
813 vlc_memstream_printf( &stream
, "Pragma: stream-switch-count=%d\r\n",
816 vlc_memstream_puts( &stream
, "Pragma: stream-switch-entry=" );
817 for( unsigned i
= 1; i
< 128; i
++ )
819 if( p_sys
->asfh
.stream
[i
].i_cat
!= ASF_CODEC_TYPE_UNKNOWN
)
821 int i_select
= p_sys
->asfh
.stream
[i
].i_selected
? 0 : 2;
822 vlc_memstream_printf( &stream
, "ffff:%x:%d ", i
, i_select
);
825 vlc_memstream_puts( &stream
, "\r\n" );
827 if( OpenConnection( p_access
, &stream
) )
830 char *psz
= net_Gets( p_access
, p_sys
->fd
);
833 msg_Err( p_access
, "cannot read data 0" );
837 if( atoi( &psz
[9] ) >= 400 )
839 msg_Err( p_access
, "error: %s", psz
);
843 msg_Dbg( p_access
, "HTTP reply '%s'", psz
);
846 /* FIXME check HTTP code */
849 psz
= net_Gets( p_access
, p_sys
->fd
);
852 msg_Err( p_access
, "cannot read data 1" );
860 msg_Dbg( p_access
, "%s", psz
);
864 p_sys
->i_packet_used
= 0;
865 p_sys
->i_packet_length
= 0;
870 /*****************************************************************************
872 *****************************************************************************/
873 static void Stop( stream_t
*p_access
)
875 access_sys_t
*p_sys
= p_access
->p_sys
;
877 msg_Dbg( p_access
, "closing stream" );
880 net_Close( p_sys
->fd
);
885 /*****************************************************************************
887 *****************************************************************************/
888 static int GetPacket( stream_t
* p_access
, chunk_t
*p_ck
)
890 access_sys_t
*p_sys
= p_access
->p_sys
;
894 memset( p_ck
, 0, sizeof( chunk_t
) );
896 /* Read the chunk header */
897 /* Some headers are short, like 0x4324. Reading 12 bytes will cause us
898 * to lose synchronization with the stream. Just read to the length
899 * (4 bytes), decode and then read up to 8 additional bytes to get the
902 if( net_Read( p_access
, p_sys
->fd
, p_sys
->buffer
, 4 ) < 4 )
904 msg_Err( p_access
, "cannot read data 2" );
908 p_ck
->i_type
= GetWLE( p_sys
->buffer
);
909 p_ck
->i_size
= GetWLE( p_sys
->buffer
+ 2);
911 restsize
= p_ck
->i_size
;
915 if( net_Read( p_access
, p_sys
->fd
, p_sys
->buffer
+ 4, restsize
) < restsize
)
917 msg_Err( p_access
, "cannot read data 3" );
920 p_ck
->i_sequence
= GetDWLE( p_sys
->buffer
+ 4);
921 p_ck
->i_unknown
= GetWLE( p_sys
->buffer
+ 8);
923 /* Set i_size2 to 8 if this header was short, since a real value won't be
924 * present in the buffer. Using 8 avoid reading additional data for the
930 p_ck
->i_size2
= GetWLE( p_sys
->buffer
+ 10);
932 p_ck
->p_data
= p_sys
->buffer
+ 12;
933 p_ck
->i_data
= p_ck
->i_size2
- 8;
935 if( p_ck
->i_type
== 0x4524 ) // $E (End-of-Stream Notification) Packet
937 if( p_ck
->i_sequence
== 0 )
939 msg_Warn( p_access
, "EOF" );
944 msg_Warn( p_access
, "next stream following" );
948 else if( p_ck
->i_type
== 0x4324 ) // $C (Stream Change Notification) Packet
950 /* 0x4324 is CHUNK_TYPE_RESET: a new stream will follow with a sequence of 0 */
951 msg_Warn( p_access
, "next stream following (reset) seq=%d", p_ck
->i_sequence
);
954 else if( (p_ck
->i_type
!= 0x4824) && (p_ck
->i_type
!= 0x4424) )
956 /* Unsupported so far:
957 * $M (Metadata) Packet 0x4D24
958 * $P (Packet-Pair) Packet 0x5024
959 * $T (Test Data Notification) Packet 0x5424
961 msg_Err( p_access
, "unrecognized chunk FATAL (0x%x)", p_ck
->i_type
);
965 if( (p_ck
->i_data
> 0) &&
966 (net_Read( p_access
, p_sys
->fd
, &p_sys
->buffer
[12],
967 p_ck
->i_data
) < p_ck
->i_data
) )
969 msg_Err( p_access
, "cannot read data 4" );
974 if( (p_sys
->i_packet_sequence
!= 0) &&
975 (p_ck
->i_sequence
!= p_sys
->i_packet_sequence
) )
977 msg_Warn( p_access
, "packet lost ? (%d != %d)", p_ck
->i_sequence
, p_sys
->i_packet_sequence
);
981 p_sys
->i_packet_sequence
= p_ck
->i_sequence
+ 1;
982 p_sys
->i_packet_used
= 0;
983 p_sys
->i_packet_length
= p_ck
->i_data
;
984 p_sys
->p_packet
= p_ck
->p_data
;