1 /*
2 * OpenSound media addon for BeOS and Haiku
3 *
4 * Copyright (c) 2007, François Revol (revol@free.fr)
5 * Distributed under the terms of the MIT License.
6 */
7
8 #include "OpenSoundDeviceEngine.h"
9
10 #include "debug.h"
11 #include "driver_io.h"
12 #include <MediaDefs.h>
13 #include <Debug.h>
14 #include <errno.h>
15 #include <string.h>
16
17 #include "SupportFunctions.h"
18
~OpenSoundDeviceEngine()19 OpenSoundDeviceEngine::~OpenSoundDeviceEngine()
20 {
21 CALLED();
22 if (fFD != 0) {
23 close(fFD);
24 }
25 }
26
OpenSoundDeviceEngine(oss_audioinfo * info)27 OpenSoundDeviceEngine::OpenSoundDeviceEngine(oss_audioinfo *info)
28 : fNextPlay(NULL)
29 , fNextRec(NULL)
30 , fOpenMode(0)
31 , fFD(-1)
32 , fMediaFormat()
33 , fDriverBufferSize(0)
34 {
35 CALLED();
36 fInitCheckStatus = B_NO_INIT;
37 memcpy(&fAudioInfo, info, sizeof(oss_audioinfo));
38
39 // XXX:REMOVEME
40 // set default format
41 /*
42 SetFormat(OpenSoundDevice::select_oss_format(info->oformats));
43 SetChannels(info->max_channels);
44 SetSpeed(info->max_rate);
45 */
46 fInitCheckStatus = B_OK;
47 }
48
49
InitCheck(void) const50 status_t OpenSoundDeviceEngine::InitCheck(void) const
51 {
52 CALLED();
53 return fInitCheckStatus;
54 }
55
56
Open(int mode)57 status_t OpenSoundDeviceEngine::Open(int mode)
58 {
59 int omode, v;
60 CALLED();
61
62 switch (mode) {
63 case OPEN_READ:
64 if (!(Caps() & DSP_CAP_INPUT))
65 return EINVAL;
66 omode = O_RDONLY;
67 break;
68 case OPEN_WRITE:
69 if (!(Caps() & DSP_CAP_OUTPUT))
70 return EINVAL;
71 omode = O_WRONLY;
72 break;
73 case OPEN_READWRITE:
74 if (!(Caps() & DSP_CAP_OUTPUT) || !(Caps() & DSP_CAP_INPUT))
75 return EINVAL;
76 omode = O_RDWR;
77 break;
78 default:
79 return EINVAL;
80 }
81 // O_EXCL = bypass soft mixer = direct access
82 omode |= O_EXCL;
83
84 Close();
85 fOpenMode = mode;
86 fFD = open(fAudioInfo.devnode, omode);
87 if (fFD < 0) {
88 fInitCheckStatus = errno;
89 return EIO;
90 }
91 // disable format convertions
92 v = 0;
93 if (ioctl(fFD, SNDCTL_DSP_COOKEDMODE, &v, sizeof(int)) < 0) {
94 fInitCheckStatus = errno;
95 Close();
96 return EIO;
97 }
98
99 // set driver buffer size by using the "fragments" API
100 // TODO: export this setting as a BParameter?
101 uint32 bufferCount = 4;
102 uint32 bufferSize = 0x000b; // 1024 bytes
103 v = (bufferCount << 16) | bufferSize;
104 if (ioctl(fFD, SNDCTL_DSP_SETFRAGMENT, &v, sizeof(int)) < 0) {
105 fInitCheckStatus = errno;
106 Close();
107 return EIO;
108 }
109
110 fDriverBufferSize = 2048;
111 // preliminary, adjusted in AcceptFormat()
112 return B_OK;
113 }
114
115
Close(void)116 status_t OpenSoundDeviceEngine::Close(void)
117 {
118 CALLED();
119 if (fFD > -1)
120 close(fFD);
121 fFD = -1;
122 fOpenMode = 0;
123 fMediaFormat = media_format();
124 return B_OK;
125 }
126
127
Read(void * buffer,size_t size)128 ssize_t OpenSoundDeviceEngine::Read(void *buffer, size_t size)
129 {
130 ssize_t done;
131 CALLED();
132 done = read(fFD, buffer, size);
133 if (done < 0)
134 return errno;
135 return done;
136 }
137
138
139 ssize_t
Write(const void * buffer,size_t size)140 OpenSoundDeviceEngine::Write(const void *buffer, size_t size)
141 {
142 CALLED();
143
144 ASSERT(size > 0);
145
146 ssize_t done = write(fFD, buffer, size);
147 if (done < 0)
148 return errno;
149
150 return done;
151 }
152
153
154 status_t
UpdateInfo()155 OpenSoundDeviceEngine::UpdateInfo()
156 {
157 CALLED();
158
159 if (fFD < 0)
160 return ENODEV;
161
162 if (ioctl(fFD, SNDCTL_ENGINEINFO, &fAudioInfo, sizeof(oss_audioinfo)) < 0)
163 return errno;
164
165 return B_OK;
166 }
167
168
169 bigtime_t
PlaybackLatency()170 OpenSoundDeviceEngine::PlaybackLatency()
171 {
172 bigtime_t latency = time_for_buffer(fDriverBufferSize, fMediaFormat);
173 bigtime_t cardLatency = CardLatency();
174 if (cardLatency == 0) {
175 // that's unrealistic, take matters into own hands
176 cardLatency = latency / 3;
177 }
178 latency += cardLatency;
179 // PRINT(("PlaybackLatency: odelay %d latency %lld card %lld\n",
180 // fDriverBufferSize, latency, CardLatency()));
181 return latency;
182 }
183
184
185 bigtime_t
RecordingLatency()186 OpenSoundDeviceEngine::RecordingLatency()
187 {
188 return 0LL; //XXX
189 }
190
191
GetChannels(void)192 int OpenSoundDeviceEngine::GetChannels(void)
193 {
194 int chans = -1;
195 CALLED();
196 if (ioctl(fFD, SNDCTL_DSP_CHANNELS, &chans, sizeof(int)) < 0) {
197 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
198 __FUNCTION__, "SNDCTL_DSP_CHANNELS", strerror(errno)));
199 return -1;
200 }
201 return chans;
202 }
203
SetChannels(int chans)204 status_t OpenSoundDeviceEngine::SetChannels(int chans)
205 {
206 CALLED();
207 if (ioctl(fFD, SNDCTL_DSP_CHANNELS, &chans, sizeof(int)) < 0) {
208 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
209 __FUNCTION__, "SNDCTL_DSP_CHANNELS", strerror(errno)));
210 return EIO;
211 }
212 PRINT(("OpenSoundDeviceEngine::%s: %d\n", __FUNCTION__, chans));
213 return B_OK;
214 }
215
216 //XXX: either GetFormat*s*() or cache SetFormat()!
GetFormat(void)217 int OpenSoundDeviceEngine::GetFormat(void)
218 {
219 int fmt = -1;
220 CALLED();
221 if (ioctl(fFD, SNDCTL_DSP_GETFMTS, &fmt, sizeof(int)) < 0) {
222 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
223 __FUNCTION__, "SNDCTL_DSP_GETFMTS", strerror(errno)));
224 return -1;
225 }
226 return fmt;
227 }
228
SetFormat(int fmt)229 status_t OpenSoundDeviceEngine::SetFormat(int fmt)
230 {
231 CALLED();
232 if (ioctl(fFD, SNDCTL_DSP_SETFMT, &fmt, sizeof(int)) < 0) {
233 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
234 __FUNCTION__, "SNDCTL_DSP_SETFMT", strerror(errno)));
235 return EIO;
236 }
237 PRINT(("OpenSoundDeviceEngine::%s: 0x%08x\n", __FUNCTION__, fmt));
238 return B_OK;
239 }
240
GetSpeed(void)241 int OpenSoundDeviceEngine::GetSpeed(void)
242 {
243 int speed = -1;
244 CALLED();
245 if (ioctl(fFD, SNDCTL_DSP_SPEED, &speed, sizeof(int)) < 0) {
246 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
247 __FUNCTION__, "SNDCTL_DSP_SPEED", strerror(errno)));
248 return -1;
249 }
250 return speed;
251 }
252
SetSpeed(int speed)253 status_t OpenSoundDeviceEngine::SetSpeed(int speed)
254 {
255 CALLED();
256 if (ioctl(fFD, SNDCTL_DSP_SPEED, &speed, sizeof(int)) < 0) {
257 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
258 __FUNCTION__, "SNDCTL_DSP_SPEED", strerror(errno)));
259 return EIO;
260 }
261 PRINT(("OpenSoundDeviceEngine::%s: %d\n", __FUNCTION__, speed));
262 return B_OK;
263 }
264
265
GetISpace(audio_buf_info * info)266 size_t OpenSoundDeviceEngine::GetISpace(audio_buf_info *info)
267 {
268 audio_buf_info abinfo;
269 CALLED();
270 if (!info)
271 info = &abinfo;
272 memset(info, 0, sizeof(audio_buf_info));
273 if (!(fOpenMode & OPEN_READ))
274 return 0;
275 if (ioctl(fFD, SNDCTL_DSP_GETISPACE, info, sizeof(audio_buf_info)) < 0) {
276 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
277 __FUNCTION__, "SNDCTL_DSP_GETISPACE", strerror(errno)));
278 return EIO;
279 }
280 //PRINT(("OpenSoundDeviceEngine::%s: ISPACE: { bytes=%d, fragments=%d, fragsize=%d, fragstotal=%d }\n", __FUNCTION__, info->bytes, info->fragments, info->fragsize, info->fragstotal));
281 return info->bytes;
282 }
283
284
GetOSpace(audio_buf_info * info)285 size_t OpenSoundDeviceEngine::GetOSpace(audio_buf_info *info)
286 {
287 audio_buf_info abinfo;
288 //CALLED();
289 if (!info)
290 info = &abinfo;
291 memset(info, 0, sizeof(audio_buf_info));
292 if (!(fOpenMode & OPEN_WRITE))
293 return 0;
294 if (ioctl(fFD, SNDCTL_DSP_GETOSPACE, info, sizeof(audio_buf_info)) < 0) {
295 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
296 __FUNCTION__, "SNDCTL_DSP_GETOSPACE", strerror(errno)));
297 return EIO;
298 }
299 //PRINT(("OpenSoundDeviceEngine::%s: OSPACE: { bytes=%d, fragments=%d, fragsize=%d, fragstotal=%d }\n", __FUNCTION__, info->bytes, info->fragments, info->fragsize, info->fragstotal));
300 return info->bytes;
301 }
302
303
304 int64
GetCurrentIPtr(int32 * fifoed,oss_count_t * info)305 OpenSoundDeviceEngine::GetCurrentIPtr(int32 *fifoed, oss_count_t *info)
306 {
307 oss_count_t ocount;
308 count_info cinfo;
309 CALLED();
310 if (!info)
311 info = &ocount;
312 memset(info, 0, sizeof(oss_count_t));
313 if (!(fOpenMode & OPEN_READ))
314 return 0;
315 if (ioctl(fFD, SNDCTL_DSP_CURRENT_IPTR, info, sizeof(oss_count_t)) < 0) {
316 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
317 __FUNCTION__, "SNDCTL_DSP_CURRENT_IPTR", strerror(errno)));
318 //return EIO;
319 // fallback: try GET*PTR
320 if (ioctl(fFD, SNDCTL_DSP_GETIPTR, &cinfo, sizeof(count_info)) < 0) {
321 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
322 __FUNCTION__, "SNDCTL_DSP_GETIPTR", strerror(errno)));
323 return 0;
324 }
325 // it's probably wrong...
326 info->samples = cinfo.bytes / (fMediaFormat.u.raw_audio.channel_count
327 * (fMediaFormat.AudioFormat() & media_raw_audio_format::B_AUDIO_SIZE_MASK));
328 info->fifo_samples = 0;
329 }
330 PRINT(("OpenSoundDeviceEngine::%s: IPTR: { samples=%lld, fifo_samples=%d }\n", __FUNCTION__, info->samples, info->fifo_samples));
331 if (fifoed)
332 *fifoed = info->fifo_samples;
333 return info->samples;
334 }
335
336
337 int64
GetCurrentOPtr(int32 * fifoed,size_t * fragmentPos)338 OpenSoundDeviceEngine::GetCurrentOPtr(int32* fifoed, size_t* fragmentPos)
339 {
340 CALLED();
341
342 if (!(fOpenMode & OPEN_WRITE)) {
343 if (fifoed != NULL)
344 *fifoed = 0;
345 return 0;
346 }
347
348 oss_count_t info;
349 memset(&info, 0, sizeof(oss_count_t));
350
351 if (ioctl(fFD, SNDCTL_DSP_CURRENT_OPTR, &info, sizeof(oss_count_t)) < 0) {
352 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
353 __FUNCTION__, "SNDCTL_DSP_CURRENT_OPTR", strerror(errno)));
354
355 return 0;
356 }
357
358 if (fragmentPos != NULL) {
359 count_info cinfo;
360 if (ioctl(fFD, SNDCTL_DSP_GETOPTR, &cinfo, sizeof(count_info)) < 0) {
361 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
362 __FUNCTION__, "SNDCTL_DSP_GETOPTR", strerror(errno)));
363 return 0;
364 }
365 *fragmentPos = cinfo.ptr;
366 }
367
368 // PRINT(("OpenSoundDeviceEngine::%s: OPTR: { samples=%lld, "
369 // "fifo_samples=%d }\n", __FUNCTION__, info->samples,
370 // info->fifo_samples));
371 if (fifoed != NULL)
372 *fifoed = info.fifo_samples;
373 return info.samples;
374 }
375
376
377 int32
GetIOverruns()378 OpenSoundDeviceEngine::GetIOverruns()
379 {
380 audio_errinfo info;
381 CALLED();
382 memset(&info, 0, sizeof(info));
383 if (!(fOpenMode & OPEN_WRITE))
384 return 0;
385 if (ioctl(fFD, SNDCTL_DSP_GETERROR, &info, sizeof(info)) < 0) {
386 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
387 __FUNCTION__, "SNDCTL_DSP_GETERROR", strerror(errno)));
388 return 0;
389 }
390 PRINT(("OpenSoundDeviceEngine::%s: IOVERRUNS: { overruns=%d }\n", __FUNCTION__, info.rec_overruns));
391 return info.rec_overruns;
392 }
393
394
395 int32
GetOUnderruns()396 OpenSoundDeviceEngine::GetOUnderruns()
397 {
398 audio_errinfo info;
399 CALLED();
400 memset(&info, 0, sizeof(info));
401 if (!(fOpenMode & OPEN_WRITE))
402 return 0;
403 if (ioctl(fFD, SNDCTL_DSP_GETERROR, &info, sizeof(info)) < 0) {
404 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
405 __FUNCTION__, "SNDCTL_DSP_GETERROR", strerror(errno)));
406 return 0;
407 }
408 //PRINT(("OpenSoundDeviceEngine::%s: OUNDERRUNS: { underruns=%d }\n", __FUNCTION__, info.play_underruns));
409 return info.play_underruns;
410 }
411
412
413 size_t
DriverBufferSize() const414 OpenSoundDeviceEngine::DriverBufferSize() const
415 {
416 return fDriverBufferSize;
417 }
418
419
StartRecording(void)420 status_t OpenSoundDeviceEngine::StartRecording(void)
421 {
422 CALLED();
423 oss_syncgroup group;
424 group.id = 0;
425 group.mode = PCM_ENABLE_INPUT;
426 if (ioctl(fFD, SNDCTL_DSP_SYNCGROUP, &group, sizeof(group)) < 0) {
427 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
428 __FUNCTION__, "SNDCTL_DSP_SYNCGROUP", strerror(errno)));
429 return EIO;
430 }
431 if (ioctl(fFD, SNDCTL_DSP_SYNCSTART, &group.id, sizeof(group.id)) < 0) {
432 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
433 __FUNCTION__, "SNDCTL_DSP_SYNCSTART", strerror(errno)));
434 return EIO;
435 }
436 return B_OK;
437 }
438
439
440 status_t
WildcardFormatFor(int fmt,media_format & format,bool rec)441 OpenSoundDeviceEngine::WildcardFormatFor(int fmt, media_format &format,
442 bool rec)
443 {
444 status_t err;
445 CALLED();
446 fmt &= rec ? Info()->iformats : Info()->oformats;
447 if (fmt == 0)
448 return B_MEDIA_BAD_FORMAT;
449 err = OpenSoundDevice::get_media_format_for(fmt, format);
450 if (err < B_OK)
451 return err;
452 char buf[1024];
453 string_for_format(format, buf, 1024);
454 if (format.type == B_MEDIA_RAW_AUDIO) {
455 format.u.raw_audio = media_multi_audio_format::wildcard;
456 format.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
457 // single rate supported
458 if (Info()->min_rate == Info()->max_rate)
459 format.u.raw_audio.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
460 } else if (format.type == B_MEDIA_ENCODED_AUDIO) {
461 format.u.encoded_audio.output = media_multi_audio_format::wildcard;
462 //format.u.encoded_audio.output.byte_order = B_MEDIA_HOST_ENDIAN;
463 // single rate supported
464 //if (Info()->min_rate == Info()->max_rate)
465 // format.u.encoded_audio.output.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
466 } else
467 return EINVAL;
468 PRINT(("%s: %s\n", __FUNCTION__, buf));
469 return B_OK;
470 }
471
472
PreferredFormatFor(int fmt,media_format & format,bool rec)473 status_t OpenSoundDeviceEngine::PreferredFormatFor(int fmt, media_format &format, bool rec)
474 {
475 status_t err;
476 CALLED();
477 fmt &= rec ? Info()->iformats : Info()->oformats;
478 if (fmt == 0)
479 return B_MEDIA_BAD_FORMAT;
480 err = WildcardFormatFor(fmt, format);
481 if (err < B_OK)
482 return err;
483 if (format.type == B_MEDIA_RAW_AUDIO) {
484 media_multi_audio_format &raw = format.u.raw_audio;
485 //format.u.raw_audio.channel_count = Info()->max_channels;
486 raw.byte_order = B_MEDIA_HOST_ENDIAN;
487 raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
488 raw.buffer_size = DEFAULT_BUFFER_SIZE;
489 /*if (rec)
490 raw.buffer_size = 2048;*/
491 /*
492 format.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
493 format.u.raw_audio.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
494 format.u.raw_audio.buffer_size = DEFAULT_BUFFER_SIZE;
495 */
496 } else if (format.type == B_MEDIA_ENCODED_AUDIO) {
497 media_raw_audio_format &raw = format.u.encoded_audio.output;
498 //format.u.encoded_audio.output.channel_count = Info()->max_channels;
499 raw.byte_order = B_MEDIA_HOST_ENDIAN;
500 // single rate supported
501 if (Info()->min_rate == Info()->max_rate)
502 raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
503 raw.buffer_size = DEFAULT_BUFFER_SIZE;
504 } else
505 return EINVAL;
506 char buf[1024];
507 string_for_format(format, buf, 1024);
508 PRINT(("%s: %s\n", __FUNCTION__, buf));
509 return B_OK;
510 }
511
512
AcceptFormatFor(int fmt,media_format & format,bool rec)513 status_t OpenSoundDeviceEngine::AcceptFormatFor(int fmt, media_format &format, bool rec)
514 {
515 status_t err;
516 int afmt = 0;
517 char buf[1024];
518 CALLED();
519 fmt &= rec ? Info()->iformats : Info()->oformats;
520
521 if (fmt == 0)
522 return B_MEDIA_BAD_FORMAT;
523 media_format wc;
524 err = WildcardFormatFor(fmt, wc);
525 if (err < B_OK)
526 return err;
527
528 err = Open(rec ? OPEN_READ : OPEN_WRITE);
529 if (err < B_OK)
530 return err;
531
532 if (format.type == B_MEDIA_RAW_AUDIO) {
533 media_multi_audio_format &raw = format.u.raw_audio;
534
535 // channel count
536 raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count));
537 err = SetChannels(raw.channel_count);
538 if (err < B_OK) {
539 Close();
540 return err;
541 }
542
543 PRINT(("%s:step1 fmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n",
544 __FUNCTION__, fmt, raw.format));
545 // if specified, try it
546 if (raw.format)
547 afmt = OpenSoundDevice::convert_media_format_to_oss_format(raw.format);
548 afmt &= fmt;
549 PRINT(("%s:step2 afmt=0x%08x\n", __FUNCTION__, afmt));
550 // select the best as default
551 if (afmt == 0) {
552 afmt = OpenSoundDevice::select_oss_format(fmt);
553 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt);
554 //Close();
555 //return B_MEDIA_BAD_FORMAT;
556 }
557 PRINT(("%s:step3 afmt=0x%08x\n", __FUNCTION__, afmt));
558 // convert back
559 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt);
560 PRINT(("%s:step4 afmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n",
561 __FUNCTION__, afmt, raw.format));
562 raw.valid_bits = OpenSoundDevice::convert_oss_format_to_valid_bits(afmt);
563
564 err = SetFormat(afmt);
565 if (err < B_OK) {
566 Close();
567 return err;
568 }
569
570 // endianness
571 raw.byte_order = OpenSoundDevice::convert_oss_format_to_endian(afmt);
572
573 // sample rate
574 raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz
575 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
576 err = SetSpeed(OpenSoundDevice::convert_media_rate_to_oss_rate(raw.frame_rate));
577 if (err < B_OK) {
578 Close();
579 return err;
580 }
581
582 // retrieve the driver buffer size (it's important to do this
583 // after all the other setup, since OSS may have adjusted it, and
584 // also weird things happen if this ioctl() is done before other
585 // setup itctl()s)
586 audio_buf_info abinfo;
587 memset(&abinfo, 0, sizeof(audio_buf_info));
588 if (ioctl(fFD, SNDCTL_DSP_GETOSPACE, &abinfo, sizeof(audio_buf_info)) < 0) {
589 fprintf(stderr, "failed to retrieve driver buffer size!\n");
590 abinfo.bytes = 0;
591 }
592 fDriverBufferSize = abinfo.bytes;
593
594 raw.buffer_size = fDriverBufferSize;
595
596 } else if (format.type == B_MEDIA_ENCODED_AUDIO) {
597 media_raw_audio_format &raw = format.u.encoded_audio.output;
598 // XXX: do we really have to do this ?
599 raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count));
600 raw.byte_order = B_MEDIA_HOST_ENDIAN;
601 raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz
602 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
603 raw.buffer_size = DEFAULT_BUFFER_SIZE;
604
605 } else {
606 PRINT(("%s: unknown media type\n", __FUNCTION__));
607 Close();
608 return EINVAL;
609 }
610 // cache it
611 fMediaFormat = format;
612
613 string_for_format(format, buf, 1024);
614 PRINT(("%s: %s\n", __FUNCTION__, buf));
615 return B_OK;
616 }
617
618
SpecializeFormatFor(int fmt,media_format & format,bool rec)619 status_t OpenSoundDeviceEngine::SpecializeFormatFor(int fmt, media_format &format, bool rec)
620 {
621 status_t err;
622 int afmt = 0;
623 CALLED();
624 fmt &= rec ? Info()->iformats : Info()->oformats;
625 if (fmt == 0)
626 return B_MEDIA_BAD_FORMAT;
627 media_format wc;
628 err = WildcardFormatFor(fmt, wc);
629 if (err < B_OK)
630 return err;
631
632 err = Open(rec ? OPEN_READ : OPEN_WRITE);
633 if (err < B_OK)
634 return err;
635
636 if (format.type == B_MEDIA_RAW_AUDIO) {
637 media_multi_audio_format &raw = format.u.raw_audio;
638
639 PRINT(("%s:step1 fmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n",
640 __FUNCTION__, fmt, raw.format));
641 // select the best as default
642 if (!raw.format) {
643 afmt = OpenSoundDevice::select_oss_format(fmt);
644 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt);
645 }
646 // if specified, try it
647 if (raw.format)
648 afmt = OpenSoundDevice::convert_media_format_to_oss_format(raw.format);
649 afmt &= fmt;
650 PRINT(("%s:step2 afmt=0x%08x\n", __FUNCTION__, afmt));
651 if (afmt == 0) {
652 Close();
653 return B_MEDIA_BAD_FORMAT;
654 }
655 // convert back
656 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt);
657 PRINT(("%s:step4 afmt=0x%08x, raw.format=0x%08" B_PRIx32 "\n",
658 __FUNCTION__, afmt, raw.format));
659 if (!raw.valid_bits)
660 raw.valid_bits = OpenSoundDevice::convert_oss_format_to_valid_bits(afmt);
661 if (raw.valid_bits != OpenSoundDevice::convert_oss_format_to_valid_bits(afmt)) {
662 Close();
663 return B_MEDIA_BAD_FORMAT;
664 }
665
666 err = SetFormat(afmt);
667 if (err < B_OK) {
668 Close();
669 return err;
670 }
671
672 // endianness
673 if (!raw.byte_order)
674 raw.byte_order = OpenSoundDevice::convert_oss_format_to_endian(afmt);
675 if ((int)raw.byte_order != OpenSoundDevice::convert_oss_format_to_endian(afmt)) {
676 Close();
677 return B_MEDIA_BAD_FORMAT;
678 }
679
680 // channel count
681 if (raw.channel_count == 0)
682 raw.channel_count = (unsigned)Info()->min_channels;
683 if ((int)raw.channel_count < Info()->min_channels
684 || (int)raw.channel_count > Info()->max_channels)
685 return B_MEDIA_BAD_FORMAT;
686 err = SetChannels(raw.channel_count);
687 if (err < B_OK) {
688 Close();
689 return err;
690 }
691
692 // sample rate
693 if (!raw.frame_rate)
694 raw.frame_rate = Info()->max_rate;
695 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
696 err = SetSpeed(OpenSoundDevice::convert_media_rate_to_oss_rate(raw.frame_rate));
697 if (err < B_OK) {
698 Close();
699 return err;
700 }
701
702 #if 0
703 raw.buffer_size = DEFAULT_BUFFER_SIZE
704 * (raw.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
705 * raw.channel_count;
706 #endif
707 audio_buf_info abinfo;
708 if (ioctl(fFD, rec?SNDCTL_DSP_GETISPACE:SNDCTL_DSP_GETOSPACE, &abinfo, sizeof(abinfo)) < 0) {
709 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n",
710 __FUNCTION__, "SNDCTL_DSP_GET?SPACE", strerror(errno)));
711 return -1;
712 }
713 PRINT(("OSS: %cSPACE: { bytes=%d, fragments=%d, fragsize=%d, fragstotal=%d }\n", rec?'I':'O', abinfo.bytes, abinfo.fragments, abinfo.fragsize, abinfo.fragstotal));
714 // cache the first one in the Device
715 // so StartThread() knows the number of frags
716 //if (!fFragments.fragstotal)
717 // memcpy(&fFragments, &abinfo, sizeof(abinfo));
718
719 // make sure buffer size is less than the driver's own buffer ( /2 to keep some margin )
720 if (/*rec && raw.buffer_size &&*/ (int)raw.buffer_size > abinfo.fragsize * abinfo.fragstotal / 4)
721 return B_MEDIA_BAD_FORMAT;
722 if (!raw.buffer_size)
723 raw.buffer_size = abinfo.fragsize;//XXX
724 /* * (raw.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
725 * raw.channel_count;*/
726 } else if (format.type == B_MEDIA_ENCODED_AUDIO) {
727 media_raw_audio_format &raw = format.u.encoded_audio.output;
728 // XXX: do we really have to do this ?
729 raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count));
730 raw.byte_order = B_MEDIA_HOST_ENDIAN;
731 raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz
732 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz
733 raw.buffer_size = DEFAULT_BUFFER_SIZE;
734
735 } else {
736 Close();
737 return EINVAL;
738 }
739 // cache it
740 fMediaFormat = format;
741 char buf[1024];
742 string_for_format(format, buf, 1024);
743 PRINT(("%s: %s\n", __FUNCTION__, buf));
744 return B_OK;
745 }
746
747