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