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 item->next = fPlayingSounds; 613 fPlayingSounds = item; 614 fLocker.Unlock(); 615 616 SetHasData(true); 617 return item->id; 618 } 619 620 621 status_t 622 BSoundPlayer::SetSoundVolume(play_id id, float newVolume) 623 { 624 CALLED(); 625 if (!fLocker.Lock()) 626 return B_ERROR; 627 628 _playing_sound *item = fPlayingSounds; 629 while (item) { 630 if (item->id == id) { 631 item->volume = newVolume; 632 fLocker.Unlock(); 633 return B_OK; 634 } 635 636 item = item->next; 637 } 638 639 fLocker.Unlock(); 640 return B_ENTRY_NOT_FOUND; 641 } 642 643 644 bool 645 BSoundPlayer::IsPlaying(play_id id) 646 { 647 CALLED(); 648 if (!fLocker.Lock()) 649 return B_ERROR; 650 651 _playing_sound *item = fPlayingSounds; 652 while (item) { 653 if (item->id == id) { 654 fLocker.Unlock(); 655 return true; 656 } 657 658 item = item->next; 659 } 660 661 fLocker.Unlock(); 662 return false; 663 } 664 665 666 status_t 667 BSoundPlayer::StopPlaying(play_id id) 668 { 669 CALLED(); 670 if (!fLocker.Lock()) 671 return B_ERROR; 672 673 _playing_sound **link = &fPlayingSounds; 674 _playing_sound *item = fPlayingSounds; 675 while (item) { 676 if (item->id == id) { 677 *link = item->next; 678 sem_id waitSem = item->wait_sem; 679 free(item); 680 fLocker.Unlock(); 681 682 NotifySoundDone(id, true); 683 if (waitSem >= 0) 684 release_sem(waitSem); 685 686 return B_OK; 687 } 688 689 link = &item->next; 690 item = item->next; 691 } 692 693 fLocker.Unlock(); 694 return B_ENTRY_NOT_FOUND; 695 } 696 697 698 status_t 699 BSoundPlayer::WaitForSound(play_id id) 700 { 701 CALLED(); 702 if (!fLocker.Lock()) 703 return B_ERROR; 704 705 _playing_sound *item = fPlayingSounds; 706 while (item) { 707 if (item->id == id) { 708 sem_id waitSem = item->wait_sem; 709 if (waitSem < 0) 710 waitSem = item->wait_sem = create_sem(0, "wait for sound"); 711 712 fLocker.Unlock(); 713 return acquire_sem(waitSem); 714 } 715 716 item = item->next; 717 } 718 719 fLocker.Unlock(); 720 return B_ENTRY_NOT_FOUND; 721 } 722 723 724 float 725 BSoundPlayer::Volume() 726 { 727 CALLED(); 728 return pow(10.0, VolumeDB(true) / 20.0); 729 } 730 731 732 void 733 BSoundPlayer::SetVolume(float new_volume) 734 { 735 CALLED(); 736 SetVolumeDB(20.0 * log10(new_volume)); 737 } 738 739 740 float 741 BSoundPlayer::VolumeDB(bool forcePoll) 742 { 743 CALLED(); 744 if (!fVolumeSlider) 745 return -94.0f; // silence 746 747 if (!forcePoll && (system_time() - fLastVolumeUpdate < 500000)) 748 return fVolumeDB; 749 750 int32 count = fVolumeSlider->CountChannels(); 751 float values[count]; 752 size_t size = count * sizeof(float); 753 fVolumeSlider->GetValue(&values, &size, NULL); 754 fLastVolumeUpdate = system_time(); 755 fVolumeDB = values[0]; 756 757 return values[0]; 758 } 759 760 761 void 762 BSoundPlayer::SetVolumeDB(float volume_dB) 763 { 764 CALLED(); 765 if (!fVolumeSlider) 766 return; 767 768 float min_dB = fVolumeSlider->MinValue(); 769 float max_dB = fVolumeSlider->MaxValue(); 770 if (volume_dB < min_dB) 771 volume_dB = min_dB; 772 if (volume_dB > max_dB) 773 volume_dB = max_dB; 774 775 int count = fVolumeSlider->CountChannels(); 776 float values[count]; 777 for (int i = 0; i < count; i++) 778 values[i] = volume_dB; 779 fVolumeSlider->SetValue(values, sizeof(float) * count, 0); 780 781 fVolumeDB = volume_dB; 782 fLastVolumeUpdate = system_time(); 783 } 784 785 786 status_t 787 BSoundPlayer::GetVolumeInfo(media_node *out_node, 788 int32 *out_parameter_id, 789 float *out_min_dB, 790 float *out_max_dB) 791 { 792 CALLED(); 793 if (!fVolumeSlider) 794 return B_NO_INIT; 795 796 if (out_node) 797 *out_node = fMediaInput.node; 798 if (out_parameter_id) 799 *out_parameter_id = fVolumeSlider->ID(); 800 if (out_min_dB) 801 *out_min_dB = fVolumeSlider->MinValue(); 802 if (out_max_dB) 803 *out_max_dB = fVolumeSlider->MaxValue(); 804 return B_OK; 805 } 806 807 808 809 /************************************************************* 810 * protected BSoundPlayer 811 *************************************************************/ 812 813 814 void 815 BSoundPlayer::SetInitError(status_t in_error) 816 { 817 CALLED(); 818 fInitStatus = in_error; 819 } 820 821 822 /************************************************************* 823 * private BSoundPlayer 824 *************************************************************/ 825 826 void 827 BSoundPlayer::_SoundPlayBufferFunc(void *cookie, void *buffer, size_t size, 828 const media_raw_audio_format &format) 829 { 830 // TODO: support more than one sound and make use of the format parameter 831 BSoundPlayer *player = (BSoundPlayer *)cookie; 832 if (!player->fLocker.Lock()) { 833 memset(buffer, 0, size); 834 return; 835 } 836 837 _playing_sound *sound = player->fPlayingSounds; 838 if (sound == NULL) { 839 player->SetHasData(false); 840 player->fLocker.Unlock(); 841 memset(buffer, 0, size); 842 return; 843 } 844 845 size_t used = 0; 846 if (!sound->sound->GetDataAt(sound->current_offset, buffer, size, &used)) { 847 // will take care of removing the item and notifying others 848 player->StopPlaying(sound->id); 849 player->fLocker.Unlock(); 850 memset(buffer, 0, size); 851 return; 852 } 853 854 sound->current_offset += used; 855 player->fLocker.Unlock(); 856 857 if (used < size) 858 memset((uint8 *)buffer + used, 0, size - used); 859 } 860 861 862 status_t BSoundPlayer::_Reserved_SoundPlayer_0(void *, ...) { return B_ERROR; } 863 status_t BSoundPlayer::_Reserved_SoundPlayer_1(void *, ...) { return B_ERROR; } 864 status_t BSoundPlayer::_Reserved_SoundPlayer_2(void *, ...) { return B_ERROR; } 865 status_t BSoundPlayer::_Reserved_SoundPlayer_3(void *, ...) { return B_ERROR; } 866 status_t BSoundPlayer::_Reserved_SoundPlayer_4(void *, ...) { return B_ERROR; } 867 status_t BSoundPlayer::_Reserved_SoundPlayer_5(void *, ...) { return B_ERROR; } 868 status_t BSoundPlayer::_Reserved_SoundPlayer_6(void *, ...) { return B_ERROR; } 869 status_t BSoundPlayer::_Reserved_SoundPlayer_7(void *, ...) { return B_ERROR; } 870 871 872 void 873 BSoundPlayer::NotifySoundDone(play_id id, bool gotToPlay) 874 { 875 CALLED(); 876 Notify(B_SOUND_DONE, id, gotToPlay); 877 } 878 879 880 void 881 BSoundPlayer::get_volume_slider() 882 { 883 CALLED(); 884 885 ASSERT(fVolumeSlider == NULL); 886 887 BMediaRoster *roster = BMediaRoster::CurrentRoster(); 888 if (!roster) { 889 TRACE("BSoundPlayer::get_volume_slider failed to get BMediaRoster"); 890 return; 891 } 892 893 if (!fParameterWeb && roster->GetParameterWebFor(fMediaInput.node, &fParameterWeb) < B_OK) { 894 TRACE("BSoundPlayer::get_volume_slider couldn't get parameter web"); 895 return; 896 } 897 898 int count = fParameterWeb->CountParameters(); 899 for (int i = 0; i < count; i++) { 900 BParameter *parameter = fParameterWeb->ParameterAt(i); 901 if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER) 902 continue; 903 if ((parameter->ID() >> 16) != fMediaInput.destination.id) 904 continue; 905 if (strcmp(parameter->Kind(), B_GAIN) != 0) 906 continue; 907 fVolumeSlider = (BContinuousParameter *)parameter; 908 break; 909 } 910 911 #if DEBUG >0 912 if (!fVolumeSlider) { 913 TRACE("BSoundPlayer::get_volume_slider couldn't find volume control"); 914 } 915 #endif 916 } 917 918 919 /* virtual */ void 920 BSoundPlayer::Notify(sound_player_notification what, ...) 921 { 922 CALLED(); 923 if (fLocker.Lock()) { 924 if (fNotifierFunc) 925 (*fNotifierFunc)(fCookie, what); 926 fLocker.Unlock(); 927 } 928 } 929 930 931 /* virtual */ void 932 BSoundPlayer::PlayBuffer(void *buffer, size_t size, const media_raw_audio_format &format) 933 { 934 if (fLocker.Lock()) { 935 if (fPlayBufferFunc) 936 (*fPlayBufferFunc)(fCookie, buffer, size, format); 937 fLocker.Unlock(); 938 } 939 } 940 941 942 /************************************************************* 943 * public sound_error 944 *************************************************************/ 945 946 947 sound_error::sound_error(const char *str) 948 { 949 m_str_const = str; 950 } 951 952 953 const char * 954 sound_error::what() const throw () 955 { 956 return m_str_const; 957 } 958 959