1 /*****************************************************************************
2 * aout.cpp: BeOS audio output
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: AudioOutput.cpp,v 1.7 2002/08/30 23:27:06 massiot Exp $
7 * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
8 * Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
29 #include <stdlib.h> /* malloc(), free() */
30 #include <kernel/OS.h>
32 #include <Application.h>
35 #include <media/MediaDefs.h>
36 #include <game/PushGameSound.h>
42 #include "aout_internal.h"
44 /*****************************************************************************
45 * aout_sys_t: BeOS audio output method descriptor
46 *****************************************************************************
47 * This structure is part of the audio output thread descriptor.
48 * It describes some BeOS specific variables.
49 *****************************************************************************/
52 BPushGameSound * p_sound;
53 gs_audio_format * p_format;
60 #define FRAME_SIZE 2048
62 /*****************************************************************************
64 *****************************************************************************/
65 static int SetFormat ( aout_instance_t * );
66 static void Play ( aout_instance_t * );
67 static int BeOSThread ( aout_instance_t * );
69 /*****************************************************************************
70 * OpenAudio: opens a BPushGameSound
71 *****************************************************************************/
72 int E_(OpenAudio) ( vlc_object_t * p_this )
74 aout_instance_t * p_aout = (aout_instance_t *)p_this;
75 struct aout_sys_t * p_sys;
77 /* Allocate structure */
78 p_aout->output.p_sys = p_sys = (aout_sys_t *)malloc( sizeof( struct aout_sys_t ) );
79 memset( p_sys, 0, sizeof( struct aout_sys_t ) );
82 msg_Err( p_aout, "out of memory" );
86 /* Initialize format */
87 p_sys->p_format = (gs_audio_format *)malloc( sizeof( struct gs_audio_format));
90 /* Allocate BPushGameSound */
91 p_sys->p_sound = new BPushGameSound( 8192,
94 if( p_sys->p_sound->InitCheck() != B_OK )
96 free( p_sys->p_format );
98 msg_Err( p_aout, "cannot initialize BPushGameSound" );
102 if( vlc_thread_create( p_aout, "aout", BeOSThread,
103 VLC_THREAD_PRIORITY_OUTPUT, VLC_FALSE ) )
105 msg_Err( p_aout, "cannot create aout thread" );
106 delete p_sys->p_sound;
107 free( p_sys->p_format );
112 p_aout->output.pf_play = Play;
117 /*****************************************************************************
118 * SetFormat: sets the dsp output format
119 *****************************************************************************/
120 static int SetFormat( aout_instance_t *p_aout )
122 /* Initialize some variables */
123 p_aout->output.p_sys->p_format->frame_rate = p_aout->output.output.i_rate;
124 p_aout->output.p_sys->p_format->channel_count = p_aout->output.output.i_channels;
126 switch (p_aout->output.output.i_format)
128 case AOUT_FMT_S16_LE:
129 p_aout->output.p_sys->p_format->format = gs_audio_format::B_GS_S16;
130 p_aout->output.p_sys->p_format->byte_order = B_MEDIA_LITTLE_ENDIAN;
132 case AOUT_FMT_S16_BE:
133 p_aout->output.p_sys->p_format->format = gs_audio_format::B_GS_S16;
134 p_aout->output.p_sys->p_format->byte_order = B_MEDIA_BIG_ENDIAN;
137 p_aout->output.p_sys->p_format->format = gs_audio_format::B_GS_U8;
138 p_aout->output.p_sys->p_format->byte_order = B_MEDIA_LITTLE_ENDIAN;
140 case AOUT_FMT_FLOAT32:
141 p_aout->output.p_sys->p_format->format = gs_audio_format::B_GS_F;
142 p_aout->output.p_sys->p_format->byte_order = B_MEDIA_LITTLE_ENDIAN;
145 msg_Err( p_aout, "cannot set audio format (%i)",
146 p_aout->output.output.i_format );
150 p_aout->output.p_sys->p_format->buffer_size = 4*8192;
155 /*****************************************************************************
156 * Play: nothing to do
157 *****************************************************************************/
158 static void Play( aout_instance_t *p_aout )
162 /*****************************************************************************
163 * CloseAudio: closes the dsp audio device
164 *****************************************************************************/
165 void E_(CloseAudio) ( vlc_object_t *p_this )
167 aout_instance_t * p_aout = (aout_instance_t *)p_this;
169 p_aout->output.p_sys->p_sound->UnlockCyclic();
170 p_aout->output.p_sys->p_sound->StopPlaying( );
171 delete p_aout->output.p_sys->p_sound;
174 free( p_aout->output.p_sys->p_format );
175 free( p_aout->output.p_sys );
178 /*****************************************************************************
179 * GetBufInfo: buffer status query
180 *****************************************************************************
181 * This function fills in the audio_buf_info structure :
182 * - returns : number of available fragments (not partially used ones)
183 * - int fragstotal : total number of fragments allocated
184 * - int fragsize : size of a fragment in bytes
185 * - int bytes : available space in bytes (includes partially used fragments)
186 * Note! 'bytes' could be more than fragments*fragsize
187 *****************************************************************************/
188 static int GetBufInfo( aout_instance_t * p_aout )
190 /* returns the allocated space in bytes */
191 return ( p_aout->output.p_sys->p_format->buffer_size );
194 /*****************************************************************************
195 * BeOSThread: asynchronous thread used to DMA the data to the device
196 *****************************************************************************/
197 static int BeOSThread( aout_instance_t * p_aout )
199 struct aout_sys_t * p_sys = p_aout->output.p_sys;
201 static uint i_buffer_pos;
203 p_sys->p_sound->StartPlaying( );
204 p_sys->p_sound->LockForCyclic( &p_sys->p_buffer,
205 (size_t *)&p_sys->i_buffer_size );
207 while ( !p_aout->b_die )
209 aout_buffer_t * p_buffer;
213 mtime_t next_date = 0;
214 /* Get the presentation date of the next write() operation. It
215 * is equal to the current date + duration of buffered samples.
216 * Order is important here, since GetBufInfo is believed to take
217 * more time than mdate(). */
218 next_date = (mtime_t)GetBufInfo( p_aout ) * 1000000
219 / p_aout->output.output.i_bytes_per_frame
220 / p_aout->output.output.i_rate
221 * p_aout->output.output.i_frame_length;
222 next_date += mdate();
224 p_buffer = aout_OutputNextBuffer( p_aout, next_date, VLC_FALSE );
227 if ( p_buffer != NULL )
229 p_bytes = p_buffer->p_buffer;
230 i_size = p_buffer->i_nb_bytes;
234 i_size = FRAME_SIZE / p_aout->output.output.i_frame_length
235 * p_aout->output.output.i_bytes_per_frame;
236 p_bytes = (byte_t *)malloc( i_size );
237 memset( p_bytes, 0, i_size );
240 if( (i_newbuf_pos = i_buffer_pos + p_buffer->i_size)
241 > p_aout->output.p_sys->i_buffer_size )
243 p_aout->p_vlc->pf_memcpy( (void *)((int)p_aout->output.p_sys->p_buffer
246 p_aout->output.p_sys->i_buffer_size - i_buffer_pos );
248 p_aout->p_vlc->pf_memcpy( (void *)((int)p_aout->output.p_sys->p_buffer),
249 p_buffer->p_buffer + p_aout->output.p_sys->i_buffer_size - i_buffer_pos,
250 p_buffer->i_size - ( p_aout->output.p_sys->i_buffer_size - i_buffer_pos ) );
252 i_buffer_pos = i_newbuf_pos - i_buffer_pos;
256 p_aout->p_vlc->pf_memcpy( (void *)((int)p_aout->output.p_sys->p_buffer + i_buffer_pos),
257 p_buffer->p_buffer, p_buffer->i_size );
259 i_buffer_pos = i_newbuf_pos;