]> git.sesse.net Git - vlc/blob - modules/audio_output/hd1000a.cpp
Use var_InheritString for --decklink-video-connection.
[vlc] / modules / audio_output / hd1000a.cpp
1 /*****************************************************************************
2  * hd1000a.cpp : Roku HD1000 audio output
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 extern "C"
28 {
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_aout.h>
36
37 #include "aout_internal.h"
38 }
39
40 #include <deschutes/libraries/hdmachinex225/PCMAudioPlayer.h>
41
42 #define FRAME_SIZE 4096
43
44 /*****************************************************************************
45  * aout_sys_t: audio output method descriptor
46  *****************************************************************************
47  * This structure is part of the audio output thread descriptor.
48  * It describes the direct sound specific properties of an audio device.
49  *****************************************************************************/
50 struct aout_sys_t
51 {
52     u32 nAlignment;
53     u32 nSizeMultiple;
54     u32 nBuffers;
55     u32 nBufferSize;
56     void ** ppBuffers;
57     u32 nNextBufferIndex;
58     PCMAudioPlayer * pPlayer;
59 };
60
61 /*****************************************************************************
62  * Local prototypes.
63  *****************************************************************************/
64 static int     Open        ( vlc_object_t * );
65 static void    Close       ( vlc_object_t * );
66
67 static void    Play        ( aout_instance_t * );
68 static void*   Thread      ( vlc_object_t * );
69
70 static void    InterleaveS16( int16_t *, int16_t * );
71
72 /*****************************************************************************
73  * Module descriptor
74  *****************************************************************************/
75 vlc_module_begin ()
76     set_shortname( "Roku HD1000" )
77     set_description( N_("Roku HD1000 audio output") )
78     set_capability( "audio output", 100 )
79     set_category( CAT_AUDIO )
80     set_subcategory( SUBCAT_AUDIO_AOUT )
81     set_callbacks( Open, Close )
82 vlc_module_end ()
83
84 /*****************************************************************************
85  * Open: open a dummy audio device
86  *****************************************************************************/
87 static int Open( vlc_object_t * p_this )
88 {
89     aout_instance_t * p_aout = (aout_instance_t *)p_this;
90     struct aout_sys_t * p_sys;
91     PCMAudioPlayer * pPlayer;
92     int i_volume;
93
94     /* Allocate structure */
95     p_aout->output.p_sys = p_sys =
96         (aout_sys_t *)malloc( sizeof( aout_sys_t ) );
97     if( p_aout->output.p_sys == NULL )
98         return VLC_ENOMEM;
99
100     /* New PCMAudioPlayer */
101     p_sys->pPlayer = pPlayer = new PCMAudioPlayer();
102     if( p_sys->pPlayer == NULL )
103     {
104         free( p_sys );
105         return VLC_ENOMEM;
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         delete pPlayer;
125         free( p_sys );
126         return VLC_ENOMEM;
127     }
128
129     /* Open PCMAudioPlayer */
130     p_sys->nBufferSize = FRAME_SIZE * 4;
131     if( !pPlayer->Open( p_sys->nBuffers, p_sys->nBufferSize,
132                         p_sys->ppBuffers ) )
133     {
134         msg_Err( p_aout, "Open failed" );
135         delete pPlayer;
136         free( p_sys->ppBuffers );
137         free( p_sys );
138         return VLC_EGENERIC;
139     }
140
141     p_sys->nNextBufferIndex = 0;
142
143     if( !pPlayer->SetSampleRate( p_aout->output.output.i_rate ) )
144     {
145         p_aout->output.output.i_rate = 44100;
146         if( !pPlayer->SetSampleRate( p_aout->output.output.i_rate ) )
147         {
148             msg_Err( p_aout, "SetSampleRate failed" );
149             pPlayer->Close();
150             delete pPlayer;
151             free( p_sys->ppBuffers );
152             free( p_sys );
153             return VLC_EGENERIC;
154         }
155     }
156
157     p_aout->output.output.i_format = VLC_CODEC_S16N;
158     p_aout->output.i_nb_samples = FRAME_SIZE;
159     p_aout->output.output.i_physical_channels
160             = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
161     p_aout->output.pf_play = Play;
162     aout_VolumeSoftInit( p_aout );
163
164     i_volume = config_GetInt( p_aout->p_libvlc, "volume" );
165     pPlayer->SetVolume( (u32)__MIN( i_volume * 64, 0xFFFF ) );
166
167     /* Create thread and wait for its readiness. */
168     if( vlc_thread_create( p_aout, "aout", Thread,
169                            VLC_THREAD_PRIORITY_OUTPUT ) )
170     {
171         msg_Err( p_aout, "cannot create OSS thread (%m)" );
172         pPlayer->Close();
173         delete pPlayer;
174         free( p_sys->ppBuffers );
175         free( p_sys );
176         return VLC_ENOMEM;
177     }
178
179     return VLC_SUCCESS;
180 }
181
182 /*****************************************************************************
183  * Close: close our file
184  *****************************************************************************/
185 static void Close( vlc_object_t * p_this )
186 {
187     u32 i;
188     aout_instance_t * p_aout = (aout_instance_t *)p_this;
189     struct aout_sys_t * p_sys = p_aout->output.p_sys;
190
191     vlc_object_kill( p_aout );
192     vlc_thread_join( p_aout );
193     p_aout->b_die = false;
194
195     do
196     {
197         i = p_sys->pPlayer->WaitForBuffer();
198     } while( i != 0 && i != p_sys->nBuffers );
199
200     p_sys->pPlayer->Close();
201     delete p_sys->pPlayer;
202
203     free( p_sys->ppBuffers );
204     free( p_sys );
205 }
206
207 /*****************************************************************************
208  * Play: do nothing
209  *****************************************************************************/
210 static void Play( aout_instance_t * p_aout )
211 {
212 }
213
214 /*****************************************************************************
215  * Thread: thread used to DMA the data to the device
216  *****************************************************************************/
217 static void* Thread( vlc_object_t *p_this )
218 {
219     aout_instance_t * p_aout = (aout_instance_t*)p_this;
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     int canc = vlc_savecancel ();
224
225     while( vlc_object_alive (p_aout) )
226     {
227         pPlayer->WaitForBuffer();
228
229         vlc_mutex_lock( &p_aout->output_fifo_lock );
230         p_buffer = aout_FifoPop( p_aout, &p_aout->output.fifo );
231         vlc_mutex_unlock( &p_aout->output_fifo_lock );
232
233 #define i p_sys->nNextBufferIndex
234         if( p_buffer == NULL )
235         {
236             vlc_memset( p_aout, p_sys->ppBuffers[ i ], 0,
237                                       p_sys->nBufferSize );
238         }
239         else
240         {
241             InterleaveS16( (int16_t *)p_buffer->p_buffer,
242                            (int16_t *)p_sys->ppBuffers[ i ] );
243             aout_BufferFree( p_buffer );
244         }
245
246         if( !pPlayer->QueueBuffer( (s16 *)p_sys->ppBuffers[ i ],
247                                    p_sys->nBufferSize / 2 ) )
248         {
249             msg_Err( p_aout, "QueueBuffer failed" );
250         }
251
252         i = (i + 1) % p_sys->nBuffers;
253 #undef i
254     }
255
256     vlc_restorecancel (canc);
257     return NULL;
258 }
259
260 /*****************************************************************************
261  * InterleaveS16: interleave samples
262  *****************************************************************************/
263 static void InterleaveS16( int16_t * p_in, int16_t * p_out )
264 {
265     for( int i = 0; i < FRAME_SIZE; i++ )
266     {
267         p_out[ i * 2 + 0 ] = p_in[ i * 2 + 1 ];
268         p_out[ i * 2 + 1 ] = p_in[ i * 2 + 0 ];
269     }
270 }