Exemplo n.º 1
0
static int
opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
                   cubeb_stream_params stream_params, unsigned int latency,
                   cubeb_data_callback data_callback, cubeb_state_callback state_callback,
                   void * user_ptr)
{
  cubeb_stream * stm;

  assert(ctx);

  *stream = NULL;

  if (stream_params.channels < 1 || stream_params.channels > 32 ||
      latency < 1 || latency > 2000) {
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  SLDataFormat_PCM format;

  format.formatType = SL_DATAFORMAT_PCM;
  format.numChannels = stream_params.channels;
  // samplesPerSec is in milliHertz
  format.samplesPerSec = stream_params.rate * 1000;
  format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
  format.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
  format.channelMask = stream_params.channels == 1 ?
    SL_SPEAKER_FRONT_CENTER :
    SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;

  switch (stream_params.format) {
  case CUBEB_SAMPLE_S16LE:
    format.endianness = SL_BYTEORDER_LITTLEENDIAN;
    break;
  case CUBEB_SAMPLE_S16BE:
    format.endianness = SL_BYTEORDER_BIGENDIAN;
    break;
  default:
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  stm = calloc(1, sizeof(*stm));
  assert(stm);

  stm->context = ctx;
  stm->data_callback = data_callback;
  stm->state_callback = state_callback;
  stm->user_ptr = user_ptr;

  stm->inputrate = stream_params.rate;
  stm->latency = latency;
  stm->stream_type = stream_params.stream_type;
  stm->framesize = stream_params.channels * sizeof(int16_t);
  stm->lastPosition = -1;
  stm->lastPositionTimeStamp = 0;
  stm->lastCompensativePosition = -1;

  int r = pthread_mutex_init(&stm->mutex, NULL);
  assert(r == 0);

  SLDataLocator_BufferQueue loc_bufq;
  loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
  loc_bufq.numBuffers = NBUFS;
  SLDataSource source;
  source.pLocator = &loc_bufq;
  source.pFormat = &format;

  SLDataLocator_OutputMix loc_outmix;
  loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
  loc_outmix.outputMix = ctx->outmixObj;
  SLDataSink sink;
  sink.pLocator = &loc_outmix;
  sink.pFormat = NULL;

#if defined(__ANDROID__)
  const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE,
                               ctx->SL_IID_VOLUME,
                               ctx->SL_IID_ANDROIDCONFIGURATION};
  const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
#else
  const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE, ctx->SL_IID_VOLUME};
  const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
#endif
  assert(NELEMS(ids) == NELEMS(req));
  SLresult res = (*ctx->eng)->CreateAudioPlayer(ctx->eng, &stm->playerObj,
                                                &source, &sink, NELEMS(ids), ids, req);

  uint32_t preferred_sampling_rate = stm->inputrate;
  // Sample rate not supported? Try again with primary sample rate!
  if (res == SL_RESULT_CONTENT_UNSUPPORTED) {
    if (opensl_get_preferred_sample_rate(ctx, &preferred_sampling_rate)) {
      opensl_stream_destroy(stm);
      return CUBEB_ERROR;
    }

    format.samplesPerSec = preferred_sampling_rate * 1000;
    res = (*ctx->eng)->CreateAudioPlayer(ctx->eng, &stm->playerObj,
                                         &source, &sink, NELEMS(ids), ids, req);
  }

  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  stm->outputrate = preferred_sampling_rate;
  stm->bytespersec = preferred_sampling_rate * stm->framesize;
  stm->queuebuf_len = (stm->bytespersec * latency) / (1000 * NBUFS);
  // round up to the next multiple of stm->framesize, if needed.
  if (stm->queuebuf_len % stm->framesize) {
    stm->queuebuf_len += stm->framesize - (stm->queuebuf_len % stm->framesize);
  }

  stm->resampler = cubeb_resampler_create(stm, stream_params,
                                          preferred_sampling_rate,
                                          data_callback,
                                          stm->queuebuf_len / stm->framesize,
                                          user_ptr,
                                          CUBEB_RESAMPLER_QUALITY_DEFAULT);

  if (!stm->resampler) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  int i;
  for (i = 0; i < NBUFS; i++) {
    stm->queuebuf[i] = malloc(stm->queuebuf_len);
    assert(stm->queuebuf[i]);
  }

#if defined(__ANDROID__)
  SLuint32 stream_type = convert_stream_type_to_sl_stream(stream_params.stream_type);
  if (stream_type != 0xFFFFFFFF) {
    SLAndroidConfigurationItf playerConfig;
    res = (*stm->playerObj)->GetInterface(stm->playerObj,
                                          ctx->SL_IID_ANDROIDCONFIGURATION, &playerConfig);
    res = (*playerConfig)->SetConfiguration(playerConfig,
                                            SL_ANDROID_KEY_STREAM_TYPE, &stream_type, sizeof(SLint32));
    if (res != SL_RESULT_SUCCESS) {
      opensl_stream_destroy(stm);
      return CUBEB_ERROR;
    }
  }
#endif

  res = (*stm->playerObj)->Realize(stm->playerObj, SL_BOOLEAN_FALSE);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_PLAY, &stm->play);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_BUFFERQUEUE,
                                        &stm->bufq);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_VOLUME,
                                        &stm->volume);

  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->play)->RegisterCallback(stm->play, play_callback, stm);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->play)->SetCallbackEventsMask(stm->play, (SLuint32)SL_PLAYEVENT_HEADATMARKER);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->bufq)->RegisterCallback(stm->bufq, bufferqueue_callback, stm);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  {
    // Enqueue a silent frame so once the player becomes playing, the frame
    // will be consumed and kick off the buffer queue callback.
    // Note the duration of a single frame is less than 1ms. We don't bother
    // adjusting the playback position.
    uint8_t *buf = stm->queuebuf[stm->queuebuf_idx++];
    memset(buf, 0, stm->framesize);
    res = (*stm->bufq)->Enqueue(stm->bufq, buf, stm->framesize);
    assert(res == SL_RESULT_SUCCESS);
  }

  *stream = stm;
  return CUBEB_OK;
}
Exemplo n.º 2
0
static int
opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
                  cubeb_stream_params stream_params, unsigned int latency,
                  cubeb_data_callback data_callback, cubeb_state_callback state_callback,
                  void * user_ptr)
{
  cubeb_stream * stm;

  assert(ctx);

  *stream = NULL;

  if (stream_params.rate < 8000 || stream_params.rate > 48000 ||
      stream_params.channels < 1 || stream_params.channels > 32 ||
      latency < 1 || latency > 2000) {
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  SLDataFormat_PCM format;

  format.formatType = SL_DATAFORMAT_PCM;
  format.numChannels = stream_params.channels;
  // samplesPerSec is in milliHertz
  format.samplesPerSec = stream_params.rate * 1000;
  format.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
  format.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16;
  format.channelMask = stream_params.channels == 1 ?
                       SL_SPEAKER_FRONT_CENTER :
                       SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;

  switch (stream_params.format) {
  case CUBEB_SAMPLE_S16LE:
    format.endianness = SL_BYTEORDER_LITTLEENDIAN;
    break;
  case CUBEB_SAMPLE_S16BE:
    format.endianness = SL_BYTEORDER_BIGENDIAN;
    break;
  default:
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  stm = calloc(1, sizeof(*stm));
  assert(stm);

  stm->context = ctx;
  stm->data_callback = data_callback;
  stm->state_callback = state_callback;
  stm->user_ptr = user_ptr;

  stm->framesize = stream_params.channels * sizeof(int16_t);
  stm->bytespersec = stream_params.rate * stm->framesize;
  stm->queuebuf_len = (stm->bytespersec * latency) / (1000 * NBUFS);
  // round up to the next multiple of stm->framesize, if needed.
  if (stm->queuebuf_len % stm->framesize) {
    stm->queuebuf_len += stm->framesize - (stm->queuebuf_len % stm->framesize);
  }
  int i;
  for (i = 0; i < NBUFS; i++) {
    stm->queuebuf[i] = malloc(stm->queuebuf_len);
    assert(stm->queuebuf[i]);
  }

  SLDataLocator_BufferQueue loc_bufq;
  loc_bufq.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
  loc_bufq.numBuffers = NBUFS;
  SLDataSource source;
  source.pLocator = &loc_bufq;
  source.pFormat = &format;

  SLDataLocator_OutputMix loc_outmix;
  loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
  loc_outmix.outputMix = ctx->outmixObj;
  SLDataSink sink;
  sink.pLocator = &loc_outmix;
  sink.pFormat = NULL;

#if defined(__ANDROID__)
  const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE, ctx->SL_IID_ANDROIDCONFIGURATION};
  const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
#else
  const SLInterfaceID ids[] = {ctx->SL_IID_BUFFERQUEUE};
  const SLboolean req[] = {SL_BOOLEAN_TRUE};
#endif
  assert(NELEMS(ids) == NELEMS(req));
  SLresult res = (*ctx->eng)->CreateAudioPlayer(ctx->eng, &stm->playerObj,
                                                &source, &sink, NELEMS(ids), ids, req);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

#if defined(__ANDROID__)
  SLuint32 stream_type = convert_stream_type_to_sl_stream(stream_params.stream_type);
  if (stream_type != 0xFFFFFFFF) {
    SLAndroidConfigurationItf playerConfig;
    res = (*stm->playerObj)->GetInterface(stm->playerObj,
          ctx->SL_IID_ANDROIDCONFIGURATION, &playerConfig);
    res = (*playerConfig)->SetConfiguration(playerConfig,
          SL_ANDROID_KEY_STREAM_TYPE, &stream_type, sizeof(SLint32));
    if (res != SL_RESULT_SUCCESS) {
      opensl_stream_destroy(stm);
      return CUBEB_ERROR;
    }
  }
#endif

  res = (*stm->playerObj)->Realize(stm->playerObj, SL_BOOLEAN_FALSE);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_PLAY, &stm->play);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->playerObj)->GetInterface(stm->playerObj, ctx->SL_IID_BUFFERQUEUE,
                                    &stm->bufq);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  res = (*stm->bufq)->RegisterCallback(stm->bufq, bufferqueue_callback, stm);
  if (res != SL_RESULT_SUCCESS) {
    opensl_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  *stream = stm;

  return CUBEB_OK;
}