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