/*****************************************************************************
- * aout_spdif: ac3 passthrough output
+ * aout_spdif.c: AC3 passthrough output
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: aout_spdif.c,v 1.18 2001/11/14 03:38:11 stef Exp $
+ * $Id: aout_spdif.c,v 1.27 2002/05/17 18:01:25 stef Exp $
*
* Authors: Michel Kaempf <maxx@via.ecp.fr>
* Stéphane Borel <stef@via.ecp.fr>
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include "defs.h"
-
#include <stdio.h> /* "intf_msg.h" */
#include <stdlib.h> /* calloc(), malloc(), free() */
#include <string.h> /* memset() */
-#include "config.h"
-#include "common.h"
-#include "threads.h"
-#include "mtime.h" /* mtime_t, mdate(), msleep() */
+#include <videolan/vlc.h>
-#include "intf_msg.h" /* intf_DbgMsg(), intf_ErrMsg() */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
#include "audio_output.h"
-#include "aout_common.h"
+#include "aout_spdif.h"
+
+/****************************************************************************
+ * iec958_build_burst: builds an iec958/spdif frame
+ ****************************************************************************/
+void iec958_build_burst( u8 * p_buf, aout_fifo_t * p_fifo )
+{
+ const u8 p_sync[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 };
+ int i_length = p_fifo->i_frame_size;
+#ifndef HAVE_SWAB
+ /* Skip the first byte if i_length is odd */
+ u16 * p_in = (u16 *)( p_fifo->buffer + ( i_length & 0x1 ) );
+ u16 * p_out = (u16 *)p_buf;
+#endif
+
+ /* Add the spdif headers */
+ memcpy( p_buf, p_sync, 6 );
+ p_buf[6] = ( i_length * 8 ) & 0xFF;
+ p_buf[7] = ( ( i_length * 8 ) >> 8 ) & 0xFF;
+
+#ifdef HAVE_SWAB
+ swab( p_fifo->buffer + p_fifo->i_start_frame * i_length,
+ p_buf + 8, i_length );
+#else
+ /* i_length should be even */
+ i_length &= ~0x1;
+
+ while( i_length )
+ {
+ *p_out = ( (*p_in & 0x00ff) << 16 ) | ( (*p_in & 0xff00) >> 16 );
+ p_in++;
+ p_out++;
+ i_length -= 2;
+ }
+#endif
+
+ /* Add zeroes to complete the spdif frame,
+ * they will be ignored by the decoder */
+ memset( p_buf + 8 + i_length, 0, SPDIF_FRAME_SIZE - 8 - i_length );
+}
+
/*****************************************************************************
* aout_SpdifThread: audio output thread that sends raw spdif data
*****************************************************************************/
void aout_SpdifThread( aout_thread_t * p_aout )
{
- int i_fifo;
- mtime_t m_frame_time = 0;
- mtime_t m_play;
- mtime_t m_old = 0;
-
-
- intf_DbgMsg( "aout debug: starting spdif output loop" );
+ int i_fifo;
+ mtime_t m_frame_time = 0;
+ mtime_t m_play;
+ mtime_t m_old;
- while( !p_aout->b_die )
- {
- for( i_fifo = 0 ; i_fifo < AOUT_MAX_FIFOS ; i_fifo++ )
+ while( !p_aout->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 )
+ i_fifo = 0;
+ /* Find spdif fifo */
+ while( ( p_aout->fifo[i_fifo].i_format != AOUT_FIFO_SPDIF ) &&
+ ( i_fifo < AOUT_MAX_FIFOS ) && !p_aout->b_die )
{
- 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 );
+ i_fifo++;
}
- else if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
+
+ m_old = 0;
+
+ while( !p_aout->b_die &&
+ !p_aout->fifo[i_fifo].b_die )
{
- /* 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;
-
- 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 )
+ vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
+ if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
{
- intf_DbgMsg( "aout debug: malformed frame ? (%lld)",
- m_play - m_old );
- mwait( m_play - m_frame_time );
+ /* Copy data from fifo to buffer to release the
+ * lock earlier */
+ iec958_build_burst( p_aout->buffer,
+ &p_aout->fifo[i_fifo] );
+
+ m_play = p_aout->fifo[i_fifo].date[p_aout->fifo[i_fifo].
+ i_start_frame];
+
+ p_aout->fifo[i_fifo].i_start_frame =
+ (p_aout->fifo[i_fifo].i_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].i_rate;
+
+ 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 )
+ {
+ mwait( m_play - m_frame_time );
+ }
+ else
+ {
+ mwait( m_play - 2 * m_frame_time );
+ }
+ m_old = m_play;
+
+ p_aout->pf_getbufinfo( p_aout, 0 );
+
+ p_aout->pf_play( p_aout, (byte_t *)p_aout->buffer,
+ SPDIF_FRAME_SIZE );
+ }
}
else
{
- mwait( m_play - 2 * m_frame_time );
+ intf_WarnMsg( 3, "aout warning: empty spdif fifo" );
+ while( AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) &&
+ !p_aout->b_die &&
+ !p_aout->fifo[i_fifo].b_die )
+
+ {
+ vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
+ msleep( m_frame_time );
+ vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
+ }
}
- 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_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 );
+ vlc_mutex_lock( &p_aout->fifos_lock );
+ aout_FreeFifo( &p_aout->fifo[i_fifo] );
+ vlc_mutex_unlock( &p_aout->fifos_lock );
+ }
- return;
+ return;
}