[Project64] Add Audio plugin for android

This commit is contained in:
zilmar 2016-06-05 11:33:35 +10:00
parent b927aedc7f
commit 06383ff638
10 changed files with 1343 additions and 0 deletions

View File

@ -0,0 +1,32 @@
/****************************************************************************
* *
* Project64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2016 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* version 2 of the License, or (at your option) any later version. *
* *
****************************************************************************/
#include "AudioSettings.h"
#include "trace.h"
#include "main.h"
void SetupAudioSettings (void)
{
SetModuleName("AndroidAudio");
RegisterSetting(Output_SwapChannels, Data_DWORD_General, "SwapChannels", "", 0, NULL);
RegisterSetting(Output_DefaultFrequency, Data_DWORD_General, "DefaultFrequency", "", DEFAULT_FREQUENCY, NULL);
RegisterSetting(Buffer_PrimarySize, Data_DWORD_General, "BufferPrimarySize", "", PRIMARY_BUFFER_SIZE, NULL);
RegisterSetting(Buffer_SecondarySize, Data_DWORD_General, "BufferSecondarySize", "", SECONDARY_BUFFER_SIZE, NULL);
RegisterSetting(Buffer_SecondaryNbr, Data_DWORD_General, "BufferSecondaryNbr", "", SECONDARY_BUFFER_NBR, NULL);
RegisterSetting(Logging_LogAudioInitShutdown, Data_DWORD_General, "AudioInitShutdown", "Logging", g_ModuleLogLevel[TraceAudioInitShutdown], NULL);
RegisterSetting(Logging_LogAudioInterface, Data_DWORD_General, "AudioInterface", "Logging", g_ModuleLogLevel[TraceAudioInterface], NULL);
g_SwapChannels = GetSetting(Output_SwapChannels);
g_GameFreq = GetSetting(Output_DefaultFrequency);
g_ModuleLogLevel[TraceAudioInitShutdown] = GetSetting(Logging_LogAudioInitShutdown);
g_ModuleLogLevel[TraceAudioInterface] = GetSetting(Logging_LogAudioInterface);
}

View File

@ -0,0 +1,26 @@
/****************************************************************************
* *
* Project64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2016 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* version 2 of the License, or (at your option) any later version. *
* *
****************************************************************************/
#pragma once
#include <Settings/Settings.h>
enum AudioSettingID
{
Output_SwapChannels,
Output_DefaultFrequency,
Buffer_PrimarySize,
Buffer_SecondarySize,
Buffer_SecondaryNbr,
Logging_LogAudioInitShutdown,
Logging_LogAudioInterface,
};
void SetupAudioSettings ( void );

View File

@ -0,0 +1,194 @@
/**********************************************************************************
Common Audio plugin spec, version #1.1
**********************************************************************************
Notes:
------
Setting the approprate bits in the MI_INTR_REG and calling CheckInterrupts which
are both passed to the DLL in InitiateAudio will generate an Interrupt from with in
the plugin.
**********************************************************************************/
#pragma once
#include <Common/stdtypes.h>
enum { PLUGIN_TYPE_AUDIO = 3 };
#if defined(_WIN32)
#define EXPORT extern "C" __declspec(dllexport)
#define CALL __cdecl
#else
#define EXPORT extern "C" __attribute__((visibility("default")))
#define CALL
#endif
enum
{
SYSTEM_NTSC = 0,
SYSTEM_PAL = 1,
SYSTEM_MPAL = 2,
};
/***** Structures *****/
typedef struct
{
uint16_t Version; /* Should be set to 0x0101 */
uint16_t Type; /* Set to PLUGIN_TYPE_AUDIO */
char Name[100]; /* Name of the DLL */
int32_t NormalMemory;
int32_t MemoryBswaped;
} PLUGIN_INFO;
typedef struct
{
void * hwnd;
void * hinst;
int32_t MemoryBswaped; // If this is set to TRUE, then the memory has been pre
// bswap on a dword (32 bits) boundry
// eg. the first 8 bytes are stored like this:
// 4 3 2 1 8 7 6 5
uint8_t * HEADER; // This is the rom header (first 40h bytes of the rom
// This will be in the same memory format as the rest of the memory.
uint8_t * RDRAM;
uint8_t * DMEM;
uint8_t * IMEM;
uint32_t * MI__INTR_REG;
uint32_t * AI__DRAM_ADDR_REG;
uint32_t * AI__LEN_REG;
uint32_t * AI__CONTROL_REG;
uint32_t * AI__STATUS_REG;
uint32_t * AI__DACRATE_REG;
uint32_t * AI__BITRATE_REG;
void(CALL *CheckInterrupts)(void);
} AUDIO_INFO;
/******************************************************************
Function: AiDacrateChanged
Purpose: This function is called to notify the dll that the
AiDacrate registers value has been changed.
input: The System type:
SYSTEM_NTSC 0
SYSTEM_PAL 1
SYSTEM_MPAL 2
output: none
*******************************************************************/
EXPORT void CALL AiDacrateChanged(int32_t SystemType);
/******************************************************************
Function: AiLenChanged
Purpose: This function is called to notify the dll that the
AiLen registers value has been changed.
input: none
output: none
*******************************************************************/
EXPORT void CALL AiLenChanged(void);
/******************************************************************
Function: AiReadLength
Purpose: This function is called to allow the dll to return the
value that AI_LEN_REG should equal
input: none
output: The amount of bytes still left to play.
*******************************************************************/
EXPORT uint32_t CALL AiReadLength(void);
/******************************************************************
Function: AiUpdate
Purpose: This function is called to allow the dll to update
things on a regular basis (check how long to sound to
go, copy more stuff to the buffer, anyhting you like).
The function is designed to go in to the message loop
of the main window ... but can be placed anywhere you
like.
input: if Wait is set to true, then this function should wait
till there is a messgae in the its message queue.
output: none
*******************************************************************/
EXPORT void CALL AiUpdate(int32_t Wait);
/******************************************************************
Function: CloseDLL
Purpose: This function is called when the emulator is closing
down allowing the dll to de-initialise.
input: none
output: none
*******************************************************************/
EXPORT void CALL CloseDLL(void);
/******************************************************************
Function: DllAbout
Purpose: This function is optional function that is provided
to give further information about the DLL.
input: a handle to the window that calls this function
output: none
*******************************************************************/
EXPORT void CALL DllAbout(void * hParent);
/******************************************************************
Function: DllConfig
Purpose: This function is optional function that is provided
to allow the user to configure the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
EXPORT void CALL DllConfig(void * hParent);
/******************************************************************
Function: DllTest
Purpose: This function is optional function that is provided
to allow the user to test the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
EXPORT void CALL DllTest(void * hParent);
/******************************************************************
Function: GetDllInfo
Purpose: This function allows the emulator to gather information
about the dll by filling in the PluginInfo structure.
input: a pointer to a PLUGIN_INFO stucture that needs to be
filled by the function. (see def above)
output: none
*******************************************************************/
EXPORT void CALL GetDllInfo(PLUGIN_INFO * PluginInfo);
/******************************************************************
Function: InitiateSound
Purpose: This function is called when the DLL is started to give
information from the emulator that the n64 audio
interface needs
Input: Audio_Info is passed to this function which is defined
above.
Output: TRUE on success
FALSE on failure to initialise
** note on interrupts **:
To generate an interrupt set the appropriate bit in MI_INTR_REG
and then call the function CheckInterrupts to tell the emulator
that there is a waiting interrupt.
*******************************************************************/
EXPORT int32_t CALL InitiateAudio(AUDIO_INFO Audio_Info);
/******************************************************************
Function: ProcessAList
Purpose: This function is called when there is a Alist to be
processed. The Dll will have to work out all the info
about the AList itself.
input: none
output: none
*******************************************************************/
EXPORT void CALL ProcessAList(void);
/******************************************************************
Function: RomClosed
Purpose: This function is called when a rom is closed.
input: none
output: none
*******************************************************************/
EXPORT void CALL RomClosed(void);

View File

@ -0,0 +1,799 @@
/****************************************************************************
* *
* Project64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2016 Project64. All rights reserved. *
* Copyright (C) 2015 Gilles Siberlin *
* Copyright (C) 2007-2009 Richard Goedeken *
* Copyright (C) 2007-2008 Ebenblues *
* Copyright (C) 2003 JttL *
* Copyright (C) 2002 Hacktarux *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* version 2 of the License, or (at your option) any later version. *
* *
****************************************************************************/
#ifdef ANDROID
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
#endif
#include "audio_1.1.h"
#include "Version.h"
#include <stdio.h>
#include <string.h>
#include "AudioSettings.h"
#include "trace.h"
#include "main.h"
#ifdef ANDROID
typedef struct threadLock_
{
pthread_mutex_t mutex;
pthread_cond_t cond;
volatile unsigned char value;
volatile unsigned char limit;
} threadLock;
#endif
/* Read header for type definition */
AUDIO_INFO g_AudioInfo;
/* Pointer to the primary audio buffer */
uint8_t * g_primaryBuffer = NULL;
/* Size of the primary buffer */
uint32_t g_primaryBufferBytes = 0;
/* Size of the primary audio buffer in equivalent output samples */
unsigned int g_PrimaryBufferSize = PRIMARY_BUFFER_SIZE;
/* Pointer to secondary buffers */
uint8_t ** g_secondaryBuffers = NULL;
/* Size of a single secondary buffer */
uint32_t g_secondaryBufferBytes = 0;
/* Size of a single secondary audio buffer in output samples */
uint32_t g_SecondaryBufferSize = SECONDARY_BUFFER_SIZE;
/* Position in the primary buffer where next audio chunk should be placed */
uint32_t g_primaryBufferPos = 0;
/* Index of the next secondary buffer available */
uint32_t g_secondaryBufferIndex = 0;
/* Number of secondary buffers */
uint32_t g_SecondaryBufferNbr = SECONDARY_BUFFER_NBR;
/* Audio frequency, this is usually obtained from the game, but for compatibility we set default value */
uint32_t g_GameFreq = DEFAULT_FREQUENCY;
/* SpeedFactor is used to increase/decrease game playback speed */
uint32_t g_speed_factor = 100;
/* If this is true then left and right channels are swapped */
bool g_SwapChannels = false;
/* Output Audio frequency */
int g_OutputFreq = 44100;
/* Indicate that the audio plugin failed to initialize, so the emulator can keep running without sound */
bool g_critical_failure = false;
#ifdef ANDROID
/* Thread Lock */
threadLock g_lock;
/* Engine interfaces */
SLObjectItf g_engineObject = NULL;
SLEngineItf g_engineEngine = NULL;
/* Output mix interfaces */
SLObjectItf g_outputMixObject = NULL;
/* Player interfaces */
SLObjectItf g_playerObject = NULL;
SLPlayItf g_playerPlay = NULL;
/* Buffer queue interfaces */
SLAndroidSimpleBufferQueueItf g_bufferQueue = NULL;
#endif
bool g_PluginInit = false;
void PluginInit ( void )
{
if (g_PluginInit)
{
return;
}
SetupTrace();
SetupAudioSettings();
g_PluginInit = true;
}
/* This callback handler is called every time a buffer finishes playing */
#ifdef ANDROID
void queueCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
{
threadLock *plock = (threadLock *) context;
pthread_mutex_lock(&(plock->mutex));
if(plock->value < plock->limit)
plock->value++;
pthread_cond_signal(&(plock->cond));
pthread_mutex_unlock(&(plock->mutex));
}
#endif
static void CloseAudio(void)
{
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start");
g_primaryBufferPos = 0;
g_secondaryBufferIndex = 0;
/* Delete Primary buffer */
if (g_primaryBuffer != NULL)
{
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Delete g_primaryBuffer (%p)",g_primaryBuffer);
g_primaryBufferBytes = 0;
delete [] g_primaryBuffer;
g_primaryBuffer = NULL;
}
/* Delete Secondary buffers */
if (g_secondaryBuffers != NULL)
{
for(uint32_t i = 0; i < g_SecondaryBufferNbr; i++)
{
if (g_secondaryBuffers[i] != NULL)
{
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Delete g_secondaryBuffers[%d] (%p)",i,g_secondaryBuffers[i]);
delete [] g_secondaryBuffers[i];
g_secondaryBuffers[i] = NULL;
}
}
g_secondaryBufferBytes = 0;
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Delete g_secondaryBuffers (%p)",g_secondaryBuffers);
delete [] g_secondaryBuffers;
g_secondaryBuffers = NULL;
}
#ifdef ANDROID
/* Destroy buffer queue audio player object, and invalidate all associated interfaces */
if (g_playerObject != NULL)
{
SLuint32 state = SL_PLAYSTATE_PLAYING;
(*g_playerPlay)->SetPlayState(g_playerPlay, SL_PLAYSTATE_STOPPED);
while(state != SL_PLAYSTATE_STOPPED)
{
(*g_playerPlay)->GetPlayState(g_playerPlay, &state);
}
(*g_playerObject)->Destroy(g_playerObject);
g_playerObject = NULL;
g_playerPlay = NULL;
g_bufferQueue = NULL;
}
/* Destroy output mix object, and invalidate all associated interfaces */
if (g_outputMixObject != NULL)
{
(*g_outputMixObject)->Destroy(g_outputMixObject);
g_outputMixObject = NULL;
}
/* Destroy engine object, and invalidate all associated interfaces */
if (g_engineObject != NULL)
{
(*g_engineObject)->Destroy(g_engineObject);
g_engineObject = NULL;
g_engineEngine = NULL;
}
/* Destroy thread Locks */
pthread_cond_signal(&(g_lock.cond));
pthread_mutex_unlock(&(g_lock.mutex));
pthread_cond_destroy(&(g_lock.cond));
pthread_mutex_destroy(&(g_lock.mutex));
#endif
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
}
static bool CreatePrimaryBuffer(void)
{
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start");
unsigned int primaryBytes = (unsigned int) (g_PrimaryBufferSize * N64_SAMPLE_BYTES);
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Allocating memory for primary audio buffer: %i bytes.", primaryBytes);
g_primaryBuffer = new uint8_t[primaryBytes];
if (g_primaryBuffer == NULL)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_primaryBuffer == NULL");
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: false)");
return false;
}
memset(g_primaryBuffer, 0, primaryBytes);
g_primaryBufferBytes = primaryBytes;
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: True)");
return true;
}
static bool CreateSecondaryBuffers(void)
{
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start");
bool status = true;
unsigned int secondaryBytes = (unsigned int) (g_SecondaryBufferSize * SLES_SAMPLE_BYTES);
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Allocating memory for %d secondary audio buffers: %i bytes.", g_SecondaryBufferNbr, secondaryBytes);
/* Allocate number of secondary buffers */
g_secondaryBuffers = new uint8_t *[g_SecondaryBufferNbr];
if (g_secondaryBuffers == NULL)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_secondaryBuffers == NULL");
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: false)");
return false;
}
/* Allocate size of each secondary buffers */
for(uint32_t i = 0; i < g_SecondaryBufferNbr; i++)
{
g_secondaryBuffers[i] = new uint8_t[secondaryBytes];
if (g_secondaryBuffers[i] == NULL)
{
status = false;
break;
}
memset(g_secondaryBuffers[i], 0, secondaryBytes);
}
g_secondaryBufferBytes = secondaryBytes;
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done (res: %s)",status?"True":"False");
return status;
}
static void InitializeAudio(uint32_t freq)
{
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Start (freq: %d)",freq);
if (freq < 4000)
{
WriteTrace(TraceAudioInitShutdown, TraceInfo, "Sometimes a bad frequency is requested so ignore it (freq: %d)",freq);
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
return;
}
if (g_GameFreq == freq && g_primaryBuffer != NULL)
{
WriteTrace(TraceAudioInitShutdown, TraceInfo, "we are already using this frequency, so ignore it (freq: %d)",freq);
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
return;
}
if (g_critical_failure)
{
WriteTrace(TraceAudioInitShutdown, TraceInfo, "had a critical failure in setting up plugin, so ignore init");
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
return;
}
/* This is important for the sync */
g_GameFreq = freq;
#ifdef ANDROID
SLuint32 sample_rate;
if((freq/1000) <= 11)
{
g_OutputFreq = 11025;
sample_rate = SL_SAMPLINGRATE_11_025;
}
else if((freq/1000) <= 22)
{
g_OutputFreq = 22050;
sample_rate = SL_SAMPLINGRATE_22_05;
}
else if((freq/1000) <= 32)
{
g_OutputFreq = 32000;
sample_rate = SL_SAMPLINGRATE_32;
}
else
{
g_OutputFreq = 44100;
sample_rate = SL_SAMPLINGRATE_44_1;
}
#endif
WriteTrace(TraceAudioInitShutdown, TraceInfo, "Requesting frequency: %iHz.", g_OutputFreq);
/* reload these because they gets re-assigned from data below, and InitializeAudio can be called more than once */
g_PrimaryBufferSize = GetSetting(Buffer_PrimarySize);
g_SecondaryBufferSize = GetSetting(Buffer_SecondarySize);
g_SecondaryBufferNbr = GetSetting(Buffer_SecondaryNbr);
/* Close everything because InitializeAudio can be called more than once */
CloseAudio();
/* Create primary buffer */
if(!CreatePrimaryBuffer())
{
WriteTrace(TraceAudioInitShutdown, TraceError, "CreatePrimaryBuffer failed");
CloseAudio();
g_critical_failure = true;
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
return;
}
/* Create secondary buffers */
if(!CreateSecondaryBuffers())
{
WriteTrace(TraceAudioInitShutdown, TraceError, "CreateSecondaryBuffers failed");
CloseAudio();
g_critical_failure = true;
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
return;
}
#ifdef ANDROID
/* Create thread Locks to ensure synchronization between callback and processing code */
if (pthread_mutex_init(&(g_lock.mutex), (pthread_mutexattr_t*) NULL) != 0)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "pthread_mutex_init failed");
CloseAudio();
g_critical_failure = true;
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
return;
}
if (pthread_cond_init(&(g_lock.cond), (pthread_condattr_t*) NULL) != 0)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "pthread_cond_init failed");
CloseAudio();
g_critical_failure = true;
WriteTrace(TraceAudioInitShutdown, TraceDebug, "Done");
return;
}
pthread_mutex_lock(&(g_lock.mutex));
g_lock.value = g_lock.limit = g_SecondaryBufferNbr;
pthread_mutex_unlock(&(g_lock.mutex));
/* Engine object */
SLresult result = slCreateEngine(&g_engineObject, 0, NULL, 0, NULL, NULL);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine failed (result: %d)",result);
}
if(result == SL_RESULT_SUCCESS)
{
result = (*g_engineObject)->Realize(g_engineObject, SL_BOOLEAN_FALSE);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine->Realize failed (result: %d)",result);
}
}
if(result == SL_RESULT_SUCCESS)
{
result = (*g_engineObject)->GetInterface(g_engineObject, SL_IID_ENGINE, &g_engineEngine);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine->GetInterface failed (result: %d)",result);
}
}
if(result == SL_RESULT_SUCCESS)
{
/* Output mix object */
result = (*g_engineEngine)->CreateOutputMix(g_engineEngine, &g_outputMixObject, 0, NULL, NULL);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "slCreateEngine->CreateOutputMix failed (result: %d)",result);
}
}
if(result == SL_RESULT_SUCCESS)
{
result = (*g_outputMixObject)->Realize(g_outputMixObject, SL_BOOLEAN_FALSE);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_outputMixObject->Realize failed (result: %d)",result);
}
}
if(result == SL_RESULT_SUCCESS)
{
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, g_SecondaryBufferNbr};
SLDataFormat_PCM format_pcm = {SL_DATAFORMAT_PCM,2, sample_rate, SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
(SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT), SL_BYTEORDER_LITTLEENDIAN};
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
/* Configure audio sink */
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, g_outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
/* Create audio player */
const SLInterfaceID ids1[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
const SLboolean req1[] = {SL_BOOLEAN_TRUE};
result = (*g_engineEngine)->CreateAudioPlayer(g_engineEngine, &(g_playerObject), &audioSrc, &audioSnk, 1, ids1, req1);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_engineEngine->CreateAudioPlayer failed (result: %d)",result);
}
}
/* Realize the player */
if(result == SL_RESULT_SUCCESS)
{
result = (*g_playerObject)->Realize(g_playerObject, SL_BOOLEAN_FALSE);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerObject->Realize failed (result: %d)",result);
}
}
/* Get the play interface */
if(result == SL_RESULT_SUCCESS)
{
result = (*g_playerObject)->GetInterface(g_playerObject, SL_IID_PLAY, &(g_playerPlay));
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerObject->GetInterface(SL_IID_PLAY) failed (result: %d)",result);
}
}
/* Get the buffer queue interface */
if(result == SL_RESULT_SUCCESS)
{
result = (*g_playerObject)->GetInterface(g_playerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(g_bufferQueue));
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerObject->GetInterface(SL_IID_ANDROIDSIMPLEBUFFERQUEUE) failed (result: %d)",result);
}
}
/* register callback on the buffer queue */
if(result == SL_RESULT_SUCCESS)
{
result = (*g_bufferQueue)->RegisterCallback(g_bufferQueue, queueCallback, &g_lock);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "bufferQueue->RegisterCallback() failed (result: %d)",result);
}
}
/* set the player's state to playing */
if(result == SL_RESULT_SUCCESS)
{
result = (*g_playerPlay)->SetPlayState(g_playerPlay, SL_PLAYSTATE_PLAYING);
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceError, "g_playerPlay->SetPlayState(SL_PLAYSTATE_PLAYING) failed (result: %d)",result);
}
}
if(result != SL_RESULT_SUCCESS)
{
WriteTrace(TraceAudioInitShutdown, TraceNotice, "Couldn't open OpenSLES audio");
CloseAudio();
g_critical_failure = true;
}
#endif
WriteTrace(TraceAudioInitShutdown, TraceNotice, "Done");
}
static int resample(unsigned char *input, int /*input_avail*/, int oldsamplerate, unsigned char *output, int output_needed, int newsamplerate)
{
int *psrc = (int*)input;
int *pdest = (int*)output;
int i = 0, j = 0;
#ifdef USE_SPEEX
spx_uint32_t in_len, out_len;
if(Resample == RESAMPLER_SPEEX)
{
if(spx_state == NULL)
{
spx_state = speex_resampler_init(2, oldsamplerate, newsamplerate, ResampleQuality, &error);
if(spx_state == NULL)
{
memset(output, 0, output_needed);
return 0;
}
}
speex_resampler_set_rate(spx_state, oldsamplerate, newsamplerate);
in_len = input_avail / 4;
out_len = output_needed / 4;
if ((error = speex_resampler_process_interleaved_int(spx_state, (const spx_int16_t *)input, &in_len, (spx_int16_t *)output, &out_len)))
{
memset(output, 0, output_needed);
return input_avail; // number of bytes consumed
}
return in_len * 4;
}
#endif
#ifdef USE_SRC
if(Resample == RESAMPLER_SRC)
{
// the high quality resampler needs more input than the samplerate ratio would indicate to work properly
if (input_avail > output_needed * 3 / 2)
input_avail = output_needed * 3 / 2; // just to avoid too much short-float-short conversion time
if (_src_len < input_avail*2 && input_avail > 0)
{
if(_src) free(_src);
_src_len = input_avail*2;
_src = malloc(_src_len);
}
if (_dest_len < output_needed*2 && output_needed > 0)
{
if(_dest) free(_dest);
_dest_len = output_needed*2;
_dest = malloc(_dest_len);
}
memset(_src,0,_src_len);
memset(_dest,0,_dest_len);
if(src_state == NULL)
{
src_state = src_new (ResampleQuality, 2, &error);
if(src_state == NULL)
{
memset(output, 0, output_needed);
return 0;
}
}
src_short_to_float_array ((short *) input, _src, input_avail/2);
src_data.end_of_input = 0;
src_data.data_in = _src;
src_data.input_frames = input_avail/4;
src_data.src_ratio = (float) newsamplerate / oldsamplerate;
src_data.data_out = _dest;
src_data.output_frames = output_needed/4;
if ((error = src_process (src_state, &src_data)))
{
memset(output, 0, output_needed);
return input_avail; // number of bytes consumed
}
src_float_to_short_array (_dest, (short *) output, output_needed/2);
return src_data.input_frames_used * 4;
}
#endif
// RESAMPLE == TRIVIAL
if (newsamplerate >= oldsamplerate)
{
int sldf = oldsamplerate;
int const2 = 2*sldf;
int dldf = newsamplerate;
int const1 = const2 - 2*dldf;
int criteria = const2 - dldf;
for (i = 0; i < output_needed/4; i++)
{
pdest[i] = psrc[j];
if(criteria >= 0)
{
++j;
criteria += const1;
}
else criteria += const2;
}
return j * 4; //number of bytes consumed
}
// newsamplerate < oldsamplerate, this only happens when speed_factor > 1
for (i = 0; i < output_needed/4; i++)
{
j = i * oldsamplerate / newsamplerate;
pdest[i] = psrc[j];
}
return j * 4; //number of bytes consumed
}
EXPORT void CALL PluginLoaded(void)
{
PluginInit();
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
}
EXPORT void CALL AiDacrateChanged(int SystemType)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Start (SystemType: %d)",SystemType);
if (!g_PluginInit)
{
WriteTrace(TraceAudioInterface, TraceNotice, "Plugin has not been initilized");
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
return;
}
int f = g_GameFreq != 0 ? g_GameFreq : DEFAULT_FREQUENCY;
switch (SystemType)
{
case SYSTEM_NTSC:
f = 48681812 / (*g_AudioInfo.AI__DACRATE_REG + 1);
break;
case SYSTEM_PAL:
f = 49656530 / (*g_AudioInfo.AI__DACRATE_REG + 1);
break;
case SYSTEM_MPAL:
f = 48628316 / (*g_AudioInfo.AI__DACRATE_REG + 1);
break;
}
InitializeAudio(f);
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
}
EXPORT void CALL AiLenChanged(void)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Start (DRAM_ADDR = 0x%X LenReg = 0x%X)", *g_AudioInfo.AI__LEN_REG, *g_AudioInfo.AI__DRAM_ADDR_REG);
uint32_t LenReg = *g_AudioInfo.AI__LEN_REG;
uint8_t * p = g_AudioInfo.RDRAM + (*g_AudioInfo.AI__DRAM_ADDR_REG & 0xFFFFFF);
WriteTrace(TraceAudioInterface, TraceDebug, "g_primaryBufferPos = 0x%X LenReg = 0x%X g_primaryBufferBytes = %X", g_primaryBufferPos, LenReg, g_primaryBufferBytes);
if (g_primaryBufferPos + LenReg < g_primaryBufferBytes)
{
unsigned int i;
for ( i = 0 ; i < LenReg ; i += 4 )
{
if(g_SwapChannels == 0)
{
/* Left channel */
g_primaryBuffer[ g_primaryBufferPos + i ] = p[ i + 2 ];
g_primaryBuffer[ g_primaryBufferPos + i + 1 ] = p[ i + 3 ];
/* Right channel */
g_primaryBuffer[ g_primaryBufferPos + i + 2 ] = p[ i ];
g_primaryBuffer[ g_primaryBufferPos + i + 3 ] = p[ i + 1 ];
}
else
{
/* Left channel */
g_primaryBuffer[ g_primaryBufferPos + i ] = p[ i ];
g_primaryBuffer[ g_primaryBufferPos + i + 1 ] = p[ i + 1 ];
/* Right channel */
g_primaryBuffer[ g_primaryBufferPos + i + 2 ] = p[ i + 2];
g_primaryBuffer[ g_primaryBufferPos + i + 3 ] = p[ i + 3 ];
}
}
g_primaryBufferPos += i;
}
else
{
WriteTrace(TraceAudioInterface, TraceDebug, "Audio primary buffer overflow. (g_primaryBufferPos: %d LenReg: %d g_primaryBufferBytes: %d)", g_primaryBufferPos, LenReg, g_primaryBufferBytes);
}
uint32_t newsamplerate = g_OutputFreq * 100 / g_speed_factor;
uint32_t oldsamplerate = g_GameFreq != 0 ? g_GameFreq : DEFAULT_FREQUENCY;
while (g_primaryBufferPos >= ((g_secondaryBufferBytes * oldsamplerate) / newsamplerate))
{
WriteTrace(TraceAudioInterface, TraceDebug, "g_secondaryBufferBytes = %d", g_secondaryBufferBytes);
WriteTrace(TraceAudioInterface, TraceDebug, "oldsamplerate = %d", oldsamplerate);
WriteTrace(TraceAudioInterface, TraceDebug, "newsamplerate = %d", newsamplerate);
WriteTrace(TraceAudioInterface, TraceDebug, "((g_secondaryBufferBytes * oldsamplerate) / newsamplerate) = %d", ((g_secondaryBufferBytes * oldsamplerate) / newsamplerate));
WriteTrace(TraceAudioInterface, TraceDebug, "g_primaryBufferPos= %d", g_primaryBufferPos);
#ifdef ANDROID
pthread_mutex_lock(&(g_lock.mutex));
/* Wait for the next callback if no more output buffers available */
while (g_lock.value == 0)
{
pthread_cond_wait(&(g_lock.cond), &(g_lock.mutex));
}
g_lock.value--;
pthread_mutex_unlock(&(g_lock.mutex));
#endif
WriteTrace(TraceAudioInterface, TraceDebug, "Finished with lock");
// TODO: don't resample if speed_factor = 100 and newsamplerate ~= oldsamplerate
int input_used = resample(g_primaryBuffer, g_primaryBufferPos, oldsamplerate, g_secondaryBuffers[g_secondaryBufferIndex], g_secondaryBufferBytes, newsamplerate);
#ifdef ANDROID
(*g_bufferQueue)->Enqueue(g_bufferQueue, g_secondaryBuffers[g_secondaryBufferIndex], g_secondaryBufferBytes);
#endif
memmove(g_primaryBuffer, &g_primaryBuffer[input_used], g_primaryBufferPos - input_used);
g_primaryBufferPos -= input_used;
g_secondaryBufferIndex++;
if(g_secondaryBufferIndex > (g_SecondaryBufferNbr-1))
{
g_secondaryBufferIndex = 0;
}
}
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
}
EXPORT uint32_t CALL AiReadLength(void)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
return 0;
}
EXPORT void CALL AiUpdate(int32_t /*Wait*/)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
}
EXPORT void CALL CloseDLL(void)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
}
EXPORT void CALL DllAbout(void * /*hParent*/)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
}
EXPORT void CALL DllConfig(void * /*hParent*/)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
}
EXPORT void CALL DllTest(void * /*hParent*/)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
}
EXPORT void CALL GetDllInfo(PLUGIN_INFO * PluginInfo)
{
PluginInfo->Version = 0x0101;
PluginInfo->Type = PLUGIN_TYPE_AUDIO;
#ifdef _DEBUG
sprintf(PluginInfo->Name, "Android Audio Debug Plugin %s", VER_FILE_VERSION_STR);
#else
sprintf(PluginInfo->Name, "Android Audio Plugin %s", VER_FILE_VERSION_STR);
#endif
PluginInfo->MemoryBswaped = true;
PluginInfo->NormalMemory = false;
}
EXPORT int32_t CALL InitiateAudio(AUDIO_INFO Audio_Info)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Start");
g_AudioInfo = Audio_Info;
WriteTrace(TraceAudioInterface, TraceDebug, "Done (res: true)");
return true;
}
EXPORT void CALL RomOpen()
{
WriteTrace(TraceAudioInterface, TraceDebug, "Start");
InitializeAudio(DEFAULT_FREQUENCY);
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
}
EXPORT void CALL RomClosed(void)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Start");
CloseAudio();
WriteTrace(TraceAudioInterface, TraceDebug, "Done");
}
EXPORT void CALL ProcessAList(void)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
}
extern "C" void UseUnregisteredSetting(int /*SettingID*/)
{
WriteTrace(TraceAudioInterface, TraceDebug, "Called");
#ifdef _WIN32
DebugBreak();
#endif
}

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{D233025A-231F-4A43-92B6-E87193C60ACC}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>PluginAudio</RootNamespace>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(SolutionDir)PropertySheets\Platform.$(Configuration).props" />
</ImportGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<PropertyGroup>
<TargetName>AndroidAudio</TargetName>
<TargetName Condition="'$(Configuration)'=='Debug'">AndroidAudio_d</TargetName>
<OutDir>$(SolutionDir)Plugin\Audio\</OutDir>
<OutDir Condition="'$(Platform)'=='x64'">$(SolutionDir)Plugin64\AndroidAudio\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="AudioSettings.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="trace.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Audio_1.1.h" />
<ClInclude Include="AudioSettings.h" />
<ClInclude Include="main.h" />
<ClInclude Include="trace.h" />
<ClInclude Include="Version.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Common\Common.vcxproj">
<Project>{b4a4b994-9111-42b1-93c2-6f1ca8bc4421}</Project>
</ProjectReference>
<ProjectReference Include="..\..\Settings\Settings.vcxproj">
<Project>{8b9961b1-88d9-4ea3-a752-507a00dd9f3d}</Project>
</ProjectReference>
</ItemGroup>
</Project>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Main.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trace.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AudioSettings.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Audio_1.1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="trace.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AudioSettings.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="main.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,42 @@
/****************************************************************************
* *
* Project64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2016 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* version 2 of the License, or (at your option) any later version. *
* *
****************************************************************************/
#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_REVISION 0
#define VERSION_BUILD 9999
#define VER_FILE_DESCRIPTION_STR "Android Audio Plugin"
#define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD
#define VER_FILE_VERSION_STR STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR) \
"." STRINGIZE(VERSION_REVISION) \
"." STRINGIZE(VERSION_BUILD) \
#define VER_PRODUCTNAME_STR "Android-Audio"
#define VER_PRODUCT_VERSION VER_FILE_VERSION
#define VER_PRODUCT_VERSION_STR VER_FILE_VERSION_STR
#define VER_ORIGINAL_FILENAME_STR VER_PRODUCTNAME_STR ".dll"
#define VER_INTERNAL_NAME_STR VER_PRODUCTNAME_STR
#define VER_COPYRIGHT_STR "Copyright (C) 2016"
#ifdef _DEBUG
#define VER_VER_DEBUG VS_FF_DEBUG
#else
#define VER_VER_DEBUG 0
#endif
#define VER_FILEOS VOS_NT_WINDOWS32
#define VER_FILEFLAGS VER_VER_DEBUG
#define VER_FILETYPE VFT_DLL

View File

@ -0,0 +1,40 @@
/****************************************************************************
* *
* Project64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2016 Project64. All rights reserved. *
* Copyright (C) 2008-2012 Tillin9, Richard42 *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* version 2 of the License, or (at your option) any later version. *
* *
****************************************************************************/
#pragma once
/* Default start-time size of primary buffer (in equivalent output samples).
This is the buffer where audio is loaded after it's extracted from n64's memory. */
enum { PRIMARY_BUFFER_SIZE = 16384 };
/* Size of a single secondary buffer, in output samples. This is the requested size of OpenSLES's
hardware buffer, this should be a power of two. */
enum { SECONDARY_BUFFER_SIZE = 1024 };
/* This is the requested number of OpenSLES's hardware buffers */
enum { SECONDARY_BUFFER_NBR = 2 };
/* This sets default frequency what is used if rom doesn't want to change it.
Probably only game that needs this is Zelda: Ocarina Of Time Master Quest
*NOTICE* We should try to find out why Demos' frequencies are always wrong
They tend to rely on a default frequency, apparently, never the same one ;) */
enum { DEFAULT_FREQUENCY = 33600 };
/* number of bytes per sample */
enum
{
N64_SAMPLE_BYTES = 4,
SLES_SAMPLE_BYTES = 4,
};
extern bool g_SwapChannels;
extern uint32_t g_GameFreq;

View File

@ -0,0 +1,83 @@
/****************************************************************************
* *
* Project64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2016 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* version 2 of the License, or (at your option) any later version. *
* *
****************************************************************************/
#include "trace.h"
#include <Common/path.h>
#include <Common/LogClass.h>
#include <Settings/Settings.h>
#ifdef ANDROID
#include <android/log.h>
class AndroidLogger : public CTraceModule
{
void Write(uint32_t module, uint8_t severity, const char * file, int line, const char * function, const char * Message)
{
switch (severity)
{
case TraceError: __android_log_print(ANDROID_LOG_ERROR, TraceModule(module), "%s: %s", function, Message); break;
case TraceWarning: __android_log_print(ANDROID_LOG_WARN, TraceModule(module), "%s: %s", function, Message); break;
case TraceNotice: __android_log_print(ANDROID_LOG_INFO, TraceModule(module), "%s: %s", function, Message); break;
case TraceInfo: __android_log_print(ANDROID_LOG_INFO, TraceModule(module), "%s: %s", function, Message); break;
case TraceDebug: __android_log_print(ANDROID_LOG_DEBUG, TraceModule(module), "%s: %s", function, Message); break;
case TraceVerbose: __android_log_print(ANDROID_LOG_VERBOSE, TraceModule(module), "%s: %s", function, Message); break;
default: __android_log_print(ANDROID_LOG_UNKNOWN, TraceModule(module), "%s: %s", function, Message); break;
}
}
};
static AndroidLogger * g_AndroidLogger = NULL;
#endif
static CTraceFileLog * g_LogFile = NULL;
void SetupTrace(void)
{
if (g_LogFile != NULL)
{
return;
}
#ifdef ANDROID
if (g_AndroidLogger == NULL)
{
g_AndroidLogger = new AndroidLogger();
}
TraceAddModule(g_AndroidLogger);
#endif
#ifdef _DEBUG
TraceSetMaxModule(MaxTraceModulePluginAudio, TraceInfo);
#else
TraceSetMaxModule(MaxTraceModulePluginAudio, TraceError);
#endif
TraceSetModuleName(TraceAudioInitShutdown, "AudioInitShutdown");
TraceSetModuleName(TraceAudioInterface, "AudioInterface");
char log_dir[260];
memset(log_dir, 0, sizeof(log_dir));
short logDirSetting = FindSystemSettingId("Dir:Log");
short logFlushSetting = FindSystemSettingId("Log Auto Flush");
if (logDirSetting != 0)
{
GetSystemSettingSz(logDirSetting, log_dir, sizeof(log_dir));
}
if (strlen(log_dir) == 0)
{
return;
}
CPath LogFilePath(log_dir,"PluginAudio.log");
if (!LogFilePath.DirectoryExists())
{
LogFilePath.DirectoryCreate();
}
g_LogFile = new CTraceFileLog(LogFilePath, GetSystemSetting(logFlushSetting) != 0, CLog::Log_New, 500);
TraceAddModule(g_LogFile);
}

View File

@ -0,0 +1,24 @@
/****************************************************************************
* *
* Project64 - A Nintendo 64 emulator. *
* http://www.pj64-emu.com/ *
* Copyright (C) 2016 Project64. All rights reserved. *
* *
* License: *
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
* version 2 of the License, or (at your option) any later version. *
* *
****************************************************************************/
#pragma once
#include <Common/TraceModulesCommon.h>
#include <Common/Trace.h>
enum TraceModuleAndroidAudio
{
TraceSettings = MaxTraceModuleCommon,
TraceAudioInitShutdown,
TraceAudioInterface,
MaxTraceModulePluginAudio,
};
void SetupTrace(void);