ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/audio_oss_esd.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/audio_oss_esd.cpp (file contents):
Revision 1.5 by cebix, 2000-07-13T13:47:06Z vs.
Revision 1.17 by gbeauche, 2004-01-04T16:35:32Z

# Line 1 | Line 1
1   /*
2   *  audio_oss_esd.cpp - Audio support, implementation for OSS and ESD (Linux and FreeBSD)
3   *
4 < *  Basilisk II (C) 1997-2000 Christian Bauer
4 > *  Basilisk II (C) 1997-2002 Christian Bauer
5   *
6   *  This program is free software; you can redistribute it and/or modify
7   *  it under the terms of the GNU General Public License as published by
# Line 49 | Line 49
49   #include "debug.h"
50  
51  
52 < // Supported sample rates, sizes and channels (defaults)
53 < int audio_num_sample_rates = 1;
54 < uint32 audio_sample_rates[] = {44100 << 16};
55 < int audio_num_sample_sizes = 1;
56 < uint16 audio_sample_sizes[] = {16};
57 < int audio_num_channel_counts = 1;
58 < uint16 audio_channel_counts[] = {2};
59 <
60 < // Constants
61 < #define DSP_NAME "/dev/dsp"
52 > // The currently selected audio parameters (indices in audio_sample_rates[] etc. vectors)
53 > static int audio_sample_rate_index = 0;
54 > static int audio_sample_size_index = 0;
55 > static int audio_channel_count_index = 0;
56  
57   // Global variables
58 < static int audio_fd = -1;                                                       // fd of /dev/dsp or ESD
59 < static int mixer_fd = -1;                                                       // fd of /dev/mixer
58 > static bool is_dsp_audio = false;                                       // Flag: is DSP audio
59 > static int audio_fd = -1;                                                       // fd of dsp or ESD
60 > static int mixer_fd = -1;                                                       // fd of mixer
61   static sem_t audio_irq_done_sem;                                        // Signal from interrupt to streaming thread: data block read
62   static bool sem_inited = false;                                         // Flag: audio_irq_done_sem initialized
63   static int sound_buffer_size;                                           // Size of sound buffer in bytes
# Line 84 | Line 79 | static void *stream_func(void *arg);
79   // Set AudioStatus to reflect current audio stream format
80   static void set_audio_status_format(void)
81   {
82 <        AudioStatus.sample_rate = audio_sample_rates[0];
83 <        AudioStatus.sample_size = audio_sample_sizes[0];
84 <        AudioStatus.channels = audio_channel_counts[0];
82 >        AudioStatus.sample_rate = audio_sample_rates[audio_sample_rate_index];
83 >        AudioStatus.sample_size = audio_sample_sizes[audio_sample_size_index];
84 >        AudioStatus.channels = audio_channel_counts[audio_channel_count_index];
85   }
86  
87 < // Init using /dev/dsp, returns false on error
88 < bool audio_init_dsp(void)
87 > // Init using the dsp device, returns false on error
88 > static bool open_dsp(void)
89   {
90 <        printf("Using " DSP_NAME " audio output\n");
91 <
92 <        // Get supported sample formats
93 <        unsigned long format;
94 <        ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format);
100 <        if ((format & (AFMT_U8 | AFMT_S16_BE | AFMT_S16_LE)) == 0) {
101 <                WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
102 <                close(audio_fd);
103 <                audio_fd = -1;
90 >        // Open the device
91 >        const char *dsp = PrefsFindString("dsp");
92 >        audio_fd = open(dsp, O_WRONLY);
93 >        if (audio_fd < 0) {
94 >                fprintf(stderr, "WARNING: Cannot open %s (%s)\n", dsp, strerror(errno));
95                  return false;
96          }
97 <        if (format & (AFMT_S16_BE | AFMT_S16_LE)) {
98 <                audio_sample_sizes[0] = 16;
99 <                silence_byte = 0;
100 <        } else {
101 <                audio_sample_sizes[0] = 8;
102 <                silence_byte = 0x80;
97 >
98 >        printf("Using %s audio output\n", dsp);
99 >        is_dsp_audio = true;
100 >
101 >        // Get supported sample formats
102 >        if (audio_sample_sizes.empty()) {
103 >                unsigned long format;
104 >                ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &format);
105 >                if (format & AFMT_U8)
106 >                        audio_sample_sizes.push_back(8);
107 >                if (format & (AFMT_S16_BE | AFMT_S16_LE))
108 >                        audio_sample_sizes.push_back(16);
109 >
110 >                int stereo = 0;
111 >                if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == 0 && stereo == 0)
112 >                        audio_channel_counts.push_back(1);
113 >                stereo = 1;
114 >                if (ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo) == 0 && stereo == 1)
115 >                        audio_channel_counts.push_back(2);
116 >
117 >                if (audio_sample_sizes.empty() || audio_channel_counts.empty()) {
118 >                        WarningAlert(GetString(STR_AUDIO_FORMAT_WARN));
119 >                        close(audio_fd);
120 >                        audio_fd = -1;
121 >                        return false;
122 >                }
123 >
124 >                audio_sample_rates.push_back(11025 << 16);
125 >                audio_sample_rates.push_back(22050 << 16);
126 >                int rate = 44100;
127 >                ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate);
128 >                if (rate > 22050)
129 >                        audio_sample_rates.push_back(rate << 16);
130 >
131 >                // Default to highest supported values
132 >                audio_sample_rate_index = audio_sample_rates.size() - 1;
133 >                audio_sample_size_index = audio_sample_sizes.size() - 1;
134 >                audio_channel_count_index = audio_channel_counts.size() - 1;
135          }
113        if (!(format & AFMT_S16_BE))
114                little_endian = true;
136  
137          // Set DSP parameters
138 <        format = audio_sample_sizes[0] == 8 ? AFMT_U8 : (little_endian ? AFMT_S16_LE : AFMT_S16_BE);
138 >        unsigned long format;
139 >        if (audio_sample_sizes[audio_sample_size_index] == 8) {
140 >                format = AFMT_U8;
141 >                little_endian = false;
142 >                silence_byte = 0x80;
143 >        } else {
144 >                unsigned long sup_format;
145 >                ioctl(audio_fd, SNDCTL_DSP_GETFMTS, &sup_format);
146 >                if (sup_format & AFMT_S16_BE) {
147 >                        little_endian = false;
148 >                        format = AFMT_S16_BE;
149 >                } else {
150 >                        little_endian = true;
151 >                        format = AFMT_S16_LE;
152 >                }
153 >                silence_byte = 0;
154 >        }
155          ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format);
156          int frag = 0x0004000c;          // Block size: 4096 frames
157          ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &frag);
158 <        int stereo = (audio_channel_counts[0] == 2);
158 >        int stereo = (audio_channel_counts[audio_channel_count_index] == 2);
159          ioctl(audio_fd, SNDCTL_DSP_STEREO, &stereo);
160 <        int rate = audio_sample_rates[0] >> 16;
160 >        int rate = audio_sample_rates[audio_sample_rate_index] >> 16;
161          ioctl(audio_fd, SNDCTL_DSP_SPEED, &rate);
125        audio_sample_rates[0] = rate << 16;
126
127        // Set AudioStatus again because we now know more about the sound
128        // system's capabilities
129        set_audio_status_format();
162  
163          // Get sound buffer size
164          ioctl(audio_fd, SNDCTL_DSP_GETBLKSIZE, &audio_frames_per_block);
165          D(bug("DSP_GETBLKSIZE %d\n", audio_frames_per_block));
134        sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
166          return true;
167   }
168  
169   // Init using ESD, returns false on error
170 < bool audio_init_esd(void)
170 > static bool open_esd(void)
171   {
172   #ifdef ENABLE_ESD
173 <        printf("Using ESD audio output\n");
143 <
144 <        // ESD audio format
173 >        int rate;
174          esd_format_t format = ESD_STREAM | ESD_PLAY;
175 <        if (AudioStatus.sample_size == 8)
176 <                format |= ESD_BITS8;
177 <        else
178 <                format |= ESD_BITS16;
179 <        if (AudioStatus.channels == 1)
180 <                format |= ESD_MONO;
181 <        else
182 <                format |= ESD_STEREO;
175 >
176 >        if (audio_sample_sizes.empty()) {
177 >
178 >                // Default values
179 >                rate = 44100;
180 >                format |= (ESD_BITS16 | ESD_STEREO);
181 >
182 >        } else {
183 >
184 >                rate = audio_sample_rates[audio_sample_rate_index] >> 16;
185 >                if (audio_sample_sizes[audio_sample_size_index] == 8)
186 >                        format |= ESD_BITS8;
187 >                else
188 >                        format |= ESD_BITS16;
189 >                if (audio_channel_counts[audio_channel_count_index] == 1)
190 >                        format |= ESD_MONO;
191 >                else
192 >                        format |= ESD_STEREO;
193 >        }
194  
195   #if WORDS_BIGENDIAN
196          little_endian = false;
# Line 160 | Line 200 | bool audio_init_esd(void)
200          silence_byte = 0;       // Is this correct for 8-bit mode?
201  
202          // Open connection to ESD server
203 <        audio_fd = esd_play_stream(format, AudioStatus.sample_rate >> 16, NULL, NULL);
203 >        audio_fd = esd_play_stream(format, rate, NULL, NULL);
204          if (audio_fd < 0) {
205 <                char str[256];
166 <                sprintf(str, GetString(STR_NO_ESD_WARN), strerror(errno));
167 <                WarningAlert(str);
205 >                fprintf(stderr, "WARNING: Cannot open ESD connection\n");
206                  return false;
207          }
208  
209 +        printf("Using ESD audio output\n");
210 +
211 +        // ESD supports a variety of twisted little audio formats, all different
212 +        if (audio_sample_sizes.empty()) {
213 +
214 +                // The reason we do this here is that we don't want to add sample
215 +                // rates etc. unless the ESD server connection could be opened
216 +                // (if ESD fails, dsp might be tried next)
217 +                audio_sample_rates.push_back(11025 << 16);
218 +                audio_sample_rates.push_back(22050 << 16);
219 +                audio_sample_rates.push_back(44100 << 16);
220 +                audio_sample_sizes.push_back(8);
221 +                audio_sample_sizes.push_back(16);
222 +                audio_channel_counts.push_back(1);
223 +                audio_channel_counts.push_back(2);
224 +
225 +                // Default to highest supported values
226 +                audio_sample_rate_index = audio_sample_rates.size() - 1;
227 +                audio_sample_size_index = audio_sample_sizes.size() - 1;
228 +                audio_channel_count_index = audio_channel_counts.size() - 1;
229 +        }
230 +
231          // Sound buffer size = 4096 frames
232          audio_frames_per_block = 4096;
173        sound_buffer_size = (AudioStatus.sample_size >> 3) * AudioStatus.channels * audio_frames_per_block;
233          return true;
234   #else
235 <        ErrorAlert("Basilisk II has been compiled with ESD support disabled.");
235 >        // ESD is not enabled, shut up the compiler
236          return false;
237   #endif
238   }
239  
240 < void AudioInit(void)
240 > static bool open_audio(void)
241   {
242 <        char str[256];
242 > #ifdef ENABLE_ESD
243 >        // If ESPEAKER is set, the user probably wants to use ESD, so try that first
244 >        if (getenv("ESPEAKER"))
245 >                if (open_esd())
246 >                        goto dev_opened;
247 > #endif
248 >
249 >        // Try to open dsp
250 >        if (open_dsp())
251 >                goto dev_opened;
252 >
253 > #ifdef ENABLE_ESD
254 >        // Hm, dsp failed so we try ESD again if ESPEAKER wasn't set
255 >        if (!getenv("ESPEAKER"))
256 >                if (open_esd())
257 >                        goto dev_opened;
258 > #endif
259 >
260 >        // No audio device succeeded
261 >        WarningAlert(GetString(STR_NO_AUDIO_WARN));
262 >        return false;
263  
264 <        // Init audio status (defaults) and feature flags
264 >        // Device opened, set AudioStatus
265 > dev_opened:
266 >        sound_buffer_size = (audio_sample_sizes[audio_sample_size_index] >> 3) * audio_channel_counts[audio_channel_count_index] * audio_frames_per_block;
267          set_audio_status_format();
268 +
269 +        // Start streaming thread
270 +        Set_pthread_attr(&stream_thread_attr, 0);
271 +        stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
272 +
273 +        // Everything went fine
274 +        audio_open = true;
275 +        return true;
276 + }
277 +
278 + void AudioInit(void)
279 + {
280 +        // Init audio status (reasonable defaults) and feature flags
281 +        AudioStatus.sample_rate = 44100 << 16;
282 +        AudioStatus.sample_size = 16;
283 +        AudioStatus.channels = 2;
284          AudioStatus.mixer = 0;
285          AudioStatus.num_sources = 0;
286          audio_component_flags = cmpWantsRegisterMessage | kStereoOut | k16BitOut;
# Line 192 | Line 289 | void AudioInit(void)
289          if (PrefsFindBool("nosound"))
290                  return;
291  
195        // Try to open /dev/dsp
196        audio_fd = open(DSP_NAME, O_WRONLY);
197        if (audio_fd < 0) {
198 #ifdef ENABLE_ESD
199                if (!audio_init_esd())
200                        return;
201 #else
202                sprintf(str, GetString(STR_NO_AUDIO_DEV_WARN), DSP_NAME, strerror(errno));
203                WarningAlert(str);
204                return;
205 #endif
206        } else
207                if (!audio_init_dsp())
208                        return;
209
210        // Try to open /dev/mixer
211        mixer_fd = open("/dev/mixer", O_RDWR);
212        if (mixer_fd < 0)
213                printf("WARNING: Cannot open /dev/mixer (%s)", strerror(errno));
214
292          // Init semaphore
293          if (sem_init(&audio_irq_done_sem, 0, 0) < 0)
294                  return;
295          sem_inited = true;
296  
297 <        // Start streaming thread
298 <        pthread_attr_init(&stream_thread_attr);
299 < #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
300 <        if (geteuid() == 0) {
301 <                pthread_attr_setinheritsched(&stream_thread_attr, PTHREAD_EXPLICIT_SCHED);
225 <                pthread_attr_setschedpolicy(&stream_thread_attr, SCHED_FIFO);
226 <                struct sched_param fifo_param;
227 <                fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
228 <                pthread_attr_setschedparam(&stream_thread_attr, &fifo_param);
229 <        }
230 < #endif
231 <        stream_thread_active = (pthread_create(&stream_thread, &stream_thread_attr, stream_func, NULL) == 0);
297 >        // Try to open the mixer device
298 >        const char *mixer = PrefsFindString("mixer");
299 >        mixer_fd = open(mixer, O_RDWR);
300 >        if (mixer_fd < 0)
301 >                printf("WARNING: Cannot open %s (%s)\n", mixer, strerror(errno));
302  
303 <        // Everything OK
304 <        audio_open = true;
303 >        // Open and initialize audio device
304 >        open_audio();
305   }
306  
307  
# Line 239 | Line 309 | void AudioInit(void)
309   *  Deinitialization
310   */
311  
312 < void AudioExit(void)
312 > static void close_audio(void)
313   {
314          // Stop stream and delete semaphore
315          if (stream_thread_active) {
# Line 250 | Line 320 | void AudioExit(void)
320                  pthread_join(stream_thread, NULL);
321                  stream_thread_active = false;
322          }
253        if (sem_inited)
254                sem_destroy(&audio_irq_done_sem);
323  
324 <        // Close /dev/dsp
325 <        if (audio_fd > 0)
324 >        // Close dsp or ESD socket
325 >        if (audio_fd >= 0) {
326                  close(audio_fd);
327 +                audio_fd = -1;
328 +        }
329  
330 <        // Close /dev/mixer
331 <        if (mixer_fd > 0)
330 >        audio_open = false;
331 > }
332 >
333 > void AudioExit(void)
334 > {
335 >        // Stop the device immediately. Otherwise, close() sends
336 >        // SNDCTL_DSP_SYNC, which may hang
337 >        if (is_dsp_audio)
338 >                ioctl(audio_fd, SNDCTL_DSP_RESET, 0);
339 >
340 >        // Close audio device
341 >        close_audio();
342 >
343 >        // Delete semaphore
344 >        if (sem_inited) {
345 >                sem_destroy(&audio_irq_done_sem);
346 >                sem_inited = false;
347 >        }
348 >
349 >        // Close mixer device
350 >        if (mixer_fd >= 0) {
351                  close(mixer_fd);
352 +                mixer_fd = -1;
353 +        }
354   }
355  
356  
# Line 287 | Line 378 | void audio_exit_stream()
378   *  Streaming function
379   */
380  
290 static uint32 apple_stream_info;        // Mac address of SoundComponentData struct describing next buffer
291
381   static void *stream_func(void *arg)
382   {
383          int16 *silent_buffer = new int16[sound_buffer_size / 2];
# Line 372 | Line 461 | void AudioInterrupt(void)
461  
462   /*
463   *  Set sampling parameters
464 < *  "index" is an index into the audio_sample_rates[] etc. arrays
464 > *  "index" is an index into the audio_sample_rates[] etc. vectors
465   *  It is guaranteed that AudioStatus.num_sources == 0
466   */
467  
468 < void audio_set_sample_rate(int index)
468 > bool audio_set_sample_rate(int index)
469   {
470 +        close_audio();
471 +        audio_sample_rate_index = index;
472 +        return open_audio();
473   }
474  
475 < void audio_set_sample_size(int index)
475 > bool audio_set_sample_size(int index)
476   {
477 +        close_audio();
478 +        audio_sample_size_index = index;
479 +        return open_audio();
480   }
481  
482 < void audio_set_channels(int index)
482 > bool audio_set_channels(int index)
483   {
484 +        close_audio();
485 +        audio_channel_count_index = index;
486 +        return open_audio();
487   }
488  
489  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines