* hd1000a: channel reordering
[vlc.git] / modules / audio_output / hd1000a.cpp
1 /*****************************************************************************
2  * hd1000a.cpp : Roku HD1000 audio output
3  *****************************************************************************
4  * Copyright (C) 2004 VideoLAN
5  * $Id$
6  *
7  * Author: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 extern "C"
28 {
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/aout.h>
35
36 #include "aout_internal.h"
37 }
38
39 #include <deschutes/libraries/hdmachinex225/PCMAudioPlayer.h>
40
41 #define FRAME_SIZE 4096
42
43 /*****************************************************************************
44  * aout_sys_t: audio output method descriptor
45  *****************************************************************************
46  * This structure is part of the audio output thread descriptor.
47  * It describes the direct sound specific properties of an audio device.
48  *****************************************************************************/
49 struct aout_sys_t
50 {
51     u32 nAlignment;
52     u32 nSizeMultiple;
53     u32 nBuffers;
54     u32 nBufferSize;
55     void ** ppBuffers;
56     u32 nNextBufferIndex;
57     PCMAudioPlayer * pPlayer;
58 };
59
60 /*****************************************************************************
61  * Local prototypes.
62  *****************************************************************************/
63 static int     Open        ( vlc_object_t * );
64 static void    Close       ( vlc_object_t * );
65
66 static void    Play        ( aout_instance_t * );
67 static int     Thread      ( aout_instance_t * );
68
69 static void    InterleaveS16( int16_t *, int16_t * );
70
71 /*****************************************************************************
72  * Module descriptor
73  *****************************************************************************/
74 vlc_module_begin();
75     set_description( N_("HD1000 audio output") );
76     set_capability( "audio output", 100 );
77     set_callbacks( Open, Close );
78 vlc_module_end();
79
80 /*****************************************************************************
81  * Open: open a dummy audio device
82  *****************************************************************************/
83 static int Open( vlc_object_t * p_this )
84 {
85     aout_instance_t * p_aout = (aout_instance_t *)p_this;
86     struct aout_sys_t * p_sys;
87     PCMAudioPlayer * pPlayer;
88     int i_volume;
89
90     /* Allocate structure */
91     p_aout->output.p_sys = p_sys =
92         (aout_sys_t *)malloc( sizeof( aout_sys_t ) );
93     if( p_aout->output.p_sys == NULL )
94     {
95         msg_Err( p_aout, "out of memory" );
96         return VLC_EGENERIC;
97     }
98
99     /* New PCMAudioPlayer */
100     p_sys->pPlayer = pPlayer = new PCMAudioPlayer();
101     if( p_sys->pPlayer == NULL )
102     {
103         msg_Err( p_aout, "out of memory" );
104         free( p_sys );
105         return VLC_EGENERIC;
106     }
107
108     /* Get Buffer Requirements */
109     if( !pPlayer->GetBufferRequirements( p_sys->nAlignment,
110                                          p_sys->nSizeMultiple,
111                                          p_sys->nBuffers ) )
112     {
113         msg_Err( p_aout, "GetBufferRequirements failed" );
114         delete pPlayer;
115         free( p_sys );
116         return VLC_EGENERIC;
117     } 
118
119     p_sys->nBuffers = __MIN( p_sys->nBuffers, 4 );
120
121     p_sys->ppBuffers = (void **)malloc( p_sys->nBuffers * sizeof( void * ) );
122     if( p_sys->ppBuffers == NULL )
123     {
124         msg_Err( p_aout, "out of memory" );
125         delete pPlayer;
126         free( p_sys );
127         return VLC_EGENERIC;
128     }
129
130     /* Open PCMAudioPlayer */
131     p_sys->nBufferSize = FRAME_SIZE * 4;
132     if( !pPlayer->Open( p_sys->nBuffers, p_sys->nBufferSize,
133                         p_sys->ppBuffers ) )
134     {
135         msg_Err( p_aout, "Open failed" );
136         delete pPlayer;
137         free( p_sys->ppBuffers );
138         free( p_sys );
139         return VLC_EGENERIC;
140     }
141
142     p_sys->nNextBufferIndex = 0;
143
144     if( !pPlayer->SetSampleRate( p_aout->output.output.i_rate ) )
145     {
146         p_aout->output.output.i_rate = 44100;
147         if( !pPlayer->SetSampleRate( p_aout->output.output.i_rate ) )
148         {
149             msg_Err( p_aout, "SetSampleRate failed" );
150             pPlayer->Close();
151             delete pPlayer;
152             free( p_sys->ppBuffers );
153             free( p_sys );
154             return VLC_EGENERIC;
155         }
156     }
157
158     p_aout->output.output.i_format = AOUT_FMT_S16_NE;
159     p_aout->output.i_nb_samples = FRAME_SIZE;
160     p_aout->output.output.i_physical_channels
161             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
162     p_aout->output.pf_play = Play;
163     aout_VolumeSoftInit( p_aout );
164
165     i_volume = config_GetInt( p_aout->p_vlc, "volume" );
166     pPlayer->SetVolume( (u32)__MIN( i_volume * 64, 0xFFFF ) );
167
168     /* Create thread and wait for its readiness. */
169     if( vlc_thread_create( p_aout, "aout", Thread,
170                            VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
171     {
172         msg_Err( p_aout, "cannot create OSS thread (%s)", strerror(errno) );
173         pPlayer->Close();
174         delete pPlayer;
175         free( p_sys->ppBuffers );
176         free( p_sys );
177         return VLC_ETHREAD;
178     }
179
180     return VLC_SUCCESS;
181 }
182
183 /*****************************************************************************
184  * Close: close our file
185  *****************************************************************************/
186 static void Close( vlc_object_t * p_this )
187 {
188     u32 i;
189     aout_instance_t * p_aout = (aout_instance_t *)p_this;
190     struct aout_sys_t * p_sys = p_aout->output.p_sys;
191
192     p_aout->b_die = VLC_TRUE;
193     vlc_thread_join( p_aout );
194     p_aout->b_die = VLC_FALSE;
195
196     do
197     {
198         i = p_sys->pPlayer->WaitForBuffer();
199     } while( i != 0 && i != p_sys->nBuffers );
200
201     p_sys->pPlayer->Close();
202     delete p_sys->pPlayer;
203
204     free( p_sys->ppBuffers );
205     free( p_sys );
206 }
207
208 /*****************************************************************************
209  * Play: do nothing
210  *****************************************************************************/
211 static void Play( aout_instance_t * p_aout )
212 {
213 }
214
215 /*****************************************************************************
216  * Thread: thread used to DMA the data to the device
217  *****************************************************************************/
218 static int Thread( aout_instance_t * p_aout )
219 {
220     aout_buffer_t * p_buffer;
221     struct aout_sys_t * p_sys = p_aout->output.p_sys;
222     PCMAudioPlayer * pPlayer = p_sys->pPlayer;
223
224     while( !p_aout->b_die )
225     {
226         pPlayer->WaitForBuffer();
227
228         vlc_mutex_lock( &p_aout->output_fifo_lock );
229         p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
230         vlc_mutex_unlock( &p_aout->output_fifo_lock );
231
232 #define i p_sys->nNextBufferIndex
233         if( p_buffer == NULL )
234         {
235             p_aout->p_vlc->pf_memset( p_sys->ppBuffers[ i ], 0,
236                                       p_sys->nBufferSize ); 
237         }
238         else
239         {
240             InterleaveS16( (int16_t *)p_buffer->p_buffer,
241                            (int16_t *)p_sys->ppBuffers[ i ] );
242             aout_BufferFree( p_buffer );
243         }
244
245         if( !pPlayer->QueueBuffer( (s16 *)p_sys->ppBuffers[ i ],
246                                    p_sys->nBufferSize / 2 ) )
247         {
248             msg_Err( p_aout, "QueueBuffer failed" );
249         } 
250
251         i = (i + 1) % p_sys->nBuffers;
252 #undef i
253     }
254
255     return VLC_SUCCESS;
256 }
257
258 /*****************************************************************************
259  * InterleaveS16: interleave samples
260  *****************************************************************************/
261 static void InterleaveS16( int16_t * p_in, int16_t * p_out )
262 {
263     for( int i = 0; i < FRAME_SIZE; i++ )
264     {
265         p_out[ i * 2 + 0 ] = p_in[ i * 2 + 1 ];
266         p_out[ i * 2 + 1 ] = p_in[ i * 2 + 0 ];
267     }
268 }