headers/bsd: Add sys/queue.h.
[haiku.git] / src / kits / media / SoundPlayer.cpp
blobc62e1d7d6d8f1f9dcda721aa59dc22f083dc3841
1 /*
2 * Copyright 2002-2009, Haiku.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Marcus Overhagen
7 * Jérôme Duval
8 */
11 #include <SoundPlayer.h>
13 #include <math.h>
14 #include <string.h>
16 #include <Autolock.h>
17 #include <MediaRoster.h>
18 #include <ParameterWeb.h>
19 #include <Sound.h>
20 #include <TimeSource.h>
22 #include "SoundPlayNode.h"
24 #include "debug.h"
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),
36 static BSoundPlayer::play_id sCurrentPlayID = 1;
39 BSoundPlayer::BSoundPlayer(const char* name, BufferPlayerFunc playerFunction,
40 EventNotifierFunc eventNotifierFunction, void* cookie)
42 CALLED();
44 TRACE("BSoundPlayer::BSoundPlayer: default constructor used\n");
46 media_multi_audio_format format = media_multi_audio_format::wildcard;
48 _Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction,
49 cookie);
53 BSoundPlayer::BSoundPlayer(const media_raw_audio_format* _format,
54 const char* name, BufferPlayerFunc playerFunction,
55 EventNotifierFunc eventNotifierFunction, void* cookie)
57 CALLED();
59 TRACE("BSoundPlayer::BSoundPlayer: raw audio format constructor used\n");
61 media_multi_audio_format format = media_multi_audio_format::wildcard;
62 *(media_raw_audio_format*)&format = *_format;
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
71 _Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction,
72 cookie);
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)
81 CALLED();
83 TRACE("BSoundPlayer::BSoundPlayer: multi audio format constructor used\n");
85 if ((toNode.kind & B_BUFFER_CONSUMER) == 0)
86 debugger("BSoundPlayer: toNode must have B_BUFFER_CONSUMER kind!\n");
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
95 _Init(&toNode, format, name, input, playerFunction, eventNotifierFunction,
96 cookie);
100 BSoundPlayer::~BSoundPlayer()
102 CALLED();
104 if ((fFlags & F_IS_STARTED) != 0) {
105 // block, but don't flush
106 Stop(true, false);
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;
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 (err != B_OK) {
125 TRACE("BSoundPlayer::~BSoundPlayer: Error disconnecting nodes: "
126 "%" B_PRId32 " (%s)\n", err, strerror(err));
130 if ((fFlags & F_MUST_RELEASE_MIXER) != 0) {
131 // Release the mixer as it was acquired
132 // through BMediaRoster::GetAudioMixer()
133 err = roster->ReleaseNode(fMediaInput.node);
134 if (err != B_OK) {
135 TRACE("BSoundPlayer::~BSoundPlayer: Error releasing input node: "
136 "%" B_PRId32 " (%s)\n", err, strerror(err));
140 cleanup:
141 // Dispose of the player node
143 // We do not call BMediaRoster::ReleaseNode(), since
144 // the player was created by using "new". We could
145 // call BMediaRoster::UnregisterNode(), but this is
146 // supposed to be done by BMediaNode destructor automatically.
148 // The node is deleted by the Release() when ref count reach 0.
149 // Since we are the sole owners, and no one acquired it
150 // this should be the case. The Quit() synchronization
151 // is handled by the DeleteHook inheritance.
152 // NOTE: this might be crucial when using a BMediaEventLooper.
153 if (fPlayerNode->Release() != NULL) {
154 TRACE("BSoundPlayer::~BSoundPlayer: Error the producer node "
155 "appears to be acquired by someone else than us!");
158 // do not delete fVolumeSlider, it belongs to the parameter web
159 delete fParameterWeb;
163 status_t
164 BSoundPlayer::InitCheck()
166 CALLED();
167 return fInitStatus;
171 media_raw_audio_format
172 BSoundPlayer::Format() const
174 CALLED();
176 if ((fFlags & F_NODES_CONNECTED) == 0)
177 return media_raw_audio_format::wildcard;
179 return fPlayerNode->Format();
183 status_t
184 BSoundPlayer::Start()
186 CALLED();
188 if ((fFlags & F_NODES_CONNECTED) == 0)
189 return B_NO_INIT;
191 if ((fFlags & F_IS_STARTED) != 0)
192 return B_OK;
194 BMediaRoster* roster = BMediaRoster::Roster();
195 if (!roster) {
196 TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n");
197 return B_ERROR;
200 if (!fPlayerNode->TimeSource()->IsRunning()) {
201 roster->StartTimeSource(fPlayerNode->TimeSource()->Node(),
202 fPlayerNode->TimeSource()->RealTime());
205 // Add latency and a few ms to the nodes current time to
206 // make sure that we give the producer enough time to run
207 // buffers through the node chain, otherwise it'll start
208 // up already late
210 status_t err = roster->StartNode(fPlayerNode->Node(),
211 fPlayerNode->TimeSource()->Now() + Latency() + 5000);
212 if (err != B_OK) {
213 TRACE("BSoundPlayer::Start: StartNode failed, %" B_PRId32, err);
214 return err;
217 if (fNotifierFunc != NULL)
218 fNotifierFunc(fCookie, B_STARTED, this);
220 SetHasData(true);
221 atomic_or(&fFlags, F_IS_STARTED);
223 return B_OK;
227 void
228 BSoundPlayer::Stop(bool block, bool flush)
230 CALLED();
232 TRACE("BSoundPlayer::Stop: block %d, flush %d\n", (int)block, (int)flush);
234 if ((fFlags & F_NODES_CONNECTED) == 0)
235 return;
237 // TODO: flush is ignored
239 if ((fFlags & F_IS_STARTED) != 0) {
240 BMediaRoster* roster = BMediaRoster::Roster();
241 if (roster == NULL) {
242 TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n");
243 return;
246 roster->StopNode(fPlayerNode->Node(), 0, true);
248 atomic_and(&fFlags, ~F_IS_STARTED);
251 if (block) {
252 // wait until the node is stopped
253 int tries;
254 for (tries = 250; fPlayerNode->IsPlaying() && tries != 0; tries--)
255 snooze(2000);
257 DEBUG_ONLY(if (tries == 0)
258 TRACE("BSoundPlayer::Stop: waiting for node stop failed\n"));
260 // Wait until all buffers on the way to the physical output have been
261 // played
262 snooze(Latency() + 2000);
265 if (fNotifierFunc)
266 fNotifierFunc(fCookie, B_STOPPED, this);
271 bigtime_t
272 BSoundPlayer::Latency()
274 CALLED();
276 if ((fFlags & F_NODES_CONNECTED) == 0)
277 return 0;
279 BMediaRoster *roster = BMediaRoster::Roster();
280 if (!roster) {
281 TRACE("BSoundPlayer::Latency: Couldn't get BMediaRoster\n");
282 return 0;
285 bigtime_t latency;
286 status_t err = roster->GetLatencyFor(fMediaOutput.node, &latency);
287 if (err != B_OK) {
288 TRACE("BSoundPlayer::Latency: GetLatencyFor failed %" B_PRId32
289 " (%s)\n", err, strerror(err));
290 return 0;
293 TRACE("BSoundPlayer::Latency: latency is %" B_PRId64 "\n", latency);
295 return latency;
299 void
300 BSoundPlayer::SetHasData(bool hasData)
302 CALLED();
303 if (hasData)
304 atomic_or(&fFlags, F_HAS_DATA);
305 else
306 atomic_and(&fFlags, ~F_HAS_DATA);
310 bool
311 BSoundPlayer::HasData()
313 CALLED();
314 return (atomic_get(&fFlags) & F_HAS_DATA) != 0;
318 BSoundPlayer::BufferPlayerFunc
319 BSoundPlayer::BufferPlayer() const
321 CALLED();
322 return fPlayBufferFunc;
326 void
327 BSoundPlayer::SetBufferPlayer(BufferPlayerFunc playerFunction)
329 CALLED();
330 BAutolock _(fLocker);
332 fPlayBufferFunc = playerFunction;
336 BSoundPlayer::EventNotifierFunc
337 BSoundPlayer::EventNotifier() const
339 CALLED();
340 return fNotifierFunc;
344 void
345 BSoundPlayer::SetNotifier(EventNotifierFunc eventNotifierFunction)
347 CALLED();
348 BAutolock _(fLocker);
350 fNotifierFunc = eventNotifierFunction;
354 void*
355 BSoundPlayer::Cookie() const
357 CALLED();
358 return fCookie;
362 void
363 BSoundPlayer::SetCookie(void *cookie)
365 CALLED();
366 BAutolock _(fLocker);
368 fCookie = cookie;
372 void
373 BSoundPlayer::SetCallbacks(BufferPlayerFunc playerFunction,
374 EventNotifierFunc eventNotifierFunction, void* cookie)
376 CALLED();
377 BAutolock _(fLocker);
379 SetBufferPlayer(playerFunction);
380 SetNotifier(eventNotifierFunction);
381 SetCookie(cookie);
385 /*! The BeBook is inaccurate about the meaning of this function.
386 The probably best interpretation is to return the time that
387 has elapsed since playing was started, whichs seems to match
388 "CurrentTime() returns the current media time"
390 bigtime_t
391 BSoundPlayer::CurrentTime()
393 if ((fFlags & F_NODES_CONNECTED) == 0)
394 return 0;
396 return fPlayerNode->CurrentTime();
400 /*! Returns the current performance time of the sound player node
401 being used by the BSoundPlayer. Will return B_ERROR if the
402 BSoundPlayer object hasn't been properly initialized.
404 bigtime_t
405 BSoundPlayer::PerformanceTime()
407 if ((fFlags & F_NODES_CONNECTED) == 0)
408 return (bigtime_t) B_ERROR;
410 return fPlayerNode->TimeSource()->Now();
414 status_t
415 BSoundPlayer::Preroll()
417 CALLED();
419 if ((fFlags & F_NODES_CONNECTED) == 0)
420 return B_NO_INIT;
422 BMediaRoster* roster = BMediaRoster::Roster();
423 if (roster == NULL) {
424 TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n");
425 return B_ERROR;
428 status_t err = roster->PrerollNode(fMediaOutput.node);
429 if (err != B_OK) {
430 TRACE("BSoundPlayer::Preroll: Error while PrerollNode: %"
431 B_PRId32 " (%s)\n", err, strerror(err));
432 return err;
435 return B_OK;
439 BSoundPlayer::play_id
440 BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime)
442 return StartPlaying(sound, atTime, 1.0);
446 BSoundPlayer::play_id
447 BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime, float withVolume)
449 CALLED();
451 // TODO: support the at_time and with_volume parameters
452 playing_sound* item = (playing_sound*)malloc(sizeof(playing_sound));
453 if (item == NULL)
454 return B_NO_MEMORY;
456 item->current_offset = 0;
457 item->sound = sound;
458 item->id = atomic_add(&sCurrentPlayID, 1);
459 item->delta = 0;
460 item->rate = 0;
461 item->volume = withVolume;
463 if (!fLocker.Lock()) {
464 free(item);
465 return B_ERROR;
468 sound->AcquireRef();
469 item->next = fPlayingSounds;
470 fPlayingSounds = item;
471 fLocker.Unlock();
473 SetHasData(true);
474 return item->id;
478 status_t
479 BSoundPlayer::SetSoundVolume(play_id id, float newVolume)
481 CALLED();
482 if (!fLocker.Lock())
483 return B_ERROR;
485 playing_sound *item = fPlayingSounds;
486 while (item) {
487 if (item->id == id) {
488 item->volume = newVolume;
489 fLocker.Unlock();
490 return B_OK;
493 item = item->next;
496 fLocker.Unlock();
497 return B_ENTRY_NOT_FOUND;
501 bool
502 BSoundPlayer::IsPlaying(play_id id)
504 CALLED();
505 if (!fLocker.Lock())
506 return B_ERROR;
508 playing_sound *item = fPlayingSounds;
509 while (item) {
510 if (item->id == id) {
511 fLocker.Unlock();
512 return true;
515 item = item->next;
518 fLocker.Unlock();
519 return false;
523 status_t
524 BSoundPlayer::StopPlaying(play_id id)
526 CALLED();
527 if (!fLocker.Lock())
528 return B_ERROR;
530 playing_sound** link = &fPlayingSounds;
531 playing_sound* item = fPlayingSounds;
533 while (item != NULL) {
534 if (item->id == id) {
535 *link = item->next;
536 sem_id waitSem = item->wait_sem;
537 item->sound->ReleaseRef();
538 free(item);
539 fLocker.Unlock();
541 _NotifySoundDone(id, true);
542 if (waitSem >= 0)
543 release_sem(waitSem);
545 return B_OK;
548 link = &item->next;
549 item = item->next;
552 fLocker.Unlock();
553 return B_ENTRY_NOT_FOUND;
557 status_t
558 BSoundPlayer::WaitForSound(play_id id)
560 CALLED();
561 if (!fLocker.Lock())
562 return B_ERROR;
564 playing_sound* item = fPlayingSounds;
565 while (item != NULL) {
566 if (item->id == id) {
567 sem_id waitSem = item->wait_sem;
568 if (waitSem < 0)
569 waitSem = item->wait_sem = create_sem(0, "wait for sound");
571 fLocker.Unlock();
572 return acquire_sem(waitSem);
575 item = item->next;
578 fLocker.Unlock();
579 return B_ENTRY_NOT_FOUND;
583 float
584 BSoundPlayer::Volume()
586 CALLED();
587 return pow(10.0, VolumeDB(true) / 20.0);
591 void
592 BSoundPlayer::SetVolume(float newVolume)
594 CALLED();
595 SetVolumeDB(20.0 * log10(newVolume));
599 float
600 BSoundPlayer::VolumeDB(bool forcePoll)
602 CALLED();
603 if (!fVolumeSlider)
604 return -94.0f; // silence
606 if (!forcePoll && system_time() - fLastVolumeUpdate < 500000)
607 return fVolumeDB;
609 int32 count = fVolumeSlider->CountChannels();
610 float values[count];
611 size_t size = count * sizeof(float);
612 fVolumeSlider->GetValue(&values, &size, NULL);
613 fLastVolumeUpdate = system_time();
614 fVolumeDB = values[0];
616 return values[0];
620 void
621 BSoundPlayer::SetVolumeDB(float volumeDB)
623 CALLED();
624 if (!fVolumeSlider)
625 return;
627 float minDB = fVolumeSlider->MinValue();
628 float maxDB = fVolumeSlider->MaxValue();
629 if (volumeDB < minDB)
630 volumeDB = minDB;
631 if (volumeDB > maxDB)
632 volumeDB = maxDB;
634 int count = fVolumeSlider->CountChannels();
635 float values[count];
636 for (int i = 0; i < count; i++)
637 values[i] = volumeDB;
638 fVolumeSlider->SetValue(values, sizeof(float) * count, 0);
640 fVolumeDB = volumeDB;
641 fLastVolumeUpdate = system_time();
645 status_t
646 BSoundPlayer::GetVolumeInfo(media_node* _node, int32* _parameterID,
647 float* _minDB, float* _maxDB)
649 CALLED();
650 if (fVolumeSlider == NULL)
651 return B_NO_INIT;
653 if (_node != NULL)
654 *_node = fMediaInput.node;
655 if (_parameterID != NULL)
656 *_parameterID = fVolumeSlider->ID();
657 if (_minDB != NULL)
658 *_minDB = fVolumeSlider->MinValue();
659 if (_maxDB != NULL)
660 *_maxDB = fVolumeSlider->MaxValue();
662 return B_OK;
666 // #pragma mark - protected BSoundPlayer
669 void
670 BSoundPlayer::SetInitError(status_t error)
672 CALLED();
673 fInitStatus = error;
677 // #pragma mark - private BSoundPlayer
680 void
681 BSoundPlayer::_SoundPlayBufferFunc(void *cookie, void *buffer, size_t size,
682 const media_raw_audio_format &format)
684 // TODO: support more than one sound and make use of the format parameter
685 BSoundPlayer *player = (BSoundPlayer *)cookie;
686 if (!player->fLocker.Lock()) {
687 memset(buffer, 0, size);
688 return;
691 playing_sound *sound = player->fPlayingSounds;
692 if (sound == NULL) {
693 player->SetHasData(false);
694 player->fLocker.Unlock();
695 memset(buffer, 0, size);
696 return;
699 size_t used = 0;
700 if (!sound->sound->GetDataAt(sound->current_offset, buffer, size, &used)) {
701 // will take care of removing the item and notifying others
702 player->StopPlaying(sound->id);
703 player->fLocker.Unlock();
704 memset(buffer, 0, size);
705 return;
708 sound->current_offset += used;
709 player->fLocker.Unlock();
711 if (used < size)
712 memset((uint8 *)buffer + used, 0, size - used);
716 status_t BSoundPlayer::_Reserved_SoundPlayer_0(void*, ...) { return B_ERROR; }
717 status_t BSoundPlayer::_Reserved_SoundPlayer_1(void*, ...) { return B_ERROR; }
718 status_t BSoundPlayer::_Reserved_SoundPlayer_2(void*, ...) { return B_ERROR; }
719 status_t BSoundPlayer::_Reserved_SoundPlayer_3(void*, ...) { return B_ERROR; }
720 status_t BSoundPlayer::_Reserved_SoundPlayer_4(void*, ...) { return B_ERROR; }
721 status_t BSoundPlayer::_Reserved_SoundPlayer_5(void*, ...) { return B_ERROR; }
722 status_t BSoundPlayer::_Reserved_SoundPlayer_6(void*, ...) { return B_ERROR; }
723 status_t BSoundPlayer::_Reserved_SoundPlayer_7(void*, ...) { return B_ERROR; }
726 void
727 BSoundPlayer::_Init(const media_node* node,
728 const media_multi_audio_format* format, const char* name,
729 const media_input* input, BufferPlayerFunc playerFunction,
730 EventNotifierFunc eventNotifierFunction, void* cookie)
732 CALLED();
733 fPlayingSounds = NULL;
734 fWaitingSounds = NULL;
736 fPlayerNode = NULL;
737 if (playerFunction == NULL) {
738 fPlayBufferFunc = _SoundPlayBufferFunc;
739 fCookie = this;
740 } else {
741 fPlayBufferFunc = playerFunction;
742 fCookie = cookie;
745 fNotifierFunc = eventNotifierFunction;
746 fVolumeDB = 0.0f;
747 fFlags = 0;
748 fInitStatus = B_ERROR;
749 fParameterWeb = NULL;
750 fVolumeSlider = NULL;
751 fLastVolumeUpdate = 0;
753 BMediaRoster* roster = BMediaRoster::Roster();
754 if (roster == NULL) {
755 TRACE("BSoundPlayer::_Init: Couldn't get BMediaRoster\n");
756 return;
759 // The inputNode that our player node will be
760 // connected with is either supplied by the user
761 // or the system audio mixer
762 media_node inputNode;
763 if (node) {
764 inputNode = *node;
765 } else {
766 fInitStatus = roster->GetAudioMixer(&inputNode);
767 if (fInitStatus != B_OK) {
768 TRACE("BSoundPlayer::_Init: Couldn't GetAudioMixer\n");
769 return;
771 fFlags |= F_MUST_RELEASE_MIXER;
774 media_output _output;
775 media_input _input;
776 int32 inputCount;
777 int32 outputCount;
778 media_format tryFormat;
780 // Create the player node and register it
781 fPlayerNode = new BPrivate::SoundPlayNode(name, this);
782 fInitStatus = roster->RegisterNode(fPlayerNode);
783 if (fInitStatus != B_OK) {
784 TRACE("BSoundPlayer::_Init: Couldn't RegisterNode: %s\n",
785 strerror(fInitStatus));
786 return;
789 // set the producer's time source to be the "default" time source,
790 // which the system audio mixer uses too.
791 media_node timeSource;
792 fInitStatus = roster->GetTimeSource(&timeSource);
793 if (fInitStatus != B_OK) {
794 TRACE("BSoundPlayer::_Init: Couldn't GetTimeSource: %s\n",
795 strerror(fInitStatus));
796 return;
798 fInitStatus = roster->SetTimeSourceFor(fPlayerNode->Node().node,
799 timeSource.node);
800 if (fInitStatus != B_OK) {
801 TRACE("BSoundPlayer::_Init: Couldn't SetTimeSourceFor: %s\n",
802 strerror(fInitStatus));
803 return;
806 // find a free media_input
807 if (!input) {
808 fInitStatus = roster->GetFreeInputsFor(inputNode, &_input, 1,
809 &inputCount, B_MEDIA_RAW_AUDIO);
810 if (fInitStatus != B_OK) {
811 TRACE("BSoundPlayer::_Init: Couldn't GetFreeInputsFor: %s\n",
812 strerror(fInitStatus));
813 return;
815 if (inputCount < 1) {
816 TRACE("BSoundPlayer::_Init: Couldn't find a free input\n");
817 fInitStatus = B_ERROR;
818 return;
820 } else {
821 _input = *input;
824 // find a free media_output
825 fInitStatus = roster->GetFreeOutputsFor(fPlayerNode->Node(), &_output, 1,
826 &outputCount, B_MEDIA_RAW_AUDIO);
827 if (fInitStatus != B_OK) {
828 TRACE("BSoundPlayer::_Init: Couldn't GetFreeOutputsFor: %s\n",
829 strerror(fInitStatus));
830 return;
832 if (outputCount < 1) {
833 TRACE("BSoundPlayer::_Init: Couldn't find a free output\n");
834 fInitStatus = B_ERROR;
835 return;
838 // Set an appropriate run mode for the producer
839 fInitStatus = roster->SetRunModeNode(fPlayerNode->Node(),
840 BMediaNode::B_INCREASE_LATENCY);
841 if (fInitStatus != B_OK) {
842 TRACE("BSoundPlayer::_Init: Couldn't SetRunModeNode: %s\n",
843 strerror(fInitStatus));
844 return;
847 // setup our requested format (can still have many wildcards)
848 tryFormat.type = B_MEDIA_RAW_AUDIO;
849 tryFormat.u.raw_audio = *format;
851 #if DEBUG > 0
852 char buf[100];
853 string_for_format(tryFormat, buf, sizeof(buf));
854 TRACE("BSoundPlayer::_Init: trying to connect with format %s\n", buf);
855 #endif
857 // and connect the nodes
858 fInitStatus = roster->Connect(_output.source, _input.destination,
859 &tryFormat, &fMediaOutput, &fMediaInput);
860 if (fInitStatus != B_OK) {
861 TRACE("BSoundPlayer::_Init: Couldn't Connect: %s\n",
862 strerror(fInitStatus));
863 return;
866 fFlags |= F_NODES_CONNECTED;
868 _GetVolumeSlider();
870 TRACE("BSoundPlayer node %" B_PRId32 " has timesource %" B_PRId32 "\n",
871 fPlayerNode->Node().node, fPlayerNode->TimeSource()->Node().node);
875 void
876 BSoundPlayer::_NotifySoundDone(play_id id, bool gotToPlay)
878 CALLED();
879 Notify(B_SOUND_DONE, id, gotToPlay);
883 void
884 BSoundPlayer::_GetVolumeSlider()
886 CALLED();
888 ASSERT(fVolumeSlider == NULL);
890 BMediaRoster *roster = BMediaRoster::CurrentRoster();
891 if (!roster) {
892 TRACE("BSoundPlayer::_GetVolumeSlider failed to get BMediaRoster");
893 return;
896 if (!fParameterWeb && roster->GetParameterWebFor(fMediaInput.node, &fParameterWeb) < B_OK) {
897 TRACE("BSoundPlayer::_GetVolumeSlider couldn't get parameter web");
898 return;
901 int count = fParameterWeb->CountParameters();
902 for (int i = 0; i < count; i++) {
903 BParameter *parameter = fParameterWeb->ParameterAt(i);
904 if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER)
905 continue;
906 if ((parameter->ID() >> 16) != fMediaInput.destination.id)
907 continue;
908 if (strcmp(parameter->Kind(), B_GAIN) != 0)
909 continue;
910 fVolumeSlider = (BContinuousParameter *)parameter;
911 break;
914 #if DEBUG >0
915 if (!fVolumeSlider) {
916 TRACE("BSoundPlayer::_GetVolumeSlider couldn't find volume control");
918 #endif
922 void
923 BSoundPlayer::Notify(sound_player_notification what, ...)
925 CALLED();
926 if (fLocker.Lock()) {
927 if (fNotifierFunc)
928 (*fNotifierFunc)(fCookie, what);
929 fLocker.Unlock();
934 void
935 BSoundPlayer::PlayBuffer(void* buffer, size_t size,
936 const media_raw_audio_format& format)
938 if (fLocker.Lock()) {
939 if (fPlayBufferFunc)
940 (*fPlayBufferFunc)(fCookie, buffer, size, format);
941 fLocker.Unlock();
946 // #pragma mark - public sound_error
949 sound_error::sound_error(const char* string)
951 m_str_const = string;
955 const char*
956 sound_error::what() const throw()
958 return m_str_const;