2016-08-18 125 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代码示例,这样其他菜鸟一样我可以很容易地找到一个可用的例子。干杯! :)