src/audio/haiku/SDL_haikuaudio.cc
author Ryan C. Gordon <icculus@icculus.org>
Fri, 05 Aug 2016 01:44:41 -0400
changeset 10255 9530fc07da6c
parent 10238 6fa358b97f4b
child 10257 f17581d00c26
permissions -rw-r--r--
audio: Clean up some CloseDevice() interface details.

- It's now always called if device->hidden isn't NULL, even if OpenDevice()
failed halfway through. This lets implementation code not have to clean up
itself on every possible failure point; just return an error and SDL will
handle it for you.

- Implementations can assume this->hidden != NULL and not check for it.

- implementations don't have to set this->hidden = NULL when done, because
the caller is always about to free(this).

- Don't reset other fields that are in a block of memory about to be free()'d.

- Implementations all now free things like internal mix buffers last, after
closing devices and such, to guarantee they definitely aren't in use anymore
at the point of deallocation.
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@0
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@0
    22
icculus@7981
    23
#if SDL_AUDIO_DRIVER_HAIKU
slouken@6044
    24
icculus@7981
    25
/* Allow access to the audio stream on Haiku */
slouken@0
    26
slouken@0
    27
#include <SoundPlayer.h>
icculus@7977
    28
#include <signal.h>
slouken@0
    29
icculus@7981
    30
#include "../../main/haiku/SDL_BeApp.h"
slouken@0
    31
slouken@1895
    32
extern "C"
slouken@1895
    33
{
slouken@0
    34
slouken@0
    35
#include "SDL_audio.h"
slouken@1361
    36
#include "../SDL_audio_c.h"
slouken@1361
    37
#include "../SDL_sysaudio.h"
icculus@7981
    38
#include "SDL_haikuaudio.h"
slouken@0
    39
icculus@2049
    40
}
slouken@0
    41
slouken@0
    42
icculus@2049
    43
/* !!! FIXME: have the callback call the higher level to avoid code dupe. */
icculus@7981
    44
/* The Haiku callback for handling the audio buffer */
icculus@2049
    45
static void
icculus@2049
    46
FillSound(void *device, void *stream, size_t len,
icculus@2049
    47
          const media_raw_audio_format & format)
icculus@2049
    48
{
icculus@2049
    49
    SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
slouken@0
    50
icculus@2049
    51
    /* Only do soemthing if audio is enabled */
icculus@10238
    52
    if (!SDL_AtomicGet(&audio->enabled)) {
icculus@2049
    53
        return;
icculus@10238
    54
    }
slouken@0
    55
icculus@10238
    56
    if (!SDL_AtomicGet(&audio->paused)) {
icculus@2049
    57
        if (audio->convert.needed) {
slouken@6977
    58
            SDL_LockMutex(audio->mixer_lock);
icculus@2049
    59
            (*audio->spec.callback) (audio->spec.userdata,
slouken@2060
    60
                                     (Uint8 *) audio->convert.buf,
slouken@2060
    61
                                     audio->convert.len);
slouken@6977
    62
            SDL_UnlockMutex(audio->mixer_lock);
icculus@2049
    63
            SDL_ConvertAudio(&audio->convert);
icculus@2049
    64
            SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
icculus@2049
    65
        } else {
slouken@6977
    66
            SDL_LockMutex(audio->mixer_lock);
icculus@2049
    67
            (*audio->spec.callback) (audio->spec.userdata,
slouken@2060
    68
                                     (Uint8 *) stream, len);
slouken@6977
    69
            SDL_UnlockMutex(audio->mixer_lock);
slouken@1895
    70
        }
slouken@1895
    71
    }
icculus@2049
    72
}
slouken@0
    73
icculus@2049
    74
static void
icculus@7981
    75
HAIKUAUDIO_CloseDevice(_THIS)
icculus@2049
    76
{
icculus@10255
    77
    if (_this->hidden->audio_obj) {
icculus@10255
    78
        _this->hidden->audio_obj->Stop();
icculus@10255
    79
        delete _this->hidden->audio_obj;
slouken@1895
    80
    }
icculus@10255
    81
    delete _this->hidden;
icculus@2049
    82
}
slouken@0
    83
icculus@7977
    84
icculus@7977
    85
static const int sig_list[] = {
icculus@7977
    86
    SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGWINCH, 0
icculus@7977
    87
};
icculus@7977
    88
icculus@7977
    89
static inline void
icculus@7977
    90
MaskSignals(sigset_t * omask)
icculus@7977
    91
{
icculus@7977
    92
    sigset_t mask;
icculus@7977
    93
    int i;
icculus@7977
    94
icculus@7977
    95
    sigemptyset(&mask);
icculus@7977
    96
    for (i = 0; sig_list[i]; ++i) {
icculus@7977
    97
        sigaddset(&mask, sig_list[i]);
icculus@7977
    98
    }
icculus@7977
    99
    sigprocmask(SIG_BLOCK, &mask, omask);
icculus@7977
   100
}
icculus@7977
   101
icculus@7977
   102
static inline void
icculus@7977
   103
UnmaskSignals(sigset_t * omask)
icculus@7977
   104
{
icculus@7977
   105
    sigprocmask(SIG_SETMASK, omask, NULL);
icculus@7977
   106
}
icculus@7977
   107
icculus@7977
   108
icculus@2049
   109
static int
icculus@9394
   110
HAIKUAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
icculus@2049
   111
{
icculus@2049
   112
    int valid_datatype = 0;
icculus@2049
   113
    media_raw_audio_format format;
icculus@2049
   114
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
icculus@1997
   115
icculus@2049
   116
    /* Initialize all variables that we clean on shutdown */
icculus@2049
   117
    _this->hidden = new SDL_PrivateAudioData;
icculus@2049
   118
    if (_this->hidden == NULL) {
icculus@7038
   119
        return SDL_OutOfMemory();
icculus@2049
   120
    }
icculus@2049
   121
    SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
icculus@2049
   122
icculus@2049
   123
    /* Parse the audio format and fill the Be raw audio format */
icculus@2049
   124
    SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
icculus@2049
   125
    format.byte_order = B_MEDIA_LITTLE_ENDIAN;
icculus@2049
   126
    format.frame_rate = (float) _this->spec.freq;
slouken@2060
   127
    format.channel_count = _this->spec.channels;        /* !!! FIXME: support > 2? */
icculus@2049
   128
    while ((!valid_datatype) && (test_format)) {
icculus@2049
   129
        valid_datatype = 1;
icculus@2049
   130
        _this->spec.format = test_format;
icculus@2049
   131
        switch (test_format) {
slouken@2060
   132
        case AUDIO_S8:
slouken@2060
   133
            format.format = media_raw_audio_format::B_AUDIO_CHAR;
slouken@2060
   134
            break;
icculus@1997
   135
slouken@2060
   136
        case AUDIO_U8:
slouken@2060
   137
            format.format = media_raw_audio_format::B_AUDIO_UCHAR;
slouken@2060
   138
            break;
icculus@1997
   139
slouken@2060
   140
        case AUDIO_S16LSB:
slouken@2060
   141
            format.format = media_raw_audio_format::B_AUDIO_SHORT;
slouken@2060
   142
            break;
icculus@1997
   143
slouken@2060
   144
        case AUDIO_S16MSB:
slouken@2060
   145
            format.format = media_raw_audio_format::B_AUDIO_SHORT;
slouken@2060
   146
            format.byte_order = B_MEDIA_BIG_ENDIAN;
slouken@2060
   147
            break;
icculus@1997
   148
slouken@2060
   149
        case AUDIO_S32LSB:
slouken@2060
   150
            format.format = media_raw_audio_format::B_AUDIO_INT;
slouken@2060
   151
            break;
icculus@1997
   152
slouken@2060
   153
        case AUDIO_S32MSB:
slouken@2060
   154
            format.format = media_raw_audio_format::B_AUDIO_INT;
slouken@2060
   155
            format.byte_order = B_MEDIA_BIG_ENDIAN;
slouken@2060
   156
            break;
icculus@1997
   157
slouken@2060
   158
        case AUDIO_F32LSB:
slouken@2060
   159
            format.format = media_raw_audio_format::B_AUDIO_FLOAT;
slouken@2060
   160
            break;
icculus@1997
   161
slouken@2060
   162
        case AUDIO_F32MSB:
slouken@2060
   163
            format.format = media_raw_audio_format::B_AUDIO_FLOAT;
slouken@2060
   164
            format.byte_order = B_MEDIA_BIG_ENDIAN;
slouken@2060
   165
            break;
icculus@1997
   166
slouken@2060
   167
        default:
slouken@2060
   168
            valid_datatype = 0;
slouken@2060
   169
            test_format = SDL_NextAudioFormat();
slouken@2060
   170
            break;
icculus@1997
   171
        }
slouken@1895
   172
    }
slouken@1895
   173
slouken@2060
   174
    if (!valid_datatype) {      /* shouldn't happen, but just in case... */
icculus@7038
   175
        return SDL_SetError("Unsupported audio format");
icculus@2049
   176
    }
icculus@2049
   177
icculus@2049
   178
    /* Calculate the final parameters for this audio specification */
icculus@2049
   179
    SDL_CalculateAudioSpec(&_this->spec);
icculus@2049
   180
slouken@6856
   181
    format.buffer_size = _this->spec.size;
slouken@6856
   182
icculus@2049
   183
    /* Subscribe to the audio stream (creates a new thread) */
icculus@2049
   184
    sigset_t omask;
icculus@7977
   185
    MaskSignals(&omask);
icculus@2049
   186
    _this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
icculus@2049
   187
                                                FillSound, NULL, _this);
icculus@7977
   188
    UnmaskSignals(&omask);
icculus@2049
   189
icculus@2049
   190
    if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
icculus@2049
   191
        _this->hidden->audio_obj->SetHasData(true);
icculus@2049
   192
    } else {
icculus@7038
   193
        return SDL_SetError("Unable to start Be audio");
icculus@2049
   194
    }
icculus@2049
   195
icculus@2049
   196
    /* We're running! */
icculus@7038
   197
    return 0;
icculus@2049
   198
}
icculus@2049
   199
icculus@2049
   200
static void
icculus@7981
   201
HAIKUAUDIO_Deinitialize(void)
icculus@2049
   202
{
icculus@2049
   203
    SDL_QuitBeApp();
icculus@2049
   204
}
icculus@2049
   205
icculus@2049
   206
static int
icculus@7981
   207
HAIKUAUDIO_Init(SDL_AudioDriverImpl * impl)
icculus@2049
   208
{
icculus@2049
   209
    /* Initialize the Be Application, if it's not already started */
icculus@2049
   210
    if (SDL_InitBeApp() < 0) {
icculus@2049
   211
        return 0;
icculus@2049
   212
    }
icculus@2049
   213
icculus@2049
   214
    /* Set the function pointers */
icculus@7981
   215
    impl->OpenDevice = HAIKUAUDIO_OpenDevice;
icculus@7981
   216
    impl->CloseDevice = HAIKUAUDIO_CloseDevice;
icculus@7981
   217
    impl->Deinitialize = HAIKUAUDIO_Deinitialize;
icculus@2049
   218
    impl->ProvidesOwnCallbackThread = 1;
icculus@2049
   219
    impl->OnlyHasDefaultOutputDevice = 1;
icculus@2049
   220
icculus@3699
   221
    return 1;   /* this audio target is available. */
icculus@2049
   222
}
icculus@2049
   223
slouken@2060
   224
extern "C"
slouken@2060
   225
{
icculus@7981
   226
    extern AudioBootStrap HAIKUAUDIO_bootstrap;
slouken@2060
   227
}
icculus@7981
   228
AudioBootStrap HAIKUAUDIO_bootstrap = {
icculus@7981
   229
    "haiku", "Haiku BSoundPlayer", HAIKUAUDIO_Init, 0
icculus@2049
   230
};
slouken@1895
   231
icculus@7981
   232
#endif /* SDL_AUDIO_DRIVER_HAIKU */
slouken@6044
   233
slouken@1895
   234
/* vi: set ts=4 sw=4 expandtab: */