JNIEXPORT void JNICALL Java_ru_suvitruf_androidndk_tutorial4_MainActivity_loadAudio(JNIEnv *pEnv, jobject pThis, jobject pNativeCallListener, jobject assetManager);
static { System.loadLibrary("AndroidNDK"); }
// native public void loadAudio(NativeCalls nativeCallListener, AssetManager mng);
loadAudio(activity, activity.getResources().getAssets());
public interface NativeCalls { public void sendLog(String result); }
protected Handler handler = new Handler() { @Override public void handleMessage(Message msg) { showResult(msg.getData().getString("result")); } }; public void showResult(String result){ ((TextView) findViewById(R.id.log)). setText(((TextView) findViewById(R.id.log)).getText()+result+"\n"); } // @Override public void sendLog(String result){ Message msg = new Message(); Bundle data = new Bundle(); data.putString("result", result); msg.setData(data); handler.sendMessage(msg); }
class NativeCallListener { public: NativeCallListener(JNIEnv* pJniEnv, jobject pWrapperInstance); NativeCallListener() {} // // Java void sendLog(jobject log); // void destroy(); ~NativeCallListener(){ } void loadAudio(); //void play(); //void playOGG(); ALCdevice* device; ALCcontext* context; private: JNIEnv* getJniEnv(); // jmethodID sendLogID; // jobject mObjectRef; JavaVM* mJVM; ALuint soundWAV; ALuint soundOGG; void load(); void clean(); };
JNIEXPORT void JNICALL Java_ru_suvitruf_androidndk_tutorial4_MainActivity_loadAudio(JNIEnv *pEnv, jobject pThis, jobject pNativeCallListener, jobject assetManager) { listener = NativeCallListener(pEnv, pNativeCallListener); mgr = AAssetManager_fromJava(pEnv, assetManager); listener.loadAudio(); }
NativeCallListener::NativeCallListener(JNIEnv* pJniEnv, jobject pWrappedInstance) { pJniEnv->GetJavaVM(&mJVM); mObjectRef = pJniEnv->NewGlobalRef(pWrappedInstance); jclass cl = pJniEnv->GetObjectClass(pWrappedInstance); // , Java sendLogID = pJniEnv->GetMethodID(cl, "sendLog", "(Ljava/lang/String;)V"); }
void NativeCallListener::sendLog(jobject log) { JNIEnv* jniEnv = getJniEnv(); jniEnv->CallIntMethod(mObjectRef, sendLogID, log); }
typedef struct { char riff[4];//'RIFF' unsigned int riffSize; char wave[4];//'WAVE' char fmt[4];//'fmt ' unsigned int fmtSize; unsigned short format; unsigned short channels; unsigned int samplesPerSec; unsigned int bytesPerSec; unsigned short blockAlign; unsigned short bitsPerSample; char data[4];//'data' unsigned int dataSize; }BasicWAVEHeader;
void OALWav::load(AAssetManager *mgr, const char* filename){ this->filename = filename; this->data = 0; // this->data = this->readWAVFull(mgr, &header); // getFormat(); // OpenAL createBufferFromWave(data); source = 0; alGenSources(1, &source); alSourcei(source, AL_BUFFER, buffer); }
char* OALWav::readWAVFull(AAssetManager *mgr, BasicWAVEHeader* header){ char* buffer = 0; AAssetFile f = AAssetFile(mgr, filename); if (f.null()) { LOGE("no file %s in readWAV",filename); return 0; } int res = f.read(header,sizeof(BasicWAVEHeader),1); if(res){ if (!( // . // , . // =/ memcmp("RIFF",header->riff,4) || memcmp("WAVE",header->wave,4) || memcmp("fmt ",header->fmt,4) || memcmp("data",header->data,4) )){ buffer = (char*)malloc(header->dataSize); if (buffer){ if(f.read(buffer,header->dataSize,1)){ f.close(); return buffer; } free(buffer); } } } f.close(); return 0; }
static size_t read_func(void* ptr, size_t size, size_t nmemb, void* datasource) { unsigned int uiBytes = Min(suiSize - suiCurrPos, (unsigned int)nmemb * (unsigned int)size); memcpy(ptr, (unsigned char*)datasource + suiCurrPos, uiBytes); suiCurrPos += uiBytes; return uiBytes; } static int seek_func(void* datasource, ogg_int64_t offset, int whence) { if (whence == SEEK_SET) suiCurrPos = (unsigned int)offset; else if (whence == SEEK_CUR) suiCurrPos = suiCurrPos + (unsigned int)offset; else if (whence == SEEK_END) suiCurrPos = suiSize; return 0; } static int close_func(void* datasource) { return 0; } static long tell_func(void* datasource) { return (long)suiCurrPos; }
void OALOgg::getInfo(unsigned int uiOggSize, char* pvOggBuffer){ // ov_callbacks callbacks; callbacks.read_func = &read_func; callbacks.seek_func = &seek_func; callbacks.close_func = &close_func; callbacks.tell_func = &tell_func; suiCurrPos = 0; suiSize = uiOggSize; int iRet = ov_open_callbacks(pvOggBuffer, &vf, NULL, 0, callbacks); // vi = ov_info(&vf, -1); uiPCMSamples = (unsigned int)ov_pcm_total(&vf, -1); } void * OALOgg::ConvertOggToPCM(unsigned int uiOggSize, char* pvOggBuffer) { if(suiSize == 0){ getInfo( uiOggSize, pvOggBuffer); current_section = 0; iRead = 0; uiCurrPos = 0; } void* pvPCMBuffer = malloc(uiPCMSamples * vi->channels * sizeof(short)); // do { iRead = ov_read(&vf, (char*)pvPCMBuffer + uiCurrPos, 4096, ¤t_section); uiCurrPos += (unsigned int)iRead; } while (iRead != 0); return pvPCMBuffer; } void OALOgg::load(AAssetManager *mgr, const char* filename){ this->filename = filename; char* buf = 0; AAssetFile f = AAssetFile(mgr, filename); if (f.null()) { LOGE("no file %s in readOgg",filename); return ; } buf = 0; buf = (char*)malloc(f.size()); if (buf){ if(f.read(buf,f.size(),1)){ } else { free(buf); f.close(); return; } } char * data = (char *)ConvertOggToPCM(f.size(),buf); f.close(); if (vi->channels == 1) format = AL_FORMAT_MONO16; else format = AL_FORMAT_STEREO16; alGenBuffers(1,&buffer); alBufferData(buffer,format,data,uiPCMSamples * vi->channels * sizeof(short),vi->rate); source = 0; alGenSources(1, &source); alSourcei(source, AL_BUFFER, buffer); }
void NativeCallListener:: load(){ oalContext = new OALContext(); //sound = new OALOgg(); sound = new OALWav(); char * fileName = new char[64]; strcpy(fileName, "audio/industrial_suspense1.wav"); //strcpy(fileName, "audio/Katatonia - Deadhouse_(piano version).ogg"); sound->load(mgr,fileName); }
sound
like OALSound
. To work with WAV and Ogg, I have classes that inherit from it. All we need for them is to write a load implementation by overriding the base class method virtual void load(AAssetManager *mgr, const char* filename)= 0;
Source: https://habr.com/ru/post/176559/