xref: /haiku/src/kits/media/SoundPlayer.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
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(fMediaInput.node.node, fMediaInput.source,
267 			fMediaOutput.node.node, fMediaOutput.destination);
268 #if DEBUG >0
269 		if (err) {
270 			TRACE("BSoundPlayer::~BSoundPlayer: Error disconnecting nodes:  %ld (%s)\n", err, strerror(err));
271 		}
272 #endif
273 	}
274 
275 	if (fFlags & F_MUST_RELEASE_MIXER) {
276 		// Release the mixer as it was acquired
277 		// through BMediaRoster::GetAudioMixer()
278 		err = roster->ReleaseNode(fMediaInput.node);
279 #if DEBUG >0
280 		if (err) {
281 			TRACE("BSoundPlayer::~BSoundPlayer: Error releasing input node:  %ld (%s)\n", err, strerror(err));
282 		}
283 #endif
284 	}
285 
286 cleanup:
287 
288 	// Dispose of the player node
289 	if (fPlayerNode) {
290 		// We do not call BMediaRoster::ReleaseNode(), since
291 		// the player was created by using "new". We could
292 		// call BMediaRoster::UnregisterNode(), but this is
293 		// supposed to be done by BMediaNode destructor automatically
294 		delete fPlayerNode;
295 	}
296 
297 	delete fParameterWeb;
298 	// do not delete fVolumeSlider, it belonged to the parameter web
299 }
300 
301 
302 status_t
303 BSoundPlayer::InitCheck()
304 {
305 	CALLED();
306 	return fInitStatus;
307 }
308 
309 
310 media_raw_audio_format
311 BSoundPlayer::Format() const
312 {
313 	CALLED();
314 
315 	if ((fFlags & F_NODES_CONNECTED) == 0)
316 		return media_raw_audio_format::wildcard;
317 
318 	return fPlayerNode->Format();
319 }
320 
321 
322 status_t
323 BSoundPlayer::Start()
324 {
325 	CALLED();
326 
327 	if ((fFlags & F_NODES_CONNECTED) == 0)
328 		return B_NO_INIT;
329 
330 	if (fFlags & F_IS_STARTED)
331 		return B_OK;
332 
333 	BMediaRoster *roster = BMediaRoster::Roster();
334 	if (!roster) {
335 		TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n");
336 		return B_ERROR;
337 	}
338 
339 	// Add latency and a few ms to the nodes current time to
340 	// make sure that we give the producer enough time to run
341 	// buffers through the node chain, otherwise it'll start
342 	// up already late
343 
344 	status_t err = roster->StartNode(fPlayerNode->Node(), fPlayerNode->TimeSource()->Now() + Latency() + 5000);
345 	if (err != B_OK) {
346 		TRACE("BSoundPlayer::Start: StartNode failed, %ld", err);
347 		return err;
348 	}
349 
350 	atomic_or(&fFlags, F_IS_STARTED);
351 
352 	return B_OK;
353 }
354 
355 
356 void
357 BSoundPlayer::Stop(bool block,
358 				   bool flush)
359 {
360 	CALLED();
361 
362 	TRACE("BSoundPlayer::Stop: block %d, flush %d\n", (int)block, (int)flush);
363 
364 	if ((fFlags & F_NODES_CONNECTED) == 0)
365 		return;
366 
367 	// XXX flush is ignored
368 
369 	if (fFlags & F_IS_STARTED) {
370 
371 		BMediaRoster *roster = BMediaRoster::Roster();
372 		if (!roster) {
373 			TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n");
374 			return;
375 		}
376 
377 		roster->StopNode(fPlayerNode->Node(), 0, true);
378 
379 		atomic_and(&fFlags, ~F_IS_STARTED);
380 	}
381 
382 	if (block) {
383 		// wait until the node is stopped
384 		int maxtrys;
385 		for (maxtrys = 250; fPlayerNode->IsPlaying() && maxtrys != 0; maxtrys--)
386 			snooze(2000);
387 
388 		DEBUG_ONLY(if (maxtrys == 0) TRACE("BSoundPlayer::Stop: waiting for node stop failed\n"));
389 
390 		// wait until all buffers on the way to the physical output have been played
391 		snooze(Latency() + 2000);
392 	}
393 }
394 
395 
396 bigtime_t
397 BSoundPlayer::Latency()
398 {
399 	CALLED();
400 
401 	if ((fFlags & F_NODES_CONNECTED) == 0)
402 		return 0;
403 
404 	BMediaRoster *roster = BMediaRoster::Roster();
405 	if (!roster) {
406 		TRACE("BSoundPlayer::Latency: Couldn't get BMediaRoster\n");
407 		return 0;
408 	}
409 
410 	bigtime_t latency;
411 	status_t err = roster->GetLatencyFor(fMediaOutput.node, &latency);
412 	if (err != B_OK) {
413 		TRACE("BSoundPlayer::Latency: GetLatencyFor failed %ld (%s)\n", err, strerror(err));
414 		return 0;
415 	}
416 
417 	TRACE("BSoundPlayer::Latency: latency is %Ld\n", latency);
418 
419 	return latency;
420 }
421 
422 
423 void
424 BSoundPlayer::SetHasData(bool has_data)
425 {
426 	CALLED();
427 	if (has_data)
428 		atomic_or(&fFlags, F_HAS_DATA);
429 	else
430 		atomic_and(&fFlags, ~F_HAS_DATA);
431 }
432 
433 
434 /* virtual */ bool
435 BSoundPlayer::HasData()
436 {
437 	CALLED();
438 	return (atomic_read(&fFlags) & F_HAS_DATA) != 0;
439 }
440 
441 
442 BSoundPlayer::BufferPlayerFunc
443 BSoundPlayer::BufferPlayer() const
444 {
445 	CALLED();
446 	return fPlayBufferFunc;
447 }
448 
449 
450 void
451 BSoundPlayer::SetBufferPlayer(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format))
452 {
453 	CALLED();
454 	fLocker.Lock();
455 	fPlayBufferFunc = PlayBuffer;
456 	fLocker.Unlock();
457 }
458 
459 
460 BSoundPlayer::EventNotifierFunc
461 BSoundPlayer::EventNotifier() const
462 {
463 	CALLED();
464 	return fNotifierFunc;
465 }
466 
467 
468 void BSoundPlayer::SetNotifier(void (*Notifier)(void *, sound_player_notification what, ...))
469 {
470 	CALLED();
471 	fLocker.Lock();
472 	fNotifierFunc = Notifier;
473 	fLocker.Unlock();
474 }
475 
476 
477 void *
478 BSoundPlayer::Cookie() const
479 {
480 	CALLED();
481 	return fCookie;
482 }
483 
484 
485 void
486 BSoundPlayer::SetCookie(void *cookie)
487 {
488 	CALLED();
489 	fLocker.Lock();
490 	fCookie = cookie;
491 	fLocker.Unlock();
492 }
493 
494 
495 void
496 BSoundPlayer::SetCallbacks(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
497 						   void (*Notifier)(void *, sound_player_notification what, ...),
498 						   void * cookie)
499 {
500 	CALLED();
501 	fLocker.Lock();
502 	SetBufferPlayer(PlayBuffer);
503 	SetNotifier(Notifier);
504 	SetCookie(cookie);
505 	fLocker.Unlock();
506 }
507 
508 
509 /* The BeBook is inaccurate about the meaning of this function.
510  * The probably best interpretation is to return the time that
511  * has elapsed since playing was started, whichs seems to match
512  * " CurrentTime() returns the current media time "
513  */
514 bigtime_t
515 BSoundPlayer::CurrentTime()
516 {
517 	if ((fFlags & F_NODES_CONNECTED) == 0)
518 		return 0;
519 
520 	return fPlayerNode->CurrentTime();
521 }
522 
523 
524 /* Returns the current performance time of the sound player node
525  * being used by the BSoundPlayer. Will return B_ERROR if the
526  * BSoundPlayer object hasn't been properly initialized.
527  */
528 bigtime_t
529 BSoundPlayer::PerformanceTime()
530 {
531 	if ((fFlags & F_NODES_CONNECTED) == 0)
532 		return (bigtime_t) B_ERROR;
533 
534 	return fPlayerNode->TimeSource()->Now();
535 }
536 
537 
538 status_t
539 BSoundPlayer::Preroll()
540 {
541 	CALLED();
542 
543 	if ((fFlags & F_NODES_CONNECTED) == 0)
544 		return B_NO_INIT;
545 
546 	BMediaRoster *roster = BMediaRoster::Roster();
547 	if (!roster) {
548 		TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n");
549 		return B_ERROR;
550 	}
551 
552 	status_t err = roster->PrerollNode(fMediaOutput.node);
553 	if (err != B_OK) {
554 		TRACE("BSoundPlayer::Preroll: Error while PrerollNode:  %ld (%s)\n", err, strerror(err));
555 		return err;
556 	}
557 
558 	return B_OK;
559 }
560 
561 
562 BSoundPlayer::play_id
563 BSoundPlayer::StartPlaying(BSound *sound,
564 						   bigtime_t at_time)
565 {
566 	UNIMPLEMENTED();
567 	return 1;
568 }
569 
570 
571 BSoundPlayer::play_id
572 BSoundPlayer::StartPlaying(BSound *sound,
573 						   bigtime_t at_time,
574 						   float with_volume)
575 {
576 	UNIMPLEMENTED();
577 	return 1;
578 }
579 
580 
581 status_t
582 BSoundPlayer::SetSoundVolume(play_id sound,
583 							 float new_volume)
584 {
585 	UNIMPLEMENTED();
586 
587 	return B_OK;
588 }
589 
590 
591 bool
592 BSoundPlayer::IsPlaying(play_id id)
593 {
594 	UNIMPLEMENTED();
595 
596 	return true;
597 }
598 
599 
600 status_t
601 BSoundPlayer::StopPlaying(play_id id)
602 {
603 	UNIMPLEMENTED();
604 
605 	return B_OK;
606 }
607 
608 
609 status_t
610 BSoundPlayer::WaitForSound(play_id id)
611 {
612 	UNIMPLEMENTED();
613 
614 	return B_OK;
615 }
616 
617 
618 float
619 BSoundPlayer::Volume()
620 {
621 	CALLED();
622 
623 	return pow(10.0, VolumeDB(true) / 20.0);
624 }
625 
626 
627 void
628 BSoundPlayer::SetVolume(float new_volume)
629 {
630 	CALLED();
631 	SetVolumeDB(20.0 * log10(new_volume));
632 }
633 
634 
635 float
636 BSoundPlayer::VolumeDB(bool forcePoll)
637 {
638 	CALLED();
639 	if (!fVolumeSlider)
640 		return -94.0f; // silence
641 
642 	if (!forcePoll && (system_time() - fLastVolumeUpdate < 500000))
643 		return fVolumeDB;
644 
645 	int32 count = fVolumeSlider->CountChannels();
646 	float values[count];
647 	size_t size = count * sizeof(float);
648 	fVolumeSlider->GetValue(&values, &size, NULL);
649 	fLastVolumeUpdate = system_time();
650 	fVolumeDB = values[0];
651 
652 	return values[0];
653 }
654 
655 
656 void
657 BSoundPlayer::SetVolumeDB(float volume_dB)
658 {
659 	CALLED();
660 	if (!fVolumeSlider)
661 		return;
662 
663 	float min_dB = fVolumeSlider->MinValue();
664 	float max_dB = fVolumeSlider->MaxValue();
665 	if (volume_dB < min_dB)
666 		volume_dB = min_dB;
667 	if (volume_dB > max_dB)
668 		volume_dB = max_dB;
669 
670 	int count = fVolumeSlider->CountChannels();
671 	float values[count];
672 	for (int i = 0; i < count; i++)
673 		values[i] = volume_dB;
674 	fVolumeSlider->SetValue(values, sizeof(float) * count, 0);
675 
676 	fVolumeDB = volume_dB;
677 	fLastVolumeUpdate = system_time();
678 }
679 
680 
681 status_t
682 BSoundPlayer::GetVolumeInfo(media_node *out_node,
683 							int32 *out_parameter_id,
684 							float *out_min_dB,
685 							float *out_max_dB)
686 {
687 	CALLED();
688 	if (!fVolumeSlider)
689 		return B_NO_INIT;
690 
691 	if (out_node)
692 		*out_node = fMediaInput.node;
693 	if (out_parameter_id)
694 		*out_parameter_id = fVolumeSlider->ID();
695 	if (out_min_dB)
696 		*out_min_dB = fVolumeSlider->MinValue();
697 	if (out_max_dB)
698 		*out_max_dB = fVolumeSlider->MaxValue();
699 	return B_OK;
700 }
701 
702 
703 
704 /*************************************************************
705  * protected BSoundPlayer
706  *************************************************************/
707 
708 
709 void
710 BSoundPlayer::SetInitError(status_t in_error)
711 {
712 	CALLED();
713 	fInitStatus = in_error;
714 }
715 
716 
717 /*************************************************************
718  * private BSoundPlayer
719  *************************************************************/
720 
721 status_t BSoundPlayer::_Reserved_SoundPlayer_0(void *, ...) { return B_ERROR; }
722 status_t BSoundPlayer::_Reserved_SoundPlayer_1(void *, ...) { return B_ERROR; }
723 status_t BSoundPlayer::_Reserved_SoundPlayer_2(void *, ...) { return B_ERROR; }
724 status_t BSoundPlayer::_Reserved_SoundPlayer_3(void *, ...) { return B_ERROR; }
725 status_t BSoundPlayer::_Reserved_SoundPlayer_4(void *, ...) { return B_ERROR; }
726 status_t BSoundPlayer::_Reserved_SoundPlayer_5(void *, ...) { return B_ERROR; }
727 status_t BSoundPlayer::_Reserved_SoundPlayer_6(void *, ...) { return B_ERROR; }
728 status_t BSoundPlayer::_Reserved_SoundPlayer_7(void *, ...) { return B_ERROR; }
729 
730 
731 void
732 BSoundPlayer::NotifySoundDone(play_id sound,
733 							  bool got_to_play)
734 {
735 	UNIMPLEMENTED();
736 }
737 
738 
739 void
740 BSoundPlayer::get_volume_slider()
741 {
742 	CALLED();
743 
744 	ASSERT(fVolumeSlider == NULL);
745 
746 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
747 	if (!roster) {
748 		TRACE("BSoundPlayer::get_volume_slider failed to get BMediaRoster");
749 		return;
750 	}
751 
752 	if (!fParameterWeb && roster->GetParameterWebFor(fMediaInput.node, &fParameterWeb) < B_OK) {
753 		TRACE("BSoundPlayer::get_volume_slider couldn't get parameter web");
754 		return;
755 	}
756 
757 	int count = fParameterWeb->CountParameters();
758 	for (int i = 0; i < count; i++) {
759 		BParameter *parameter = fParameterWeb->ParameterAt(i);
760 		if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER)
761 			continue;
762 		if ((parameter->ID() >> 16) != fMediaInput.destination.id)
763 			continue;
764 		if  (strcmp(parameter->Kind(), B_GAIN) != 0)
765 			continue;
766 		fVolumeSlider = (BContinuousParameter *)parameter;
767 		break;
768 	}
769 
770 #if DEBUG >0
771 	if (!fVolumeSlider) {
772 		TRACE("BSoundPlayer::get_volume_slider couldn't find volume control");
773 	}
774 #endif
775 }
776 
777 
778 /* virtual */ void
779 BSoundPlayer::Notify(sound_player_notification what, ...)
780 {
781 	CALLED();
782 	if (fLocker.Lock()) {
783 		if (fNotifierFunc)
784 			(*fNotifierFunc)(fCookie, what);
785 		fLocker.Unlock();
786 	}
787 }
788 
789 
790 /* virtual */ void
791 BSoundPlayer::PlayBuffer(void *buffer, size_t size, const media_raw_audio_format &format)
792 {
793 	if (fLocker.Lock()) {
794 		if (fPlayBufferFunc)
795 			(*fPlayBufferFunc)(fCookie, buffer, size, format);
796 		fLocker.Unlock();
797 	}
798 }
799 
800 
801 /*************************************************************
802  * public sound_error
803  *************************************************************/
804 
805 
806 sound_error::sound_error(const char *str)
807 {
808 	m_str_const = str;
809 }
810 
811 
812 const char *
813 sound_error::what() const
814 {
815 	return m_str_const;
816 }
817 
818