src/audio/fusionsound/SDL_fsaudio.c
author Sam Lantinga
Thu, 01 Jan 2009 21:34:22 +0000
changeset 2947 fec0db6c44b7
child 3230 816a7a65a59a
permissions -rw-r--r--
Date: Thu, 01 Jan 2009 21:32:12 +0100
From: Couriersud
Subject: Fusionsound audio driver

attached is a diff containing a audio driver for the FusionSound
library. This sound library is closely related to DirectFB and uses the
same transport (fusion) as DirectFB when running applications "remote",
i.e. over the network. As such, it natively redirects sound where
DirectFB redirects video. This may be handy for everyone using SDL over
DirectFB.
slouken@2947
     1
/*
slouken@2947
     2
    SDL - Simple DirectMedia Layer
slouken@2947
     3
    Copyright (C) 1997-2009 Sam Lantinga
slouken@2947
     4
slouken@2947
     5
    This library is free software; you can redistribute it and/or
slouken@2947
     6
    modify it under the terms of the GNU Lesser General Public
slouken@2947
     7
    License as published by the Free Software Foundation; either
slouken@2947
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@2947
     9
slouken@2947
    10
    This library is distributed in the hope that it will be useful,
slouken@2947
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@2947
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@2947
    13
    Lesser General Public License for more details.
slouken@2947
    14
slouken@2947
    15
    You should have received a copy of the GNU Lesser General Public
slouken@2947
    16
    License along with this library; if not, write to the Free Software
slouken@2947
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@2947
    18
slouken@2947
    19
    Sam Lantinga
slouken@2947
    20
    slouken@libsdl.org
slouken@2947
    21
*/
slouken@2947
    22
#include "SDL_config.h"
slouken@2947
    23
slouken@2947
    24
/* Allow access to a raw mixing buffer */
slouken@2947
    25
slouken@2947
    26
#ifdef HAVE_SIGNAL_H
slouken@2947
    27
#include <signal.h>
slouken@2947
    28
#endif
slouken@2947
    29
#include <unistd.h>
slouken@2947
    30
slouken@2947
    31
#include "SDL_timer.h"
slouken@2947
    32
#include "SDL_audio.h"
slouken@2947
    33
#include "../SDL_audiomem.h"
slouken@2947
    34
#include "../SDL_audio_c.h"
slouken@2947
    35
#include "SDL_fsaudio.h"
slouken@2947
    36
slouken@2947
    37
//#define SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "libfusionsound.so"
slouken@2947
    38
slouken@2947
    39
#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
slouken@2947
    40
#include "SDL_name.h"
slouken@2947
    41
#include "SDL_loadso.h"
slouken@2947
    42
#else
slouken@2947
    43
#define SDL_NAME(X)	X
slouken@2947
    44
#endif
slouken@2947
    45
slouken@2947
    46
/* The tag name used by fusionsoundc audio */
slouken@2947
    47
#define SDL_FS_DRIVER_NAME         "fusionsound"
slouken@2947
    48
/* Buffers to use - more than 2 gives a lot of latency */
slouken@2947
    49
#define FUSION_BUFFERS				(2)
slouken@2947
    50
slouken@2947
    51
#ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
slouken@2947
    52
slouken@2947
    53
static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC;
slouken@2947
    54
static void *fs_handle = NULL;
slouken@2947
    55
slouken@2947
    56
static DirectResult(*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[]));
slouken@2947
    57
static DirectResult(*SDL_NAME(FusionSoundCreate)) (IFusionSound **
slouken@2947
    58
                                                   ret_interface);
slouken@2947
    59
slouken@2947
    60
#define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
slouken@2947
    61
static struct
slouken@2947
    62
{
slouken@2947
    63
    const char *name;
slouken@2947
    64
    void **func;
slouken@2947
    65
} fs_functions[] = {
slouken@2947
    66
/* *INDENT-OFF* */
slouken@2947
    67
    SDL_FS_SYM(FusionSoundInit),
slouken@2947
    68
    SDL_FS_SYM(FusionSoundCreate),
slouken@2947
    69
/* *INDENT-ON* */
slouken@2947
    70
};
slouken@2947
    71
slouken@2947
    72
#undef SDL_FS_SYM
slouken@2947
    73
slouken@2947
    74
static void
slouken@2947
    75
UnloadFusionSoundLibrary()
slouken@2947
    76
{
slouken@2947
    77
    if (fs_handle != NULL) {
slouken@2947
    78
        SDL_UnloadObject(fs_handle);
slouken@2947
    79
        fs_handle = NULL;
slouken@2947
    80
    }
slouken@2947
    81
}
slouken@2947
    82
slouken@2947
    83
static int
slouken@2947
    84
LoadFusionSoundLibrary(void)
slouken@2947
    85
{
slouken@2947
    86
    int i, retval = -1;
slouken@2947
    87
slouken@2947
    88
    if (fs_handle == NULL) {
slouken@2947
    89
        fs_handle = SDL_LoadObject(fs_library);
slouken@2947
    90
        if (fs_handle != NULL) {
slouken@2947
    91
            retval = 0;
slouken@2947
    92
            for (i = 0; i < SDL_arraysize(fs_functions); ++i) {
slouken@2947
    93
                *fs_functions[i].func =
slouken@2947
    94
                    SDL_LoadFunction(fs_handle, fs_functions[i].name);
slouken@2947
    95
                if (!*fs_functions[i].func) {
slouken@2947
    96
                    retval = -1;
slouken@2947
    97
                    UnloadFusionSoundLibrary();
slouken@2947
    98
                    break;
slouken@2947
    99
                }
slouken@2947
   100
            }
slouken@2947
   101
        }
slouken@2947
   102
    }
slouken@2947
   103
slouken@2947
   104
    return retval;
slouken@2947
   105
}
slouken@2947
   106
slouken@2947
   107
#else
slouken@2947
   108
slouken@2947
   109
static void
slouken@2947
   110
UnloadFusionSoundLibrary()
slouken@2947
   111
{
slouken@2947
   112
    return;
slouken@2947
   113
}
slouken@2947
   114
slouken@2947
   115
static int
slouken@2947
   116
LoadFusionSoundLibrary(void)
slouken@2947
   117
{
slouken@2947
   118
    return 0;
slouken@2947
   119
}
slouken@2947
   120
slouken@2947
   121
#endif /* SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC */
slouken@2947
   122
slouken@2947
   123
/* This function waits until it is possible to write a full sound buffer */
slouken@2947
   124
static void
slouken@2947
   125
SDL_FS_WaitDevice(_THIS)
slouken@2947
   126
{
slouken@2947
   127
    this->hidden->stream->Wait(this->hidden->stream,
slouken@2947
   128
                               this->hidden->mixsamples);
slouken@2947
   129
}
slouken@2947
   130
slouken@2947
   131
static void
slouken@2947
   132
SDL_FS_PlayDevice(_THIS)
slouken@2947
   133
{
slouken@2947
   134
    DirectResult ret;
slouken@2947
   135
slouken@2947
   136
    ret = this->hidden->stream->Write(this->hidden->stream,
slouken@2947
   137
                                      this->hidden->mixbuf,
slouken@2947
   138
                                      this->hidden->mixsamples);
slouken@2947
   139
    /* If we couldn't write, assume fatal error for now */
slouken@2947
   140
    if (ret) {
slouken@2947
   141
        this->enabled = 0;
slouken@2947
   142
    }
slouken@2947
   143
#ifdef DEBUG_AUDIO
slouken@2947
   144
    fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
slouken@2947
   145
#endif
slouken@2947
   146
}
slouken@2947
   147
slouken@2947
   148
static void
slouken@2947
   149
SDL_FS_WaitDone(_THIS)
slouken@2947
   150
{
slouken@2947
   151
    this->hidden->stream->Wait(this->hidden->stream,
slouken@2947
   152
                               this->hidden->mixsamples * FUSION_BUFFERS);
slouken@2947
   153
}
slouken@2947
   154
slouken@2947
   155
slouken@2947
   156
static Uint8 *
slouken@2947
   157
SDL_FS_GetDeviceBuf(_THIS)
slouken@2947
   158
{
slouken@2947
   159
    return (this->hidden->mixbuf);
slouken@2947
   160
}
slouken@2947
   161
slouken@2947
   162
slouken@2947
   163
static void
slouken@2947
   164
SDL_FS_CloseDevice(_THIS)
slouken@2947
   165
{
slouken@2947
   166
    if (this->hidden != NULL) {
slouken@2947
   167
        if (this->hidden->mixbuf != NULL) {
slouken@2947
   168
            SDL_FreeAudioMem(this->hidden->mixbuf);
slouken@2947
   169
            this->hidden->mixbuf = NULL;
slouken@2947
   170
        }
slouken@2947
   171
        if (this->hidden->stream) {
slouken@2947
   172
            this->hidden->stream->Release(this->hidden->stream);
slouken@2947
   173
            this->hidden->stream = NULL;
slouken@2947
   174
        }
slouken@2947
   175
        if (this->hidden->fs) {
slouken@2947
   176
            this->hidden->fs->Release(this->hidden->fs);
slouken@2947
   177
            this->hidden->fs = NULL;
slouken@2947
   178
        }
slouken@2947
   179
        SDL_free(this->hidden);
slouken@2947
   180
        this->hidden = NULL;
slouken@2947
   181
    }
slouken@2947
   182
}
slouken@2947
   183
slouken@2947
   184
slouken@2947
   185
static int
slouken@2947
   186
SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture)
slouken@2947
   187
{
slouken@2947
   188
    int bytes;
slouken@2947
   189
    SDL_AudioFormat test_format = 0, format = 0;
slouken@2947
   190
    FSSampleFormat fs_format;
slouken@2947
   191
    FSStreamDescription desc;
slouken@2947
   192
    DirectResult ret;
slouken@2947
   193
slouken@2947
   194
    /* Initialize all variables that we clean on shutdown */
slouken@2947
   195
    this->hidden = (struct SDL_PrivateAudioData *)
slouken@2947
   196
        SDL_malloc((sizeof *this->hidden));
slouken@2947
   197
    if (this->hidden == NULL) {
slouken@2947
   198
        SDL_OutOfMemory();
slouken@2947
   199
        return 0;
slouken@2947
   200
    }
slouken@2947
   201
    SDL_memset(this->hidden, 0, (sizeof *this->hidden));
slouken@2947
   202
slouken@2947
   203
    /* Try for a closest match on audio format */
slouken@2947
   204
    for (test_format = SDL_FirstAudioFormat(this->spec.format);
slouken@2947
   205
         !format && test_format;) {
slouken@2947
   206
#ifdef DEBUG_AUDIO
slouken@2947
   207
        fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
slouken@2947
   208
#endif
slouken@2947
   209
        switch (test_format) {
slouken@2947
   210
        case AUDIO_U8:
slouken@2947
   211
            fs_format = FSSF_U8;
slouken@2947
   212
            bytes = 1;
slouken@2947
   213
            format = 1;
slouken@2947
   214
            break;
slouken@2947
   215
        case AUDIO_S16SYS:
slouken@2947
   216
            fs_format = FSSF_S16;
slouken@2947
   217
            bytes = 2;
slouken@2947
   218
            format = 1;
slouken@2947
   219
            break;
slouken@2947
   220
        case AUDIO_S32SYS:
slouken@2947
   221
            fs_format = FSSF_S32;
slouken@2947
   222
            bytes = 4;
slouken@2947
   223
            format = 1;
slouken@2947
   224
            break;
slouken@2947
   225
        case AUDIO_F32SYS:
slouken@2947
   226
            fs_format = FSSF_FLOAT;
slouken@2947
   227
            bytes = 4;
slouken@2947
   228
            format = 1;
slouken@2947
   229
            break;
slouken@2947
   230
        default:
slouken@2947
   231
            format = 0;
slouken@2947
   232
            break;
slouken@2947
   233
        }
slouken@2947
   234
        if (!format) {
slouken@2947
   235
            test_format = SDL_NextAudioFormat();
slouken@2947
   236
        }
slouken@2947
   237
    }
slouken@2947
   238
slouken@2947
   239
    if (format == 0) {
slouken@2947
   240
        SDL_FS_CloseDevice(this);
slouken@2947
   241
        SDL_SetError("Couldn't find any hardware audio formats");
slouken@2947
   242
        return 0;
slouken@2947
   243
    }
slouken@2947
   244
    this->spec.format = test_format;
slouken@2947
   245
slouken@2947
   246
    /* Retrieve the main sound interface. */
slouken@2947
   247
    ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
slouken@2947
   248
    if (ret) {
slouken@2947
   249
        SDL_FS_CloseDevice(this);
slouken@2947
   250
        SDL_SetError("Unable to initialize FusionSound: %d", ret);
slouken@2947
   251
        return 0;
slouken@2947
   252
    }
slouken@2947
   253
slouken@2947
   254
    this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels;
slouken@2947
   255
slouken@2947
   256
    /* Fill stream description. */
slouken@2947
   257
    desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
slouken@2947
   258
        FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER;
slouken@2947
   259
    desc.samplerate = this->spec.freq;
slouken@2947
   260
    desc.buffersize = this->spec.size * FUSION_BUFFERS;
slouken@2947
   261
    desc.channels = this->spec.channels;
slouken@2947
   262
    desc.prebuffer = 10;
slouken@2947
   263
    desc.sampleformat = fs_format;
slouken@2947
   264
slouken@2947
   265
    ret =
slouken@2947
   266
        this->hidden->fs->CreateStream(this->hidden->fs, &desc,
slouken@2947
   267
                                       &this->hidden->stream);
slouken@2947
   268
    if (ret) {
slouken@2947
   269
        SDL_FS_CloseDevice(this);
slouken@2947
   270
        SDL_SetError("Unable to create FusionSoundStream: %d", ret);
slouken@2947
   271
        return 0;
slouken@2947
   272
    }
slouken@2947
   273
slouken@2947
   274
    /* See what we got */
slouken@2947
   275
    desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
slouken@2947
   276
        FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT;
slouken@2947
   277
    ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc);
slouken@2947
   278
slouken@2947
   279
    this->spec.freq = desc.samplerate;
slouken@2947
   280
    this->spec.size =
slouken@2947
   281
        desc.buffersize / FUSION_BUFFERS * bytes * desc.channels;
slouken@2947
   282
    this->spec.channels = desc.channels;
slouken@2947
   283
slouken@2947
   284
    /* Calculate the final parameters for this audio specification */
slouken@2947
   285
    SDL_CalculateAudioSpec(&this->spec);
slouken@2947
   286
slouken@2947
   287
    /* Allocate mixing buffer */
slouken@2947
   288
    this->hidden->mixlen = this->spec.size;
slouken@2947
   289
    this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
slouken@2947
   290
    if (this->hidden->mixbuf == NULL) {
slouken@2947
   291
        SDL_FS_CloseDevice(this);
slouken@2947
   292
        SDL_OutOfMemory();
slouken@2947
   293
        return 0;
slouken@2947
   294
    }
slouken@2947
   295
    SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
slouken@2947
   296
slouken@2947
   297
    /* We're ready to rock and roll. :-) */
slouken@2947
   298
    return 1;
slouken@2947
   299
}
slouken@2947
   300
slouken@2947
   301
slouken@2947
   302
static void
slouken@2947
   303
SDL_FS_Deinitialize(void)
slouken@2947
   304
{
slouken@2947
   305
    UnloadFusionSoundLibrary();
slouken@2947
   306
}
slouken@2947
   307
slouken@2947
   308
slouken@2947
   309
static int
slouken@2947
   310
SDL_FS_Init(SDL_AudioDriverImpl * impl)
slouken@2947
   311
{
slouken@2947
   312
    if (LoadFusionSoundLibrary() < 0) {
slouken@2947
   313
        return 0;
slouken@2947
   314
    } else {
slouken@2947
   315
        DirectResult ret;
slouken@2947
   316
slouken@2947
   317
        ret = SDL_NAME(FusionSoundInit) (NULL, NULL);
slouken@2947
   318
        if (ret) {
slouken@2947
   319
            UnloadFusionSoundLibrary();
slouken@2947
   320
            SDL_SetError
slouken@2947
   321
                ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)",
slouken@2947
   322
                 ret);
slouken@2947
   323
            return 0;
slouken@2947
   324
        }
slouken@2947
   325
    }
slouken@2947
   326
slouken@2947
   327
    /* Set the function pointers */
slouken@2947
   328
    impl->OpenDevice = SDL_FS_OpenDevice;
slouken@2947
   329
    impl->PlayDevice = SDL_FS_PlayDevice;
slouken@2947
   330
    impl->WaitDevice = SDL_FS_WaitDevice;
slouken@2947
   331
    impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
slouken@2947
   332
    impl->CloseDevice = SDL_FS_CloseDevice;
slouken@2947
   333
    impl->WaitDone = SDL_FS_WaitDone;
slouken@2947
   334
    impl->Deinitialize = SDL_FS_Deinitialize;
slouken@2947
   335
    impl->OnlyHasDefaultOutputDevice = 1;
slouken@2947
   336
slouken@2947
   337
    return 1;
slouken@2947
   338
}
slouken@2947
   339
slouken@2947
   340
slouken@2947
   341
AudioBootStrap FUSIONSOUND_bootstrap = {
slouken@2947
   342
    SDL_FS_DRIVER_NAME, "FusionSound", SDL_FS_Init, 0
slouken@2947
   343
};
slouken@2947
   344
slouken@2947
   345
/* vi: set ts=4 sw=4 expandtab: */