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.3 by cebix, 1999-11-03T10:56:22Z vs.
Revision 1.15 by cebix, 2002-10-15T16:25:04Z

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines