Android NDK 音频回调

Android NDK Audio Callback

开发一个 Android 应用程序来进行实时合成。我正在使用 NDK 生成波形等 Java 来完成所有 UI。我有以下内容:

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 代码中进行大量信号处理工作,现在这就是全部 groovy。因为有很多工作正在进行,所以我的 UI 延迟非常高,并且在我尝试更改信号处理代码的参数(例如频率、ADSR 包络、滤波器截止频率等)时导致点击。

有哪些方法可以减少这种延迟?在 iOS 和 PortAudio 中有音频回调,当时间 interval/buffer 满时会例行调用。我尝试搜索 Android 中存在的类似音频回调,但找不到。我应该编写自己的计时器来调用我的处理代码吗?

谢谢!

是的所以我完全错误地设置了我的回叫...事实上我什至根本没有设置回叫。

为了纠正这个问题,我按照网上的一些提示创建了一个处理回调:

// 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;
} 

我如何 declared/initialized 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);
}

当我完成整理后,我将 link 我的 github opensl_stream 代码示例,以便像我这样的其他菜鸟可以轻松找到可用的示例。干杯! :)