]> git.sesse.net Git - vlc/blob - src/audio_output/aout_spdif.c
- better communication between audio decoder and output: aout plugins
[vlc] / src / audio_output / aout_spdif.c
1 /*****************************************************************************
2  * aout_spdif: ac3 passthrough output
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: aout_spdif.c,v 1.21 2001/12/30 07:09:56 sam Exp $
6  *
7  * Authors: Michel Kaempf <maxx@via.ecp.fr>
8  *          Stéphane Borel <stef@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdio.h>                                           /* "intf_msg.h" */
29 #include <stdlib.h>                            /* calloc(), malloc(), free() */
30 #include <string.h>                                              /* memset() */
31
32 #include <videolan/vlc.h>
33
34 #include "audio_output.h"
35 #include "aout_common.h"
36
37 /*****************************************************************************
38  * aout_SpdifThread: audio output thread that sends raw spdif data
39  *                   to an external decoder
40  *****************************************************************************
41  * This output thread is quite specific as it can only handle one fifo now.
42  *
43  * Note: spdif can demux up to 8 ac3 streams, and can even take
44  * care of time stamps (cf ac3 spec) but I'm not sure all decoders
45  * implement it.
46  *****************************************************************************/
47 void aout_SpdifThread( aout_thread_t * p_aout )
48 {
49   int         i_fifo;
50   mtime_t     m_frame_time = 0;
51   mtime_t     m_play;
52   mtime_t     m_old = 0;
53
54
55   intf_DbgMsg( "aout debug: starting spdif output loop" );
56
57   while( !p_aout->b_die )
58   {
59     for( i_fifo = 0 ; i_fifo < AOUT_MAX_FIFOS ; i_fifo++ )
60     {
61       /* the loop read each fifo so that we can change the stream
62        * on the fly but mulitplexing is not handled yet so
63        * the sound will be broken is more than one fifo has data */ 
64       /* TODO: write the muliplexer :) */
65       if( p_aout->fifo[i_fifo].i_type == AOUT_ADEC_SPDIF_FIFO )
66       {
67         vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
68         if( p_aout->fifo[i_fifo].b_die )
69         {
70           vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
71
72           vlc_mutex_lock( &p_aout->fifos_lock );
73           aout_FreeFifo( &p_aout->fifo[i_fifo] );
74           vlc_mutex_unlock( &p_aout->fifos_lock );
75         }
76         else if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
77         {
78           /* Copy data from fifo to buffer to release the lock earlier */
79           memcpy( p_aout->buffer,
80                   (byte_t *)p_aout->fifo[i_fifo].buffer
81                           + p_aout->fifo[i_fifo].l_start_frame
82                           * SPDIF_FRAME_SIZE,
83                   SPDIF_FRAME_SIZE );
84
85           m_play = p_aout->fifo[i_fifo].date[p_aout->fifo[i_fifo].
86                        l_start_frame];
87
88           p_aout->fifo[i_fifo].l_start_frame =
89               (p_aout->fifo[i_fifo].l_start_frame + 1 )
90               & AOUT_FIFO_SIZE;
91
92           /* Compute the theorical duration of an ac3 frame */
93           m_frame_time = 1000000 * AC3_FRAME_SIZE
94                                  / p_aout->fifo[i_fifo].l_rate;
95
96           vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
97
98           /* play spdif frame to the external decoder 
99            * the kernel driver will sleep until the
100            * dsp buffer is empty enough to accept the data */
101           if( m_play > ( mdate() - m_frame_time ) )
102           {
103             /* check continuity */
104             if( (m_play - m_old) != m_frame_time )
105             {
106               intf_DbgMsg( "aout debug: malformed frame ? (%lld)",
107                                m_play - m_old );
108               mwait( m_play - m_frame_time );
109             }
110             else
111             {
112               mwait( m_play - 2 * m_frame_time );
113             }
114             m_old = m_play;
115
116             p_aout->pf_play( p_aout,
117                              (byte_t *)p_aout->buffer,
118                              SPDIF_FRAME_SIZE );
119           }
120           else
121           {
122             intf_DbgMsg( "aout debug: late spdif frame" );
123           }
124         }
125         else
126         {
127           vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
128           msleep( m_frame_time );
129           intf_WarnMsg( 3, "aout warning: empty spdif fifo" );
130         }
131       }
132     }
133   }
134
135   intf_DbgMsg( "aout debug: exiting spdif loop" );
136   vlc_mutex_lock( &p_aout->fifos_lock );
137
138   for ( i_fifo = 0; i_fifo < AOUT_MAX_FIFOS; i_fifo++ )
139   {
140     aout_FreeFifo( &p_aout->fifo[i_fifo] );
141   }
142
143   vlc_mutex_unlock( &p_aout->fifos_lock );
144
145   return;
146 }
147