/* this file is basically a copy of the SDL one java code has a function or two which just periodically calls us to ask us to dump out audio for it */ #include "quakedef.h" #include #include static soundcardinfo_t *sys_sc = NULL; extern int sys_soundflags; //called by the java code when it wants to know what sort of AudioTrack format to use. JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_audioinfo(JNIEnv *env, jclass this, jint arg) { soundcardinfo_t *sc = sys_sc; if (!sc) return 0; switch(arg) { case 1: return sc->sn.numchannels; case 2: return sc->sn.samplebytes*8; default: return sc->sn.speed; } } extern int S_GetMixerTime(soundcardinfo_t *sc); //transfer the 'dma' buffer into the buffer it requests, called from a dedicated sound thread created by the java code. JNIEXPORT jint JNICALL Java_com_fteqw_FTEDroidEngine_paintaudio(JNIEnv *env, jclass this, jbyteArray stream, jint len) { int offset = 0; soundcardinfo_t *sc = sys_sc; int framesz; if (sc) { int buffersize = sc->sn.samples*sc->sn.samplebytes; int curtime = S_GetMixerTime(sc); framesz = sc->sn.numchannels * sc->sn.samplebytes; S_PaintChannels (sc, curtime + (len / framesz)); if (len > buffersize) { len = buffersize; //whoa nellie! } if (len + sc->snd_sent%buffersize > buffersize) { //buffer will wrap, fill in the rest (*env)->SetByteArrayRegion(env, stream, offset, buffersize - (sc->snd_sent%buffersize), (char*)sc->sn.buffer + (sc->snd_sent%buffersize)); offset += buffersize - (sc->snd_sent%buffersize); sc->snd_sent += buffersize - (sc->snd_sent%buffersize); len -= buffersize - (sc->snd_sent%buffersize); if (len < 0) /*this must be impossible, surely?*/ len = 0; } //and finish from the start (*env)->SetByteArrayRegion(env, stream, offset, len, (char*)sc->sn.buffer + (sc->snd_sent%buffersize)); offset += len; sc->snd_sent += len; } else offset = len; /*so the playback thread ends up blocked properly*/ return offset; } static void Droid_Shutdown(soundcardinfo_t *sc) { //fixme: what if we're currently inside Java_com_fteqw_FTEDroidEngine_paintaudio? sys_sc = NULL; free(sc->sn.buffer); sys_soundflags = 0; } //return the number of samples that have already been submitted to the device. static unsigned int Droid_GetDMAPos(soundcardinfo_t *sc) { sc->sn.samplepos = sc->snd_sent / sc->sn.samplebytes; return sc->sn.samplepos; } static void Droid_UnlockBuffer(soundcardinfo_t *sc, void *buffer) { } static void *Droid_LockBuffer(soundcardinfo_t *sc, unsigned int *sampidx) { return sc->sn.buffer; } /* static void Droid_SetEnvironmentReverb(soundcardinfo_t *sc, qboolean uw) { } */ static void Droid_Submit(soundcardinfo_t *sc, int start, int end) { } //on android, 16bit audio is 'guarenteed'. //8bit is not guarenteed. //there's no reference to sample rates. I assume 44.1khz will always work, though we want to avoid that cpu+mem load if we can //nor any guarentee about channels supported. I assume mono will always work. static qboolean Droid_InitCard (soundcardinfo_t *sc, const char *cardname) { if (sys_sc) return false; //can only cope with one device. if (cardname && *cardname) return false; //only the default device sc->selfpainting = true; // sc->sn.speed = 11025; // sc->sn.samplebytes = 2; // sc->sn.numchannels = 1; if (sc->sn.samplebytes == 1) sc->sn.sampleformat = QSF_U8; else /*if (sc->sn.samplebytes == 2)*/ { sc->sn.samplebytes = 2; sc->sn.sampleformat = QSF_S16; } /*internal buffer should have 1 sec audio*/ sc->sn.samples = sc->sn.speed*sc->sn.numchannels; sc->Lock = Droid_LockBuffer; sc->Unlock = Droid_UnlockBuffer; // sc->SetEnvironmentReverb = Droid_SetEnvironmentReverb; sc->Submit = Droid_Submit; sc->Shutdown = Droid_Shutdown; sc->GetDMAPos = Droid_GetDMAPos; sc->sn.buffer = malloc(sc->sn.samples*sc->sn.samplebytes); sys_sc = sc; sys_soundflags = 3; return 1; } sounddriver_t Droid_AudioOutput = { "Android", Droid_InitCard, NULL };