/*---------------------------------------------------------------------------- ChucK Concurrent, On-the-fly Audio Programming Language Compiler and Virtual Machine Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved. http://chuck.stanford.edu/ http://chuck.cs.princeton.edu/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 U.S.A.-----------------------------------------------------------------------------*/ #include "chuck_audio.h"#include "chuck_errmsg.h"#include "util_thread.h"#include <unistd.h>#include <al.h>#include <alc.h>#define AL_ALEXT_PROTOTYPES#include <alext.h> // sample#if defined(__CHUCK_USE_64_BIT_SAMPLE__)#define AUDIO_FORMAT AL_FORMAT_STEREO_DOUBLE_EXT#else#define AUDIO_FORMAT AL_FORMAT_STEREO_FLOAT32#endif // real-time watch dogt_CKBOOL g_do_watchdog = FALSE;// countermeasure#ifdef __MACOSX_CORE__t_CKUINT g_watchdog_countermeasure_priority = 10;#elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)t_CKUINT g_watchdog_countermeasure_priority = THREAD_PRIORITY_LOWEST;#elset_CKUINT g_watchdog_countermeasure_priority = 0;#endif// watchdog timeoutt_CKFLOAT g_watchdog_timeout = 0.5; // static initializationt_CKBOOL ChuckAudio::m_init = FALSE;t_CKBOOL ChuckAudio::m_start = FALSE;t_CKBOOL ChuckAudio::m_go = FALSE;t_CKBOOL ChuckAudio::m_silent = FALSE;t_CKBOOL ChuckAudio::m_expand_in_mono2stereo= FALSE;t_CKUINT ChuckAudio::m_num_channels_out = NUM_CHANNELS_DEFAULT;t_CKUINT ChuckAudio::m_num_channels_in = NUM_CHANNELS_DEFAULT;t_CKUINT ChuckAudio::m_num_channels_max = NUM_CHANNELS_DEFAULT;t_CKUINT ChuckAudio::m_sample_rate = SAMPLE_RATE_DEFAULT;t_CKUINT ChuckAudio::m_buffer_size = BUFFER_SIZE_DEFAULT;t_CKUINT ChuckAudio::m_num_buffers = NUM_BUFFERS_DEFAULT;SAMPLE * ChuckAudio::m_buffer_out = NULL;SAMPLE * ChuckAudio::m_buffer_in = NULL;SAMPLE * ChuckAudio::m_extern_in = NULL;SAMPLE * ChuckAudio::m_extern_out = NULL;f_audio_cb ChuckAudio::m_audio_cb = NULL;void * ChuckAudio::m_cb_user_data = NULL;t_CKINT ChuckAudio::m_adc_n = 0;t_CKINT ChuckAudio::m_dac_n = 0;std::string ChuckAudio::m_adc_name = "";std::string ChuckAudio::m_dac_name = "";std::string ChuckAudio::m_driver_name = ""; static ALCdevice *aldev = NULL;static ALCcontext *alc = NULL;static ALuint albuf;static ALuint alsrc;static pthread_t althread; void ChuckAudio::probe( const char * driver ){} t_CKINT ChuckAudio::device_named( const char * driver, const std::string & name, t_CKBOOL needs_dac, t_CKBOOL needs_adc ){ if(needs_adc || !needs_dac) return -1; const char *dev = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); if(dev == NULL) return -1; const char *s = dev; for(int i = 1; *s; i++){ if(strcmp(s, name.c_str()) == 0) return i; s += strlen(s) + 1; } for(int i = 1; *s; i++){ if(strncmp(s, name.c_str(), name.length()) == 0) return i; s += strlen(s) + 1; } return -1;} static t_CKFLOAT get_current_time( t_CKBOOL fresh = TRUE ){#ifdef __PLATFORM_WIN32__ struct _timeb t; _ftime(&t); return t.time + t.millitm/1000.0;#else static struct timeval t; if( fresh ) gettimeofday(&t,NULL); return t.tv_sec + (t_CKFLOAT)t.tv_usec/1000000;#endif} // watch dog globalsstatic CHUCK_THREAD g_tid_synthesis = 0;static XThread * g_watchdog_thread = NULL;static t_CKBOOL g_watchdog_state = FALSE;static t_CKFLOAT g_watchdog_time = 0; #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)static void * watch_dog( void * )#elsestatic unsigned int __stdcall watch_dog( void * )#endif{ // time t_CKFLOAT time = 0; // boost priority? t_CKUINT priority = XThreadUtil::our_priority; // log EM_log( CK_LOG_SEVERE, "starting real-time watch dog process..." ); // push log EM_pushlog(); EM_log( CK_LOG_INFO, "watchdog timeout: %f::second", g_watchdog_timeout ); EM_log( CK_LOG_INFO, "watchdog thread priority: %d", priority ); EM_log( CK_LOG_INFO, "watchdog countermeasure priority: %d", g_watchdog_countermeasure_priority ); // pop log EM_poplog(); // boost watchdog by same priority if( XThreadUtil::our_priority != 0x7fffffff ) XThreadUtil::set_priority( priority ); // while going while( g_do_watchdog ) { // get time = get_current_time( TRUE ); // CK_FPRINTF_STDERR( "last: %f now: %f\n", g_watchdog_time, time ); // resting if( g_watchdog_state == FALSE ) { // check time vs timeout if( time - g_watchdog_time > g_watchdog_timeout ) { // log EM_log( CK_LOG_SEVERE, "real-time watchdog counter-measure activating..." ); // lowering priority if( g_tid_synthesis && XThreadUtil::our_priority != 0x7fffffff ) XThreadUtil::set_priority( g_tid_synthesis, g_watchdog_countermeasure_priority ); // set state g_watchdog_state = TRUE; } } else { // check time vs timeout if( time - g_watchdog_time < g_watchdog_timeout ) { // log EM_log( CK_LOG_SEVERE, "real-time watchdog resting..." ); // raise priority if( g_tid_synthesis && XThreadUtil::our_priority != 0x7fffffff ) XThreadUtil::set_priority( g_tid_synthesis, XThreadUtil::our_priority ); // set state g_watchdog_state = FALSE; } } // advance time usleep( 40000 ); } // log EM_log( CK_LOG_SEVERE, "stopping real-time watch dog process..." ); return 0;} t_CKBOOL ChuckAudio::watchdog_start(){ // already if( g_watchdog_thread ) return FALSE; // flag g_do_watchdog = TRUE; // allocate it g_watchdog_thread = new XThread; // start it g_watchdog_thread->start( watch_dog, NULL ); return TRUE;} t_CKBOOL ChuckAudio::watchdog_stop(){ // already if( !g_watchdog_thread ) return FALSE; // stop things g_do_watchdog = FALSE; // wait a bit | TODO: is this needed? usleep( 100000 ); // delete watchdog thread | TODO: is this safe? SAFE_DELETE( g_watchdog_thread ); return TRUE;} ALsizei ChuckAudio::alcb(ALvoid *userptr, ALvoid *output_buffer, ALsizei len){ // priority boost if( !m_go && XThreadUtil::our_priority != 0x7fffffff ) {#if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__) g_tid_synthesis = pthread_self();#else // must duplicate for handle to be usable by other threads g_tid_synthesis = NULL; DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &g_tid_synthesis, 0, FALSE, DUPLICATE_SAME_ACCESS ); // TODO: close the duplicate handle?#endif XThreadUtil::set_priority( XThreadUtil::our_priority ); memset( output_buffer, 0, len ); m_go = TRUE; // start watchdog if( g_do_watchdog ) { // timestamp g_watchdog_time = get_current_time( TRUE ); // start watchdog watchdog_start(); } // let it go the first time return len; } // timestamp if( g_do_watchdog ) g_watchdog_time = get_current_time( TRUE ); // call the audio cb m_audio_cb( m_buffer_in, m_buffer_out, len/(sizeof(SAMPLE) * m_num_channels_out), m_num_channels_in, m_num_channels_out, m_cb_user_data ); // copy local buffer to be rendered // REFACTOR-2017: TODO: m_end was the signal to end, what should it be now? if( m_start ) // REFACTOR-2017: now using m_start to gate this { memcpy( output_buffer, m_buffer_out, len ); } // set all elements of local buffer to silence else { memset( output_buffer, 0, len ); } // copy to extern if( m_extern_out ) memcpy( m_extern_out, output_buffer, len ); return len;} const char * ChuckAudio::defaultDriverName(){ return "";} t_CKBOOL ChuckAudio::initialize( t_CKUINT dac_device, t_CKUINT adc_device, t_CKUINT num_dac_channels, t_CKUINT num_adc_channels, t_CKUINT sample_rate, t_CKUINT buffer_size, t_CKUINT num_buffers, f_audio_cb callback, void * data, t_CKBOOL force_srate, // force_srate | 1.3.1.2 (added) const char * driver // NULL means default for build | 1.5.0.0 (added) ){ if( m_init ) return FALSE; m_num_channels_out = num_dac_channels; m_num_channels_in = num_adc_channels; m_sample_rate = sample_rate; m_buffer_size = buffer_size; m_num_buffers = num_buffers; m_start = 0; m_go = 0; m_silent = 0; // remember callback m_audio_cb = callback; // remember user data to pass to callback m_cb_user_data = data; // variable to pass by reference into OpenAL unsigned int bufsize = (unsigned int)m_buffer_size; // log EM_log( CK_LOG_FINE, "initializing OpenAL..." ); // push indent EM_pushlog(); const char *dev = NULL; if(m_dac_n > 0){ const char *s = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); for(int i = 1; *s; i++){ if(i == m_dac_n){ dev = s; break; } s += strlen(s) + 1; } } const ALCint attrlist[] = {ALC_FREQUENCY, (ALCint)sample_rate, 0, 0}; althread = pthread_self(); if((aldev = alcOpenDevice(dev)) == NULL) goto error; if((alc = alcCreateContext(aldev, attrlist)) == NULL) goto error; alcMakeContextCurrent(alc); alGenSources(1, &alsrc); alGenBuffers(1, &albuf); alBufferCallbackSOFT(albuf, AUDIO_FORMAT, sample_rate, alcb, NULL); alSourcei(alsrc, AL_SOURCE_SPATIALIZE_SOFT, AL_FALSE); alSourcei(alsrc, AL_BUFFER, albuf); // pop indent EM_poplog(); // allocate buffers m_buffer_in = new SAMPLE[m_buffer_size * m_num_channels_max]; m_buffer_out = new SAMPLE[m_buffer_size * m_num_channels_max]; memset( m_buffer_in, 0, m_buffer_size * sizeof(SAMPLE) * m_num_channels_max ); memset( m_buffer_out, 0, m_buffer_size * sizeof(SAMPLE) * m_num_channels_max ); // set flag and return return m_init = TRUE; // handle common error case (added 1.4.1.0)error: if(alc != NULL){ alcDestroyContext(alc); alc = NULL; } if(aldev != NULL){ alcCloseDevice(aldev); aldev = NULL; } // pop log indent (added 1.4.1.0) EM_poplog(); // set flag and return return m_init = FALSE;} t_CKBOOL ChuckAudio::start( ){ alSourcePlay(alsrc); if( !m_start ) alcDeviceResumeSOFT(aldev); m_start = TRUE; return m_start;} t_CKBOOL ChuckAudio::stop( ){ alSourceStop(alsrc); if( m_start ) alcDevicePauseSOFT(aldev); m_start = FALSE; // REFACTOR-2017: set end flag m_silent = TRUE; return !m_start;} void ChuckAudio::shutdown(){ // check flag if( !m_init ) return; // stop watchdog | REFACTOR-2017: moved this earlier to give watchdog // a head start in stopping, to avoid unneeded countermeasure deployment watchdog_stop(); if(althread == pthread_self() && alc != NULL){ alSourceStop(alsrc); alDeleteSources(1, &alsrc); alDeleteBuffers(1, &albuf); alcDestroyContext(alc); alc = NULL; alcCloseDevice(aldev); aldev = NULL; } // unflag m_init = FALSE; m_start = FALSE;}
/*----------------------------------------------------------------------------
ChucK Concurrent, On-the-fly Audio Programming Language
Compiler and Virtual Machine
Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
http://chuck.stanford.edu/
http://chuck.cs.princeton.edu/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
U.S.A.
-----------------------------------------------------------------------------*/
#include "chuck_audio.h"
#include "chuck_errmsg.h"
#include "util_thread.h"
#include <unistd.h>
#include <al.h>
#include <alc.h>
#define AL_ALEXT_PROTOTYPES
#include <alext.h>
// sample
#if defined(__CHUCK_USE_64_BIT_SAMPLE__)
#define AUDIO_FORMAT AL_FORMAT_STEREO_DOUBLE_EXT
#else
#define AUDIO_FORMAT AL_FORMAT_STEREO_FLOAT32
#endif
// real-time watch dog
t_CKBOOL g_do_watchdog = FALSE;
// countermeasure
#ifdef __MACOSX_CORE__
t_CKUINT g_watchdog_countermeasure_priority = 10;
#elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
t_CKUINT g_watchdog_countermeasure_priority = THREAD_PRIORITY_LOWEST;
#else
t_CKUINT g_watchdog_countermeasure_priority = 0;
#endif
// watchdog timeout
t_CKFLOAT g_watchdog_timeout = 0.5;
// static initialization
t_CKBOOL ChuckAudio::m_init = FALSE;
t_CKBOOL ChuckAudio::m_start = FALSE;
t_CKBOOL ChuckAudio::m_go = FALSE;
t_CKBOOL ChuckAudio::m_silent = FALSE;
t_CKBOOL ChuckAudio::m_expand_in_mono2stereo= FALSE;
t_CKUINT ChuckAudio::m_num_channels_out = NUM_CHANNELS_DEFAULT;
t_CKUINT ChuckAudio::m_num_channels_in = NUM_CHANNELS_DEFAULT;
t_CKUINT ChuckAudio::m_num_channels_max = NUM_CHANNELS_DEFAULT;
t_CKUINT ChuckAudio::m_sample_rate = SAMPLE_RATE_DEFAULT;
t_CKUINT ChuckAudio::m_buffer_size = BUFFER_SIZE_DEFAULT;
t_CKUINT ChuckAudio::m_num_buffers = NUM_BUFFERS_DEFAULT;
SAMPLE * ChuckAudio::m_buffer_out = NULL;
SAMPLE * ChuckAudio::m_buffer_in = NULL;
SAMPLE * ChuckAudio::m_extern_in = NULL;
SAMPLE * ChuckAudio::m_extern_out = NULL;
f_audio_cb ChuckAudio::m_audio_cb = NULL;
void * ChuckAudio::m_cb_user_data = NULL;
t_CKINT ChuckAudio::m_adc_n = 0;
t_CKINT ChuckAudio::m_dac_n = 0;
std::string ChuckAudio::m_adc_name = "";
std::string ChuckAudio::m_dac_name = "";
std::string ChuckAudio::m_driver_name = "";
static ALCdevice *aldev = NULL;
static ALCcontext *alc = NULL;
static ALuint albuf;
static ALuint alsrc;
static pthread_t althread;
void ChuckAudio::probe( const char * driver )
{
}
t_CKINT ChuckAudio::device_named( const char * driver,
const std::string & name, t_CKBOOL needs_dac,
t_CKBOOL needs_adc )
{
if(needs_adc || !needs_dac)
return -1;
const char *dev = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
if(dev == NULL)
return -1;
const char *s = dev;
for(int i = 1; *s; i++){
if(strcmp(s, name.c_str()) == 0)
return i;
s += strlen(s) + 1;
}
for(int i = 1; *s; i++){
if(strncmp(s, name.c_str(), name.length()) == 0)
return i;
s += strlen(s) + 1;
}
return -1;
}
static t_CKFLOAT get_current_time( t_CKBOOL fresh = TRUE )
{
#ifdef __PLATFORM_WIN32__
struct _timeb t;
_ftime(&t);
return t.time + t.millitm/1000.0;
#else
static struct timeval t;
if( fresh ) gettimeofday(&t,NULL);
return t.tv_sec + (t_CKFLOAT)t.tv_usec/1000000;
#endif
}
// watch dog globals
static CHUCK_THREAD g_tid_synthesis = 0;
static XThread * g_watchdog_thread = NULL;
static t_CKBOOL g_watchdog_state = FALSE;
static t_CKFLOAT g_watchdog_time = 0;
#if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
static void * watch_dog( void * )
#else
static unsigned int __stdcall watch_dog( void * )
#endif
{
// time
t_CKFLOAT time = 0;
// boost priority?
t_CKUINT priority = XThreadUtil::our_priority;
// log
EM_log( CK_LOG_SEVERE, "starting real-time watch dog process..." );
// push log
EM_pushlog();
EM_log( CK_LOG_INFO, "watchdog timeout: %f::second", g_watchdog_timeout );
EM_log( CK_LOG_INFO, "watchdog thread priority: %d", priority );
EM_log( CK_LOG_INFO, "watchdog countermeasure priority: %d", g_watchdog_countermeasure_priority );
// pop log
EM_poplog();
// boost watchdog by same priority
if( XThreadUtil::our_priority != 0x7fffffff )
XThreadUtil::set_priority( priority );
// while going
while( g_do_watchdog )
{
// get
time = get_current_time( TRUE );
// CK_FPRINTF_STDERR( "last: %f now: %f\n", g_watchdog_time, time );
// resting
if( g_watchdog_state == FALSE )
{
// check time vs timeout
if( time - g_watchdog_time > g_watchdog_timeout )
{
// log
EM_log( CK_LOG_SEVERE, "real-time watchdog counter-measure activating..." );
// lowering priority
if( g_tid_synthesis && XThreadUtil::our_priority != 0x7fffffff )
XThreadUtil::set_priority( g_tid_synthesis, g_watchdog_countermeasure_priority );
// set state
g_watchdog_state = TRUE;
}
}
else
{
// check time vs timeout
if( time - g_watchdog_time < g_watchdog_timeout )
{
// log
EM_log( CK_LOG_SEVERE, "real-time watchdog resting..." );
// raise priority
if( g_tid_synthesis && XThreadUtil::our_priority != 0x7fffffff )
XThreadUtil::set_priority( g_tid_synthesis, XThreadUtil::our_priority );
// set state
g_watchdog_state = FALSE;
}
}
// advance time
usleep( 40000 );
}
// log
EM_log( CK_LOG_SEVERE, "stopping real-time watch dog process..." );
return 0;
}
t_CKBOOL ChuckAudio::watchdog_start()
{
// already
if( g_watchdog_thread )
return FALSE;
// flag
g_do_watchdog = TRUE;
// allocate it
g_watchdog_thread = new XThread;
// start it
g_watchdog_thread->start( watch_dog, NULL );
return TRUE;
}
t_CKBOOL ChuckAudio::watchdog_stop()
{
// already
if( !g_watchdog_thread )
return FALSE;
// stop things
g_do_watchdog = FALSE;
// wait a bit | TODO: is this needed?
usleep( 100000 );
// delete watchdog thread | TODO: is this safe?
SAFE_DELETE( g_watchdog_thread );
return TRUE;
}
ALsizei ChuckAudio::alcb(ALvoid *userptr, ALvoid *output_buffer, ALsizei len)
{
// priority boost
if( !m_go && XThreadUtil::our_priority != 0x7fffffff )
{
#if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
g_tid_synthesis = pthread_self();
#else
// must duplicate for handle to be usable by other threads
g_tid_synthesis = NULL;
DuplicateHandle(
GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
&g_tid_synthesis,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);
// TODO: close the duplicate handle?
#endif
XThreadUtil::set_priority( XThreadUtil::our_priority );
memset( output_buffer, 0, len );
m_go = TRUE;
// start watchdog
if( g_do_watchdog )
{
// timestamp
g_watchdog_time = get_current_time( TRUE );
// start watchdog
watchdog_start();
}
// let it go the first time
return len;
}
// timestamp
if( g_do_watchdog ) g_watchdog_time = get_current_time( TRUE );
// call the audio cb
m_audio_cb( m_buffer_in, m_buffer_out, len/(sizeof(SAMPLE) * m_num_channels_out),
m_num_channels_in, m_num_channels_out, m_cb_user_data );
// copy local buffer to be rendered
// REFACTOR-2017: TODO: m_end was the signal to end, what should it be now?
if( m_start ) // REFACTOR-2017: now using m_start to gate this
{
memcpy( output_buffer, m_buffer_out, len );
}
// set all elements of local buffer to silence
else
{
memset( output_buffer, 0, len );
}
// copy to extern
if( m_extern_out ) memcpy( m_extern_out, output_buffer, len );
return len;
}
const char * ChuckAudio::defaultDriverName()
{
return "";
}
t_CKBOOL ChuckAudio::initialize( t_CKUINT dac_device,
t_CKUINT adc_device,
t_CKUINT num_dac_channels,
t_CKUINT num_adc_channels,
t_CKUINT sample_rate,
t_CKUINT buffer_size,
t_CKUINT num_buffers,
f_audio_cb callback,
void * data,
t_CKBOOL force_srate, // force_srate | 1.3.1.2 (added)
const char * driver // NULL means default for build | 1.5.0.0 (added)
)
{
if( m_init )
return FALSE;
m_num_channels_out = num_dac_channels;
m_num_channels_in = num_adc_channels;
m_sample_rate = sample_rate;
m_buffer_size = buffer_size;
m_num_buffers = num_buffers;
m_start = 0;
m_go = 0;
m_silent = 0;
// remember callback
m_audio_cb = callback;
// remember user data to pass to callback
m_cb_user_data = data;
// variable to pass by reference into OpenAL
unsigned int bufsize = (unsigned int)m_buffer_size;
// log
EM_log( CK_LOG_FINE, "initializing OpenAL..." );
// push indent
EM_pushlog();
const char *dev = NULL;
if(m_dac_n > 0){
const char *s = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
for(int i = 1; *s; i++){
if(i == m_dac_n){
dev = s;
break;
}
s += strlen(s) + 1;
}
}
const ALCint attrlist[] = {ALC_FREQUENCY, (ALCint)sample_rate, 0, 0};
althread = pthread_self();
if((aldev = alcOpenDevice(dev)) == NULL)
goto error;
if((alc = alcCreateContext(aldev, attrlist)) == NULL)
goto error;
alcMakeContextCurrent(alc);
alGenSources(1, &alsrc);
alGenBuffers(1, &albuf);
alBufferCallbackSOFT(albuf, AUDIO_FORMAT, sample_rate, alcb, NULL);
alSourcei(alsrc, AL_SOURCE_SPATIALIZE_SOFT, AL_FALSE);
alSourcei(alsrc, AL_BUFFER, albuf);
// pop indent
EM_poplog();
// allocate buffers
m_buffer_in = new SAMPLE[m_buffer_size * m_num_channels_max];
m_buffer_out = new SAMPLE[m_buffer_size * m_num_channels_max];
memset( m_buffer_in, 0, m_buffer_size * sizeof(SAMPLE) * m_num_channels_max );
memset( m_buffer_out, 0, m_buffer_size * sizeof(SAMPLE) * m_num_channels_max );
// set flag and return
return m_init = TRUE;
// handle common error case (added 1.4.1.0)
error:
if(alc != NULL){
alcDestroyContext(alc);
alc = NULL;
}
if(aldev != NULL){
alcCloseDevice(aldev);
aldev = NULL;
}
// pop log indent (added 1.4.1.0)
EM_poplog();
// set flag and return
return m_init = FALSE;
}
t_CKBOOL ChuckAudio::start( )
{
alSourcePlay(alsrc);
if( !m_start )
alcDeviceResumeSOFT(aldev);
m_start = TRUE;
return m_start;
}
t_CKBOOL ChuckAudio::stop( )
{
alSourceStop(alsrc);
if( m_start )
alcDevicePauseSOFT(aldev);
m_start = FALSE;
// REFACTOR-2017: set end flag
m_silent = TRUE;
return !m_start;
}
void ChuckAudio::shutdown()
{
// check flag
if( !m_init ) return;
// stop watchdog | REFACTOR-2017: moved this earlier to give watchdog
// a head start in stopping, to avoid unneeded countermeasure deployment
watchdog_stop();
if(althread == pthread_self() && alc != NULL){
alSourceStop(alsrc);
alDeleteSources(1, &alsrc);
alDeleteBuffers(1, &albuf);
alcDestroyContext(alc);
alc = NULL;
alcCloseDevice(aldev);
aldev = NULL;
}
// unflag
m_init = FALSE;
m_start = FALSE;
}