1 /*
2 Copyright (C) 1997-2020 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 #include "SDL.h"
13
14 #include <stdio.h> /* for fflush() and stdout */
15
16 #ifdef __EMSCRIPTEN__
17 #include <emscripten/emscripten.h>
18 #endif
19
20 static SDL_AudioSpec spec;
21 static Uint8 *sound = NULL; /* Pointer to wave data */
22 static Uint32 soundlen = 0; /* Length of wave data */
23
24 typedef struct
25 {
26 SDL_AudioDeviceID dev;
27 int soundpos;
28 SDL_atomic_t done;
29 } callback_data;
30
31 callback_data cbd[64];
32
33 void SDLCALL
play_through_once(void * arg,Uint8 * stream,int len)34 play_through_once(void *arg, Uint8 * stream, int len)
35 {
36 callback_data *cbd = (callback_data *) arg;
37 Uint8 *waveptr = sound + cbd->soundpos;
38 int waveleft = soundlen - cbd->soundpos;
39 int cpy = len;
40 if (cpy > waveleft)
41 cpy = waveleft;
42
43 SDL_memcpy(stream, waveptr, cpy);
44 len -= cpy;
45 cbd->soundpos += cpy;
46 if (len > 0) {
47 stream += cpy;
48 SDL_memset(stream, spec.silence, len);
49 SDL_AtomicSet(&cbd->done, 1);
50 }
51 }
52
53 void
loop()54 loop()
55 {
56 if (SDL_AtomicGet(&cbd[0].done)) {
57 #ifdef __EMSCRIPTEN__
58 emscripten_cancel_main_loop();
59 #endif
60 SDL_PauseAudioDevice(cbd[0].dev, 1);
61 SDL_CloseAudioDevice(cbd[0].dev);
62 SDL_FreeWAV(sound);
63 SDL_Quit();
64 }
65 }
66
67 static void
test_multi_audio(int devcount)68 test_multi_audio(int devcount)
69 {
70 int keep_going = 1;
71 int i;
72
73 #ifdef __ANDROID__
74 SDL_Event event;
75
76 /* Create a Window to get fully initialized event processing for testing pause on Android. */
77 SDL_CreateWindow("testmultiaudio", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 240, 0);
78 #endif
79
80 if (devcount > 64) {
81 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Too many devices (%d), clamping to 64...\n",
82 devcount);
83 devcount = 64;
84 }
85
86 spec.callback = play_through_once;
87
88 for (i = 0; i < devcount; i++) {
89 const char *devname = SDL_GetAudioDeviceName(i, 0);
90 SDL_Log("playing on device #%d: ('%s')...", i, devname);
91 fflush(stdout);
92
93 SDL_memset(&cbd[0], '\0', sizeof(callback_data));
94 spec.userdata = &cbd[0];
95 cbd[0].dev = SDL_OpenAudioDevice(devname, 0, &spec, NULL, 0);
96 if (cbd[0].dev == 0) {
97 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Open device failed: %s\n", SDL_GetError());
98 } else {
99 SDL_PauseAudioDevice(cbd[0].dev, 0);
100 #ifdef __EMSCRIPTEN__
101 emscripten_set_main_loop(loop, 0, 1);
102 #else
103 while (!SDL_AtomicGet(&cbd[0].done)) {
104 #ifdef __ANDROID__
105 /* Empty queue, some application events would prevent pause. */
106 while (SDL_PollEvent(&event)){}
107 #endif
108 SDL_Delay(100);
109 }
110 SDL_PauseAudioDevice(cbd[0].dev, 1);
111 #endif
112 SDL_Log("done.\n");
113 SDL_CloseAudioDevice(cbd[0].dev);
114 }
115 }
116
117 SDL_memset(cbd, '\0', sizeof(cbd));
118
119 SDL_Log("playing on all devices...\n");
120 for (i = 0; i < devcount; i++) {
121 const char *devname = SDL_GetAudioDeviceName(i, 0);
122 spec.userdata = &cbd[i];
123 cbd[i].dev = SDL_OpenAudioDevice(devname, 0, &spec, NULL, 0);
124 if (cbd[i].dev == 0) {
125 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Open device %d failed: %s\n", i, SDL_GetError());
126 }
127 }
128
129 for (i = 0; i < devcount; i++) {
130 if (cbd[i].dev) {
131 SDL_PauseAudioDevice(cbd[i].dev, 0);
132 }
133 }
134
135 while (keep_going) {
136 keep_going = 0;
137 for (i = 0; i < devcount; i++) {
138 if ((cbd[i].dev) && (!SDL_AtomicGet(&cbd[i].done))) {
139 keep_going = 1;
140 }
141 }
142 #ifdef __ANDROID__
143 /* Empty queue, some application events would prevent pause. */
144 while (SDL_PollEvent(&event)){}
145 #endif
146
147 SDL_Delay(100);
148 }
149
150 #ifndef __EMSCRIPTEN__
151 for (i = 0; i < devcount; i++) {
152 if (cbd[i].dev) {
153 SDL_PauseAudioDevice(cbd[i].dev, 1);
154 SDL_CloseAudioDevice(cbd[i].dev);
155 }
156 }
157
158 SDL_Log("All done!\n");
159 #endif
160 }
161
162
163 int
main(int argc,char ** argv)164 main(int argc, char **argv)
165 {
166 int devcount = 0;
167
168 /* Enable standard application logging */
169 SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
170
171 /* Load the SDL library */
172 if (SDL_Init(SDL_INIT_AUDIO) < 0) {
173 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError());
174 return (1);
175 }
176
177 SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
178
179 devcount = SDL_GetNumAudioDevices(0);
180 if (devcount < 1) {
181 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Don't see any specific audio devices!\n");
182 } else {
183 if (argv[1] == NULL) {
184 argv[1] = "sample.wav";
185 }
186
187 /* Load the wave file into memory */
188 if (SDL_LoadWAV(argv[1], &spec, &sound, &soundlen) == NULL) {
189 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", argv[1],
190 SDL_GetError());
191 } else {
192 test_multi_audio(devcount);
193 SDL_FreeWAV(sound);
194 }
195 }
196
197 SDL_Quit();
198 return 0;
199 }
200