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