xref: /haiku/src/kits/media/SoundPlayer.cpp (revision f1059fbd7f64bf0ae8324e3e6bed9ce28f593b23)
1812fde99SAxel Dörfler /*
2812fde99SAxel Dörfler  * Copyright 2002-2009, Haiku.
3812fde99SAxel Dörfler  * Distributed under the terms of the MIT License.
4812fde99SAxel Dörfler  *
5812fde99SAxel Dörfler  * Authors:
6812fde99SAxel Dörfler  *		Marcus Overhagen
7812fde99SAxel Dörfler  *		Jérôme Duval
8812fde99SAxel Dörfler  */
9812fde99SAxel Dörfler 
10812fde99SAxel Dörfler 
11812fde99SAxel Dörfler #include <SoundPlayer.h>
12812fde99SAxel Dörfler 
1352a38012Sejakowatz #include <math.h>
142386ff94SIngo Weinhold #include <string.h>
1552a38012Sejakowatz 
16812fde99SAxel Dörfler #include <Autolock.h>
17812fde99SAxel Dörfler #include <MediaRoster.h>
18812fde99SAxel Dörfler #include <ParameterWeb.h>
19812fde99SAxel Dörfler #include <Sound.h>
20812fde99SAxel Dörfler #include <TimeSource.h>
21812fde99SAxel Dörfler 
2252a38012Sejakowatz #include "SoundPlayNode.h"
23812fde99SAxel Dörfler 
24812fde99SAxel Dörfler #include "debug.h"
2552a38012Sejakowatz 
26df42a7b5Sbeveloper 
27d6105cedSbeveloper // Flags used internally in BSoundPlayer
28d6105cedSbeveloper enum {
29df42a7b5Sbeveloper 	F_NODES_CONNECTED	= (1 << 0),
30df42a7b5Sbeveloper 	F_HAS_DATA			= (1 << 1),
31df42a7b5Sbeveloper 	F_IS_STARTED		= (1 << 2),
32df42a7b5Sbeveloper 	F_MUST_RELEASE_MIXER = (1 << 3),
33d6105cedSbeveloper };
34d6105cedSbeveloper 
3552a38012Sejakowatz 
369b9aa75aSMichael Lotz static BSoundPlayer::play_id sCurrentPlayID = 1;
379b9aa75aSMichael Lotz 
389b9aa75aSMichael Lotz 
39812fde99SAxel Dörfler BSoundPlayer::BSoundPlayer(const char* name, BufferPlayerFunc playerFunction,
40812fde99SAxel Dörfler 	EventNotifierFunc eventNotifierFunction, void* cookie)
4152a38012Sejakowatz {
4252a38012Sejakowatz 	CALLED();
43df42a7b5Sbeveloper 
4440c2c00aSbeveloper 	TRACE("BSoundPlayer::BSoundPlayer: default constructor used\n");
45df42a7b5Sbeveloper 
46812fde99SAxel Dörfler 	media_multi_audio_format format = media_multi_audio_format::wildcard;
4740c2c00aSbeveloper 
48812fde99SAxel Dörfler 	_Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction,
49812fde99SAxel Dörfler 		cookie);
5052a38012Sejakowatz }
5152a38012Sejakowatz 
52df42a7b5Sbeveloper 
53812fde99SAxel Dörfler BSoundPlayer::BSoundPlayer(const media_raw_audio_format* _format,
54812fde99SAxel Dörfler 	const char* name, BufferPlayerFunc playerFunction,
55812fde99SAxel Dörfler 	EventNotifierFunc eventNotifierFunction, void* cookie)
5652a38012Sejakowatz {
5752a38012Sejakowatz 	CALLED();
58df42a7b5Sbeveloper 
5940c2c00aSbeveloper 	TRACE("BSoundPlayer::BSoundPlayer: raw audio format constructor used\n");
60df42a7b5Sbeveloper 
61812fde99SAxel Dörfler 	media_multi_audio_format format = media_multi_audio_format::wildcard;
62812fde99SAxel Dörfler 	*(media_raw_audio_format*)&format = *_format;
6340c2c00aSbeveloper 
6440c2c00aSbeveloper #if DEBUG > 0
6540c2c00aSbeveloper 	char buf[100];
66812fde99SAxel Dörfler 	media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = format;
6740c2c00aSbeveloper 	string_for_format(tmp, buf, sizeof(buf));
6840c2c00aSbeveloper 	TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf);
6940c2c00aSbeveloper #endif
7040c2c00aSbeveloper 
71812fde99SAxel Dörfler 	_Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction,
72812fde99SAxel Dörfler 		cookie);
7352a38012Sejakowatz }
7452a38012Sejakowatz 
75df42a7b5Sbeveloper 
7652a38012Sejakowatz BSoundPlayer::BSoundPlayer(const media_node& toNode,
77812fde99SAxel Dörfler 	const media_multi_audio_format* format, const char* name,
78812fde99SAxel Dörfler 	const media_input* input, BufferPlayerFunc playerFunction,
79812fde99SAxel Dörfler 	EventNotifierFunc eventNotifierFunction, void* cookie)
8052a38012Sejakowatz {
8152a38012Sejakowatz 	CALLED();
82df42a7b5Sbeveloper 
8340c2c00aSbeveloper 	TRACE("BSoundPlayer::BSoundPlayer: multi audio format constructor used\n");
84df42a7b5Sbeveloper 
859490cc05SMichael Lotz 	if ((toNode.kind & B_BUFFER_CONSUMER) == 0)
8652a38012Sejakowatz 		debugger("BSoundPlayer: toNode must have B_BUFFER_CONSUMER kind!\n");
87df42a7b5Sbeveloper 
8840c2c00aSbeveloper #if DEBUG > 0
8940c2c00aSbeveloper 	char buf[100];
9040c2c00aSbeveloper 	media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = *format;
9140c2c00aSbeveloper 	string_for_format(tmp, buf, sizeof(buf));
9240c2c00aSbeveloper 	TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf);
9340c2c00aSbeveloper #endif
9440c2c00aSbeveloper 
95812fde99SAxel Dörfler 	_Init(&toNode, format, name, input, playerFunction, eventNotifierFunction,
96812fde99SAxel Dörfler 		cookie);
9752a38012Sejakowatz }
9852a38012Sejakowatz 
99df42a7b5Sbeveloper 
10052a38012Sejakowatz BSoundPlayer::~BSoundPlayer()
10152a38012Sejakowatz {
10252a38012Sejakowatz 	CALLED();
103d6105cedSbeveloper 
104812fde99SAxel Dörfler 	if ((fFlags & F_IS_STARTED) != 0) {
105812fde99SAxel Dörfler 		// block, but don't flush
106812fde99SAxel Dörfler 		Stop(true, false);
107df42a7b5Sbeveloper 	}
108d6105cedSbeveloper 
109df42a7b5Sbeveloper 	status_t err;
11095531d1eSJérôme Duval 	BMediaRoster* roster = BMediaRoster::Roster();
111812fde99SAxel Dörfler 	if (roster == NULL) {
11295531d1eSJérôme Duval 		TRACE("BSoundPlayer::~BSoundPlayer: Couldn't get BMediaRoster\n");
113df42a7b5Sbeveloper 		goto cleanup;
114df42a7b5Sbeveloper 	}
11595531d1eSJérôme Duval 
116812fde99SAxel Dörfler 	if ((fFlags & F_NODES_CONNECTED) != 0) {
117812fde99SAxel Dörfler 		// Ordinarily we'd stop *all* of the nodes in the chain before
118812fde99SAxel Dörfler 		// disconnecting. However, our node is already stopped, and we can't
119812fde99SAxel Dörfler 		// stop the System Mixer.
120812fde99SAxel Dörfler 		// So, we just disconnect from it, and release our references to the
121812fde99SAxel Dörfler 		// nodes that we're using. We *are* supposed to do that even for global
122812fde99SAxel Dörfler 		// nodes like the Mixer.
12375daf556SMarcus Overhagen 		err = roster->Disconnect(fMediaOutput, fMediaInput);
124812fde99SAxel Dörfler 		if (err != B_OK) {
125812fde99SAxel Dörfler 			TRACE("BSoundPlayer::~BSoundPlayer: Error disconnecting nodes: "
126812fde99SAxel Dörfler 				"%ld (%s)\n", err, strerror(err));
12795531d1eSJérôme Duval 		}
128df42a7b5Sbeveloper 	}
12995531d1eSJérôme Duval 
130812fde99SAxel Dörfler 	if ((fFlags & F_MUST_RELEASE_MIXER) != 0) {
131df42a7b5Sbeveloper 		// Release the mixer as it was acquired
132df42a7b5Sbeveloper 		// through BMediaRoster::GetAudioMixer()
133d6105cedSbeveloper 		err = roster->ReleaseNode(fMediaInput.node);
134812fde99SAxel Dörfler 		if (err != B_OK) {
135812fde99SAxel Dörfler 			TRACE("BSoundPlayer::~BSoundPlayer: Error releasing input node: "
136812fde99SAxel Dörfler 				"%ld (%s)\n", err, strerror(err));
137df42a7b5Sbeveloper 		}
13895531d1eSJérôme Duval 	}
13995531d1eSJérôme Duval 
140df42a7b5Sbeveloper cleanup:
141df42a7b5Sbeveloper 	// Dispose of the player node
142812fde99SAxel Dörfler 
143df42a7b5Sbeveloper 	// We do not call BMediaRoster::ReleaseNode(), since
144df42a7b5Sbeveloper 	// the player was created by using "new". We could
145df42a7b5Sbeveloper 	// call BMediaRoster::UnregisterNode(), but this is
146*f1059fbdSDario Casalinuovo 	// supposed to be done by BMediaNode destructor automatically.
147*f1059fbdSDario Casalinuovo 
148*f1059fbdSDario Casalinuovo 	// The node is deleted by the Release() when ref count reach 0.
149*f1059fbdSDario Casalinuovo 	// Since we are the sole owners, and no one acquired it
150*f1059fbdSDario Casalinuovo 	// this should be the case. The Quit() synchronization
151*f1059fbdSDario Casalinuovo 	// is handled by the DeleteHook inheritance.
152*f1059fbdSDario Casalinuovo 	// NOTE: this might be crucial when using a BMediaEventLooper.
153*f1059fbdSDario Casalinuovo 	if (fPlayerNode->Release() != NULL) {
154*f1059fbdSDario Casalinuovo 		TRACE("BSoundPlayer::~BSoundPlayer: Error the producer node "
155*f1059fbdSDario Casalinuovo 			"appears to be acquired by someone else than us!");
156*f1059fbdSDario Casalinuovo 	}
157d6105cedSbeveloper 
158812fde99SAxel Dörfler 	// do not delete fVolumeSlider, it belongs to the parameter web
159d6105cedSbeveloper 	delete fParameterWeb;
16052a38012Sejakowatz }
16152a38012Sejakowatz 
16252a38012Sejakowatz 
16352a38012Sejakowatz status_t
16452a38012Sejakowatz BSoundPlayer::InitCheck()
16552a38012Sejakowatz {
16652a38012Sejakowatz 	CALLED();
167d6105cedSbeveloper 	return fInitStatus;
16852a38012Sejakowatz }
16952a38012Sejakowatz 
17052a38012Sejakowatz 
17152a38012Sejakowatz media_raw_audio_format
17252a38012Sejakowatz BSoundPlayer::Format() const
17352a38012Sejakowatz {
17452a38012Sejakowatz 	CALLED();
17552a38012Sejakowatz 
176df42a7b5Sbeveloper 	if ((fFlags & F_NODES_CONNECTED) == 0)
177df42a7b5Sbeveloper 		return media_raw_audio_format::wildcard;
178df42a7b5Sbeveloper 
179df42a7b5Sbeveloper 	return fPlayerNode->Format();
18052a38012Sejakowatz }
18152a38012Sejakowatz 
18252a38012Sejakowatz 
18352a38012Sejakowatz status_t
18452a38012Sejakowatz BSoundPlayer::Start()
18552a38012Sejakowatz {
18652a38012Sejakowatz 	CALLED();
18752a38012Sejakowatz 
188df42a7b5Sbeveloper 	if ((fFlags & F_NODES_CONNECTED) == 0)
189df42a7b5Sbeveloper 		return B_NO_INIT;
190df42a7b5Sbeveloper 
191812fde99SAxel Dörfler 	if ((fFlags & F_IS_STARTED) != 0)
192df42a7b5Sbeveloper 		return B_OK;
19352a38012Sejakowatz 
19495531d1eSJérôme Duval 	BMediaRoster* roster = BMediaRoster::Roster();
19595531d1eSJérôme Duval 	if (!roster) {
19695531d1eSJérôme Duval 		TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n");
19795531d1eSJérôme Duval 		return B_ERROR;
19895531d1eSJérôme Duval 	}
19995531d1eSJérôme Duval 
20095096991SJérôme Duval 	if (!fPlayerNode->TimeSource()->IsRunning()) {
20195096991SJérôme Duval 		roster->StartTimeSource(fPlayerNode->TimeSource()->Node(),
20295096991SJérôme Duval 			fPlayerNode->TimeSource()->RealTime());
20395096991SJérôme Duval 	}
20495096991SJérôme Duval 
205df42a7b5Sbeveloper 	// Add latency and a few ms to the nodes current time to
206df42a7b5Sbeveloper 	// make sure that we give the producer enough time to run
207df42a7b5Sbeveloper 	// buffers through the node chain, otherwise it'll start
208df42a7b5Sbeveloper 	// up already late
20995531d1eSJérôme Duval 
210812fde99SAxel Dörfler 	status_t err = roster->StartNode(fPlayerNode->Node(),
211812fde99SAxel Dörfler 		fPlayerNode->TimeSource()->Now() + Latency() + 5000);
212df42a7b5Sbeveloper 	if (err != B_OK) {
213df42a7b5Sbeveloper 		TRACE("BSoundPlayer::Start: StartNode failed, %ld", err);
21495531d1eSJérôme Duval 		return err;
21552a38012Sejakowatz 	}
21652a38012Sejakowatz 
217812fde99SAxel Dörfler 	if (fNotifierFunc != NULL)
21895096991SJérôme Duval 		fNotifierFunc(fCookie, B_STARTED, this);
21995096991SJérôme Duval 
22095096991SJérôme Duval 	SetHasData(true);
221df42a7b5Sbeveloper 	atomic_or(&fFlags, F_IS_STARTED);
222df42a7b5Sbeveloper 
223df42a7b5Sbeveloper 	return B_OK;
224df42a7b5Sbeveloper }
225df42a7b5Sbeveloper 
22652a38012Sejakowatz 
22752a38012Sejakowatz void
228812fde99SAxel Dörfler BSoundPlayer::Stop(bool block, bool flush)
22952a38012Sejakowatz {
23052a38012Sejakowatz 	CALLED();
23152a38012Sejakowatz 
232df42a7b5Sbeveloper 	TRACE("BSoundPlayer::Stop: block %d, flush %d\n", (int)block, (int)flush);
233df42a7b5Sbeveloper 
234df42a7b5Sbeveloper 	if ((fFlags & F_NODES_CONNECTED) == 0)
23552a38012Sejakowatz 		return;
23652a38012Sejakowatz 
237812fde99SAxel Dörfler 	// TODO: flush is ignored
238a0703a47Sbeveloper 
239812fde99SAxel Dörfler 	if ((fFlags & F_IS_STARTED) != 0) {
24095531d1eSJérôme Duval 		BMediaRoster* roster = BMediaRoster::Roster();
241812fde99SAxel Dörfler 		if (roster == NULL) {
24295531d1eSJérôme Duval 			TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n");
24395531d1eSJérôme Duval 			return;
24495531d1eSJérôme Duval 		}
24595531d1eSJérôme Duval 
246d6105cedSbeveloper 		roster->StopNode(fPlayerNode->Node(), 0, true);
24795531d1eSJérôme Duval 
248df42a7b5Sbeveloper 		atomic_and(&fFlags, ~F_IS_STARTED);
249df42a7b5Sbeveloper 	}
250df42a7b5Sbeveloper 
251a0703a47Sbeveloper 	if (block) {
252a0703a47Sbeveloper 		// wait until the node is stopped
253812fde99SAxel Dörfler 		int tries;
254812fde99SAxel Dörfler 		for (tries = 250; fPlayerNode->IsPlaying() && tries != 0; tries--)
255a0703a47Sbeveloper 			snooze(2000);
256a0703a47Sbeveloper 
2576813f2c7SIngo Weinhold 		DEBUG_ONLY(if (tries == 0)
258812fde99SAxel Dörfler 			TRACE("BSoundPlayer::Stop: waiting for node stop failed\n"));
259a0703a47Sbeveloper 
260812fde99SAxel Dörfler 		// Wait until all buffers on the way to the physical output have been
261812fde99SAxel Dörfler 		// played
262df42a7b5Sbeveloper 		snooze(Latency() + 2000);
263a0703a47Sbeveloper 	}
26495096991SJérôme Duval 
26595096991SJérôme Duval 	if (fNotifierFunc)
26695096991SJérôme Duval 		fNotifierFunc(fCookie, B_STOPPED, this);
26795096991SJérôme Duval 
26852a38012Sejakowatz }
26952a38012Sejakowatz 
270df42a7b5Sbeveloper 
271df42a7b5Sbeveloper bigtime_t
272df42a7b5Sbeveloper BSoundPlayer::Latency()
273df42a7b5Sbeveloper {
274df42a7b5Sbeveloper 	CALLED();
275df42a7b5Sbeveloper 
276df42a7b5Sbeveloper 	if ((fFlags & F_NODES_CONNECTED) == 0)
277df42a7b5Sbeveloper 		return 0;
278df42a7b5Sbeveloper 
279df42a7b5Sbeveloper 	BMediaRoster *roster = BMediaRoster::Roster();
280df42a7b5Sbeveloper 	if (!roster) {
281df42a7b5Sbeveloper 		TRACE("BSoundPlayer::Latency: Couldn't get BMediaRoster\n");
282df42a7b5Sbeveloper 		return 0;
283df42a7b5Sbeveloper 	}
284df42a7b5Sbeveloper 
285df42a7b5Sbeveloper 	bigtime_t latency;
286df42a7b5Sbeveloper 	status_t err = roster->GetLatencyFor(fMediaOutput.node, &latency);
287df42a7b5Sbeveloper 	if (err != B_OK) {
288812fde99SAxel Dörfler 		TRACE("BSoundPlayer::Latency: GetLatencyFor failed %ld (%s)\n", err,
289812fde99SAxel Dörfler 			strerror(err));
290df42a7b5Sbeveloper 		return 0;
291df42a7b5Sbeveloper 	}
292df42a7b5Sbeveloper 
29340c2c00aSbeveloper 	TRACE("BSoundPlayer::Latency: latency is %Ld\n", latency);
29440c2c00aSbeveloper 
295df42a7b5Sbeveloper 	return latency;
296df42a7b5Sbeveloper }
297df42a7b5Sbeveloper 
298df42a7b5Sbeveloper 
299df42a7b5Sbeveloper void
3004ed344afSAxel Dörfler BSoundPlayer::SetHasData(bool hasData)
301df42a7b5Sbeveloper {
302df42a7b5Sbeveloper 	CALLED();
3034ed344afSAxel Dörfler 	if (hasData)
304df42a7b5Sbeveloper 		atomic_or(&fFlags, F_HAS_DATA);
305df42a7b5Sbeveloper 	else
306df42a7b5Sbeveloper 		atomic_and(&fFlags, ~F_HAS_DATA);
307df42a7b5Sbeveloper }
308df42a7b5Sbeveloper 
309df42a7b5Sbeveloper 
310812fde99SAxel Dörfler bool
311df42a7b5Sbeveloper BSoundPlayer::HasData()
312df42a7b5Sbeveloper {
313df42a7b5Sbeveloper 	CALLED();
3144ed344afSAxel Dörfler 	return (atomic_get(&fFlags) & F_HAS_DATA) != 0;
315df42a7b5Sbeveloper }
316df42a7b5Sbeveloper 
317df42a7b5Sbeveloper 
31852a38012Sejakowatz BSoundPlayer::BufferPlayerFunc
31952a38012Sejakowatz BSoundPlayer::BufferPlayer() const
32052a38012Sejakowatz {
32152a38012Sejakowatz 	CALLED();
322d6105cedSbeveloper 	return fPlayBufferFunc;
32352a38012Sejakowatz }
32452a38012Sejakowatz 
325df42a7b5Sbeveloper 
326df42a7b5Sbeveloper void
327812fde99SAxel Dörfler BSoundPlayer::SetBufferPlayer(BufferPlayerFunc playerFunction)
32852a38012Sejakowatz {
32952a38012Sejakowatz 	CALLED();
330812fde99SAxel Dörfler 	BAutolock _(fLocker);
331812fde99SAxel Dörfler 
332812fde99SAxel Dörfler 	fPlayBufferFunc = playerFunction;
33352a38012Sejakowatz }
33452a38012Sejakowatz 
335df42a7b5Sbeveloper 
33652a38012Sejakowatz BSoundPlayer::EventNotifierFunc
33752a38012Sejakowatz BSoundPlayer::EventNotifier() const
33852a38012Sejakowatz {
33952a38012Sejakowatz 	CALLED();
340d6105cedSbeveloper 	return fNotifierFunc;
34152a38012Sejakowatz }
34252a38012Sejakowatz 
343df42a7b5Sbeveloper 
344812fde99SAxel Dörfler void
345812fde99SAxel Dörfler BSoundPlayer::SetNotifier(EventNotifierFunc eventNotifierFunction)
34652a38012Sejakowatz {
34752a38012Sejakowatz 	CALLED();
348812fde99SAxel Dörfler 	BAutolock _(fLocker);
349812fde99SAxel Dörfler 
350812fde99SAxel Dörfler 	fNotifierFunc = eventNotifierFunction;
35152a38012Sejakowatz }
35252a38012Sejakowatz 
353df42a7b5Sbeveloper 
35452a38012Sejakowatz void*
35552a38012Sejakowatz BSoundPlayer::Cookie() const
35652a38012Sejakowatz {
35752a38012Sejakowatz 	CALLED();
358d6105cedSbeveloper 	return fCookie;
35952a38012Sejakowatz }
36052a38012Sejakowatz 
361df42a7b5Sbeveloper 
36252a38012Sejakowatz void
36352a38012Sejakowatz BSoundPlayer::SetCookie(void *cookie)
36452a38012Sejakowatz {
36552a38012Sejakowatz 	CALLED();
366812fde99SAxel Dörfler 	BAutolock _(fLocker);
367812fde99SAxel Dörfler 
368d6105cedSbeveloper 	fCookie = cookie;
36952a38012Sejakowatz }
37052a38012Sejakowatz 
371df42a7b5Sbeveloper 
372df42a7b5Sbeveloper void
373812fde99SAxel Dörfler BSoundPlayer::SetCallbacks(BufferPlayerFunc playerFunction,
374812fde99SAxel Dörfler 	EventNotifierFunc eventNotifierFunction, void* cookie)
37552a38012Sejakowatz {
37652a38012Sejakowatz 	CALLED();
377812fde99SAxel Dörfler 	BAutolock _(fLocker);
378812fde99SAxel Dörfler 
379812fde99SAxel Dörfler 	SetBufferPlayer(playerFunction);
380812fde99SAxel Dörfler 	SetNotifier(eventNotifierFunction);
38152a38012Sejakowatz 	SetCookie(cookie);
38252a38012Sejakowatz }
38352a38012Sejakowatz 
38452a38012Sejakowatz 
385812fde99SAxel Dörfler /*!	The BeBook is inaccurate about the meaning of this function.
386812fde99SAxel Dörfler 	The probably best interpretation is to return the time that
387812fde99SAxel Dörfler 	has elapsed since playing was started, whichs seems to match
388812fde99SAxel Dörfler 	"CurrentTime() returns the current media time"
389df42a7b5Sbeveloper */
39052a38012Sejakowatz bigtime_t
39152a38012Sejakowatz BSoundPlayer::CurrentTime()
39252a38012Sejakowatz {
393df42a7b5Sbeveloper 	if ((fFlags & F_NODES_CONNECTED) == 0)
394df42a7b5Sbeveloper 		return 0;
39595531d1eSJérôme Duval 
396df42a7b5Sbeveloper 	return fPlayerNode->CurrentTime();
39752a38012Sejakowatz }
39852a38012Sejakowatz 
39952a38012Sejakowatz 
400812fde99SAxel Dörfler /*!	Returns the current performance time of the sound player node
401812fde99SAxel Dörfler 	being used by the BSoundPlayer. Will return B_ERROR if the
402812fde99SAxel Dörfler 	BSoundPlayer object hasn't been properly initialized.
403df42a7b5Sbeveloper */
40452a38012Sejakowatz bigtime_t
40552a38012Sejakowatz BSoundPlayer::PerformanceTime()
40652a38012Sejakowatz {
407df42a7b5Sbeveloper 	if ((fFlags & F_NODES_CONNECTED) == 0)
40852a38012Sejakowatz 		return (bigtime_t) B_ERROR;
40995531d1eSJérôme Duval 
410d6105cedSbeveloper 	return fPlayerNode->TimeSource()->Now();
41152a38012Sejakowatz }
41252a38012Sejakowatz 
41352a38012Sejakowatz 
41452a38012Sejakowatz status_t
41552a38012Sejakowatz BSoundPlayer::Preroll()
41652a38012Sejakowatz {
41795531d1eSJérôme Duval 	CALLED();
41852a38012Sejakowatz 
419df42a7b5Sbeveloper 	if ((fFlags & F_NODES_CONNECTED) == 0)
420df42a7b5Sbeveloper 		return B_NO_INIT;
421df42a7b5Sbeveloper 
42295531d1eSJérôme Duval 	BMediaRoster* roster = BMediaRoster::Roster();
423812fde99SAxel Dörfler 	if (roster == NULL) {
42495531d1eSJérôme Duval 		TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n");
42595531d1eSJérôme Duval 		return B_ERROR;
42695531d1eSJérôme Duval 	}
42795531d1eSJérôme Duval 
428d6105cedSbeveloper 	status_t err = roster->PrerollNode(fMediaOutput.node);
42995531d1eSJérôme Duval 	if (err != B_OK) {
430812fde99SAxel Dörfler 		TRACE("BSoundPlayer::Preroll: Error while PrerollNode:  %ld (%s)\n",
431812fde99SAxel Dörfler 			err, strerror(err));
432df42a7b5Sbeveloper 		return err;
43395531d1eSJérôme Duval 	}
43495531d1eSJérôme Duval 
435df42a7b5Sbeveloper 	return B_OK;
43652a38012Sejakowatz }
43752a38012Sejakowatz 
43852a38012Sejakowatz 
43952a38012Sejakowatz BSoundPlayer::play_id
4409b9aa75aSMichael Lotz BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime)
44152a38012Sejakowatz {
4429b9aa75aSMichael Lotz 	return StartPlaying(sound, atTime, 1.0);
44352a38012Sejakowatz }
44452a38012Sejakowatz 
44552a38012Sejakowatz 
44652a38012Sejakowatz BSoundPlayer::play_id
4479b9aa75aSMichael Lotz BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime, float withVolume)
44852a38012Sejakowatz {
4499b9aa75aSMichael Lotz 	CALLED();
4509b9aa75aSMichael Lotz 
4519b9aa75aSMichael Lotz 	// TODO: support the at_time and with_volume parameters
4524ed344afSAxel Dörfler 	playing_sound* item = (playing_sound*)malloc(sizeof(playing_sound));
4539b9aa75aSMichael Lotz 	if (item == NULL)
4549b9aa75aSMichael Lotz 		return B_NO_MEMORY;
4559b9aa75aSMichael Lotz 
4569b9aa75aSMichael Lotz 	item->current_offset = 0;
4579b9aa75aSMichael Lotz 	item->sound = sound;
4589b9aa75aSMichael Lotz 	item->id = atomic_add(&sCurrentPlayID, 1);
4599b9aa75aSMichael Lotz 	item->delta = 0;
4609b9aa75aSMichael Lotz 	item->rate = 0;
4619b9aa75aSMichael Lotz 	item->volume = withVolume;
4629b9aa75aSMichael Lotz 
4639b9aa75aSMichael Lotz 	if (!fLocker.Lock()) {
4649b9aa75aSMichael Lotz 		free(item);
4659b9aa75aSMichael Lotz 		return B_ERROR;
4669b9aa75aSMichael Lotz 	}
4679b9aa75aSMichael Lotz 
4686fb91db7SMichael Lotz 	sound->AcquireRef();
4699b9aa75aSMichael Lotz 	item->next = fPlayingSounds;
4709b9aa75aSMichael Lotz 	fPlayingSounds = item;
4719b9aa75aSMichael Lotz 	fLocker.Unlock();
4729b9aa75aSMichael Lotz 
4739b9aa75aSMichael Lotz 	SetHasData(true);
4749b9aa75aSMichael Lotz 	return item->id;
47552a38012Sejakowatz }
47652a38012Sejakowatz 
47752a38012Sejakowatz 
47852a38012Sejakowatz status_t
4799b9aa75aSMichael Lotz BSoundPlayer::SetSoundVolume(play_id id, float newVolume)
48052a38012Sejakowatz {
4819b9aa75aSMichael Lotz 	CALLED();
4829b9aa75aSMichael Lotz 	if (!fLocker.Lock())
4839b9aa75aSMichael Lotz 		return B_ERROR;
48452a38012Sejakowatz 
4854ed344afSAxel Dörfler 	playing_sound *item = fPlayingSounds;
4869b9aa75aSMichael Lotz 	while (item) {
4879b9aa75aSMichael Lotz 		if (item->id == id) {
4889b9aa75aSMichael Lotz 			item->volume = newVolume;
4899b9aa75aSMichael Lotz 			fLocker.Unlock();
49052a38012Sejakowatz 			return B_OK;
49152a38012Sejakowatz 		}
49252a38012Sejakowatz 
4939b9aa75aSMichael Lotz 		item = item->next;
4949b9aa75aSMichael Lotz 	}
4959b9aa75aSMichael Lotz 
4969b9aa75aSMichael Lotz 	fLocker.Unlock();
4979b9aa75aSMichael Lotz 	return B_ENTRY_NOT_FOUND;
4989b9aa75aSMichael Lotz }
4999b9aa75aSMichael Lotz 
50052a38012Sejakowatz 
50152a38012Sejakowatz bool
50252a38012Sejakowatz BSoundPlayer::IsPlaying(play_id id)
50352a38012Sejakowatz {
5049b9aa75aSMichael Lotz 	CALLED();
5059b9aa75aSMichael Lotz 	if (!fLocker.Lock())
5069b9aa75aSMichael Lotz 		return B_ERROR;
50752a38012Sejakowatz 
5084ed344afSAxel Dörfler 	playing_sound *item = fPlayingSounds;
5099b9aa75aSMichael Lotz 	while (item) {
5109b9aa75aSMichael Lotz 		if (item->id == id) {
5119b9aa75aSMichael Lotz 			fLocker.Unlock();
51252a38012Sejakowatz 			return true;
51352a38012Sejakowatz 		}
51452a38012Sejakowatz 
5159b9aa75aSMichael Lotz 		item = item->next;
5169b9aa75aSMichael Lotz 	}
5179b9aa75aSMichael Lotz 
5189b9aa75aSMichael Lotz 	fLocker.Unlock();
5199b9aa75aSMichael Lotz 	return false;
5209b9aa75aSMichael Lotz }
5219b9aa75aSMichael Lotz 
52252a38012Sejakowatz 
52352a38012Sejakowatz status_t
52452a38012Sejakowatz BSoundPlayer::StopPlaying(play_id id)
52552a38012Sejakowatz {
5269b9aa75aSMichael Lotz 	CALLED();
5279b9aa75aSMichael Lotz 	if (!fLocker.Lock())
5289b9aa75aSMichael Lotz 		return B_ERROR;
5299b9aa75aSMichael Lotz 
5304ed344afSAxel Dörfler 	playing_sound** link = &fPlayingSounds;
5314ed344afSAxel Dörfler 	playing_sound* item = fPlayingSounds;
532812fde99SAxel Dörfler 
533812fde99SAxel Dörfler 	while (item != NULL) {
5349b9aa75aSMichael Lotz 		if (item->id == id) {
5359b9aa75aSMichael Lotz 			*link = item->next;
5369b9aa75aSMichael Lotz 			sem_id waitSem = item->wait_sem;
5376fb91db7SMichael Lotz 			item->sound->ReleaseRef();
5389b9aa75aSMichael Lotz 			free(item);
5399b9aa75aSMichael Lotz 			fLocker.Unlock();
5409b9aa75aSMichael Lotz 
541812fde99SAxel Dörfler 			_NotifySoundDone(id, true);
5429b9aa75aSMichael Lotz 			if (waitSem >= 0)
5439b9aa75aSMichael Lotz 				release_sem(waitSem);
54452a38012Sejakowatz 
54552a38012Sejakowatz 			return B_OK;
54652a38012Sejakowatz 		}
54752a38012Sejakowatz 
5489b9aa75aSMichael Lotz 		link = &item->next;
5499b9aa75aSMichael Lotz 		item = item->next;
5509b9aa75aSMichael Lotz 	}
5519b9aa75aSMichael Lotz 
5529b9aa75aSMichael Lotz 	fLocker.Unlock();
5539b9aa75aSMichael Lotz 	return B_ENTRY_NOT_FOUND;
5549b9aa75aSMichael Lotz }
5559b9aa75aSMichael Lotz 
55652a38012Sejakowatz 
55752a38012Sejakowatz status_t
55852a38012Sejakowatz BSoundPlayer::WaitForSound(play_id id)
55952a38012Sejakowatz {
5609b9aa75aSMichael Lotz 	CALLED();
5619b9aa75aSMichael Lotz 	if (!fLocker.Lock())
5629b9aa75aSMichael Lotz 		return B_ERROR;
56352a38012Sejakowatz 
5644ed344afSAxel Dörfler 	playing_sound* item = fPlayingSounds;
565812fde99SAxel Dörfler 	while (item != NULL) {
5669b9aa75aSMichael Lotz 		if (item->id == id) {
5679b9aa75aSMichael Lotz 			sem_id waitSem = item->wait_sem;
5689b9aa75aSMichael Lotz 			if (waitSem < 0)
5699b9aa75aSMichael Lotz 				waitSem = item->wait_sem = create_sem(0, "wait for sound");
5709b9aa75aSMichael Lotz 
5719b9aa75aSMichael Lotz 			fLocker.Unlock();
5729b9aa75aSMichael Lotz 			return acquire_sem(waitSem);
5739b9aa75aSMichael Lotz 		}
5749b9aa75aSMichael Lotz 
5759b9aa75aSMichael Lotz 		item = item->next;
5769b9aa75aSMichael Lotz 	}
5779b9aa75aSMichael Lotz 
5789b9aa75aSMichael Lotz 	fLocker.Unlock();
5799b9aa75aSMichael Lotz 	return B_ENTRY_NOT_FOUND;
58052a38012Sejakowatz }
58152a38012Sejakowatz 
58252a38012Sejakowatz 
58352a38012Sejakowatz float
58452a38012Sejakowatz BSoundPlayer::Volume()
58552a38012Sejakowatz {
58652a38012Sejakowatz 	CALLED();
587adc3b786SJérôme Duval 	return pow(10.0, VolumeDB(true) / 20.0);
58852a38012Sejakowatz }
58952a38012Sejakowatz 
59052a38012Sejakowatz 
59152a38012Sejakowatz void
592812fde99SAxel Dörfler BSoundPlayer::SetVolume(float newVolume)
59352a38012Sejakowatz {
59452a38012Sejakowatz 	CALLED();
595812fde99SAxel Dörfler 	SetVolumeDB(20.0 * log10(newVolume));
59652a38012Sejakowatz }
59752a38012Sejakowatz 
59852a38012Sejakowatz 
59952a38012Sejakowatz float
60052a38012Sejakowatz BSoundPlayer::VolumeDB(bool forcePoll)
60152a38012Sejakowatz {
60252a38012Sejakowatz 	CALLED();
603d6105cedSbeveloper 	if (!fVolumeSlider)
604df42a7b5Sbeveloper 		return -94.0f; // silence
60537ed595fSJérôme Duval 
606812fde99SAxel Dörfler 	if (!forcePoll && system_time() - fLastVolumeUpdate < 500000)
607df42a7b5Sbeveloper 		return fVolumeDB;
608adc3b786SJérôme Duval 
609d6105cedSbeveloper 	int32 count = fVolumeSlider->CountChannels();
610adc3b786SJérôme Duval 	float values[count];
611adc3b786SJérôme Duval 	size_t size = count * sizeof(float);
612d6105cedSbeveloper 	fVolumeSlider->GetValue(&values, &size, NULL);
613d6105cedSbeveloper 	fLastVolumeUpdate = system_time();
614df42a7b5Sbeveloper 	fVolumeDB = values[0];
615adc3b786SJérôme Duval 
616adc3b786SJérôme Duval 	return values[0];
61752a38012Sejakowatz }
61852a38012Sejakowatz 
61952a38012Sejakowatz 
62052a38012Sejakowatz void
621812fde99SAxel Dörfler BSoundPlayer::SetVolumeDB(float volumeDB)
62252a38012Sejakowatz {
62352a38012Sejakowatz 	CALLED();
624d6105cedSbeveloper 	if (!fVolumeSlider)
62537ed595fSJérôme Duval 		return;
62637ed595fSJérôme Duval 
627812fde99SAxel Dörfler 	float minDB = fVolumeSlider->MinValue();
628812fde99SAxel Dörfler 	float maxDB = fVolumeSlider->MaxValue();
629812fde99SAxel Dörfler 	if (volumeDB < minDB)
630812fde99SAxel Dörfler 		volumeDB = minDB;
631812fde99SAxel Dörfler 	if (volumeDB > maxDB)
632812fde99SAxel Dörfler 		volumeDB = maxDB;
633adc3b786SJérôme Duval 
634d6105cedSbeveloper 	int count = fVolumeSlider->CountChannels();
63537ed595fSJérôme Duval 	float values[count];
636d6105cedSbeveloper 	for (int i = 0; i < count; i++)
637812fde99SAxel Dörfler 		values[i] = volumeDB;
638d6105cedSbeveloper 	fVolumeSlider->SetValue(values, sizeof(float) * count, 0);
639d6105cedSbeveloper 
640812fde99SAxel Dörfler 	fVolumeDB = volumeDB;
641d6105cedSbeveloper 	fLastVolumeUpdate = system_time();
64252a38012Sejakowatz }
64352a38012Sejakowatz 
64452a38012Sejakowatz 
64552a38012Sejakowatz status_t
646812fde99SAxel Dörfler BSoundPlayer::GetVolumeInfo(media_node* _node, int32* _parameterID,
647812fde99SAxel Dörfler 	float* _minDB, float* _maxDB)
64852a38012Sejakowatz {
64937ed595fSJérôme Duval 	CALLED();
650812fde99SAxel Dörfler 	if (fVolumeSlider == NULL)
651d6105cedSbeveloper 		return B_NO_INIT;
65252a38012Sejakowatz 
653812fde99SAxel Dörfler 	if (_node != NULL)
654812fde99SAxel Dörfler 		*_node = fMediaInput.node;
655812fde99SAxel Dörfler 	if (_parameterID != NULL)
656812fde99SAxel Dörfler 		*_parameterID = fVolumeSlider->ID();
657812fde99SAxel Dörfler 	if (_minDB != NULL)
658812fde99SAxel Dörfler 		*_minDB = fVolumeSlider->MinValue();
659812fde99SAxel Dörfler 	if (_maxDB != NULL)
660812fde99SAxel Dörfler 		*_maxDB = fVolumeSlider->MaxValue();
661812fde99SAxel Dörfler 
66252a38012Sejakowatz 	return B_OK;
66352a38012Sejakowatz }
66452a38012Sejakowatz 
66552a38012Sejakowatz 
666812fde99SAxel Dörfler // #pragma mark - protected BSoundPlayer
66752a38012Sejakowatz 
668df42a7b5Sbeveloper 
66952a38012Sejakowatz void
670812fde99SAxel Dörfler BSoundPlayer::SetInitError(status_t error)
67152a38012Sejakowatz {
67252a38012Sejakowatz 	CALLED();
673812fde99SAxel Dörfler 	fInitStatus = error;
67452a38012Sejakowatz }
67552a38012Sejakowatz 
67652a38012Sejakowatz 
677812fde99SAxel Dörfler // #pragma mark - private BSoundPlayer
678812fde99SAxel Dörfler 
67952a38012Sejakowatz 
6809b9aa75aSMichael Lotz void
6819b9aa75aSMichael Lotz BSoundPlayer::_SoundPlayBufferFunc(void *cookie, void *buffer, size_t size,
6829b9aa75aSMichael Lotz 	const media_raw_audio_format &format)
6839b9aa75aSMichael Lotz {
6849b9aa75aSMichael Lotz 	// TODO: support more than one sound and make use of the format parameter
6859b9aa75aSMichael Lotz 	BSoundPlayer *player = (BSoundPlayer *)cookie;
6869b9aa75aSMichael Lotz 	if (!player->fLocker.Lock()) {
6879b9aa75aSMichael Lotz 		memset(buffer, 0, size);
6889b9aa75aSMichael Lotz 		return;
6899b9aa75aSMichael Lotz 	}
6909b9aa75aSMichael Lotz 
6914ed344afSAxel Dörfler 	playing_sound *sound = player->fPlayingSounds;
6929b9aa75aSMichael Lotz 	if (sound == NULL) {
6939b9aa75aSMichael Lotz 		player->SetHasData(false);
6949b9aa75aSMichael Lotz 		player->fLocker.Unlock();
6959b9aa75aSMichael Lotz 		memset(buffer, 0, size);
6969b9aa75aSMichael Lotz 		return;
6979b9aa75aSMichael Lotz 	}
6989b9aa75aSMichael Lotz 
6999b9aa75aSMichael Lotz 	size_t used = 0;
7009b9aa75aSMichael Lotz 	if (!sound->sound->GetDataAt(sound->current_offset, buffer, size, &used)) {
7019b9aa75aSMichael Lotz 		// will take care of removing the item and notifying others
7029b9aa75aSMichael Lotz 		player->StopPlaying(sound->id);
7039b9aa75aSMichael Lotz 		player->fLocker.Unlock();
7049b9aa75aSMichael Lotz 		memset(buffer, 0, size);
7059b9aa75aSMichael Lotz 		return;
7069b9aa75aSMichael Lotz 	}
7079b9aa75aSMichael Lotz 
7089b9aa75aSMichael Lotz 	sound->current_offset += used;
7099b9aa75aSMichael Lotz 	player->fLocker.Unlock();
7109b9aa75aSMichael Lotz 
7119b9aa75aSMichael Lotz 	if (used < size)
7129b9aa75aSMichael Lotz 		memset((uint8 *)buffer + used, 0, size - used);
7139b9aa75aSMichael Lotz }
7149b9aa75aSMichael Lotz 
7159b9aa75aSMichael Lotz 
71652a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_0(void*, ...) { return B_ERROR; }
71752a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_1(void*, ...) { return B_ERROR; }
71852a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_2(void*, ...) { return B_ERROR; }
71952a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_3(void*, ...) { return B_ERROR; }
72052a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_4(void*, ...) { return B_ERROR; }
72152a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_5(void*, ...) { return B_ERROR; }
72252a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_6(void*, ...) { return B_ERROR; }
72352a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_7(void*, ...) { return B_ERROR; }
72452a38012Sejakowatz 
72552a38012Sejakowatz 
72652a38012Sejakowatz void
727812fde99SAxel Dörfler BSoundPlayer::_Init(const media_node* node,
728812fde99SAxel Dörfler 	const media_multi_audio_format* format, const char* name,
729812fde99SAxel Dörfler 	const media_input* input, BufferPlayerFunc playerFunction,
730812fde99SAxel Dörfler 	EventNotifierFunc eventNotifierFunction, void* cookie)
73152a38012Sejakowatz {
7329b9aa75aSMichael Lotz 	CALLED();
733812fde99SAxel Dörfler 	fPlayingSounds = NULL;
734812fde99SAxel Dörfler 	fWaitingSounds = NULL;
735812fde99SAxel Dörfler 
736812fde99SAxel Dörfler 	fPlayerNode = NULL;
737812fde99SAxel Dörfler 	if (playerFunction == NULL) {
738812fde99SAxel Dörfler 		fPlayBufferFunc = _SoundPlayBufferFunc;
739812fde99SAxel Dörfler 		fCookie = this;
740812fde99SAxel Dörfler 	} else {
741812fde99SAxel Dörfler 		fPlayBufferFunc = playerFunction;
742812fde99SAxel Dörfler 		fCookie = cookie;
743812fde99SAxel Dörfler 	}
744812fde99SAxel Dörfler 
745812fde99SAxel Dörfler 	fNotifierFunc = eventNotifierFunction;
746812fde99SAxel Dörfler 	fVolumeDB = 0.0f;
747812fde99SAxel Dörfler 	fFlags = 0;
748812fde99SAxel Dörfler 	fInitStatus = B_ERROR;
749812fde99SAxel Dörfler 	fParameterWeb = NULL;
750812fde99SAxel Dörfler 	fVolumeSlider = NULL;
751812fde99SAxel Dörfler 	fLastVolumeUpdate = 0;
752812fde99SAxel Dörfler 
753812fde99SAxel Dörfler 	BMediaRoster* roster = BMediaRoster::Roster();
754812fde99SAxel Dörfler 	if (roster == NULL) {
755812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't get BMediaRoster\n");
756812fde99SAxel Dörfler 		return;
757812fde99SAxel Dörfler 	}
758812fde99SAxel Dörfler 
759812fde99SAxel Dörfler 	// The inputNode that our player node will be
760812fde99SAxel Dörfler 	// connected with is either supplied by the user
761812fde99SAxel Dörfler 	// or the system audio mixer
762812fde99SAxel Dörfler 	media_node inputNode;
763812fde99SAxel Dörfler 	if (node) {
764812fde99SAxel Dörfler 		inputNode = *node;
765812fde99SAxel Dörfler 	} else {
766812fde99SAxel Dörfler 		fInitStatus = roster->GetAudioMixer(&inputNode);
767812fde99SAxel Dörfler 		if (fInitStatus != B_OK) {
768812fde99SAxel Dörfler 			TRACE("BSoundPlayer::_Init: Couldn't GetAudioMixer\n");
769812fde99SAxel Dörfler 			return;
770812fde99SAxel Dörfler 		}
771812fde99SAxel Dörfler 		fFlags |= F_MUST_RELEASE_MIXER;
772812fde99SAxel Dörfler 	}
773812fde99SAxel Dörfler 
774812fde99SAxel Dörfler 	media_output _output;
775812fde99SAxel Dörfler 	media_input _input;
776812fde99SAxel Dörfler 	int32 inputCount;
777812fde99SAxel Dörfler 	int32 outputCount;
778812fde99SAxel Dörfler 	media_format tryFormat;
779812fde99SAxel Dörfler 
780812fde99SAxel Dörfler 	// Create the player node and register it
7814ed344afSAxel Dörfler 	fPlayerNode = new BPrivate::SoundPlayNode(name, this);
782812fde99SAxel Dörfler 	fInitStatus = roster->RegisterNode(fPlayerNode);
783812fde99SAxel Dörfler 	if (fInitStatus != B_OK) {
784812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't RegisterNode: %s\n",
785812fde99SAxel Dörfler 			strerror(fInitStatus));
786812fde99SAxel Dörfler 		return;
787812fde99SAxel Dörfler 	}
788812fde99SAxel Dörfler 
789812fde99SAxel Dörfler 	// set the producer's time source to be the "default" time source,
790812fde99SAxel Dörfler 	// which the system audio mixer uses too.
791812fde99SAxel Dörfler 	media_node timeSource;
792812fde99SAxel Dörfler 	fInitStatus = roster->GetTimeSource(&timeSource);
793812fde99SAxel Dörfler 	if (fInitStatus != B_OK) {
794812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't GetTimeSource: %s\n",
795812fde99SAxel Dörfler 			strerror(fInitStatus));
796812fde99SAxel Dörfler 		return;
797812fde99SAxel Dörfler 	}
798812fde99SAxel Dörfler 	fInitStatus = roster->SetTimeSourceFor(fPlayerNode->Node().node,
799812fde99SAxel Dörfler 		timeSource.node);
800812fde99SAxel Dörfler 	if (fInitStatus != B_OK) {
801812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't SetTimeSourceFor: %s\n",
802812fde99SAxel Dörfler 			strerror(fInitStatus));
803812fde99SAxel Dörfler 		return;
804812fde99SAxel Dörfler 	}
805812fde99SAxel Dörfler 
806812fde99SAxel Dörfler 	// find a free media_input
807812fde99SAxel Dörfler 	if (!input) {
808812fde99SAxel Dörfler 		fInitStatus = roster->GetFreeInputsFor(inputNode, &_input, 1,
809812fde99SAxel Dörfler 			&inputCount, B_MEDIA_RAW_AUDIO);
810812fde99SAxel Dörfler 		if (fInitStatus != B_OK) {
811812fde99SAxel Dörfler 			TRACE("BSoundPlayer::_Init: Couldn't GetFreeInputsFor: %s\n",
812812fde99SAxel Dörfler 				strerror(fInitStatus));
813812fde99SAxel Dörfler 			return;
814812fde99SAxel Dörfler 		}
815812fde99SAxel Dörfler 		if (inputCount < 1) {
816812fde99SAxel Dörfler 			TRACE("BSoundPlayer::_Init: Couldn't find a free input\n");
817812fde99SAxel Dörfler 			fInitStatus = B_ERROR;
818812fde99SAxel Dörfler 			return;
819812fde99SAxel Dörfler 		}
820812fde99SAxel Dörfler 	} else {
821812fde99SAxel Dörfler 		_input = *input;
822812fde99SAxel Dörfler 	}
823812fde99SAxel Dörfler 
824812fde99SAxel Dörfler 	// find a free media_output
825812fde99SAxel Dörfler 	fInitStatus = roster->GetFreeOutputsFor(fPlayerNode->Node(), &_output, 1,
826812fde99SAxel Dörfler 		&outputCount, B_MEDIA_RAW_AUDIO);
827812fde99SAxel Dörfler 	if (fInitStatus != B_OK) {
828812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't GetFreeOutputsFor: %s\n",
829812fde99SAxel Dörfler 			strerror(fInitStatus));
830812fde99SAxel Dörfler 		return;
831812fde99SAxel Dörfler 	}
832812fde99SAxel Dörfler 	if (outputCount < 1) {
833812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't find a free output\n");
834812fde99SAxel Dörfler 		fInitStatus = B_ERROR;
835812fde99SAxel Dörfler 		return;
836812fde99SAxel Dörfler 	}
837812fde99SAxel Dörfler 
838812fde99SAxel Dörfler 	// Set an appropriate run mode for the producer
839812fde99SAxel Dörfler 	fInitStatus = roster->SetRunModeNode(fPlayerNode->Node(),
840812fde99SAxel Dörfler 		BMediaNode::B_INCREASE_LATENCY);
841812fde99SAxel Dörfler 	if (fInitStatus != B_OK) {
842812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't SetRunModeNode: %s\n",
843812fde99SAxel Dörfler 			strerror(fInitStatus));
844812fde99SAxel Dörfler 		return;
845812fde99SAxel Dörfler 	}
846812fde99SAxel Dörfler 
847812fde99SAxel Dörfler 	// setup our requested format (can still have many wildcards)
848812fde99SAxel Dörfler 	tryFormat.type = B_MEDIA_RAW_AUDIO;
849812fde99SAxel Dörfler 	tryFormat.u.raw_audio = *format;
850812fde99SAxel Dörfler 
851812fde99SAxel Dörfler #if DEBUG > 0
852812fde99SAxel Dörfler 	char buf[100];
853812fde99SAxel Dörfler 	string_for_format(tryFormat, buf, sizeof(buf));
854812fde99SAxel Dörfler 	TRACE("BSoundPlayer::_Init: trying to connect with format %s\n", buf);
855812fde99SAxel Dörfler #endif
856812fde99SAxel Dörfler 
857812fde99SAxel Dörfler 	// and connect the nodes
858812fde99SAxel Dörfler 	fInitStatus = roster->Connect(_output.source, _input.destination,
859812fde99SAxel Dörfler 		&tryFormat, &fMediaOutput, &fMediaInput);
860812fde99SAxel Dörfler 	if (fInitStatus != B_OK) {
861812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_Init: Couldn't Connect: %s\n",
862812fde99SAxel Dörfler 			strerror(fInitStatus));
863812fde99SAxel Dörfler 		return;
864812fde99SAxel Dörfler 	}
865812fde99SAxel Dörfler 
866812fde99SAxel Dörfler 	fFlags |= F_NODES_CONNECTED;
867812fde99SAxel Dörfler 
868812fde99SAxel Dörfler 	_GetVolumeSlider();
869812fde99SAxel Dörfler 
870812fde99SAxel Dörfler 	TRACE("BSoundPlayer node %ld has timesource %ld\n",
871812fde99SAxel Dörfler 		fPlayerNode->Node().node, fPlayerNode->TimeSource()->Node().node);
87252a38012Sejakowatz }
87352a38012Sejakowatz 
87452a38012Sejakowatz 
87552a38012Sejakowatz void
876812fde99SAxel Dörfler BSoundPlayer::_NotifySoundDone(play_id id, bool gotToPlay)
877812fde99SAxel Dörfler {
878812fde99SAxel Dörfler 	CALLED();
87915c81466SAxel Dörfler 	Notify(B_SOUND_DONE, id, gotToPlay);
880812fde99SAxel Dörfler }
881812fde99SAxel Dörfler 
882812fde99SAxel Dörfler 
883812fde99SAxel Dörfler void
884812fde99SAxel Dörfler BSoundPlayer::_GetVolumeSlider()
88552a38012Sejakowatz {
886adc3b786SJérôme Duval 	CALLED();
887adc3b786SJérôme Duval 
888d6105cedSbeveloper 	ASSERT(fVolumeSlider == NULL);
889d6105cedSbeveloper 
89037ed595fSJérôme Duval 	BMediaRoster *roster = BMediaRoster::CurrentRoster();
89140c2c00aSbeveloper 	if (!roster) {
892812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_GetVolumeSlider failed to get BMediaRoster");
89337ed595fSJérôme Duval 		return;
89440c2c00aSbeveloper 	}
895d6105cedSbeveloper 
89640c2c00aSbeveloper 	if (!fParameterWeb && roster->GetParameterWebFor(fMediaInput.node, &fParameterWeb) < B_OK) {
897812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_GetVolumeSlider couldn't get parameter web");
89837ed595fSJérôme Duval 		return;
89940c2c00aSbeveloper 	}
900d6105cedSbeveloper 
901d6105cedSbeveloper 	int count = fParameterWeb->CountParameters();
902d6105cedSbeveloper 	for (int i = 0; i < count; i++) {
903df42a7b5Sbeveloper 		BParameter *parameter = fParameterWeb->ParameterAt(i);
904d6105cedSbeveloper 		if (parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER)
90537ed595fSJérôme Duval 			continue;
906df42a7b5Sbeveloper 		if ((parameter->ID() >> 16) != fMediaInput.destination.id)
907d6105cedSbeveloper 			continue;
908d6105cedSbeveloper 		if  (strcmp(parameter->Kind(), B_GAIN) != 0)
909d6105cedSbeveloper 			continue;
910d6105cedSbeveloper 		fVolumeSlider = (BContinuousParameter *)parameter;
91137ed595fSJérôme Duval 		break;
91237ed595fSJérôme Duval 	}
91340c2c00aSbeveloper 
91440c2c00aSbeveloper #if DEBUG >0
91540c2c00aSbeveloper 	if (!fVolumeSlider) {
916812fde99SAxel Dörfler 		TRACE("BSoundPlayer::_GetVolumeSlider couldn't find volume control");
91740c2c00aSbeveloper 	}
91840c2c00aSbeveloper #endif
91952a38012Sejakowatz }
92052a38012Sejakowatz 
921d6105cedSbeveloper 
922812fde99SAxel Dörfler void
92315c81466SAxel Dörfler BSoundPlayer::Notify(sound_player_notification what, ...)
92452a38012Sejakowatz {
92552a38012Sejakowatz 	CALLED();
926d6105cedSbeveloper 	if (fLocker.Lock()) {
927d6105cedSbeveloper 		if (fNotifierFunc)
928d6105cedSbeveloper 			(*fNotifierFunc)(fCookie, what);
929d6105cedSbeveloper 		fLocker.Unlock();
93052a38012Sejakowatz 	}
93152a38012Sejakowatz }
93252a38012Sejakowatz 
93352a38012Sejakowatz 
934812fde99SAxel Dörfler void
93515c81466SAxel Dörfler BSoundPlayer::PlayBuffer(void* buffer, size_t size,
936812fde99SAxel Dörfler 	const media_raw_audio_format& format)
93752a38012Sejakowatz {
938d6105cedSbeveloper 	if (fLocker.Lock()) {
939d6105cedSbeveloper 		if (fPlayBufferFunc)
940d6105cedSbeveloper 			(*fPlayBufferFunc)(fCookie, buffer, size, format);
941d6105cedSbeveloper 		fLocker.Unlock();
94252a38012Sejakowatz 	}
94352a38012Sejakowatz }
944df42a7b5Sbeveloper 
945df42a7b5Sbeveloper 
946812fde99SAxel Dörfler // #pragma mark - public sound_error
947df42a7b5Sbeveloper 
948df42a7b5Sbeveloper 
949812fde99SAxel Dörfler sound_error::sound_error(const char* string)
950df42a7b5Sbeveloper {
951812fde99SAxel Dörfler 	m_str_const = string;
952df42a7b5Sbeveloper }
953df42a7b5Sbeveloper 
954df42a7b5Sbeveloper 
955df42a7b5Sbeveloper const char*
956bedeb04eSIngo Weinhold sound_error::what() const throw()
957df42a7b5Sbeveloper {
958df42a7b5Sbeveloper 	return m_str_const;
959df42a7b5Sbeveloper }
960df42a7b5Sbeveloper 
961