xref: /haiku/src/add-ons/media/media-add-ons/opensound/OpenSoundDeviceEngine.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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 
19 OpenSoundDeviceEngine::~OpenSoundDeviceEngine()
20 {
21 	CALLED();
22 	if (fFD != 0) {
23 		close(fFD);
24 	}
25 }
26 
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 
50 status_t OpenSoundDeviceEngine::InitCheck(void) const
51 {
52 	CALLED();
53 	return fInitCheckStatus;
54 }
55 
56 
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 
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 
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
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
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
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
186 OpenSoundDeviceEngine::RecordingLatency()
187 {
188 	return 0LL; //XXX
189 }
190 
191 
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 
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()!
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 
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 
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 
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 
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 
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
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
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
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
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
414 OpenSoundDeviceEngine::DriverBufferSize() const
415 {
416 	return fDriverBufferSize;
417 }
418 
419 
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
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 
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 
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 
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