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