* aout_spdif: ac3 passthrough output
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: aout_spdif.c,v 1.3 2001/05/06 18:32:30 stef Exp $
+ * $Id: aout_spdif.c,v 1.18 2001/11/14 03:38:11 stef Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Stéphane Borel <stef@via.ecp.fr>
#include "audio_output.h"
#include "aout_common.h"
-#define BLANK_FRAME_MAX 1000
-
/*****************************************************************************
* aout_SpdifThread: audio output thread that sends raw spdif data
* to an external decoder
* This output thread is quite specific as it can only handle one fifo now.
*
* Note: spdif can demux up to 8 ac3 streams, and can even take
- * care of time stamps (cf ac3 spec).
+ * care of time stamps (cf ac3 spec) but I'm not sure all decoders
+ * implement it.
*****************************************************************************/
void aout_SpdifThread( aout_thread_t * p_aout )
{
- u8 pi_spdif_blank [9] =
- { 0x72, 0xf8, 0x1f, 0x4e, 0x01, 0x00, 0x08, 0x00, 0x77 };
- u8 pi_blank[SPDIF_FRAME_SIZE];
- int i_fifo;
- int i_frame;
- int i_blank;
-
- /* get a blank frame ready */
- memset( pi_blank, 0, sizeof(pi_blank) );
- memcpy( pi_blank, pi_spdif_blank, sizeof(pi_spdif_blank) );
-
- intf_WarnMsg( 1, "aout info: starting spdif output loop" );
-
- /* variable used to compute the nnumber of blank frames since the
- * last significant frame */
- i_blank = 0;
-
- while( !p_aout->b_die )
- {
- /* we leave some time for aout fifo to fill and not to stress
- * the external decoder too much */
- msleep( 10000 );
+ int i_fifo;
+ mtime_t m_frame_time = 0;
+ mtime_t m_play;
+ mtime_t m_old = 0;
+
- /* variable to check that we send data to the decoder
- * once per loop at least */
- i_frame = 0;
+ intf_DbgMsg( "aout debug: starting spdif output loop" );
- /* FIXME: find a way to hnadle the locks here */
- for( i_fifo = 0 ; i_fifo < AOUT_MAX_FIFOS ; i_fifo++ )
+ while( !p_aout->b_die )
+ {
+ for( i_fifo = 0 ; i_fifo < AOUT_MAX_FIFOS ; i_fifo++ )
+ {
+ /* the loop read each fifo so that we can change the stream
+ * on the fly but mulitplexing is not handled yet so
+ * the sound will be broken is more than one fifo has data */
+ /* TODO: write the muliplexer :) */
+ if( p_aout->fifo[i_fifo].i_type == AOUT_ADEC_SPDIF_FIFO )
+ {
+ vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
+ if( p_aout->fifo[i_fifo].b_die )
{
- /* the loop read each fifo so that we can change the stream
- * on the fly but mulitplexing is not handled yet so
- * the sound will be broken is more than one fifo has data */
- /* TODO: write the muliplexer :) */
- if( p_aout->fifo[i_fifo].i_type == AOUT_ADEC_SPDIF_FIFO )
- {
-// vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
- if( p_aout->fifo[i_fifo].b_die )
- {
-// vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
- aout_FreeFifo( &p_aout->fifo[i_fifo] );
- }
- else if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
- {
- vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
- /* play spdif frame to the external decoder */
- p_aout->pf_play( p_aout,
- p_aout->fifo[i_fifo].buffer +
- p_aout->fifo[i_fifo].l_start_frame*
- SPDIF_FRAME_SIZE,
- p_aout->fifo[i_fifo].l_frame_size );
-
-// vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
- p_aout->fifo[i_fifo].l_start_frame =
- (p_aout->fifo[i_fifo].l_start_frame + 1 )
- & AOUT_FIFO_SIZE;
-// vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
-
- i_frame++;
- i_blank = 0;
- }
- }
+ vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
+
+ vlc_mutex_lock( &p_aout->fifos_lock );
+ aout_FreeFifo( &p_aout->fifo[i_fifo] );
+ vlc_mutex_unlock( &p_aout->fifos_lock );
}
- if( !i_frame )
+ else if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
{
- /* insert blank frame for stream continuity to
- * the external decoder */
- p_aout->pf_play( p_aout, pi_blank, SPDIF_FRAME_SIZE );
+ /* Copy data from fifo to buffer to release the lock earlier */
+ memcpy( p_aout->buffer,
+ (byte_t *)p_aout->fifo[i_fifo].buffer
+ + p_aout->fifo[i_fifo].l_start_frame
+ * SPDIF_FRAME_SIZE,
+ SPDIF_FRAME_SIZE );
+
+ m_play = p_aout->fifo[i_fifo].date[p_aout->fifo[i_fifo].
+ l_start_frame];
+
+ p_aout->fifo[i_fifo].l_start_frame =
+ (p_aout->fifo[i_fifo].l_start_frame + 1 )
+ & AOUT_FIFO_SIZE;
+
+ /* Compute the theorical duration of an ac3 frame */
+ m_frame_time = 1000000 * AC3_FRAME_SIZE
+ / p_aout->fifo[i_fifo].l_rate;
- /* we kill the output if we don't have any stream */
- if( ++i_blank > BLANK_FRAME_MAX )
+ vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
+
+ /* play spdif frame to the external decoder
+ * the kernel driver will sleep until the
+ * dsp buffer is empty enough to accept the data */
+ if( m_play > ( mdate() - m_frame_time ) )
+ {
+ /* check continuity */
+ if( (m_play - m_old) != m_frame_time )
+ {
+ intf_DbgMsg( "aout debug: malformed frame ? (%lld)",
+ m_play - m_old );
+ mwait( m_play - m_frame_time );
+ }
+ else
{
- p_aout->b_die = 1;
+ mwait( m_play - 2 * m_frame_time );
}
+ m_old = m_play;
+
+ p_aout->pf_play( p_aout,
+ (byte_t *)p_aout->buffer,
+ SPDIF_FRAME_SIZE );
+ }
+ else
+ {
+ intf_DbgMsg( "aout debug: late spdif frame" );
+ }
}
+ else
+ {
+ vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
+ msleep( m_frame_time );
+ intf_WarnMsg( 3, "aout warning: empty spdif fifo" );
+ }
+ }
}
-
- intf_WarnMsg( 2, "aout info: exiting spdif loop" );
+ }
+
+ intf_DbgMsg( "aout debug: exiting spdif loop" );
+ vlc_mutex_lock( &p_aout->fifos_lock );
+
+ for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
+ {
+ aout_FreeFifo( &p_aout->fifo[i_fifo] );
+ }
+
+ vlc_mutex_unlock( &p_aout->fifos_lock );
- return;
+ return;
}