1

I'm implementing audio playback into my game engine using OpenSL ES on Android. So far I'm supporting Android file descriptor data locators (AndroidFD) only. The problem is, that the audio playback won't always work if I'm using wrapper classes for OpenSL ES.

The wrappers:

AudioEngine.cpp

AudioEngine::AudioEngine()
    : _engine(NULL),
      _engineInterface(NULL),
      _outputMix(NULL)
{
    createEngine();
    createOutputMix();
}

AudioEngine::~AudioEngine()
{
    (*_outputMix)->Destroy(_outputMix);
    (*_engine)->Destroy(_engine);
}

Sound* AudioEngine::loadSound(const String& filename) const
{
    return NEW Sound(_engineInterface, _outputMix, filename);
}


// Private

void AudioEngine::createEngine()
{
    Uint32 result = slCreateEngine(&_engine, 0u, NULL, 0u, NULL, NULL);

    CHECK_OPENSLES_ERROR(result, "Platform::AudioEngine (OpenSLES)",
        "Failed to create the engine");

    result = (*_engine)->Realize(_engine, SL_BOOLEAN_FALSE);

    CHECK_OPENSLES_ERROR(result, "Platform::AudioEngine (OpenSLES)",
        "Failed to initialise the engine");

    result = (*_engine)->GetInterface(_engine, SL_IID_ENGINE, &_engineInterface);

    CHECK_OPENSLES_ERROR(result, "Platform::AudioEngine (OpenSLES)",
        "Failed to get the engine interface");
}

void AudioEngine::createOutputMix()
{
    Uint32 result = (*_engineInterface)->CreateOutputMix(_engineInterface, &_outputMix, 0u,
        NULL, NULL);

    CHECK_OPENSLES_ERROR(result, "Platform::AudioEngine (OpenSLES)",
        "Failed to create the output mix");

    result = (*_outputMix)->Realize(_outputMix, SL_BOOLEAN_FALSE);

    CHECK_OPENSLES_ERROR(result, "Platform::AudioEngine (OpenSLES)",
        "Failed to initialise the output mix");
}

Sound.cpp

// Public

Sound::Sound(SLEngineItf engineInterface, SLObjectItf outputMix, const String& filename)
    : _engineInterface(engineInterface),
      _outputMix(outputMix),
      _player(NULL),
      _playerInterface(NULL)
{
    // Member (SLDataFormat_MIME)
    _dataSourceFormat.formatType = SL_DATAFORMAT_MIME;
    _dataSourceFormat.mimeType = NULL;
    _dataSourceFormat.containerType = SL_CONTAINERTYPE_UNSPECIFIED;

    // Member (SLDataLocator_AndroidFD)
    _dataSourceLocator.locatorType = SL_DATALOCATOR_ANDROIDFD;

    AAssetManager* assetManager = Application::assetManager();
    AAsset* asset = AAssetManager_open(assetManager, filename.data(), AASSET_MODE_UNKNOWN);

    _dataSourceLocator.fd = AAsset_openFileDescriptor(asset,
        reinterpret_cast<off_t*>(&_dataSourceLocator.offset),
        reinterpret_cast<off_t*>(&_dataSourceLocator.length));

    AAsset_close(asset);
    createPlayer();
}

Sound::~Sound()
{
    (*_player)->Destroy(_player);
}

void Sound::play() const
{
    const Uint32 result = (*_playerInterface)->SetPlayState(_playerInterface,
        SL_PLAYSTATE_PLAYING);

    CHECK_OPENSLES_ERROR(result, "Platform::Sound (OpenSLES)",
        "Failed to set the play state"); 
}


// Private

void Sound::createPlayer()
{
    SLDataSource dataSource =
    {
        &_dataSourceLocator,
        &_dataSourceFormat
    };

    SLDataLocator_OutputMix outputMixLocator =
    {
        SL_DATALOCATOR_OUTPUTMIX,
        _outputMix
    };

    SLDataSink dataSink =
    {
        &outputMixLocator,
        NULL
    };

    Uint32 result = (*_engineInterface)->CreateAudioPlayer(_engineInterface, &_player,
        &dataSource, &dataSink, 0u, NULL, NULL);

    CHECK_OPENSLES_ERROR(result, "Platform::Sound (OpenSLES)",
        "Failed to create a player");

    result = (*_player)->Realize(_player, SL_BOOLEAN_FALSE);

    CHECK_OPENSLES_ERROR(result, "Platform::Sound (OpenSLES)",
        "Failed to initialise the player");

    result = (*_player)->GetInterface(_player, SL_IID_PLAY, &_playerInterface);

    CHECK_OPENSLES_ERROR(result, "Platform::SoundInstance (OpenSLES)",
        "Failed to get the player interface");
}

Game.cpp

Game::initialise()
{
    _audioEngine = NEW AudioEngine();
    _sound = _audioEngine->loadSound("music.ogg");
    _sound->play();
}

When the application starts, the sound won't always play. If I write all OpenSL ES code above inside Game::initialise(), the sound will always play. I can't figure out why the same code won't work inside the wrapper classes.

I ran the application on Samsung Galaxy S III (GT-I9305), Android 4.2.2, CyanogenMod 10.1.3-i9305

4

1 回答 1

0

您可能必须在播放声音时将 dataSource、outputMixLocator 和 dataSink 保持在范围内,因为它们是作为指针传递的。使它们成为成员变量,以使它们在对象的生命周期内保持活动状态。

于 2014-02-20T23:39:59.983 回答