src/audio/baudio/SDL_beaudio.cc
author Sam Lantinga <slouken@libsdl.org>
Mon, 11 Feb 2013 20:56:34 -0800
changeset 6856 245a50142ffb
parent 6352 a9bcd26e7105
child 6885 700f1b25f77f
permissions -rw-r--r--
Fixed bug 1679 - Error in buffer size setting in Haiku/BeOS audio driver

PulkoMandy

Just like in SDL, audio buffer sizes for BeOS and Haiku BSoundPlayer are sized
in bytes, not frames. SDL was feeding the wrong value, leading to buffers
smaller than expected and weird behaviour in some unsuspecting programs
(noticed it in HivelyTracker but others are likely affected as well. The fix is
fortunately very simple
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 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
*/
slouken@1403
    21
#include "SDL_config.h"
slouken@0
    22
slouken@6044
    23
#if SDL_AUDIO_DRIVER_BEOSAUDIO
slouken@6044
    24
slouken@0
    25
/* Allow access to the audio stream on BeOS */
slouken@0
    26
slouken@0
    27
#include <SoundPlayer.h>
slouken@0
    28
slouken@1367
    29
#include "../../main/beos/SDL_BeApp.h"
slouken@0
    30
slouken@1895
    31
extern "C"
slouken@1895
    32
{
slouken@0
    33
slouken@0
    34
#include "SDL_audio.h"
slouken@1361
    35
#include "../SDL_audio_c.h"
slouken@1361
    36
#include "../SDL_sysaudio.h"
slouken@1367
    37
#include "../../thread/beos/SDL_systhread_c.h"
slouken@0
    38
#include "SDL_beaudio.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@2049
    44
/* The BeOS 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@2049
    52
    if (!audio->enabled)
icculus@2049
    53
        return;
slouken@0
    54
icculus@2049
    55
    if (!audio->paused) {
icculus@2049
    56
        if (audio->convert.needed) {
icculus@2049
    57
            SDL_mutexP(audio->mixer_lock);
icculus@2049
    58
            (*audio->spec.callback) (audio->spec.userdata,
slouken@2060
    59
                                     (Uint8 *) audio->convert.buf,
slouken@2060
    60
                                     audio->convert.len);
icculus@2049
    61
            SDL_mutexV(audio->mixer_lock);
icculus@2049
    62
            SDL_ConvertAudio(&audio->convert);
icculus@2049
    63
            SDL_memcpy(stream, audio->convert.buf, audio->convert.len_cvt);
icculus@2049
    64
        } else {
icculus@2049
    65
            SDL_mutexP(audio->mixer_lock);
icculus@2049
    66
            (*audio->spec.callback) (audio->spec.userdata,
slouken@2060
    67
                                     (Uint8 *) stream, len);
icculus@2049
    68
            SDL_mutexV(audio->mixer_lock);
slouken@1895
    69
        }
slouken@1895
    70
    }
icculus@2049
    71
}
slouken@0
    72
icculus@2049
    73
static void
icculus@2049
    74
BEOSAUDIO_CloseDevice(_THIS)
icculus@2049
    75
{
icculus@2049
    76
    if (_this->hidden != NULL) {
icculus@2049
    77
        if (_this->hidden->audio_obj) {
icculus@2049
    78
            _this->hidden->audio_obj->Stop();
icculus@2049
    79
            delete _this->hidden->audio_obj;
icculus@2049
    80
            _this->hidden->audio_obj = NULL;
slouken@1895
    81
        }
slouken@0
    82
icculus@2049
    83
        delete _this->hidden;
icculus@2049
    84
        _this->hidden = NULL;
slouken@1895
    85
    }
icculus@2049
    86
}
slouken@0
    87
icculus@2049
    88
static int
icculus@2049
    89
BEOSAUDIO_OpenDevice(_THIS, const char *devname, int iscapture)
icculus@2049
    90
{
icculus@2049
    91
    int valid_datatype = 0;
icculus@2049
    92
    media_raw_audio_format format;
icculus@2049
    93
    SDL_AudioFormat test_format = SDL_FirstAudioFormat(_this->spec.format);
icculus@1997
    94
icculus@2049
    95
    /* Initialize all variables that we clean on shutdown */
icculus@2049
    96
    _this->hidden = new SDL_PrivateAudioData;
icculus@2049
    97
    if (_this->hidden == NULL) {
icculus@2049
    98
        SDL_OutOfMemory();
icculus@2049
    99
        return 0;
icculus@2049
   100
    }
icculus@2049
   101
    SDL_memset(_this->hidden, 0, (sizeof *_this->hidden));
icculus@2049
   102
icculus@2049
   103
    /* Parse the audio format and fill the Be raw audio format */
icculus@2049
   104
    SDL_memset(&format, '\0', sizeof(media_raw_audio_format));
icculus@2049
   105
    format.byte_order = B_MEDIA_LITTLE_ENDIAN;
icculus@2049
   106
    format.frame_rate = (float) _this->spec.freq;
slouken@2060
   107
    format.channel_count = _this->spec.channels;        /* !!! FIXME: support > 2? */
icculus@2049
   108
    while ((!valid_datatype) && (test_format)) {
icculus@2049
   109
        valid_datatype = 1;
icculus@2049
   110
        _this->spec.format = test_format;
icculus@2049
   111
        switch (test_format) {
slouken@2060
   112
        case AUDIO_S8:
slouken@2060
   113
            format.format = media_raw_audio_format::B_AUDIO_CHAR;
slouken@2060
   114
            break;
icculus@1997
   115
slouken@2060
   116
        case AUDIO_U8:
slouken@2060
   117
            format.format = media_raw_audio_format::B_AUDIO_UCHAR;
slouken@2060
   118
            break;
icculus@1997
   119
slouken@2060
   120
        case AUDIO_S16LSB:
slouken@2060
   121
            format.format = media_raw_audio_format::B_AUDIO_SHORT;
slouken@2060
   122
            break;
icculus@1997
   123
slouken@2060
   124
        case AUDIO_S16MSB:
slouken@2060
   125
            format.format = media_raw_audio_format::B_AUDIO_SHORT;
slouken@2060
   126
            format.byte_order = B_MEDIA_BIG_ENDIAN;
slouken@2060
   127
            break;
icculus@1997
   128
slouken@2060
   129
        case AUDIO_S32LSB:
slouken@2060
   130
            format.format = media_raw_audio_format::B_AUDIO_INT;
slouken@2060
   131
            break;
icculus@1997
   132
slouken@2060
   133
        case AUDIO_S32MSB:
slouken@2060
   134
            format.format = media_raw_audio_format::B_AUDIO_INT;
slouken@2060
   135
            format.byte_order = B_MEDIA_BIG_ENDIAN;
slouken@2060
   136
            break;
icculus@1997
   137
slouken@2060
   138
        case AUDIO_F32LSB:
slouken@2060
   139
            format.format = media_raw_audio_format::B_AUDIO_FLOAT;
slouken@2060
   140
            break;
icculus@1997
   141
slouken@2060
   142
        case AUDIO_F32MSB:
slouken@2060
   143
            format.format = media_raw_audio_format::B_AUDIO_FLOAT;
slouken@2060
   144
            format.byte_order = B_MEDIA_BIG_ENDIAN;
slouken@2060
   145
            break;
icculus@1997
   146
slouken@2060
   147
        default:
slouken@2060
   148
            valid_datatype = 0;
slouken@2060
   149
            test_format = SDL_NextAudioFormat();
slouken@2060
   150
            break;
icculus@1997
   151
        }
slouken@1895
   152
    }
slouken@1895
   153
slouken@2060
   154
    if (!valid_datatype) {      /* shouldn't happen, but just in case... */
icculus@2049
   155
        BEOSAUDIO_CloseDevice(_this);
icculus@2049
   156
        SDL_SetError("Unsupported audio format");
icculus@2049
   157
        return 0;
icculus@2049
   158
    }
icculus@2049
   159
icculus@2049
   160
    /* Calculate the final parameters for this audio specification */
icculus@2049
   161
    SDL_CalculateAudioSpec(&_this->spec);
icculus@2049
   162
slouken@6856
   163
    format.buffer_size = _this->spec.size;
slouken@6856
   164
icculus@2049
   165
    /* Subscribe to the audio stream (creates a new thread) */
icculus@2049
   166
    sigset_t omask;
icculus@2049
   167
    SDL_MaskSignals(&omask);
icculus@2049
   168
    _this->hidden->audio_obj = new BSoundPlayer(&format, "SDL Audio",
icculus@2049
   169
                                                FillSound, NULL, _this);
icculus@2049
   170
    SDL_UnmaskSignals(&omask);
icculus@2049
   171
icculus@2049
   172
    if (_this->hidden->audio_obj->Start() == B_NO_ERROR) {
icculus@2049
   173
        _this->hidden->audio_obj->SetHasData(true);
icculus@2049
   174
    } else {
icculus@2049
   175
        BEOSAUDIO_CloseDevice(_this);
icculus@2049
   176
        SDL_SetError("Unable to start Be audio");
icculus@2049
   177
        return 0;
icculus@2049
   178
    }
icculus@2049
   179
icculus@2049
   180
    /* We're running! */
icculus@2049
   181
    return 1;
icculus@2049
   182
}
icculus@2049
   183
icculus@2049
   184
static void
icculus@2049
   185
BEOSAUDIO_Deinitialize(void)
icculus@2049
   186
{
icculus@2049
   187
    SDL_QuitBeApp();
icculus@2049
   188
}
icculus@2049
   189
icculus@2049
   190
static int
slouken@2060
   191
BEOSAUDIO_Init(SDL_AudioDriverImpl * impl)
icculus@2049
   192
{
icculus@2049
   193
    /* Initialize the Be Application, if it's not already started */
icculus@2049
   194
    if (SDL_InitBeApp() < 0) {
icculus@2049
   195
        return 0;
icculus@2049
   196
    }
icculus@2049
   197
icculus@2049
   198
    /* Set the function pointers */
icculus@2049
   199
    impl->OpenDevice = BEOSAUDIO_OpenDevice;
icculus@2049
   200
    impl->CloseDevice = BEOSAUDIO_CloseDevice;
icculus@2049
   201
    impl->Deinitialize = BEOSAUDIO_Deinitialize;
icculus@2049
   202
    impl->ProvidesOwnCallbackThread = 1;
icculus@2049
   203
    impl->OnlyHasDefaultOutputDevice = 1;
icculus@2049
   204
icculus@3699
   205
    return 1;   /* this audio target is available. */
icculus@2049
   206
}
icculus@2049
   207
slouken@2060
   208
extern "C"
slouken@2060
   209
{
slouken@2060
   210
    extern AudioBootStrap BEOSAUDIO_bootstrap;
slouken@2060
   211
}
icculus@2049
   212
AudioBootStrap BEOSAUDIO_bootstrap = {
icculus@2049
   213
    "baudio", "BeOS BSoundPlayer", BEOSAUDIO_Init, 0
icculus@2049
   214
};
slouken@1895
   215
slouken@6044
   216
#endif /* SDL_AUDIO_DRIVER_BEOSAUDIO */
slouken@6044
   217
slouken@1895
   218
/* vi: set ts=4 sw=4 expandtab: */