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