misc/libopenalbridge/openalbridge.c
author Zorg <zorgiepoo@gmail.com>
Wed, 08 Jun 2011 03:36:54 -0400
changeset 5229 148d581b17ab
parent 3697 d5b30d6373fc
permissions -rw-r--r--
Attempt to fix issue #125. The password pop-up doesn't appear every time when going into the official server anymore, now it only does it when the password is blank. If a user enters an invalid password, the password is set blank to avoid the user going back to the official server just to be rejected. When entering an invalid password, the unknown error dialog doesn't show up anymore, but the connection lost to server one still does. This fixes the bug where the user would be spammed with error messages. The user can also now change his password in the settings page.

/*
* OpenAL Bridge - a simple portable library for OpenAL interface
* Copyright (c) 2009 Vittorio Giovara <vittorio.giovara@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 2 of the License
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/

#include "openalbridge.h"
#include "globals.h"
#include "al.h"
#include "alc.h"
#include "wrappers.h"
#include "loaders.h"
#include "string.h"

// Sources are points emitting sound, their number is limited, but a single source can play many buffers
// Buffers hold sound data and are unlimited
ALuint *Sources;
ALuint cache_size, cache_index, sources_number;
ALboolean instances_number;
al_sound_t *the_sounds;
ALint cache_pointer;

// Initialize an OpenAL contex and allocate memory space for data and buffers
// It can be called twice to increase the cache size
int openal_init (void) {
    ALCcontext *context;
    ALCdevice *device;
    int i;

    // reuse old context and resize the existing
    if (openal_ready() == AL_TRUE) {
        fprintf(stderr,"(Bridge Info) - already initialized\n");
        instances_number++;
        return AL_TRUE;
    }

    cache_pointer = 0;
    instances_number++;

    // initial memory size
    cache_size = 50;

    // open hardware device if present
    device = alcOpenDevice(NULL);
    sources_number = 16;
    if (device == NULL) {
        fprintf(stderr,"(Bridge Warning) - failed to open sound device, using software renderer\n");
        device = alcOpenDevice("Generic Software");
        sources_number = 32;
        if (device == NULL) {
            fprintf(stderr,"(Bridge ERROR) - failed to start software renderer, sound will be disabled\n");
            return -1;
        }
    }

    fprintf(stderr,"(Bridge Info) - output device: %s\n", alcGetString(device, ALC_DEVICE_SPECIFIER));

    context = alcCreateContext(device, NULL);
    alcMakeContextCurrent(context);
    alcProcessContext(context);

    if (AL_NO_ERROR != alGetError()) {
        fprintf(stderr,"(Bridge ERROR) - Failed to create a new contex\n");
        alcMakeContextCurrent(NULL);
        alcDestroyContext(context);
        alcCloseDevice(device);
        return -2;
    }

    Sources = (ALuint *)Malloc (sizeof(ALuint) * sources_number);
    alGenSources(sources_number, Sources);

    // set the listener gain, position (on xyz axes), velocity (one value for each axe) and orientation
    // Position, Velocity and Orientation of the listener
    ALfloat ListenerPos[] = {0.0, 0.0, 0.0};
    ALfloat ListenerVel[] = {0.0, 0.0, 0.0};
    ALfloat ListenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0};

    alListenerf (AL_GAIN,        1.0f       );
    alListenerfv(AL_POSITION,    ListenerPos);
    alListenerfv(AL_VELOCITY,    ListenerVel);
    alListenerfv(AL_ORIENTATION, ListenerOri);

    if (AL_NO_ERROR != alGetError()) {
        fprintf(stderr,"(Bridge ERROR) - Failed to set Listener properties\n");
        return -3;
    }

    the_sounds = (al_sound_t *)Malloc (sizeof(al_sound_t) * cache_size);
    for (i = 0; i < cache_size; i++)
        the_sounds[i] = new_sound_el();

    alGetError();
    return AL_TRUE;
}


// Stop all sounds, deallocate all memory and close OpenAL context
void openal_close (void) {
    ALCcontext *context;
    ALCdevice  *device;
    int i;

    if (instances_number == 0) {
        fprintf(stderr,"(Bridge Warning) - OpenAL not initialized\n");
        return;
    }

    instances_number--;
    if (instances_number > 0) {
        // release memory only when last session ends
        return;
    }

    for (i = 0; i < cache_size; i++) {
        openal_unloadfile(i);
    }
    free(the_sounds);

    alSourceStopv (sources_number, Sources);
    alDeleteSources (sources_number, Sources);

    free(Sources);

    context = alcGetCurrentContext();
    device  = alcGetContextsDevice(context);

    alcMakeContextCurrent(NULL);
    alcDestroyContext(context);
    alcCloseDevice(device);

    fprintf(stderr,"(Bridge Info) - closed\n");

    return;
}


ALboolean openal_ready (void) {
    if (instances_number >= 1)
        return AL_TRUE;
    else
        return AL_FALSE;
}


// Open a file, load into memory and allocate the Source buffer for playing
int openal_loadfile (const char *filename){
    ALenum format, error;
    ALsizei bitsize, freq;
    uint32_t fileformat;
    al_sound_t sound_data;
    int len, i, index = -1;
    char *data;
    FILE *fp;

    if (openal_ready() == AL_FALSE) {
        fprintf(stderr,"(Bridge Warning) - not initialized\n");
        return -1;
    }

    // if this sound is already loaded return the index from the_sounds
    len = strlen(filename);
    for (i = 0; i < cache_size; i++) {
        if (the_sounds[i].filename != NULL && strncmp(the_sounds[i].filename, filename, len) == 0) {
#ifdef DEBUG
            fprintf(stderr,"(Bridge Debug) - sound %d is already loaded\n", i);
#endif
            return i;
        }
        // if we don't have memory available search for a free element
        if (cache_pointer >= cache_size)
            if (the_sounds[i].is_used == AL_FALSE)
                index = i;
    }

    if (index == -1 && cache_pointer >= cache_size) {
        fprintf(stderr,"(Bridge Info) - No free spots found; doubling cache size\n", filename);
        cache_size *= 2;
        the_sounds = (al_sound_t *)Realloc (the_sounds, sizeof(al_sound_t) * cache_size);
        for (i = cache_size - 50; i < cache_size; i++)
            the_sounds[i] = new_sound_el();
    } else
        index = ++cache_pointer;


    // detect the file format, as written in the first 4 bytes of the header
    fp = Fopen (filename, "rb");
    if (fp == NULL) {
        fprintf(stderr,"(Bridge ERROR) - File %s not loaded\n", filename);
        return -3;
    }

    error = fread (&fileformat, sizeof(uint32_t), 1, fp);
    fclose (fp);
    if (error < 0) {
        fprintf(stderr,"(Bridge ERROR) - File %s is too short\n", filename);
        return -4;
    }

    switch (ENDIAN_BIG_32(fileformat)) {
        case OGG_FILE_FORMAT:
            error = load_oggvorbis (filename, &format, &data, &bitsize, &freq);
            break;
        case WAV_FILE_FORMAT:
            error = load_wavpcm (filename, &format, &data, &bitsize, &freq);
            break;
        default:
            fprintf(stderr,"(Bridge ERROR) - File format (%08X) not supported\n", ENDIAN_BIG_32(fileformat));
            return -5;
            break;
    }

    if (error != 0) {
        fprintf(stderr,"(Bridge ERROR) - error loading file %s\n", filename);
        if(data)
            free(data);
        return -6;
    }

    // alGenBuffers happens here
    sound_data = init_sound_el(filename);

    if (AL_NO_ERROR != alGetError()) {
        fprintf(stderr,"(Bridge ERROR) - Failed to allocate memory for buffer %d\n", index);
        free(data);
        return -5;
    }

    // copy pcm data in one buffer and free it
    alBufferData(sound_data.buffer, format, data, bitsize, freq);
    free(data);

    if (AL_NO_ERROR != alGetError()) {
        fprintf(stderr,"(Bridge ERROR) - Failed to write data to buffer %d\n", index);
        return -8;
    }

    // clear any AL errors beforehand
    alGetError();

    fprintf(stderr,"(Bridge Info) - successfully loaded %s\n", filename);

    // returns the index of the source you just loaded, increments it and exits
    the_sounds[index] = sound_data;
    return index;
}


void openal_unloadfile (uint32_t index) {
    ALint state;

    if (openal_ready() == AL_TRUE && index < cache_size && the_sounds[index].is_used == AL_TRUE) {
        alGetSourcei (Sources[the_sounds[index].source_index], AL_SOURCE_STATE, &state);
        if (state == AL_PLAYING || state == AL_PAUSED)
            openal_stopsound(index);

        // free memory and
        alDeleteBuffers (1, &the_sounds[index].buffer);
        the_sounds[index] = new_sound_el();
    }
}