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