]> git.sesse.net Git - vlc/blob - src/audio_output/aout_spdif.c
*A lock was not released;
[vlc] / src / audio_output / aout_spdif.c
1 /*****************************************************************************
2  * aout_spdif.c: AC3 passthrough output
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: aout_spdif.c,v 1.28 2002/05/18 08:50:54 stef 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 #ifdef HAVE_UNISTD_H
35 #   include <unistd.h>
36 #endif
37
38 #include "audio_output.h"
39 #include "aout_spdif.h"
40
41 /****************************************************************************
42  * iec958_build_burst: builds an iec958/spdif frame
43  ****************************************************************************/
44 void iec958_build_burst( u8 * p_buf, aout_fifo_t * p_fifo )
45 {
46     const u8 p_sync[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 };
47     int      i_length  = p_fifo->i_frame_size;
48 #ifndef HAVE_SWAB
49     /* Skip the first byte if i_length is odd */
50     u16 * p_in  = (u16 *)( p_fifo->buffer + ( i_length & 0x1 ) );
51     u16 * p_out = (u16 *)p_buf;
52 #endif
53
54     /* Add the spdif headers */
55     memcpy( p_buf, p_sync, 6 );
56     p_buf[6] = ( i_length * 8 ) & 0xFF;
57     p_buf[7] = ( ( i_length * 8 ) >> 8 ) & 0xFF;
58
59 #ifdef HAVE_SWAB
60     swab( p_fifo->buffer + p_fifo->i_start_frame * i_length,
61           p_buf + 8, i_length );
62 #else
63     /* i_length should be even */
64     i_length &= ~0x1;
65
66     while( i_length )
67     {
68         *p_out = ( (*p_in & 0x00ff) << 16 ) | ( (*p_in & 0xff00) >> 16 );
69         p_in++;
70         p_out++;
71         i_length -= 2;
72     }
73 #endif
74
75     /* Add zeroes to complete the spdif frame,
76      * they will be ignored by the decoder */
77     memset( p_buf + 8 + i_length, 0, SPDIF_FRAME_SIZE - 8 - i_length );
78 }
79
80
81 /*****************************************************************************
82  * aout_SpdifThread: audio output thread that sends raw spdif data
83  *                   to an external decoder
84  *****************************************************************************
85  * This output thread is quite specific as it can only handle one fifo now.
86  *
87  * Note: spdif can demux up to 8 ac3 streams, and can even take
88  * care of time stamps (cf ac3 spec) but I'm not sure all decoders
89  * implement it.
90  *****************************************************************************/
91 void aout_SpdifThread( aout_thread_t * p_aout )
92 {
93     int         i_fifo;
94     mtime_t     m_frame_time = 0;
95     mtime_t     m_play;
96     mtime_t     m_old;
97
98     while( !p_aout->b_die )
99     {
100         i_fifo = 0;
101         /* Find spdif fifo */
102         while( ( p_aout->fifo[i_fifo].i_format != AOUT_FIFO_SPDIF ) &&
103                ( i_fifo < AOUT_MAX_FIFOS ) && !p_aout->b_die )
104         {
105             i_fifo++;
106         }
107
108         m_old = 0;
109
110         while( !p_aout->b_die && 
111                !p_aout->fifo[i_fifo].b_die )
112         {
113             vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
114             if( !AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) )
115             {
116                 /* Copy data from fifo to buffer to release the
117                  * lock earlier */
118                 iec958_build_burst( p_aout->buffer,
119                                     &p_aout->fifo[i_fifo] );
120
121                 m_play = p_aout->fifo[i_fifo].date[p_aout->fifo[i_fifo].
122                              i_start_frame];
123
124                 p_aout->fifo[i_fifo].i_start_frame =
125                     (p_aout->fifo[i_fifo].i_start_frame + 1 )
126                     & AOUT_FIFO_SIZE;
127
128                 /* Compute the theorical duration of an ac3 frame */
129                 m_frame_time = 1000000 * AC3_FRAME_SIZE
130                                        / p_aout->fifo[i_fifo].i_rate;
131
132                 vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
133
134                 /* Play spdif frame to the external decoder 
135                  * the kernel driver will sleep until the
136                  * dsp buffer is empty enough to accept the data */
137                 if( m_play > ( mdate() - m_frame_time ) )
138                 {
139                     /* check continuity */
140                     if( (m_play - m_old) != m_frame_time )
141                     {
142                         mwait( m_play - m_frame_time );
143                     }
144                     else
145                     {
146                         mwait( m_play - 2 * m_frame_time );
147                     }
148                     m_old = m_play;
149                     
150                     p_aout->pf_getbufinfo( p_aout, 0 );
151
152                     p_aout->pf_play( p_aout, (byte_t *)p_aout->buffer,
153                                      SPDIF_FRAME_SIZE );
154                 }
155             }
156             else
157             {
158                 intf_WarnMsg( 3, "aout warning: empty spdif fifo" );
159                 while( AOUT_FIFO_ISEMPTY( p_aout->fifo[i_fifo] ) &&
160                        !p_aout->b_die && 
161                        !p_aout->fifo[i_fifo].b_die )
162
163                 {
164                     vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
165                     msleep( m_frame_time );
166                     vlc_mutex_lock( &p_aout->fifo[i_fifo].data_lock );
167                 }
168                 vlc_mutex_unlock( &p_aout->fifo[i_fifo].data_lock );
169             }
170         }
171
172         vlc_mutex_lock( &p_aout->fifos_lock );
173         aout_FreeFifo( &p_aout->fifo[i_fifo] );
174         vlc_mutex_unlock( &p_aout->fifos_lock );
175     }
176
177     return;
178 }
179