2016-08-18 124 views
0

開發一個實時合成的Android應用程序。我正在使用NDK生成波形和Java以執行所有UI。我有以下幾點:Android NDK音頻回撥

private Thread audioThread; 

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    // UI Initializations here 
    // Audio Thread creation: 
     if (audioThread == null) { 
     audioThread = new Thread() { 
      public void run() { 
       setPriority(Thread.MAX_PRIORITY); 
       JNIWrapper.runProcess(); 
      } 
     }; 
     audioThread.start(); 
    } 
} 

在我的C++文件:

void Java_com_rfoo_runProcess() { 
    OPENSL_STREAM *p = android_OpenAudioDevice(SAMPLE_RATE, 0, 2, FRAME_SIZE); 
    double outBuffer[FRAME_SIZE]; 

    while (true) { 
     // Audio Processing code happens HERE 
     // Write to output buffer here 
     android_AudioOut(p, outBuffer, FRAME_SIZE); 
    } 
    android_CloseAudioDevice(p); 
} 

現在,這將是所有常規,如果我沒有做很多信號處理工作,在我runProcess代碼。由於正在進行大量工作,當我嘗試更改信號處理代碼的參數(例如頻率,ADSR包絡,濾波器截止頻率等)時,我的UI延遲非常高,並導致點擊次數。

有什麼方法可以減少這種延遲?在iOS和PortAudio中有音頻回調,當時間間隔/緩衝區被填滿時,通常會調用這些回調。我試圖搜索Android中存在的類似音頻回調,但無法找到它。我應該編程自己的計時器來調用我的處理代碼嗎?

謝謝!

+1

您是否嘗試過使用openSLES爲您進行音頻播放?它的延遲可能與您可以獲得的一樣低,並且還使用回調機制來排隊下一個緩衝區。 – WLGfx

+0

@WLGfx這就是我所做的 –

+0

其實經過仔細檢查,我設置了我的openSLES驅動程序錯誤。要重做它 –

回答

1

是的所以我完全設置了我的回調錯誤...其實我甚至沒有設置回調。

爲了改善這種情況,我跟着一些技巧在線,創造了加工回調:

// Define the callback: 
typedef void (*opensl_callback) (void *context, int buffer_frames, 
           int output_channels, short *output_buffer); 
// Declare callback: 
static opensl_callback myAudioCallback; 
// Define custom callback: 
static void audioCallback(void *context, int buffer_frames, 
          int output_channels, short *output_buffer) { 
    // Get my object's data 
    AudioData *data = (AudioData *)context; 
    // Process here! Then: 
    output_buffer[i] = final_sample; 
} 

我如何聲明/初始化OpenSL流:

jboolean Java_com_rfoo_AudioProcessor_runProcess(JNIEnv *, jobject, 
               int srate, int numFrames) { 
    myAudioCallback = audioCallback; 
    OPENSL_Stream *p = opensl_openDevice(srate, 2, numFrames, myAudioCallback, audioData); 
    // Check if successful initialization 
    if (!p) return JNI_FALSE; 
    // Start our process: 
    opensl_startProcess(p); 
    return JNI_TRUE; 
} 

基本上什麼opensl_openDevice()opensl_startProcess()做:

OPENSL_STREAM *opensl_openDevice(int sampleRate, int outChans, int numFrames, opensl_callback cb, void *data) { 
    if (!cb) { 
     return NULL; 
    } 
    if (outChans == 0) { 
     return NULL; 
    } 

    SLuint32 srmillihz = convertSampleRate(sampleRate); 
    if (srmillihz < 0) { 
     return NULL; 
    } 

    OPENSL_STREAM *p = (OPENSL_STREAM *) calloc(1, sizeof(OPENSL_STREAM)); 
    if (!p) { 
     return NULL; 
    } 

    p->callback = cb; 
    p->data = data; 
    p->isRunning = 0; 

    p->outputChannels = outChans; 
    p->sampleRate = sampleRate; 

    p->thresholdMillis = 750.0 * numFrames/sampleRate; 

    p->outputBuffer = NULL; 
    p->dummyBuffer = NULL; 

    p->numFrames = numFrames; 
    p->outputBufferFrames = OUTPUT_BUFFERS * numFrames; 

    if (openSLCreateEngine(p) != SL_RESULT_SUCCESS) { 
     opensl_close(p); 
     return NULL; 
    } 

    if (outChans) { 
     int outBufSize = p->outputBufferFrames * outChans; 
     if (!(openSLPlayOpen(p, srmillihz) == SL_RESULT_SUCCESS && 
     (p->outputBuffer = (short *) calloc(outBufSize, sizeof(short))))) { 
     opensl_close(p); 
     return NULL; 
    } 
    } 

    LOGI("OpenSL_Stream", "Created OPENSL_STREAM(%d, %d, %d, %d)", 
     sampleRate, inChans, outChans, callbackBufferFrames); 
    LOGI("OpenSL_Stream", "numBuffers: %d", OUTPUT_BUFFERS); 
    return p; 
} 

起始流代碼:

int opensl_startProcess(OPENSL_STREAM *p) { 
    if (p->isRunning) { 
     return 0; // Already running. 
    } 

    p->outputIndex = 0; 
    p->readIndex = -1; 

    p->outputTime.tv_sec = 0; 
    p->outputTime.tv_nsec = 0; 
    p->outputIntervals = 0; 
    p->previousOutputIndex = 0; 
    p->outputOffset = 0; 

    p->lowestMargin = p->inputBufferFrames; 

    if (p->playerPlay) { 
     LOGI("OpenSL_Stream", "Starting player queue."); 
     int i; 
     for (i = 0; i < OUTPUT_BUFFERS; ++i) { 
     playerCallback(p->playerBufferQueue, p); 
     } 
     if ((*p->playerPlay)->SetPlayState(p->playerPlay, 
      SL_PLAYSTATE_PLAYING) != SL_RESULT_SUCCESS) { 
     opensl_pause(p); 
     return -1; 
     } 
    } 
    p->isRunning = 1; 
    return 0; 
} 

我的音頻播放器的回調:

static void playerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) { 
    OPENSL_STREAM *p = (OPENSL_STREAM *) context; 

    short *currentOutputBuffer = p->outputBuffer + 
     (p->outputIndex % p->numFrames) * p->outputChannels; 

    memset(currentOutputBuffer, 0, p->callbackBufferFrames * p->outputChannels * sizeof(short)); 

    p->callback(p->context, p->sampleRate, p->callbackBufferFrames, 
     p->inputChannels, p->dummyBuffer, 
     p->outputChannels, currentOutputBuffer); 
    } 
    (*bq)->Enqueue(bq, currentOutputBuffer, p->callbackBufferFrames * p->outputChannels * sizeof(short)); 
    p->outputIndex = nextIndex(p->outputIndex, p->callbackBufferFrames); 
} 

當我完成整理,我會聯繫我github上opensl_stream代碼示例,這樣其他菜鳥一樣我可以很容易地找到一個可用的例子。乾杯! :)