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
24b84955d4SBarrett17 #include "MediaDebug.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
BSoundPlayer(const char * name,BufferPlayerFunc playerFunction,EventNotifierFunc eventNotifierFunction,void * cookie)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
BSoundPlayer(const media_raw_audio_format * _format,const char * name,BufferPlayerFunc playerFunction,EventNotifierFunc eventNotifierFunction,void * cookie)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
BSoundPlayer(const media_node & toNode,const media_multi_audio_format * format,const char * name,const media_input * input,BufferPlayerFunc playerFunction,EventNotifierFunc eventNotifierFunction,void * cookie)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
~BSoundPlayer()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: "
1262ceb090fSDario Casalinuovo "%" B_PRId32 " (%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: "
1362ceb090fSDario Casalinuovo "%" B_PRId32 " (%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
146f1059fbdSDario Casalinuovo // supposed to be done by BMediaNode destructor automatically.
147f1059fbdSDario Casalinuovo
148f1059fbdSDario Casalinuovo // The node is deleted by the Release() when ref count reach 0.
149f1059fbdSDario Casalinuovo // Since we are the sole owners, and no one acquired it
150f1059fbdSDario Casalinuovo // this should be the case. The Quit() synchronization
151f1059fbdSDario Casalinuovo // is handled by the DeleteHook inheritance.
152f1059fbdSDario Casalinuovo // NOTE: this might be crucial when using a BMediaEventLooper.
153*80a920f6SMáximo Castañeda if (fPlayerNode != NULL && fPlayerNode->Release() != NULL) {
154f1059fbdSDario Casalinuovo TRACE("BSoundPlayer::~BSoundPlayer: Error the producer node "
155f1059fbdSDario Casalinuovo "appears to be acquired by someone else than us!");
156f1059fbdSDario Casalinuovo }
157d6105cedSbeveloper
158812fde99SAxel Dörfler // do not delete fVolumeSlider, it belongs to the parameter web
159d6105cedSbeveloper delete fParameterWeb;
16052a38012Sejakowatz }
16152a38012Sejakowatz
16252a38012Sejakowatz
16352a38012Sejakowatz status_t
InitCheck()16452a38012Sejakowatz BSoundPlayer::InitCheck()
16552a38012Sejakowatz {
16652a38012Sejakowatz CALLED();
167d6105cedSbeveloper return fInitStatus;
16852a38012Sejakowatz }
16952a38012Sejakowatz
17052a38012Sejakowatz
17152a38012Sejakowatz media_raw_audio_format
Format() const17252a38012Sejakowatz 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
Start()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) {
2132ceb090fSDario Casalinuovo TRACE("BSoundPlayer::Start: StartNode failed, %" B_PRId32, 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
Stop(bool block,bool flush)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
Latency()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) {
2882ceb090fSDario Casalinuovo TRACE("BSoundPlayer::Latency: GetLatencyFor failed %" B_PRId32
2892ceb090fSDario Casalinuovo " (%s)\n", err, strerror(err));
290df42a7b5Sbeveloper return 0;
291df42a7b5Sbeveloper }
292df42a7b5Sbeveloper
293f4ba347bSDario Casalinuovo TRACE("BSoundPlayer::Latency: latency is %" B_PRId64 "\n", latency);
29440c2c00aSbeveloper
295df42a7b5Sbeveloper return latency;
296df42a7b5Sbeveloper }
297df42a7b5Sbeveloper
298df42a7b5Sbeveloper
299df42a7b5Sbeveloper void
SetHasData(bool hasData)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
HasData()311df42a7b5Sbeveloper BSoundPlayer::HasData()
312df42a7b5Sbeveloper {
313df42a7b5Sbeveloper CALLED();
3144ed344afSAxel Dörfler return (atomic_get(&fFlags) & F_HAS_DATA) != 0;
315df42a7b5Sbeveloper }
316df42a7b5Sbeveloper
317df42a7b5Sbeveloper
31852a38012Sejakowatz BSoundPlayer::BufferPlayerFunc
BufferPlayer() const31952a38012Sejakowatz BSoundPlayer::BufferPlayer() const
32052a38012Sejakowatz {
32152a38012Sejakowatz CALLED();
322d6105cedSbeveloper return fPlayBufferFunc;
32352a38012Sejakowatz }
32452a38012Sejakowatz
325df42a7b5Sbeveloper
326df42a7b5Sbeveloper void
SetBufferPlayer(BufferPlayerFunc playerFunction)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
EventNotifier() const33752a38012Sejakowatz BSoundPlayer::EventNotifier() const
33852a38012Sejakowatz {
33952a38012Sejakowatz CALLED();
340d6105cedSbeveloper return fNotifierFunc;
34152a38012Sejakowatz }
34252a38012Sejakowatz
343df42a7b5Sbeveloper
344812fde99SAxel Dörfler void
SetNotifier(EventNotifierFunc eventNotifierFunction)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*
Cookie() const35552a38012Sejakowatz BSoundPlayer::Cookie() const
35652a38012Sejakowatz {
35752a38012Sejakowatz CALLED();
358d6105cedSbeveloper return fCookie;
35952a38012Sejakowatz }
36052a38012Sejakowatz
361df42a7b5Sbeveloper
36252a38012Sejakowatz void
SetCookie(void * cookie)36352a38012Sejakowatz BSoundPlayer::SetCookie(void *cookie)
36452a38012Sejakowatz {
36552a38012Sejakowatz CALLED();
366812fde99SAxel Dörfler BAutolock _(fLocker);
367812fde99SAxel Dörfler
368d6105cedSbeveloper fCookie = cookie;
36952a38012Sejakowatz }
37052a38012Sejakowatz
371df42a7b5Sbeveloper
372df42a7b5Sbeveloper void
SetCallbacks(BufferPlayerFunc playerFunction,EventNotifierFunc eventNotifierFunction,void * cookie)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
CurrentTime()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
PerformanceTime()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
Preroll()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) {
4302ceb090fSDario Casalinuovo TRACE("BSoundPlayer::Preroll: Error while PrerollNode: %"
4312ceb090fSDario Casalinuovo B_PRId32 " (%s)\n", 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
StartPlaying(BSound * sound,bigtime_t atTime)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
StartPlaying(BSound * sound,bigtime_t atTime,float withVolume)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
SetSoundVolume(play_id id,float newVolume)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
IsPlaying(play_id id)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
StopPlaying(play_id id)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
WaitForSound(play_id id)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
Volume()58452a38012Sejakowatz BSoundPlayer::Volume()
58552a38012Sejakowatz {
58652a38012Sejakowatz CALLED();
587adc3b786SJérôme Duval return pow(10.0, VolumeDB(true) / 20.0);
58852a38012Sejakowatz }
58952a38012Sejakowatz
59052a38012Sejakowatz
59152a38012Sejakowatz void
SetVolume(float newVolume)592812fde99SAxel Dörfler BSoundPlayer::SetVolume(float newVolume)
59352a38012Sejakowatz {
59452a38012Sejakowatz CALLED();
595812fde99SAxel Dörfler SetVolumeDB(20.0 * log10(newVolume));
59652a38012Sejakowatz }
59752a38012Sejakowatz
59852a38012Sejakowatz
59952a38012Sejakowatz float
VolumeDB(bool forcePoll)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
SetVolumeDB(float volumeDB)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
GetVolumeInfo(media_node * _node,int32 * _parameterID,float * _minDB,float * _maxDB)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
SetInitError(status_t error)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
_SoundPlayBufferFunc(void * cookie,void * buffer,size_t size,const media_raw_audio_format & format)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
_Reserved_SoundPlayer_0(void *,...)71652a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_0(void*, ...) { return B_ERROR; }
_Reserved_SoundPlayer_1(void *,...)71752a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_1(void*, ...) { return B_ERROR; }
_Reserved_SoundPlayer_2(void *,...)71852a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_2(void*, ...) { return B_ERROR; }
_Reserved_SoundPlayer_3(void *,...)71952a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_3(void*, ...) { return B_ERROR; }
_Reserved_SoundPlayer_4(void *,...)72052a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_4(void*, ...) { return B_ERROR; }
_Reserved_SoundPlayer_5(void *,...)72152a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_5(void*, ...) { return B_ERROR; }
_Reserved_SoundPlayer_6(void *,...)72252a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_6(void*, ...) { return B_ERROR; }
_Reserved_SoundPlayer_7(void *,...)72352a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_7(void*, ...) { return B_ERROR; }
72452a38012Sejakowatz
72552a38012Sejakowatz
72652a38012Sejakowatz void
_Init(const media_node * node,const media_multi_audio_format * format,const char * name,const media_input * input,BufferPlayerFunc playerFunction,EventNotifierFunc eventNotifierFunction,void * cookie)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
8702ceb090fSDario Casalinuovo TRACE("BSoundPlayer node %" B_PRId32 " has timesource %" B_PRId32 "\n",
871812fde99SAxel Dörfler fPlayerNode->Node().node, fPlayerNode->TimeSource()->Node().node);
87252a38012Sejakowatz }
87352a38012Sejakowatz
87452a38012Sejakowatz
87552a38012Sejakowatz void
_NotifySoundDone(play_id id,bool gotToPlay)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
_GetVolumeSlider()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
Notify(sound_player_notification what,...)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
PlayBuffer(void * buffer,size_t size,const media_raw_audio_format & format)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
sound_error(const char * string)949812fde99SAxel Dörfler sound_error::sound_error(const char* string)
950df42a7b5Sbeveloper {
951812fde99SAxel Dörfler m_str_const = string;
952df42a7b5Sbeveloper }
953df42a7b5Sbeveloper
954df42a7b5Sbeveloper
955df42a7b5Sbeveloper const char*
what() const956bedeb04eSIngo Weinhold sound_error::what() const throw()
957df42a7b5Sbeveloper {
958df42a7b5Sbeveloper return m_str_const;
959df42a7b5Sbeveloper }
960df42a7b5Sbeveloper
961