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 19OpenSoundDeviceEngine::~OpenSoundDeviceEngine() 20{ 21 CALLED(); 22 if (fFD != 0) { 23 close(fFD); 24 } 25} 26 27OpenSoundDeviceEngine::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 50status_t OpenSoundDeviceEngine::InitCheck(void) const 51{ 52 CALLED(); 53 return fInitCheckStatus; 54} 55 56 57status_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 116status_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 128ssize_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 139ssize_t 140OpenSoundDeviceEngine::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 154status_t 155OpenSoundDeviceEngine::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 169bigtime_t 170OpenSoundDeviceEngine::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 %Ld card %Ld\n", 180// fDriverBufferSize, latency, CardLatency())); 181 return latency; 182} 183 184 185bigtime_t 186OpenSoundDeviceEngine::RecordingLatency() 187{ 188 return 0LL; //XXX 189} 190 191 192int 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 204status_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()! 217int 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 229status_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 241int 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 253status_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 266size_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 285size_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 304int64 305OpenSoundDeviceEngine::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=%Ld, 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 337int64 338OpenSoundDeviceEngine::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=%Ld, " 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 377int32 378OpenSoundDeviceEngine::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 395int32 396OpenSoundDeviceEngine::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 413size_t 414OpenSoundDeviceEngine::DriverBufferSize() const 415{ 416 return fDriverBufferSize; 417} 418 419 420status_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 440status_t 441OpenSoundDeviceEngine::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 473status_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 513status_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%08lx\n", __FUNCTION__, fmt, raw.format)); 544 // if specified, try it 545 if (raw.format) 546 afmt = OpenSoundDevice::convert_media_format_to_oss_format(raw.format); 547 afmt &= fmt; 548 PRINT(("%s:step2 afmt=0x%08x\n", __FUNCTION__, afmt)); 549 // select the best as default 550 if (afmt == 0) { 551 afmt = OpenSoundDevice::select_oss_format(fmt); 552 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); 553 //Close(); 554 //return B_MEDIA_BAD_FORMAT; 555 } 556 PRINT(("%s:step3 afmt=0x%08x\n", __FUNCTION__, afmt)); 557 // convert back 558 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); 559 PRINT(("%s:step4 afmt=0x%08x, raw.format=0x%08lx\n", __FUNCTION__, afmt, raw.format)); 560 raw.valid_bits = OpenSoundDevice::convert_oss_format_to_valid_bits(afmt); 561 562 err = SetFormat(afmt); 563 if (err < B_OK) { 564 Close(); 565 return err; 566 } 567 568 // endianness 569 raw.byte_order = OpenSoundDevice::convert_oss_format_to_endian(afmt); 570 571 // sample rate 572 raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz 573 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz 574 err = SetSpeed(OpenSoundDevice::convert_media_rate_to_oss_rate(raw.frame_rate)); 575 if (err < B_OK) { 576 Close(); 577 return err; 578 } 579 580 // retrieve the driver buffer size (it's important to do this 581 // after all the other setup, since OSS may have adjusted it, and 582 // also weird things happen if this ioctl() is done before other 583 // setup itctl()s) 584 audio_buf_info abinfo; 585 memset(&abinfo, 0, sizeof(audio_buf_info)); 586 if (ioctl(fFD, SNDCTL_DSP_GETOSPACE, &abinfo, sizeof(audio_buf_info)) < 0) { 587 fprintf(stderr, "failed to retrieve driver buffer size!\n"); 588 abinfo.bytes = 0; 589 } 590 fDriverBufferSize = abinfo.bytes; 591 592 raw.buffer_size = fDriverBufferSize; 593 594 } else if (format.type == B_MEDIA_ENCODED_AUDIO) { 595 media_raw_audio_format &raw = format.u.encoded_audio.output; 596 // XXX: do we really have to do this ? 597 raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count)); 598 raw.byte_order = B_MEDIA_HOST_ENDIAN; 599 raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz 600 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz 601 raw.buffer_size = DEFAULT_BUFFER_SIZE; 602 603 } else { 604 PRINT(("%s: unknown media type\n", __FUNCTION__)); 605 Close(); 606 return EINVAL; 607 } 608 // cache it 609 fMediaFormat = format; 610 611 string_for_format(format, buf, 1024); 612 PRINT(("%s: %s\n", __FUNCTION__, buf)); 613 return B_OK; 614} 615 616 617status_t OpenSoundDeviceEngine::SpecializeFormatFor(int fmt, media_format &format, bool rec) 618{ 619 status_t err; 620 int afmt = 0; 621 CALLED(); 622 fmt &= rec ? Info()->iformats : Info()->oformats; 623 if (fmt == 0) 624 return B_MEDIA_BAD_FORMAT; 625 media_format wc; 626 err = WildcardFormatFor(fmt, wc); 627 if (err < B_OK) 628 return err; 629 630 err = Open(rec ? OPEN_READ : OPEN_WRITE); 631 if (err < B_OK) 632 return err; 633 634 if (format.type == B_MEDIA_RAW_AUDIO) { 635 media_multi_audio_format &raw = format.u.raw_audio; 636 637 PRINT(("%s:step1 fmt=0x%08x, raw.format=0x%08lx\n", __FUNCTION__, fmt, raw.format)); 638 // select the best as default 639 if (!raw.format) { 640 afmt = OpenSoundDevice::select_oss_format(fmt); 641 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); 642 } 643 // if specified, try it 644 if (raw.format) 645 afmt = OpenSoundDevice::convert_media_format_to_oss_format(raw.format); 646 afmt &= fmt; 647 PRINT(("%s:step2 afmt=0x%08x\n", __FUNCTION__, afmt)); 648 if (afmt == 0) { 649 Close(); 650 return B_MEDIA_BAD_FORMAT; 651 } 652 // convert back 653 raw.format = OpenSoundDevice::convert_oss_format_to_media_format(afmt); 654 PRINT(("%s:step4 afmt=0x%08x, raw.format=0x%08lx\n", __FUNCTION__, afmt, raw.format)); 655 if (!raw.valid_bits) 656 raw.valid_bits = OpenSoundDevice::convert_oss_format_to_valid_bits(afmt); 657 if (raw.valid_bits != OpenSoundDevice::convert_oss_format_to_valid_bits(afmt)) { 658 Close(); 659 return B_MEDIA_BAD_FORMAT; 660 } 661 662 err = SetFormat(afmt); 663 if (err < B_OK) { 664 Close(); 665 return err; 666 } 667 668 // endianness 669 if (!raw.byte_order) 670 raw.byte_order = OpenSoundDevice::convert_oss_format_to_endian(afmt); 671 if ((int)raw.byte_order != OpenSoundDevice::convert_oss_format_to_endian(afmt)) { 672 Close(); 673 return B_MEDIA_BAD_FORMAT; 674 } 675 676 // channel count 677 if (raw.channel_count == 0) 678 raw.channel_count = (unsigned)Info()->min_channels; 679 if ((int)raw.channel_count < Info()->min_channels 680 || (int)raw.channel_count > Info()->max_channels) 681 return B_MEDIA_BAD_FORMAT; 682 err = SetChannels(raw.channel_count); 683 if (err < B_OK) { 684 Close(); 685 return err; 686 } 687 688 // sample rate 689 if (!raw.frame_rate) 690 raw.frame_rate = Info()->max_rate; 691 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz 692 err = SetSpeed(OpenSoundDevice::convert_media_rate_to_oss_rate(raw.frame_rate)); 693 if (err < B_OK) { 694 Close(); 695 return err; 696 } 697 698#if 0 699 raw.buffer_size = DEFAULT_BUFFER_SIZE 700 * (raw.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 701 * raw.channel_count; 702#endif 703 audio_buf_info abinfo; 704 if (ioctl(fFD, rec?SNDCTL_DSP_GETISPACE:SNDCTL_DSP_GETOSPACE, &abinfo, sizeof(abinfo)) < 0) { 705 PRINT(("OpenSoundDeviceEngine::%s: %s: %s\n", 706 __FUNCTION__, "SNDCTL_DSP_GET?SPACE", strerror(errno))); 707 return -1; 708 } 709 PRINT(("OSS: %cSPACE: { bytes=%d, fragments=%d, fragsize=%d, fragstotal=%d }\n", rec?'I':'O', abinfo.bytes, abinfo.fragments, abinfo.fragsize, abinfo.fragstotal)); 710 // cache the first one in the Device 711 // so StartThread() knows the number of frags 712 //if (!fFragments.fragstotal) 713 // memcpy(&fFragments, &abinfo, sizeof(abinfo)); 714 715 // make sure buffer size is less than the driver's own buffer ( /2 to keep some margin ) 716 if (/*rec && raw.buffer_size &&*/ (int)raw.buffer_size > abinfo.fragsize * abinfo.fragstotal / 4) 717 return B_MEDIA_BAD_FORMAT; 718 if (!raw.buffer_size) 719 raw.buffer_size = abinfo.fragsize;//XXX 720/* * (raw.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) 721 * raw.channel_count;*/ 722 } else if (format.type == B_MEDIA_ENCODED_AUDIO) { 723 media_raw_audio_format &raw = format.u.encoded_audio.output; 724 // XXX: do we really have to do this ? 725 raw.channel_count = MAX((unsigned)(Info()->min_channels), MIN((unsigned)(Info()->max_channels), raw.channel_count)); 726 raw.byte_order = B_MEDIA_HOST_ENDIAN; 727 raw.frame_rate = OpenSoundDevice::select_oss_rate(Info(), raw.frame_rate); // measured in Hertz 728 //raw.frame_rate = OpenSoundDevice::convert_oss_rate_to_media_rate(Info()->max_rate); // measured in Hertz 729 raw.buffer_size = DEFAULT_BUFFER_SIZE; 730 731 } else { 732 Close(); 733 return EINVAL; 734 } 735 // cache it 736 fMediaFormat = format; 737 char buf[1024]; 738 string_for_format(format, buf, 1024); 739 PRINT(("%s: %s\n", __FUNCTION__, buf)); 740 return B_OK; 741} 742 743