1 /*****************************************************************************
2 * ac3_spdif.c: ac3 pass-through to external decoder with enabled soundcard
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: ac3_spdif.c,v 1.12 2001/09/30 20:25:13 bozo Exp $
7 * Authors: Stéphane Borel <stef@via.ecp.fr>
8 * Juha Yrjola <jyrjola@cc.hut.fi>
9 * German Gomez Garcia <german@piraos.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
33 #include <string.h> /* memcpy() */
45 #include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
47 #include "stream_control.h"
48 #include "input_ext-dec.h"
50 #include "audio_output.h"
52 #include "ac3_spdif.h"
53 #include "ac3_iec958.h"
57 /****************************************************************************
59 ****************************************************************************/
60 static int InitThread ( ac3_spdif_thread_t * );
61 static void RunThread ( ac3_spdif_thread_t * );
62 static void ErrorThread ( ac3_spdif_thread_t * );
63 static void EndThread ( ac3_spdif_thread_t * );
64 static void BitstreamCallback( bit_stream_t *, boolean_t );
66 /****************************************************************************
67 * spdif_CreateThread: initialize the spdif thread
68 ****************************************************************************/
69 vlc_thread_t spdif_CreateThread( adec_config_t * p_config )
71 ac3_spdif_thread_t * p_spdif;
73 intf_DbgMsg( "spdif debug: creating ac3 pass-through thread" );
75 /* Allocate the memory needed to store the thread's structure */
76 p_spdif = malloc( sizeof(ac3_spdif_thread_t) );
80 intf_ErrMsg ( "spdif error: not enough memory "
81 "for spdif_CreateThread() to create the new thread");
85 /* Temporary buffer to store ac3 frames to be transformed */
86 p_spdif->p_ac3 = malloc( SPDIF_FRAME_SIZE );
88 if( p_spdif->p_ac3 == NULL )
90 free( p_spdif->p_ac3 );
95 * Initialize the thread properties
97 p_spdif->p_config = p_config;
98 p_spdif->p_fifo = p_config->decoder_config.p_decoder_fifo;
100 p_spdif->p_aout_fifo = NULL;
102 /* Spawn the ac3 to spdif thread */
103 if (vlc_thread_create(&p_spdif->thread_id, "spdif",
104 (vlc_thread_func_t)RunThread, (void *)p_spdif))
106 intf_ErrMsg( "spdif error: can't spawn spdif thread" );
107 free( p_spdif->p_ac3 );
112 intf_DbgMsg( "spdif debug: spdif thread (%p) created", p_spdif );
114 return p_spdif->thread_id;
121 /****************************************************************************
122 * InitThread: initialize thread data and create output fifo
123 ****************************************************************************/
124 static int InitThread( ac3_spdif_thread_t * p_spdif )
126 boolean_t b_sync = 0;
128 p_spdif->p_config->decoder_config.pf_init_bit_stream(
129 &p_spdif->bit_stream,
130 p_spdif->p_config->decoder_config.p_decoder_fifo,
131 BitstreamCallback, (void*)p_spdif );
133 /* Creating the audio output fifo */
134 p_spdif->p_aout_fifo = aout_CreateFifo( AOUT_ADEC_SPDIF_FIFO, 1, 48000, 0,
135 SPDIF_FRAME_SIZE, NULL );
137 if( p_spdif->p_aout_fifo == NULL )
142 intf_WarnMsg( 3, "spdif: aout fifo #%d created",
143 p_spdif->p_aout_fifo->i_fifo );
146 p_spdif->p_ac3[0] = 0x0b;
147 p_spdif->p_ac3[1] = 0x77;
152 while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
153 p_spdif->i_real_pts = p_spdif->i_pts;
155 b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
157 RemoveBits( &p_spdif->bit_stream, 8 );
159 /* Check stream properties */
160 if( ac3_iec958_parse_syncinfo( p_spdif ) < 0 )
162 intf_ErrMsg( "spdif error: stream not valid");
164 aout_DestroyFifo( p_spdif->p_aout_fifo );
168 /* Check that we can handle the rate
169 * FIXME: we should check that we have the same rate for all fifos
170 * but all rates should be supported by the decoder (32, 44.1, 48) */
171 if( p_spdif->ac3_info.i_sample_rate != 48000 )
173 intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
175 aout_DestroyFifo( p_spdif->p_aout_fifo );
178 p_spdif->p_aout_fifo->l_rate = p_spdif->ac3_info.i_sample_rate;
180 GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + sizeof(sync_frame_t),
181 p_spdif->ac3_info.i_frame_size - sizeof(sync_frame_t) );
186 /****************************************************************************
187 * RunThread: loop that reads ac3 ES and transform it to
188 * an spdif compliant stream.
189 ****************************************************************************/
190 static void RunThread( ac3_spdif_thread_t * p_spdif )
192 mtime_t i_frame_time;
194 /* PTS of the current frame */
195 mtime_t i_current_pts = 0;
197 /* Initializing the spdif decoder thread */
198 if( InitThread( p_spdif ) )
200 p_spdif->p_fifo->b_error = 1;
203 /* Compute the theorical duration of an ac3 frame */
204 i_frame_time = 1000000 * AC3_FRAME_SIZE /
205 p_spdif->ac3_info.i_sample_rate;
207 while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
209 /* Handle the dates */
210 if( p_spdif->i_real_pts )
212 if(i_current_pts + i_frame_time != p_spdif->i_real_pts)
214 intf_WarnMsg( 2, "spdif warning: date discontinuity (%d)",
215 p_spdif->i_real_pts - i_current_pts -
218 i_current_pts = p_spdif->i_real_pts;
219 p_spdif->i_real_pts = 0;
223 i_current_pts += i_frame_time;
226 /* if we're late here the output won't have to play the frame */
227 if( i_current_pts > mdate() )
229 p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
232 /* Write in the first free packet of aout fifo */
233 p_spdif->p_iec = ((u8*)(p_spdif->p_aout_fifo->buffer) +
234 (p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME_SIZE ));
236 /* Build burst to be sent to hardware decoder */
237 ac3_iec958_build_burst( p_spdif );
239 vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
240 p_spdif->p_aout_fifo->l_end_frame =
241 (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
242 vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
245 /* Find syncword again in case of stream discontinuity */
246 /* Here we have p_spdif->i_pts == 0
247 * Therefore a non-zero value after a call to GetBits() means the PES
252 while( GetBits( &p_spdif->bit_stream, 8 ) != 0x0b );
253 p_spdif->i_real_pts = p_spdif->i_pts;
255 b_sync = ( ShowBits( &p_spdif->bit_stream, 8 ) == 0x77 );
257 RemoveBits( &p_spdif->bit_stream, 8 );
259 /* Read data from bitstream */
260 GetChunk( &p_spdif->bit_stream, p_spdif->p_ac3 + 2,
261 p_spdif->ac3_info.i_frame_size - 2 );
264 /* If b_error is set, the ac3 spdif thread enters the error loop */
265 if( p_spdif->p_fifo->b_error )
267 ErrorThread( p_spdif );
270 /* End of the ac3 decoder thread */
271 EndThread( p_spdif );
276 /*****************************************************************************
277 * ErrorThread : ac3 spdif's RunThread() error loop
278 *****************************************************************************/
279 static void ErrorThread( ac3_spdif_thread_t * p_spdif )
281 /* We take the lock, because we are going to read/write the start/end
282 * indexes of the decoder fifo */
283 vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
285 /* Wait until a `die' order is sent */
286 while( !p_spdif->p_fifo->b_die )
288 /* Trash all received PES packets */
289 while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
291 p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
292 DECODER_FIFO_START( *p_spdif->p_fifo ) );
293 DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
296 /* Waiting for the input thread to put new PES packets in the fifo */
297 vlc_cond_wait( &p_spdif->p_fifo->data_wait,
298 &p_spdif->p_fifo->data_lock );
301 /* We can release the lock before leaving */
302 vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
305 /*****************************************************************************
306 * EndThread : ac3 spdif thread destruction
307 *****************************************************************************/
308 static void EndThread( ac3_spdif_thread_t * p_spdif )
310 intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
312 /* If the audio output fifo was created, we destroy it */
313 if( p_spdif->p_aout_fifo != NULL )
315 aout_DestroyFifo( p_spdif->p_aout_fifo );
317 /* Make sure the output thread leaves the NextFrame() function */
318 vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
319 vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
320 vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
324 /* Destroy descriptor */
325 free( p_spdif->p_config );
326 free( p_spdif->p_ac3 );
329 intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
332 /*****************************************************************************
333 * BitstreamCallback: Import parameters from the new data/PES packet
334 *****************************************************************************
335 * This function is called by input's NextDataPacket.
336 *****************************************************************************/
337 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
340 ac3_spdif_thread_t * p_spdif;
344 p_spdif = (ac3_spdif_thread_t *)p_bit_stream->p_callback_arg;
346 p_bit_stream->p_byte += 3;
349 DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts;
350 DECODER_FIFO_START( *p_bit_stream->p_decoder_fifo )->i_pts = 0;