static int aout_open_audio(SDL_Aout *aout, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
{
    SDLTRACE("%s\n", __func__);
    assert(desired);
    SDLTRACE("aout_open_audio()\n");
    SDL_Aout_Opaque  *opaque     = aout->opaque;
    SLEngineItf       slEngine   = opaque->slEngine;
    SLDataFormat_PCM *format_pcm = &opaque->format_pcm;
    int               ret = 0;

    opaque->spec = *desired;

    // config audio src
    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {
        SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE,
        OPENSLES_BUFFERS
    };

    int native_sample_rate = audiotrack_get_native_output_sample_rate(NULL);
    ALOGI("OpenSL-ES: native sample rate %d Hz\n", native_sample_rate);

    CHECK_COND_ERROR((desired->format == AUDIO_S16SYS), "%s: not AUDIO_S16SYS", __func__);
    CHECK_COND_ERROR((desired->channels == 2 || desired->channels == 1), "%s: not 1,2 channel", __func__);
    CHECK_COND_ERROR((desired->freq >= 8000 && desired->freq <= 48000), "%s: unsupport freq %d Hz", __func__, desired->freq);
    if (SDL_Android_GetApiLevel() < IJK_API_21_LOLLIPOP &&
        native_sample_rate > 0 &&
        desired->freq < native_sample_rate) {
        // Don't try to play back a sample rate higher than the native one,
        // since OpenSL ES will try to use the fast path, which AudioFlinger
        // will reject (fast path can't do resampling), and will end up with
        // too small buffers for the resampling. See http://b.android.com/59453
        // for details. This bug is still present in 4.4. If it is fixed later
        // this workaround could be made conditional.
        //
        // by VLC/android_opensles.c
        ALOGW("OpenSL-ES: force resample %lu to native sample rate %d\n",
              (unsigned long) format_pcm->samplesPerSec / 1000,
              (int) native_sample_rate);
        format_pcm->samplesPerSec = native_sample_rate * 1000;
    }

    format_pcm->formatType       = SL_DATAFORMAT_PCM;
    format_pcm->numChannels      = desired->channels;
    format_pcm->samplesPerSec    = desired->freq * 1000; // milli Hz
    // format_pcm->numChannels      = 2;
    // format_pcm->samplesPerSec    = SL_SAMPLINGRATE_44_1;

    format_pcm->bitsPerSample    = SL_PCMSAMPLEFORMAT_FIXED_16;
    format_pcm->containerSize    = SL_PCMSAMPLEFORMAT_FIXED_16;
    switch (desired->channels) {
    case 2:
        format_pcm->channelMask  = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
        break;
    case 1:
        format_pcm->channelMask  = SL_SPEAKER_FRONT_CENTER;
        break;
    default:
        ALOGE("%s, invalid channel %d", __func__, desired->channels);
        goto fail;
    }
    format_pcm->endianness       = SL_BYTEORDER_LITTLEENDIAN;

    SLDataSource audio_source = {&loc_bufq, format_pcm};

    // config audio sink
    SLDataLocator_OutputMix loc_outmix = {
        SL_DATALOCATOR_OUTPUTMIX,
        opaque->slOutputMixObject
    };
    SLDataSink audio_sink = {&loc_outmix, NULL};

    SLObjectItf slPlayerObject = NULL;
    const SLInterfaceID ids2[] = { SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_VOLUME, SL_IID_PLAY };
    static const SLboolean req2[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
    ret = (*slEngine)->CreateAudioPlayer(slEngine, &slPlayerObject, &audio_source,
                                &audio_sink, sizeof(ids2) / sizeof(*ids2),
                                ids2, req2);
    CHECK_OPENSL_ERROR(ret, "%s: slEngine->CreateAudioPlayer() failed", __func__);
    opaque->slPlayerObject = slPlayerObject;

    ret = (*slPlayerObject)->Realize(slPlayerObject, SL_BOOLEAN_FALSE);
    CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->Realize() failed", __func__);

    ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_PLAY, &opaque->slPlayItf);
    CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_PLAY) failed", __func__);

    ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_VOLUME, &opaque->slVolumeItf);
    CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_VOLUME) failed", __func__);

    ret = (*slPlayerObject)->GetInterface(slPlayerObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &opaque->slBufferQueueItf);
    CHECK_OPENSL_ERROR(ret, "%s: slPlayerObject->GetInterface(SL_IID_ANDROIDSIMPLEBUFFERQUEUE) failed", __func__);

    ret = (*opaque->slBufferQueueItf)->RegisterCallback(opaque->slBufferQueueItf, aout_opensles_callback, (void*)aout);
    CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->RegisterCallback() failed", __func__);

    // set the player's state to playing
    // ret = (*opaque->slPlayItf)->SetPlayState(opaque->slPlayItf, SL_PLAYSTATE_PLAYING);
    // CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->slPlayItf() failed", __func__);

    opaque->bytes_per_frame   = format_pcm->numChannels * format_pcm->bitsPerSample / 8;
    opaque->milli_per_buffer  = OPENSLES_BUFLEN;
    opaque->frames_per_buffer = opaque->milli_per_buffer * format_pcm->samplesPerSec / 1000000; // samplesPerSec is in milli
    opaque->bytes_per_buffer  = opaque->bytes_per_frame * opaque->frames_per_buffer;
    opaque->buffer_capacity   = OPENSLES_BUFFERS * opaque->bytes_per_buffer;
    ALOGI("OpenSL-ES: bytes_per_frame  = %d bytes\n",  (int)opaque->bytes_per_frame);
    ALOGI("OpenSL-ES: milli_per_buffer = %d ms\n",     (int)opaque->milli_per_buffer);
    ALOGI("OpenSL-ES: frame_per_buffer = %d frames\n", (int)opaque->frames_per_buffer);
    ALOGI("OpenSL-ES: bytes_per_buffer = %d bytes\n",  (int)opaque->bytes_per_buffer);
    ALOGI("OpenSL-ES: buffer_capacity  = %d bytes\n",  (int)opaque->buffer_capacity);
    opaque->buffer          = malloc(opaque->buffer_capacity);
    CHECK_COND_ERROR(opaque->buffer, "%s: failed to alloc buffer %d\n", __func__, (int)opaque->buffer_capacity);

    // (*opaque->slPlayItf)->SetPositionUpdatePeriod(opaque->slPlayItf, 1000);

    // enqueue empty buffer to start play
    memset(opaque->buffer, 0, opaque->buffer_capacity);
    for(int i = 0; i < OPENSLES_BUFFERS; ++i) {
        ret = (*opaque->slBufferQueueItf)->Enqueue(opaque->slBufferQueueItf, opaque->buffer + i * opaque->bytes_per_buffer, opaque->bytes_per_buffer);
        CHECK_OPENSL_ERROR(ret, "%s: slBufferQueueItf->Enqueue(000...) failed", __func__);
    }

    opaque->pause_on = 1;
    opaque->abort_request = 0;
    opaque->audio_tid = SDL_CreateThreadEx(&opaque->_audio_tid, aout_thread, aout, "ff_aout_opensles");
    CHECK_COND_ERROR(opaque->audio_tid, "%s: failed to SDL_CreateThreadEx", __func__);

    if (obtained) {
        *obtained      = *desired;
        obtained->size = opaque->buffer_capacity;
        obtained->freq = format_pcm->samplesPerSec / 1000;
    }

    return opaque->buffer_capacity;
fail:
    aout_close_audio(aout);
    return -1;
}
Beispiel #2
0
SDL_AndroidAudioTrack *sdl_audiotrack_new_from_spec(JNIEnv *env, SDL_AndroidAudioTrack_Spec *spec)
{
    assert(spec);

    switch (spec->channel_config) {
    case CHANNEL_OUT_MONO:
        ALOGI("SDL_AndroidAudioTrack: %s", "CHANNEL_OUT_MONO");
        break;
    case CHANNEL_OUT_STEREO:
        ALOGI("SDL_AndroidAudioTrack: %s", "CHANNEL_OUT_STEREO");
        break;
    default:
        ALOGE("sdl_audiotrack_new_from_spec: invalid channel %d", spec->channel_config);
        return NULL;
    }

    switch (spec->audio_format) {
    case ENCODING_PCM_16BIT:
        ALOGI("SDL_AndroidAudioTrack: %s", "ENCODING_PCM_16BIT");
        break;
    case ENCODING_PCM_8BIT:
        ALOGI("SDL_AndroidAudioTrack: %s", "ENCODING_PCM_8BIT");
        break;
    default:
        ALOGE("sdl_audiotrack_new_from_spec: invalid format %d", spec->audio_format);
        return NULL;
    }

    SDL_AndroidAudioTrack *atrack = (SDL_AndroidAudioTrack*) mallocz(sizeof(SDL_AndroidAudioTrack));
    if (!atrack) {
        (*env)->CallVoidMethod(env, g_clazz.clazz, atrack->thiz, g_clazz.release);
        return NULL;
    }
    atrack->spec = *spec;

    if (atrack->spec.sample_rate_in_hz < 4000 || atrack->spec.sample_rate_in_hz > 48000) {
        int native_sample_rate_in_hz = audiotrack_get_native_output_sample_rate(env);
        if (native_sample_rate_in_hz > 0) {
            ALOGE("sdl_audiotrack_new: cast sample rate %d to %d:",
                  atrack->spec.sample_rate_in_hz,
                  native_sample_rate_in_hz);
            atrack->spec.sample_rate_in_hz = native_sample_rate_in_hz;
        }
    }

    int min_buffer_size = audiotrack_get_min_buffer_size(env, &atrack->spec);
    if (min_buffer_size <= 0) {
        ALOGE("sdl_audiotrack_new: sdl_audiotrack_get_min_buffer_size: return %d:", min_buffer_size);
        free(atrack);
        return NULL;
    }

    jobject thiz = (*env)->NewObject(env, g_clazz.clazz, g_clazz.constructor,
                                     (int) atrack->spec.stream_type,
                                     (int) atrack->spec.sample_rate_in_hz,
                                     (int) atrack->spec.channel_config,
                                     (int) atrack->spec.audio_format,
                                     (int) min_buffer_size,
                                     (int) atrack->spec.mode);
    if (!thiz || (*env)->ExceptionCheck(env)) {
        ALOGE("sdl_audiotrack_new: NewObject: Exception:");
        if ((*env)->ExceptionCheck(env)) {
            (*env)->ExceptionDescribe(env);
            (*env)->ExceptionClear(env);
        }
        free(atrack);
        return NULL;
    }

    atrack->min_buffer_size = min_buffer_size;
    atrack->spec.buffer_size_in_bytes = min_buffer_size;
    atrack->max_volume = audiotrack_get_max_volume(env);
    atrack->min_volume = audiotrack_get_min_volume(env);

    atrack->thiz = (*env)->NewGlobalRef(env, thiz);
    (*env)->DeleteLocalRef(env, thiz);

    // extra init
    float init_volume = 1.0f;
    init_volume = TXMIN(init_volume, atrack->max_volume);
    init_volume = TXMAX(init_volume, atrack->min_volume);
    ALOGI("sdl_audiotrack_new: init volume as %f/(%f,%f)", init_volume, atrack->min_volume, atrack->max_volume);
    audiotrack_set_stereo_volume(env, atrack, init_volume, init_volume);

    return atrack;
}