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.1 2001/04/29 02:48:51 stef 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 ****************************************************************************/
41 #include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
43 #include "stream_control.h"
44 #include "input_ext-dec.h"
46 #include "audio_output.h"
48 #include "ac3_spdif.h"
49 #include "ac3_iec958.h"
53 /****************************************************************************
55 ****************************************************************************/
56 static int InitThread ( ac3_spdif_thread_t * );
57 static void RunThread ( ac3_spdif_thread_t * );
58 static void ErrorThread ( ac3_spdif_thread_t * );
59 static void EndThread ( ac3_spdif_thread_t * );
60 static void BitstreamCallback( bit_stream_t *, boolean_t );
62 /****************************************************************************
63 * spdif_CreateThread: initialize the spdif thread
64 ****************************************************************************/
65 vlc_thread_t spdif_CreateThread( adec_config_t * p_config )
67 ac3_spdif_thread_t * p_spdif;
69 intf_DbgMsg( "spdif debug: creating ac3 pass-through thread" );
71 /* Allocate the memory needed to store the thread's structure */
72 if( ( p_spdif = malloc( sizeof(ac3_spdif_thread_t) ) ) == NULL )
74 intf_ErrMsg ( "spdif error: not enough memory "
75 "for spdif_CreateThread() to create the new thread");
80 * Initialize the thread properties
82 p_spdif->p_config = p_config;
83 p_spdif->p_fifo = p_config->decoder_config.p_decoder_fifo;
85 p_spdif->p_aout = p_config->p_aout;
86 p_spdif->p_aout_fifo = NULL;
88 /* Spawn the ac3 to spdif thread */
89 if (vlc_thread_create(&p_spdif->thread_id, "spdif",
90 (vlc_thread_func_t)RunThread, (void *)p_spdif))
92 intf_ErrMsg( "spdif error: can't spawn spdif thread" );
97 intf_DbgMsg( "spdif debug: spdif thread (%p) created", p_spdif );
99 return p_spdif->thread_id;
106 /****************************************************************************
107 * InitThread: initialize thread data and create output fifo
108 ****************************************************************************/
109 static int InitThread( ac3_spdif_thread_t * p_spdif )
111 aout_fifo_t aout_fifo;
113 p_spdif->p_config->decoder_config.pf_init_bit_stream(
114 &p_spdif->bit_stream,
115 p_spdif->p_config->decoder_config.p_decoder_fifo,
116 BitstreamCallback, (void*)p_spdif );
118 aout_fifo.i_type = AOUT_ADEC_MONO_FIFO;
119 aout_fifo.i_channels = 1;
120 aout_fifo.b_stereo = 0;
122 aout_fifo.l_frame_size = SPDIF_FRAME;
124 /* Creating the audio output fifo */
125 if( (p_spdif->p_aout_fifo =
126 aout_CreateFifo( p_spdif->p_aout, &aout_fifo ) ) == NULL )
131 intf_WarnMsg( 1, "aout fifo for spdif created" );
136 /****************************************************************************
137 * RunThread: loop that reads ac3 ES and transform it to
138 * an spdif compliant stream.
139 ****************************************************************************/
140 static void RunThread( ac3_spdif_thread_t * p_spdif )
146 InitThread( p_spdif );
148 /* temporary buffer to store ac3 frames to be transformed */
149 pi_ac3 = malloc( /*ac3_info.i_frame_size*/SPDIF_FRAME );
151 /* check stream properties */
152 if( ac3_iec958_parse_syncinfo( p_spdif, &ac3_info, pi_ac3 ) < 0)
154 intf_ErrMsg( "spdif error: stream not valid");
158 if( ac3_info.i_sample_rate != 48000) {
159 intf_ErrMsg( "spdif error: Only 48000 Hz streams supported");
163 GetChunk( &p_spdif->bit_stream, pi_ac3 + sizeof(sync_frame_t),
164 ac3_info.i_frame_size - sizeof(sync_frame_t) );
166 vlc_cond_signal( &p_spdif->p_aout_fifo->data_wait );
167 while( !p_spdif->p_fifo->b_die && !p_spdif->p_fifo->b_error )
169 /* handle the dates */
170 if(DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts)
172 p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
173 DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts;
174 DECODER_FIFO_START(*p_spdif->p_fifo)->i_pts = 0;
178 p_spdif->p_aout_fifo->date[p_spdif->p_aout_fifo->l_end_frame] =
182 /* write in the first free packet of aout fifo */
183 pi_iec = (p_spdif->p_aout_fifo->buffer) +
184 (p_spdif->p_aout_fifo->l_end_frame * SPDIF_FRAME );
186 /* build burst to be sent to hardware decoder */
187 ac3_iec958_build_burst( ac3_info.i_frame_size, pi_ac3, pi_iec );
189 vlc_mutex_lock (&p_spdif->p_aout_fifo->data_lock);
191 p_spdif->p_aout_fifo->l_end_frame =
192 (p_spdif->p_aout_fifo->l_end_frame + 1 ) & AOUT_FIFO_SIZE;
194 vlc_mutex_unlock (&p_spdif->p_aout_fifo->data_lock);
197 while( ShowBits( &p_spdif->bit_stream, 16 ) != 0xb77 )
199 RemoveBits( &p_spdif->bit_stream, 8 );
202 /* read data from bitstream */
203 GetChunk( &p_spdif->bit_stream, pi_ac3, ac3_info.i_frame_size );
208 /* If b_error is set, the ac3 spdif thread enters the error loop */
209 if( p_spdif->p_fifo->b_error )
211 ErrorThread( p_spdif );
214 /* End of the ac3 decoder thread */
215 EndThread( p_spdif );
220 /*****************************************************************************
221 * ErrorThread : ac3 spdif's RunThread() error loop
222 *****************************************************************************/
223 static void ErrorThread( ac3_spdif_thread_t * p_spdif )
225 /* We take the lock, because we are going to read/write the start/end
226 * indexes of the decoder fifo */
227 vlc_mutex_lock (&p_spdif->p_fifo->data_lock);
229 /* Wait until a `die' order is sent */
230 while( !p_spdif->p_fifo->b_die )
232 /* Trash all received PES packets */
233 while( !DECODER_FIFO_ISEMPTY( *p_spdif->p_fifo ) )
235 p_spdif->p_fifo->pf_delete_pes(p_spdif->p_fifo->p_packets_mgt,
236 DECODER_FIFO_START( *p_spdif->p_fifo ) );
237 DECODER_FIFO_INCSTART( *p_spdif->p_fifo );
240 /* Waiting for the input thread to put new PES packets in the fifo */
241 vlc_cond_wait( &p_spdif->p_fifo->data_wait,
242 &p_spdif->p_fifo->data_lock );
245 /* We can release the lock before leaving */
246 vlc_mutex_unlock( &p_spdif->p_fifo->data_lock );
249 /*****************************************************************************
250 * EndThread : ac3 spdif thread destruction
251 *****************************************************************************/
252 static void EndThread( ac3_spdif_thread_t * p_spdif )
254 intf_DbgMsg( "spdif debug: destroying thread %p", p_spdif );
256 /* If the audio output fifo was created, we destroy it */
257 if( p_spdif->p_aout_fifo != NULL )
259 aout_DestroyFifo( p_spdif->p_aout_fifo );
261 /* Make sure the output thread leaves the NextFrame() function */
262 vlc_mutex_lock( &(p_spdif->p_aout_fifo->data_lock ) );
263 vlc_cond_signal( &(p_spdif->p_aout_fifo->data_wait ) );
264 vlc_mutex_unlock( &(p_spdif->p_aout_fifo->data_lock ) );
268 /* Destroy descriptor */
269 free( p_spdif->p_config );
272 intf_DbgMsg ("spdif debug: thread %p destroyed", p_spdif );
275 /*****************************************************************************
276 * BitstreamCallback: Import parameters from the new data/PES packet
277 *****************************************************************************
278 * This function is called by input's NextDataPacket.
279 *****************************************************************************/
280 static void BitstreamCallback ( bit_stream_t * p_bit_stream,
285 p_bit_stream->p_byte += 3;