1 /* 2 * Copyright 2002-2009, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marcus Overhagen 7 * Jérôme Duval 8 */ 9 10 11 #include <SoundPlayer.h> 12 13 #include <math.h> 14 #include <string.h> 15 16 #include <Autolock.h> 17 #include <MediaRoster.h> 18 #include <ParameterWeb.h> 19 #include <Sound.h> 20 #include <TimeSource.h> 21 22 #include "SoundPlayNode.h" 23 24 #include "debug.h" 25 26 27 // Flags used internally in BSoundPlayer 28 enum { 29 F_NODES_CONNECTED = (1 << 0), 30 F_HAS_DATA = (1 << 1), 31 F_IS_STARTED = (1 << 2), 32 F_MUST_RELEASE_MIXER = (1 << 3), 33 }; 34 35 36 static BSoundPlayer::play_id sCurrentPlayID = 1; 37 38 39 BSoundPlayer::BSoundPlayer(const char* name, BufferPlayerFunc playerFunction, 40 EventNotifierFunc eventNotifierFunction, void* cookie) 41 { 42 CALLED(); 43 44 TRACE("BSoundPlayer::BSoundPlayer: default constructor used\n"); 45 46 media_multi_audio_format format = media_multi_audio_format::wildcard; 47 48 _Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction, 49 cookie); 50 } 51 52 53 BSoundPlayer::BSoundPlayer(const media_raw_audio_format* _format, 54 const char* name, BufferPlayerFunc playerFunction, 55 EventNotifierFunc eventNotifierFunction, void* cookie) 56 { 57 CALLED(); 58 59 TRACE("BSoundPlayer::BSoundPlayer: raw audio format constructor used\n"); 60 61 media_multi_audio_format format = media_multi_audio_format::wildcard; 62 *(media_raw_audio_format*)&format = *_format; 63 64 #if DEBUG > 0 65 char buf[100]; 66 media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = format; 67 string_for_format(tmp, buf, sizeof(buf)); 68 TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf); 69 #endif 70 71 _Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction, 72 cookie); 73 } 74 75 76 BSoundPlayer::BSoundPlayer(const media_node& toNode, 77 const media_multi_audio_format* format, const char* name, 78 const media_input* input, BufferPlayerFunc playerFunction, 79 EventNotifierFunc eventNotifierFunction, void* cookie) 80 { 81 CALLED(); 82 83 TRACE("BSoundPlayer::BSoundPlayer: multi audio format constructor used\n"); 84 85 if ((toNode.kind & B_BUFFER_CONSUMER) == 0) 86 debugger("BSoundPlayer: toNode must have B_BUFFER_CONSUMER kind!\n"); 87 88 #if DEBUG > 0 89 char buf[100]; 90 media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = *format; 91 string_for_format(tmp, buf, sizeof(buf)); 92 TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf); 93 #endif 94 95 _Init(&toNode, format, name, input, playerFunction, eventNotifierFunction, 96 cookie); 97 } 98 99 100 BSoundPlayer::~BSoundPlayer() 101 { 102 CALLED(); 103 104 if ((fFlags & F_IS_STARTED) != 0) { 105 // block, but don't flush 106 Stop(true, false); 107 } 108 109 status_t err; 110 BMediaRoster* roster = BMediaRoster::Roster(); 111 if (roster == NULL) { 112 TRACE("BSoundPlayer::~BSoundPlayer: Couldn't get BMediaRoster\n"); 113 goto cleanup; 114 } 115 116 if ((fFlags & F_NODES_CONNECTED) != 0) { 117 // Ordinarily we'd stop *all* of the nodes in the chain before 118 // disconnecting. However, our node is already stopped, and we can't 119 // stop the System Mixer. 120 // So, we just disconnect from it, and release our references to the 121 // nodes that we're using. We *are* supposed to do that even for global 122 // nodes like the Mixer. 123 err = roster->Disconnect(fMediaOutput, fMediaInput); 124 #if DEBUG > 0 125 if (err != B_OK) { 126 TRACE("BSoundPlayer::~BSoundPlayer: Error disconnecting nodes: " 127 "%ld (%s)\n", err, strerror(err)); 128 } 129 #endif 130 } 131 132 if ((fFlags & F_MUST_RELEASE_MIXER) != 0) { 133 // Release the mixer as it was acquired 134 // through BMediaRoster::GetAudioMixer() 135 err = roster->ReleaseNode(fMediaInput.node); 136 #if DEBUG > 0 137 if (err != B_OK) { 138 TRACE("BSoundPlayer::~BSoundPlayer: Error releasing input node: " 139 "%ld (%s)\n", err, strerror(err)); 140 } 141 #endif 142 } 143 144 cleanup: 145 // Dispose of the player node 146 147 // We do not call BMediaRoster::ReleaseNode(), since 148 // the player was created by using "new". We could 149 // call BMediaRoster::UnregisterNode(), but this is 150 // supposed to be done by BMediaNode destructor automatically 151 delete fPlayerNode; 152 153 // do not delete fVolumeSlider, it belongs to the parameter web 154 delete fParameterWeb; 155 } 156 157 158 status_t 159 BSoundPlayer::InitCheck() 160 { 161 CALLED(); 162 return fInitStatus; 163 } 164 165 166 media_raw_audio_format 167 BSoundPlayer::Format() const 168 { 169 CALLED(); 170 171 if ((fFlags & F_NODES_CONNECTED) == 0) 172 return media_raw_audio_format::wildcard; 173 174 return fPlayerNode->Format(); 175 } 176 177 178 status_t 179 BSoundPlayer::Start() 180 { 181 CALLED(); 182 183 if ((fFlags & F_NODES_CONNECTED) == 0) 184 return B_NO_INIT; 185 186 if ((fFlags & F_IS_STARTED) != 0) 187 return B_OK; 188 189 BMediaRoster* roster = BMediaRoster::Roster(); 190 if (!roster) { 191 TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n"); 192 return B_ERROR; 193 } 194 195 if (!fPlayerNode->TimeSource()->IsRunning()) { 196 roster->StartTimeSource(fPlayerNode->TimeSource()->Node(), 197 fPlayerNode->TimeSource()->RealTime()); 198 } 199 200 // Add latency and a few ms to the nodes current time to 201 // make sure that we give the producer enough time to run 202 // buffers through the node chain, otherwise it'll start 203 // up already late 204 205 status_t err = roster->StartNode(fPlayerNode->Node(), 206 fPlayerNode->TimeSource()->Now() + Latency() + 5000); 207 if (err != B_OK) { 208 TRACE("BSoundPlayer::Start: StartNode failed, %ld", err); 209 return err; 210 } 211 212 if (fNotifierFunc != NULL) 213 fNotifierFunc(fCookie, B_STARTED, this); 214 215 SetHasData(true); 216 atomic_or(&fFlags, F_IS_STARTED); 217 218 return B_OK; 219 } 220 221 222 void 223 BSoundPlayer::Stop(bool block, bool flush) 224 { 225 CALLED(); 226 227 TRACE("BSoundPlayer::Stop: block %d, flush %d\n", (int)block, (int)flush); 228 229 if ((fFlags & F_NODES_CONNECTED) == 0) 230 return; 231 232 // TODO: flush is ignored 233 234 if ((fFlags & F_IS_STARTED) != 0) { 235 BMediaRoster* roster = BMediaRoster::Roster(); 236 if (roster == NULL) { 237 TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n"); 238 return; 239 } 240 241 roster->StopNode(fPlayerNode->Node(), 0, true); 242 243 atomic_and(&fFlags, ~F_IS_STARTED); 244 } 245 246 if (block) { 247 // wait until the node is stopped 248 int tries; 249 for (tries = 250; fPlayerNode->IsPlaying() && tries != 0; tries--) 250 snooze(2000); 251 252 DEBUG_ONLY(if (tries == 0) 253 TRACE("BSoundPlayer::Stop: waiting for node stop failed\n")); 254 255 // Wait until all buffers on the way to the physical output have been 256 // played 257 snooze(Latency() + 2000); 258 } 259 260 if (fNotifierFunc) 261 fNotifierFunc(fCookie, B_STOPPED, this); 262 263 } 264 265 266 bigtime_t 267 BSoundPlayer::Latency() 268 { 269 CALLED(); 270 271 if ((fFlags & F_NODES_CONNECTED) == 0) 272 return 0; 273 274 BMediaRoster *roster = BMediaRoster::Roster(); 275 if (!roster) { 276 TRACE("BSoundPlayer::Latency: Couldn't get BMediaRoster\n"); 277 return 0; 278 } 279 280 bigtime_t latency; 281 status_t err = roster->GetLatencyFor(fMediaOutput.node, &latency); 282 if (err != B_OK) { 283 TRACE("BSoundPlayer::Latency: GetLatencyFor failed %ld (%s)\n", err, 284 strerror(err)); 285 return 0; 286 } 287 288 TRACE("BSoundPlayer::Latency: latency is %Ld\n", latency); 289 290 return latency; 291 } 292 293 294 void 295 BSoundPlayer::SetHasData(bool hasData) 296 { 297 CALLED(); 298 if (hasData) 299 atomic_or(&fFlags, F_HAS_DATA); 300 else 301 atomic_and(&fFlags, ~F_HAS_DATA); 302 } 303 304 305 bool 306 BSoundPlayer::HasData() 307 { 308 CALLED(); 309 return (atomic_get(&fFlags) & F_HAS_DATA) != 0; 310 } 311 312 313 BSoundPlayer::BufferPlayerFunc 314 BSoundPlayer::BufferPlayer() const 315 { 316 CALLED(); 317 return fPlayBufferFunc; 318 } 319 320 321 void 322 BSoundPlayer::SetBufferPlayer(BufferPlayerFunc playerFunction) 323 { 324 CALLED(); 325 BAutolock _(fLocker); 326 327 fPlayBufferFunc = playerFunction; 328 } 329 330 331 BSoundPlayer::EventNotifierFunc 332 BSoundPlayer::EventNotifier() const 333 { 334 CALLED(); 335 return fNotifierFunc; 336 } 337 338 339 void 340 BSoundPlayer::SetNotifier(EventNotifierFunc eventNotifierFunction) 341 { 342 CALLED(); 343 BAutolock _(fLocker); 344 345 fNotifierFunc = eventNotifierFunction; 346 } 347 348 349 void* 350 BSoundPlayer::Cookie() const 351 { 352 CALLED(); 353 return fCookie; 354 } 355 356 357 void 358 BSoundPlayer::SetCookie(void *cookie) 359 { 360 CALLED(); 361 BAutolock _(fLocker); 362 363 fCookie = cookie; 364 } 365 366 367 void 368 BSoundPlayer::SetCallbacks(BufferPlayerFunc playerFunction, 369 EventNotifierFunc eventNotifierFunction, void* cookie) 370 { 371 CALLED(); 372 BAutolock _(fLocker); 373 374 SetBufferPlayer(playerFunction); 375 SetNotifier(eventNotifierFunction); 376 SetCookie(cookie); 377 } 378 379 380 /*! The BeBook is inaccurate about the meaning of this function. 381 The probably best interpretation is to return the time that 382 has elapsed since playing was started, whichs seems to match 383 "CurrentTime() returns the current media time" 384 */ 385 bigtime_t 386 BSoundPlayer::CurrentTime() 387 { 388 if ((fFlags & F_NODES_CONNECTED) == 0) 389 return 0; 390 391 return fPlayerNode->CurrentTime(); 392 } 393 394 395 /*! Returns the current performance time of the sound player node 396 being used by the BSoundPlayer. Will return B_ERROR if the 397 BSoundPlayer object hasn't been properly initialized. 398 */ 399 bigtime_t 400 BSoundPlayer::PerformanceTime() 401 { 402 if ((fFlags & F_NODES_CONNECTED) == 0) 403 return (bigtime_t) B_ERROR; 404 405 return fPlayerNode->TimeSource()->Now(); 406 } 407 408 409 status_t 410 BSoundPlayer::Preroll() 411 { 412 CALLED(); 413 414 if ((fFlags & F_NODES_CONNECTED) == 0) 415 return B_NO_INIT; 416 417 BMediaRoster* roster = BMediaRoster::Roster(); 418 if (roster == NULL) { 419 TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n"); 420 return B_ERROR; 421 } 422 423 status_t err = roster->PrerollNode(fMediaOutput.node); 424 if (err != B_OK) { 425 TRACE("BSoundPlayer::Preroll: Error while PrerollNode: %ld (%s)\n", 426 err, strerror(err)); 427 return err; 428 } 429 430 return B_OK; 431 } 432 433 434 BSoundPlayer::play_id 435 BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime) 436 { 437 return StartPlaying(sound, atTime, 1.0); 438 } 439 440 441 BSoundPlayer::play_id 442 BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime, float withVolume) 443 { 444 CALLED(); 445 446 // TODO: support the at_time and with_volume parameters 447 playing_sound* item = (playing_sound*)malloc(sizeof(playing_sound)); 448 if (item == NULL) 449 return B_NO_MEMORY; 450 451 item->current_offset = 0; 452 item->sound = sound; 453 item->id = atomic_add(&sCurrentPlayID, 1); 454 item->delta = 0; 455 item->rate = 0; 456 item->volume = withVolume; 457 458 if (!fLocker.Lock()) { 459 free(item); 460 return B_ERROR; 461 } 462 463 sound->AcquireRef(); 464 item->next = fPlayingSounds; 465 fPlayingSounds = item; 466 fLocker.Unlock(); 467 468 SetHasData(true); 469 return item->id; 470 } 471 472 473 status_t 474 BSoundPlayer::SetSoundVolume(play_id id, float newVolume) 475 { 476 CALLED(); 477 if (!fLocker.Lock()) 478 return B_ERROR; 479 480 playing_sound *item = fPlayingSounds; 481 while (item) { 482 if (item->id == id) { 483 item->volume = newVolume; 484 fLocker.Unlock(); 485 return B_OK; 486 } 487 488 item = item->next; 489 } 490 491 fLocker.Unlock(); 492 return B_ENTRY_NOT_FOUND; 493 } 494 495 496 bool 497 BSoundPlayer::IsPlaying(play_id id) 498 { 499 CALLED(); 500 if (!fLocker.Lock()) 501 return B_ERROR; 502 503 playing_sound *item = fPlayingSounds; 504 while (item) { 505 if (item->id == id) { 506 fLocker.Unlock(); 507 return true; 508 } 509 510 item = item->next; 511 } 512 513 fLocker.Unlock(); 514 return false; 515 } 516 517 518 status_t 519 BSoundPlayer::StopPlaying(play_id id) 520 { 521 CALLED(); 522 if (!fLocker.Lock()) 523 return B_ERROR; 524 525 playing_sound** link = &fPlayingSounds; 526 playing_sound* item = fPlayingSounds; 527 528 while (item != NULL) { 529 if (item->id == id) { 530 *link = item->next; 531 sem_id waitSem = item->wait_sem; 532 item->sound->ReleaseRef(); 533 free(item); 534 fLocker.Unlock(); 535 536 _NotifySoundDone(id, true); 537 if (waitSem >= 0) 538 release_sem(waitSem); 539 540 return B_OK; 541 } 542 543 link = &item->next; 544 item = item->next; 545 } 546 547 fLocker.Unlock(); 548 return B_ENTRY_NOT_FOUND; 549 } 550 551 552 status_t 553 BSoundPlayer::WaitForSound(play_id id) 554 { 555 CALLED(); 556 if (!fLocker.Lock()) 557 return B_ERROR; 558 559 playing_sound* item = fPlayingSounds; 560 while (item != NULL) { 561 if (item->id == id) { 562 sem_id waitSem = item->wait_sem; 563 if (waitSem < 0) 564 waitSem = item->wait_sem = create_sem(0, "wait for sound"); 565 566 fLocker.Unlock(); 567 return acquire_sem(waitSem); 568 } 569 570 item = item->next; 571 } 572 573 fLocker.Unlock(); 574 return B_ENTRY_NOT_FOUND; 575 } 576 577 578 float 579 BSoundPlayer::Volume() 580 { 581 CALLED(); 582 return pow(10.0, VolumeDB(true) / 20.0); 583 } 584 585 586 void 587 BSoundPlayer::SetVolume(float newVolume) 588 { 589 CALLED(); 590 SetVolumeDB(20.0 * log10(newVolume)); 591 } 592 593 594 float 595 BSoundPlayer::VolumeDB(bool forcePoll) 596 { 597 CALLED(); 598 if (!fVolumeSlider) 599 return -94.0f; // silence 600 601 if (!forcePoll && system_time() - fLastVolumeUpdate < 500000) 602 return fVolumeDB; 603 604 int32 count = fVolumeSlider->CountChannels(); 605 float values[count]; 606 size_t size = count * sizeof(float); 607 fVolumeSlider->GetValue(&values, &size, NULL); 608 fLastVolumeUpdate = system_time(); 609 fVolumeDB = values[0]; 610 611 return values[0]; 612 } 613 614 615 void 616 BSoundPlayer::SetVolumeDB(float volumeDB) 617 { 618 CALLED(); 619 if (!fVolumeSlider) 620 return; 621 622 float minDB = fVolumeSlider->MinValue(); 623 float maxDB = fVolumeSlider->MaxValue(); 624 if (volumeDB < minDB) 625 volumeDB = minDB; 626 if (volumeDB > maxDB) 627 volumeDB = maxDB; 628 629 int count = fVolumeSlider->CountChannels(); 630 float values[count]; 631 for (int i = 0; i < count; i++) 632 values[i] = volumeDB; 633 fVolumeSlider->SetValue(values, sizeof(float) * count, 0); 634 635 fVolumeDB = volumeDB; 636 fLastVolumeUpdate = system_time(); 637 } 638 639 640 status_t 641 BSoundPlayer::GetVolumeInfo(media_node* _node, int32* _parameterID, 642 float* _minDB, float* _maxDB) 643 { 644 CALLED(); 645 if (fVolumeSlider == NULL) 646 return B_NO_INIT; 647 648 if (_node != NULL) 649 *_node = fMediaInput.node; 650 if (_parameterID != NULL) 651 *_parameterID = fVolumeSlider->ID(); 652 if (_minDB != NULL) 653 *_minDB = fVolumeSlider->MinValue(); 654 if (_maxDB != NULL) 655 *_maxDB = fVolumeSlider->MaxValue(); 656 657 return B_OK; 658 } 659 660 661 // #pragma mark - protected BSoundPlayer 662 663 664 void 665 BSoundPlayer::SetInitError(status_t error) 666 { 667 CALLED(); 668 fInitStatus = error; 669 } 670 671 672 // #pragma mark - private BSoundPlayer 673 674 675 void 676 BSoundPlayer::_SoundPlayBufferFunc(void *cookie, void *buffer, size_t size, 677 const media_raw_audio_format &format) 678 { 679 // TODO: support more than one sound and make use of the format parameter 680 BSoundPlayer *player = (BSoundPlayer *)cookie; 681 if (!player->fLocker.Lock()) { 682 memset(buffer, 0, size); 683 return; 684 } 685 686 playing_sound *sound = player->fPlayingSounds; 687 if (sound == NULL) { 688 player->SetHasData(false); 689 player->fLocker.Unlock(); 690 memset(buffer, 0, size); 691 return; 692 } 693 694 size_t used = 0; 695 if (!sound->sound->GetDataAt(sound->current_offset, buffer, size, &used)) { 696 // will take care of removing the item and notifying others 697 player->StopPlaying(sound->id); 698 player->fLocker.Unlock(); 699 memset(buffer, 0, size); 700 return; 701 } 702 703 sound->current_offset += used; 704 player->fLocker.Unlock(); 705 706 if (used < size) 707 memset((uint8 *)buffer + used, 0, size - used); 708 } 709 710 711 status_t BSoundPlayer::_Reserved_SoundPlayer_0(void*, ...) { return B_ERROR; } 712 status_t BSoundPlayer::_Reserved_SoundPlayer_1(void*, ...) { return B_ERROR; } 713 status_t BSoundPlayer::_Reserved_SoundPlayer_2(void*, ...) { return B_ERROR; } 714 status_t BSoundPlayer::_Reserved_SoundPlayer_3(void*, ...) { return B_ERROR; } 715 status_t BSoundPlayer::_Reserved_SoundPlayer_4(void*, ...) { return B_ERROR; } 716 status_t BSoundPlayer::_Reserved_SoundPlayer_5(void*, ...) { return B_ERROR; } 717 status_t BSoundPlayer::_Reserved_SoundPlayer_6(void*, ...) { return B_ERROR; } 718 status_t BSoundPlayer::_Reserved_SoundPlayer_7(void*, ...) { return B_ERROR; } 719 720 721 void 722 BSoundPlayer::_Init(const media_node* node, 723 const media_multi_audio_format* format, const char* name, 724 const media_input* input, BufferPlayerFunc playerFunction, 725 EventNotifierFunc eventNotifierFunction, void* cookie) 726 { 727 CALLED(); 728 fPlayingSounds = NULL; 729 fWaitingSounds = NULL; 730 731 fPlayerNode = NULL; 732 if (playerFunction == NULL) { 733 fPlayBufferFunc = _SoundPlayBufferFunc; 734 fCookie = this; 735 } else { 736 fPlayBufferFunc = playerFunction; 737 fCookie = cookie; 738 } 739 740 fNotifierFunc = eventNotifierFunction; 741 fVolumeDB = 0.0f; 742 fFlags = 0; 743 fInitStatus = B_ERROR; 744 fParameterWeb = NULL; 745 fVolumeSlider = NULL; 746 fLastVolumeUpdate = 0; 747 748 BMediaRoster* roster = BMediaRoster::Roster(); 749 if (roster == NULL) { 750 TRACE("BSoundPlayer::_Init: Couldn't get BMediaRoster\n"); 751 return; 752 } 753 754 // The inputNode that our player node will be 755 // connected with is either supplied by the user 756 // or the system audio mixer 757 media_node inputNode; 758 if (node) { 759 inputNode = *node; 760 } else { 761 fInitStatus = roster->GetAudioMixer(&inputNode); 762 if (fInitStatus != B_OK) { 763 TRACE("BSoundPlayer::_Init: Couldn't GetAudioMixer\n"); 764 return; 765 } 766 fFlags |= F_MUST_RELEASE_MIXER; 767 } 768 769 media_output _output; 770 media_input _input; 771 int32 inputCount; 772 int32 outputCount; 773 media_format tryFormat; 774 775 // Create the player node and register it 776 fPlayerNode = new BPrivate::SoundPlayNode(name, this); 777 fInitStatus = roster->RegisterNode(fPlayerNode); 778 if (fInitStatus != B_OK) { 779 TRACE("BSoundPlayer::_Init: Couldn't RegisterNode: %s\n", 780 strerror(fInitStatus)); 781 return; 782 } 783 784 // set the producer's time source to be the "default" time source, 785 // which the system audio mixer uses too. 786 media_node timeSource; 787 fInitStatus = roster->GetTimeSource(&timeSource); 788 if (fInitStatus != B_OK) { 789 TRACE("BSoundPlayer::_Init: Couldn't GetTimeSource: %s\n", 790 strerror(fInitStatus)); 791 return; 792 } 793 fInitStatus = roster->SetTimeSourceFor(fPlayerNode->Node().node, 794 timeSource.node); 795 if (fInitStatus != B_OK) { 796 TRACE("BSoundPlayer::_Init: Couldn't SetTimeSourceFor: %s\n", 797 strerror(fInitStatus)); 798 return; 799 } 800 801 // find a free media_input 802 if (!input) { 803 fInitStatus = roster->GetFreeInputsFor(inputNode, &_input, 1, 804 &inputCount, B_MEDIA_RAW_AUDIO); 805 if (fInitStatus != B_OK) { 806 TRACE("BSoundPlayer::_Init: Couldn't GetFreeInputsFor: %s\n", 807 strerror(fInitStatus)); 808 return; 809 } 810 if (inputCount < 1) { 811 TRACE("BSoundPlayer::_Init: Couldn't find a free input\n"); 812 fInitStatus = B_ERROR; 813 return; 814 } 815 } else { 816 _input = *input; 817 } 818 819 // find a free media_output 820 fInitStatus = roster->GetFreeOutputsFor(fPlayerNode->Node(), &_output, 1, 821 &outputCount, B_MEDIA_RAW_AUDIO); 822 if (fInitStatus != B_OK) { 823 TRACE("BSoundPlayer::_Init: Couldn't GetFreeOutputsFor: %s\n", 824 strerror(fInitStatus)); 825 return; 826 } 827 if (outputCount < 1) { 828 TRACE("BSoundPlayer::_Init: Couldn't find a free output\n"); 829 fInitStatus = B_ERROR; 830 return; 831 } 832 833 // Set an appropriate run mode for the producer 834 fInitStatus = roster->SetRunModeNode(fPlayerNode->Node(), 835 BMediaNode::B_INCREASE_LATENCY); 836 if (fInitStatus != B_OK) { 837 TRACE("BSoundPlayer::_Init: Couldn't SetRunModeNode: %s\n", 838 strerror(fInitStatus)); 839 return; 840 } 841 842 // setup our requested format (can still have many wildcards) 843 tryFormat.type = B_MEDIA_RAW_AUDIO; 844 tryFormat.u.raw_audio = *format; 845 846 #if DEBUG > 0 847 char buf[100]; 848 string_for_format(tryFormat, buf, sizeof(buf)); 849 TRACE("BSoundPlayer::_Init: trying to connect with format %s\n", buf); 850 #endif 851 852 // and connect the nodes 853 fInitStatus = roster->Connect(_output.source, _input.destination, 854 &tryFormat, &fMediaOutput, &fMediaInput); 855 if (fInitStatus != B_OK) { 856 TRACE("BSoundPlayer::_Init: Couldn't Connect: %s\n", 857 strerror(fInitStatus)); 858 return; 859 } 860 861 fFlags |= F_NODES_CONNECTED; 862 863 _GetVolumeSlider(); 864 865 TRACE("BSoundPlayer node %ld has timesource %ld\n", 866 fPlayerNode->Node().node, fPlayerNode->TimeSource()->Node().node); 867 } 868 869 870 void 871 BSoundPlayer::_NotifySoundDone(play_id id, bool gotToPlay) 872 { 873 CALLED(); 874 Notify(B_SOUND_DONE, id, gotToPlay); 875 } 876 877 878 void 879 BSoundPlayer::_GetVolumeSlider() 880 { 881 CALLED(); 882 883 ASSERT(fVolumeSlider == NULL); 884 885 BMediaRoster *roster = BMediaRoster::CurrentRoster(); 886 if (!roster) { 887 TRACE("BSoundPlayer::_GetVolumeSlider failed to get BMediaRoster"); 888 return; 889 } 890 891 if (!fParameterWeb && roster->GetParameterWebFor(fMediaInput.node, &fParameterWeb) < B_OK) { 892 TRACE("BSoundPlayer::_GetVolumeSlider couldn't get parameter web"); 893 return; 894 } 895 896 int count = fParameterWeb->CountParameters(); 897 for (int i = 0; i < count; i++) { 898 BParameter *parameter = fParameterWeb->ParameterAt(i); 899 if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER) 900 continue; 901 if ((parameter->ID() >> 16) != fMediaInput.destination.id) 902 continue; 903 if (strcmp(parameter->Kind(), B_GAIN) != 0) 904 continue; 905 fVolumeSlider = (BContinuousParameter *)parameter; 906 break; 907 } 908 909 #if DEBUG >0 910 if (!fVolumeSlider) { 911 TRACE("BSoundPlayer::_GetVolumeSlider couldn't find volume control"); 912 } 913 #endif 914 } 915 916 917 void 918 BSoundPlayer::Notify(sound_player_notification what, ...) 919 { 920 CALLED(); 921 if (fLocker.Lock()) { 922 if (fNotifierFunc) 923 (*fNotifierFunc)(fCookie, what); 924 fLocker.Unlock(); 925 } 926 } 927 928 929 void 930 BSoundPlayer::PlayBuffer(void* buffer, size_t size, 931 const media_raw_audio_format& format) 932 { 933 if (fLocker.Lock()) { 934 if (fPlayBufferFunc) 935 (*fPlayBufferFunc)(fCookie, buffer, size, format); 936 fLocker.Unlock(); 937 } 938 } 939 940 941 // #pragma mark - public sound_error 942 943 944 sound_error::sound_error(const char* string) 945 { 946 m_str_const = string; 947 } 948 949 950 const char* 951 sound_error::what() const throw() 952 { 953 return m_str_const; 954 } 955 956