从playfield开源代码复制的opensl es初始化代码

/* -*- coding: utf-8; tab-width: 8; indent-tabs-mode: t; -*- */

/*
 * Copyright (c) 2025, Awe Morris. All rights reserved.
 */

/*
 * HAL for OpenSL ES on Android
 */

/* Base */
#include "stratohal/platform.h"

/* OpenSLES */
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>

/* POSIX */
#include <pthread.h>
#include <sys/types.h>

/* C */
#include <stdlib.h>
#include <string.h>
#include <math.h>

/*
 * sound Buffer Parameters
 */
#define SAMPLING_RATE        (44100)
#define CHANNELS        (2)
#define FRAME_SIZE        (4)
#define BUF_FRAMES        (SAMPLING_RATE / 4)

/*
 * OpenSL ES Objects
 */
static SLObjectItf engine_object;
static SLEngineItf engine_engine;
static SLObjectItf output_mix_object;
static SLObjectItf bq_player_object[SOUND_TRACKS];
static SLPlayItf bq_player_play[SOUND_TRACKS];
static SLAndroidSimpleBufferQueueItf bq_player_buffer_queue[SOUND_TRACKS];

/* Buffers */
static uint32_t sample_buf[SOUND_TRACKS][BUF_FRAMES];

/* Mutex objects to synchronize accesses to sample_buf */
static pthread_mutex_t sound_mutex[SOUND_TRACKS];

/* Input Streams */
static struct wave *wave[SOUND_TRACKS];

/* Volume Values */
static float volume[SOUND_TRACKS];

/* Finish Flags */
static bool pre_finish[SOUND_TRACKS];     /* Shows if we reached an end-of-stream. */
static bool post_finish[SOUND_TRACKS];     /* Shows if we finished a playback of a final buffer. */

/*
 * Forward Declarations
 */
static void play_callback(SLAndroidSimpleBufferQueueItf bq, void *context);
static void enqueue(int stream);
static void scale_samples(uint32_t *buf, int frames, float vol);

/*
 * Initialize OpenSL ES.
 */
void init_opensl_es(void)
{
    for (int i = 0; i < SOUND_TRACKS; i++)
        pthread_mutex_init(&sound_mutex[i], NULL);

    slCreateEngine(&engine_object, 0, NULL, 0, NULL, NULL);
    (*engine_object)->Realize(engine_object, SL_BOOLEAN_FALSE);
    (*engine_object)->GetInterface(engine_object, SL_IID_ENGINE, &engine_engine);

    const SLInterfaceID outids[1] = {SL_IID_PLAYBACKRATE};
    const SLboolean outreq[1] = {SL_BOOLEAN_FALSE};
    (*engine_engine)->CreateOutputMix(engine_engine, &output_mix_object, 1, outids, outreq);
    (*output_mix_object)->Realize(output_mix_object, SL_BOOLEAN_FALSE);

    SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
    SLDataFormat_PCM format_pcm = {
        SL_DATAFORMAT_PCM,
        2,
        SL_SAMPLINGRATE_44_1,
        SL_PCMSAMPLEFORMAT_FIXED_16,
        SL_PCMSAMPLEFORMAT_FIXED_16,
        SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
        SL_BYTEORDER_LITTLEENDIAN
    };
    SLDataSource audio_src = {&loc_bufq, &format_pcm};
    SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, output_mix_object};
    SLDataSink audioSnk = {&loc_outmix, NULL};
    const SLInterfaceID bqids[1] = {SL_IID_BUFFERQUEUE};
    const SLboolean bqreq[1] = {SL_BOOLEAN_TRUE};
    for (int i = 0; i < SOUND_TRACKS; i++) {
        (*engine_engine)->CreateAudioPlayer(engine_engine, &bq_player_object[i], &audio_src, &audioSnk, 1, bqids, bqreq);
        (*bq_player_object[i])->Realize(bq_player_object[i], SL_BOOLEAN_FALSE);
        (*bq_player_object[i])->GetInterface(bq_player_object[i], SL_IID_PLAY, &bq_player_play[i]);
        (*bq_player_object[i])->GetInterface(bq_player_object[i], SL_IID_BUFFERQUEUE, &bq_player_buffer_queue[i]);
        (*bq_player_buffer_queue[i])->RegisterCallback(bq_player_buffer_queue[i], play_callback, (void *)(intptr_t)i);
        (*bq_player_play[i])->SetCallbackEventsMask(bq_player_play[i], SL_PLAYEVENT_HEADATEND);
        (*bq_player_play[i])->SetPlayState(bq_player_play[i], SL_PLAYSTATE_PLAYING);
    }
}

void sl_pause_sound(void)
{
    for (int i = 0; i < SOUND_TRACKS; i++) {
        if (bq_player_play[i] != NULL)
            (*bq_player_play[i])->SetPlayState(bq_player_play[i], SL_PLAYSTATE_STOPPED);
    }
}

void sl_resume_sound(void)
{
    for (int i = 0; i < SOUND_TRACKS; i++) {
        if (bq_player_play[i] != NULL)
            (*bq_player_play[i])->SetPlayState(bq_player_play[i], SL_PLAYSTATE_PLAYING);
    }
}

static void play_callback(SLAndroidSimpleBufferQueueItf bq, void *context)
{
    int stream = (intptr_t)context;

    pthread_mutex_lock(&sound_mutex[stream]);
    enqueue(stream);
    pthread_mutex_unlock(&sound_mutex[stream]);
}

static void enqueue(int stream)
{
    if (wave[stream] == NULL)
        return;

    /* Set a post-finish flag if an end-of-stream was detected in a previous filling. */
    if (pre_finish[stream]) {
        wave[stream] = NULL;
        post_finish[stream] = true;
        return;
    }

    /* Get PCM samples. */
    int read_samples = get_wave_samples(wave[stream], sample_buf[stream], BUF_FRAMES);

    /* Fill the remaining samples by zeros for a case where we have reached an end-of-stream. */
    if (read_samples < BUF_FRAMES)
        memset(sample_buf[stream] + read_samples, 0, (size_t)(BUF_FRAMES - read_samples) * FRAME_SIZE);

    /* Scale samples by a volume value. */
    scale_samples(sample_buf[stream], BUF_FRAMES, volume[stream]);

    /* Write the buffer. */
    (*bq_player_buffer_queue[stream])->Enqueue(bq_player_buffer_queue[stream], sample_buf[stream], read_samples * FRAME_SIZE);

    /* Set a pre-finish flag if we reached an end-of-stream. */
    if (is_wave_eos(wave[stream]))
        pre_finish[stream] = true;
}

static void scale_samples(uint32_t *buf, int frames, float vol)
{
    float scale;
    uint32_t frame;
    int32_t il, ir;    /* intermediate L/R */
    int16_t sl, sr;    /* source L/R*/
    int16_t dl, dr;    /* destination L/R */
    int i;

    __sync_synchronize();

    /* Convert a scale factor to an exponential value. */
    scale = (powf(10.0f, vol) - 1.0f) / (10.0f - 1.0f);

    /* Scale samples. */
    for (i = 0; i < frames; i++) {
        frame = buf[i];

        sl = (int16_t)(uint16_t)frame;
        sr = (int16_t)(uint16_t)(frame >> 16);

        il = (int)(sl * scale);
        ir = (int)(sr * scale);

        il = il > 32767 ? 32767 : il;
        il = il < -32768 ? -32768 : il;
        ir = ir > 32767 ? 32767 : ir;
        ir = ir < -32768 ? -32768 : ir;

        dl = (int16_t)il;
        dr = (int16_t)ir;

        buf[i] = ((uint32_t)(uint16_t)dl) | (((uint32_t)(uint16_t)dr) << 16);
    }
}

/*
 * HAL
 */

bool play_sound(int stream, struct wave *w)
{
    if (bq_player_play[stream] == NULL)
        return true;

    pthread_mutex_lock(&sound_mutex[stream]);
    {
        wave[stream] = w;
        pre_finish[stream] = false;
        post_finish[stream] = false;
        enqueue(stream);
    }
    pthread_mutex_unlock(&sound_mutex[stream]);

    return true;
}

bool stop_sound(int stream)
{
    if (bq_player_play[stream] == NULL)
        return true;

    pthread_mutex_lock(&sound_mutex[stream]);
    {
        wave[stream] = NULL;
        pre_finish[stream] = false;
        post_finish[stream] = false;
    }
    pthread_mutex_unlock(&sound_mutex[stream]);

    return true;
}

bool set_sound_volume(int stream, float vol)
{
    volume[stream] = vol;

    __sync_synchronize();

    return true;
}

bool is_sound_finished(int stream)
{
    __sync_synchronize();

    if (!post_finish[stream])
        return false;

    return true;
}

 

posted on 2025-10-16 09:37  小沙盒工作室  阅读(1)  评论(0)    收藏  举报