src/audio/nacl/SDL_naclaudio.c
author Ryan C. Gordon
Tue, 24 Jan 2017 16:18:25 -0500
changeset 10850 c9dc0068b0e7
parent 10765 61312c8c59fe
child 10997 b6315b6bc32f
permissions -rw-r--r--
configure: report libsamplerate support status.
gabomdq@8833
     1
/*
gabomdq@8833
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
gabomdq@8833
     4
gabomdq@8833
     5
  This software is provided 'as-is', without any express or implied
gabomdq@8833
     6
  warranty.  In no event will the authors be held liable for any damages
gabomdq@8833
     7
  arising from the use of this software.
gabomdq@8833
     8
gabomdq@8833
     9
  Permission is granted to anyone to use this software for any purpose,
gabomdq@8833
    10
  including commercial applications, and to alter it and redistribute it
gabomdq@8833
    11
  freely, subject to the following restrictions:
gabomdq@8833
    12
gabomdq@8833
    13
  1. The origin of this software must not be misrepresented; you must not
gabomdq@8833
    14
     claim that you wrote the original software. If you use this software
gabomdq@8833
    15
     in a product, an acknowledgment in the product documentation would be
gabomdq@8833
    16
     appreciated but is not required.
gabomdq@8833
    17
  2. Altered source versions must be plainly marked as such, and must not be
gabomdq@8833
    18
     misrepresented as being the original software.
gabomdq@8833
    19
  3. This notice may not be removed or altered from any source distribution.
gabomdq@8833
    20
*/
gabomdq@8833
    21
gabomdq@8833
    22
#include "../../SDL_internal.h"
philipp@9332
    23
philipp@9332
    24
#if SDL_AUDIO_DRIVER_NACL
philipp@9332
    25
gabomdq@8833
    26
#include "SDL_naclaudio.h"
gabomdq@8833
    27
gabomdq@8833
    28
#include "SDL_audio.h"
gabomdq@8833
    29
#include "SDL_mutex.h"
gabomdq@8833
    30
#include "../SDL_audio_c.h"
gabomdq@8833
    31
#include "../SDL_audiodev_c.h"
gabomdq@8833
    32
gabomdq@8833
    33
#include "ppapi/c/pp_errors.h"
gabomdq@8833
    34
#include "ppapi/c/pp_instance.h"
gabomdq@8833
    35
#include "ppapi_simple/ps.h"
gabomdq@8833
    36
#include "ppapi_simple/ps_interface.h"
gabomdq@8833
    37
#include "ppapi_simple/ps_event.h"
gabomdq@8833
    38
gabomdq@8833
    39
/* The tag name used by NACL audio */
icculus@10281
    40
#define NACLAUDIO_DRIVER_NAME         "nacl"
gabomdq@8833
    41
gabomdq@8833
    42
#define SAMPLE_FRAME_COUNT 4096
gabomdq@8833
    43
gabomdq@8833
    44
/* Audio driver functions */
gabomdq@8833
    45
static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelta latency, void* data);
gabomdq@8833
    46
gabomdq@8833
    47
/* FIXME: Make use of latency if needed */
icculus@10763
    48
static void nacl_audio_callback(void* stream, uint32_t buffer_size, PP_TimeDelta latency, void* data) {
icculus@10763
    49
    const int len = (int) buffer_size;
gabomdq@8833
    50
    SDL_AudioDevice* _this = (SDL_AudioDevice*) data;
icculus@10763
    51
    SDL_AudioCallback callback = _this->spec.callback;
gabomdq@8833
    52
    
icculus@10234
    53
    SDL_LockMutex(private->mutex);  /* !!! FIXME: is this mutex necessary? */
gabomdq@8851
    54
icculus@10763
    55
    /* Only do something if audio is enabled */
icculus@10763
    56
    if (!SDL_AtomicGet(&_this->enabled) || SDL_AtomicGet(&_this->paused)) {
icculus@10763
    57
        if (_this->stream) {
icculus@10763
    58
            SDL_AudioStreamClear(_this->stream);
gabomdq@8851
    59
        }
icculus@10763
    60
        SDL_memset(stream, _this->spec.silence, len);
icculus@10763
    61
        return;
gabomdq@8851
    62
    }
icculus@10763
    63
icculus@10763
    64
    SDL_assert(_this->spec.size == len);
icculus@10763
    65
icculus@10763
    66
    if (_this->stream == NULL) {  /* no conversion necessary. */
icculus@10763
    67
        SDL_LockMutex(_this->mixer_lock);
icculus@10763
    68
        callback(_this->spec.userdata, stream, len);
icculus@10763
    69
        SDL_UnlockMutex(_this->mixer_lock);
icculus@10763
    70
    } else {  /* streaming/converting */
icculus@10763
    71
        const int stream_len = _this->callbackspec.size;
icculus@10763
    72
        while (SDL_AudioStreamAvailable(_this->stream) < len) {
icculus@10765
    73
            callback(_this->spec.userdata, _this->work_buffer, stream_len);
icculus@10765
    74
            if (SDL_AudioStreamPut(_this->stream, _this->work_buffer, stream_len) == -1) {
icculus@10763
    75
                SDL_AudioStreamClear(_this->stream);
icculus@10763
    76
                SDL_AtomicSet(&_this->enabled, 0);
icculus@10763
    77
                break;
icculus@10763
    78
            }
icculus@10763
    79
        }
icculus@10763
    80
icculus@10764
    81
        const int got = SDL_AudioStreamGet(_this->stream, stream, len);
icculus@10763
    82
        SDL_assert((got < 0) || (got == len));
icculus@10763
    83
        if (got != len) {
icculus@10763
    84
            SDL_memset(stream, _this->spec.silence, len);
icculus@10763
    85
        }
icculus@10763
    86
    }
icculus@10763
    87
icculus@10234
    88
    SDL_UnlockMutex(private->mutex);
gabomdq@8833
    89
}
gabomdq@8833
    90
icculus@10281
    91
static void NACLAUDIO_CloseDevice(SDL_AudioDevice *device) {
gabomdq@8833
    92
    const PPB_Core *core = PSInterfaceCore();
gabomdq@8833
    93
    const PPB_Audio *ppb_audio = PSInterfaceAudio();
gabomdq@8833
    94
    SDL_PrivateAudioData *hidden = (SDL_PrivateAudioData *) device->hidden;
gabomdq@8833
    95
    
gabomdq@8833
    96
    ppb_audio->StopPlayback(hidden->audio);
gabomdq@8833
    97
    SDL_DestroyMutex(hidden->mutex);
gabomdq@8833
    98
    core->ReleaseResource(hidden->audio);
gabomdq@8833
    99
}
gabomdq@8833
   100
gabomdq@8833
   101
static int
icculus@10281
   102
NACLAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture) {
gabomdq@8833
   103
    PP_Instance instance = PSGetInstanceId();
gabomdq@8833
   104
    const PPB_Audio *ppb_audio = PSInterfaceAudio();
gabomdq@8833
   105
    const PPB_AudioConfig *ppb_audiocfg = PSInterfaceAudioConfig();
gabomdq@8833
   106
    
gabomdq@8833
   107
    private = (SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *private));
gabomdq@8833
   108
    if (private == NULL) {
gabomdq@8833
   109
        SDL_OutOfMemory();
gabomdq@8833
   110
        return 0;
gabomdq@8833
   111
    }
gabomdq@8833
   112
    
gabomdq@8833
   113
    private->mutex = SDL_CreateMutex();
gabomdq@8833
   114
    _this->spec.freq = 44100;
gabomdq@8833
   115
    _this->spec.format = AUDIO_S16LSB;
gabomdq@8833
   116
    _this->spec.channels = 2;
gabomdq@8833
   117
    _this->spec.samples = ppb_audiocfg->RecommendSampleFrameCount(
gabomdq@8833
   118
        instance, 
gabomdq@8833
   119
        PP_AUDIOSAMPLERATE_44100, 
gabomdq@8833
   120
        SAMPLE_FRAME_COUNT);
gabomdq@8833
   121
    
gabomdq@8851
   122
    /* Calculate the final parameters for this audio specification */
gabomdq@8851
   123
    SDL_CalculateAudioSpec(&_this->spec);
gabomdq@8851
   124
    
gabomdq@8833
   125
    private->audio = ppb_audio->Create(
gabomdq@8833
   126
        instance,
gabomdq@8833
   127
        ppb_audiocfg->CreateStereo16Bit(instance, PP_AUDIOSAMPLERATE_44100, _this->spec.samples),
gabomdq@8833
   128
        nacl_audio_callback, 
gabomdq@8833
   129
        _this);
gabomdq@8833
   130
    
gabomdq@8833
   131
    /* Start audio playback while we are still on the main thread. */
gabomdq@8833
   132
    ppb_audio->StartPlayback(private->audio);
gabomdq@8833
   133
    
gabomdq@8833
   134
    return 1;
gabomdq@8833
   135
}
gabomdq@8833
   136
gabomdq@8833
   137
static int
icculus@10281
   138
NACLAUDIO_Init(SDL_AudioDriverImpl * impl)
gabomdq@8833
   139
{
gabomdq@8833
   140
    if (PSGetInstanceId() == 0) {
gabomdq@8833
   141
        return 0;
gabomdq@8833
   142
    }
gabomdq@8833
   143
    
gabomdq@8833
   144
    /* Set the function pointers */
icculus@10281
   145
    impl->OpenDevice = NACLAUDIO_OpenDevice;
icculus@10281
   146
    impl->CloseDevice = NACLAUDIO_CloseDevice;
gabomdq@8833
   147
    impl->OnlyHasDefaultOutputDevice = 1;
gabomdq@8833
   148
    impl->ProvidesOwnCallbackThread = 1;
gabomdq@8833
   149
    /*
icculus@10281
   150
     *    impl->WaitDevice = NACLAUDIO_WaitDevice;
icculus@10281
   151
     *    impl->GetDeviceBuf = NACLAUDIO_GetDeviceBuf;
icculus@10281
   152
     *    impl->PlayDevice = NACLAUDIO_PlayDevice;
icculus@10281
   153
     *    impl->Deinitialize = NACLAUDIO_Deinitialize;
gabomdq@8833
   154
     */
gabomdq@8833
   155
    
gabomdq@8833
   156
    return 1;
gabomdq@8833
   157
}
gabomdq@8833
   158
icculus@10281
   159
AudioBootStrap NACLAUDIO_bootstrap = {
icculus@10281
   160
    NACLAUDIO_DRIVER_NAME, "SDL NaCl Audio Driver",
icculus@10281
   161
    NACLAUDIO_Init, 0
gabomdq@8833
   162
};
philipp@9332
   163
philipp@9332
   164
#endif /* SDL_AUDIO_DRIVER_NACL */
philipp@9332
   165
philipp@9332
   166
/* vi: set ts=4 sw=4 expandtab: */