test/testaudiohotplug.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 07 Jul 2019 09:10:56 -0700
changeset 12928 3c4a4b1077cd
parent 12503 806492103856
permissions -rw-r--r--
Fixed bug 4710 - audio/alsa: avoid configuring hardware parameters with only a single period

Anthony Pesch

The previous code first configured the period size using snd_pcm_hw_par-
ams_set_period_size_near. Then, it further narrowed the configuration
space by calling snd_pcm_hw_params_set_buffer_size_near using a buffer
size of 2 times the _requested_ period size in order to try and get a
configuration with only 2 periods. If the configured period size was
larger than the requested size, the second call could inadvertently
narrow the configuration space to contain only a single period.

Rather than fixing the call to snd_pcm_hw_params_set_buffer_size_near
to use a size of 2 times the configured period size, the code has been
changed to use snd_pcm_hw_params_set_periods_min in order to more
clearly explain the intent.
icculus@9393
     1
/*
slouken@12503
     2
  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
icculus@9393
     3
icculus@9393
     4
  This software is provided 'as-is', without any express or implied
icculus@9393
     5
  warranty.  In no event will the authors be held liable for any damages
icculus@9393
     6
  arising from the use of this software.
icculus@9393
     7
icculus@9393
     8
  Permission is granted to anyone to use this software for any purpose,
icculus@9393
     9
  including commercial applications, and to alter it and redistribute it
icculus@9393
    10
  freely.
icculus@9393
    11
*/
icculus@9393
    12
icculus@9393
    13
/* Program to test hotplugging of audio devices */
icculus@9393
    14
icculus@9393
    15
#include "SDL_config.h"
icculus@9393
    16
icculus@9393
    17
#include <stdio.h>
icculus@9393
    18
#include <stdlib.h>
icculus@9393
    19
icculus@9393
    20
#if HAVE_SIGNAL_H
icculus@9393
    21
#include <signal.h>
icculus@9393
    22
#endif
icculus@9393
    23
icculus@9393
    24
#ifdef __EMSCRIPTEN__
icculus@9393
    25
#include <emscripten/emscripten.h>
icculus@9393
    26
#endif
icculus@9393
    27
icculus@9393
    28
#include "SDL.h"
icculus@9393
    29
icculus@9393
    30
static SDL_AudioSpec spec;
icculus@9393
    31
static Uint8 *sound = NULL;     /* Pointer to wave data */
icculus@9393
    32
static Uint32 soundlen = 0;     /* Length of wave data */
icculus@9393
    33
icculus@9393
    34
static int posindex = 0;
icculus@9393
    35
static Uint32 positions[64];
icculus@9393
    36
icculus@9393
    37
/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
icculus@9393
    38
static void
icculus@9393
    39
quit(int rc)
icculus@9393
    40
{
icculus@9393
    41
    SDL_Quit();
icculus@9393
    42
    exit(rc);
icculus@9393
    43
}
icculus@9393
    44
icculus@9393
    45
void SDLCALL
icculus@9393
    46
fillerup(void *_pos, Uint8 * stream, int len)
icculus@9393
    47
{
icculus@9393
    48
    Uint32 pos = *((Uint32 *) _pos);
icculus@9393
    49
    Uint8 *waveptr;
icculus@9393
    50
    int waveleft;
icculus@9393
    51
icculus@9393
    52
    /* Set up the pointers */
icculus@9393
    53
    waveptr = sound + pos;
icculus@9393
    54
    waveleft = soundlen - pos;
icculus@9393
    55
icculus@9393
    56
    /* Go! */
icculus@9393
    57
    while (waveleft <= len) {
icculus@9393
    58
        SDL_memcpy(stream, waveptr, waveleft);
icculus@9393
    59
        stream += waveleft;
icculus@9393
    60
        len -= waveleft;
icculus@9393
    61
        waveptr = sound;
icculus@9393
    62
        waveleft = soundlen;
icculus@9393
    63
        pos = 0;
icculus@9393
    64
    }
icculus@9393
    65
    SDL_memcpy(stream, waveptr, len);
icculus@9393
    66
    pos += len;
icculus@9393
    67
    *((Uint32 *) _pos) = pos;
icculus@9393
    68
}
icculus@9393
    69
icculus@9393
    70
static int done = 0;
icculus@9393
    71
void
icculus@9393
    72
poked(int sig)
icculus@9393
    73
{
icculus@9393
    74
    done = 1;
icculus@9393
    75
}
icculus@9393
    76
slouken@10413
    77
static const char*
slouken@10413
    78
devtypestr(int iscapture)
slouken@10413
    79
{
slouken@10413
    80
    return iscapture ? "capture" : "output";
slouken@10413
    81
}
slouken@10413
    82
icculus@9393
    83
static void
icculus@9393
    84
iteration()
icculus@9393
    85
{
icculus@9393
    86
    SDL_Event e;
icculus@9393
    87
    SDL_AudioDeviceID dev;
icculus@9393
    88
    while (SDL_PollEvent(&e)) {
icculus@9393
    89
        if (e.type == SDL_QUIT) {
icculus@9393
    90
            done = 1;
slouken@10413
    91
        } else if (e.type == SDL_KEYUP) {
slouken@10413
    92
            if (e.key.keysym.sym == SDLK_ESCAPE)
slouken@10413
    93
                done = 1;
icculus@9393
    94
        } else if (e.type == SDL_AUDIODEVICEADDED) {
slouken@10413
    95
            int index = e.adevice.which;
slouken@10413
    96
            int iscapture = e.adevice.iscapture;
slouken@10413
    97
            const char *name = SDL_GetAudioDeviceName(index, iscapture);
slouken@10413
    98
            if (name != NULL)
slouken@10413
    99
                SDL_Log("New %s audio device at index %u: %s\n", devtypestr(iscapture), (unsigned int) index, name);
slouken@10413
   100
            else {
slouken@10413
   101
                SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Got new %s device at index %u, but failed to get the name: %s\n",
slouken@10413
   102
                    devtypestr(iscapture), (unsigned int) index, SDL_GetError());
slouken@10413
   103
                continue;
slouken@10413
   104
            }
slouken@10413
   105
            if (!iscapture) {
icculus@9393
   106
                positions[posindex] = 0;
icculus@9393
   107
                spec.userdata = &positions[posindex++];
icculus@9393
   108
                spec.callback = fillerup;
icculus@9393
   109
                dev = SDL_OpenAudioDevice(name, 0, &spec, NULL, 0);
icculus@9393
   110
                if (!dev) {
icculus@9393
   111
                    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open '%s': %s\n", name, SDL_GetError());
icculus@9393
   112
                } else {
icculus@9393
   113
                    SDL_Log("Opened '%s' as %u\n", name, (unsigned int) dev);
icculus@9393
   114
                    SDL_PauseAudioDevice(dev, 0);
icculus@9393
   115
                }
icculus@9393
   116
            }
icculus@9393
   117
        } else if (e.type == SDL_AUDIODEVICEREMOVED) {
icculus@9393
   118
            dev = (SDL_AudioDeviceID) e.adevice.which;
slouken@10413
   119
            SDL_Log("%s device %u removed.\n", devtypestr(e.adevice.iscapture), (unsigned int) dev);
icculus@9393
   120
            SDL_CloseAudioDevice(dev);
icculus@9393
   121
        }
icculus@9393
   122
    }
icculus@9393
   123
}
icculus@9393
   124
icculus@9393
   125
#ifdef __EMSCRIPTEN__
icculus@9393
   126
void
icculus@9393
   127
loop()
icculus@9393
   128
{
icculus@9393
   129
    if(done)
icculus@9393
   130
        emscripten_cancel_main_loop();
icculus@9393
   131
    else
icculus@9393
   132
        iteration();
icculus@9393
   133
}
icculus@9393
   134
#endif
icculus@9393
   135
icculus@9393
   136
int
icculus@9393
   137
main(int argc, char *argv[])
icculus@9393
   138
{
icculus@9393
   139
    int i;
icculus@9393
   140
    char filename[4096];
icculus@9393
   141
philipp@9922
   142
    /* Enable standard application logging */
philipp@9922
   143
    SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
icculus@9393
   144
icculus@9393
   145
    /* Load the SDL library */
icculus@9393
   146
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) {
icculus@9393
   147
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
icculus@9393
   148
        return (1);
icculus@9393
   149
    }
icculus@9393
   150
icculus@9402
   151
    /* Some targets (Mac CoreAudio) need an event queue for audio hotplug, so make and immediately hide a window. */
icculus@9402
   152
    SDL_MinimizeWindow(SDL_CreateWindow("testaudiohotplug", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0));
icculus@9393
   153
icculus@9393
   154
    if (argc > 1) {
icculus@9393
   155
        SDL_strlcpy(filename, argv[1], sizeof(filename));
icculus@9393
   156
    } else {
icculus@9393
   157
        SDL_strlcpy(filename, "sample.wav", sizeof(filename));
icculus@9393
   158
    }
icculus@9393
   159
    /* Load the wave file into memory */
icculus@9393
   160
    if (SDL_LoadWAV(filename, &spec, &sound, &soundlen) == NULL) {
icculus@9393
   161
        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError());
icculus@9393
   162
        quit(1);
icculus@9393
   163
    }
icculus@9393
   164
icculus@9393
   165
#if HAVE_SIGNAL_H
icculus@9393
   166
    /* Set the signals */
icculus@9393
   167
#ifdef SIGHUP
icculus@9393
   168
    signal(SIGHUP, poked);
icculus@9393
   169
#endif
icculus@9393
   170
    signal(SIGINT, poked);
icculus@9393
   171
#ifdef SIGQUIT
icculus@9393
   172
    signal(SIGQUIT, poked);
icculus@9393
   173
#endif
icculus@9393
   174
    signal(SIGTERM, poked);
icculus@9393
   175
#endif /* HAVE_SIGNAL_H */
icculus@9393
   176
icculus@9393
   177
    /* Show the list of available drivers */
icculus@9393
   178
    SDL_Log("Available audio drivers:");
icculus@9393
   179
    for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
philipp@9922
   180
        SDL_Log("%i: %s", i, SDL_GetAudioDriver(i));
icculus@9393
   181
    }
icculus@9393
   182
slouken@10413
   183
    SDL_Log("Select a driver with the SDL_AUDIODRIVER environment variable.\n");
icculus@9393
   184
    SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
icculus@9393
   185
icculus@9393
   186
#ifdef __EMSCRIPTEN__
icculus@9393
   187
    emscripten_set_main_loop(loop, 0, 1);
icculus@9393
   188
#else
icculus@9393
   189
    while (!done) {
icculus@9393
   190
        SDL_Delay(100);
icculus@9393
   191
        iteration();
icculus@9393
   192
    }
icculus@9393
   193
#endif
icculus@9393
   194
icculus@9393
   195
    /* Clean up on signal */
slouken@10413
   196
    /* Quit audio first, then free WAV. This prevents access violations in the audio threads. */
slouken@10413
   197
    SDL_QuitSubSystem(SDL_INIT_AUDIO);
philipp@9610
   198
    SDL_FreeWAV(sound);
icculus@9393
   199
    SDL_Quit();
icculus@9393
   200
    return (0);
icculus@9393
   201
}
icculus@9393
   202
icculus@9393
   203
/* vi: set ts=4 sw=4 expandtab: */