xref: /haiku/src/kits/media/SoundPlayer.cpp (revision 95531d1e1b20987bfa84ee66d625abb5e1ea52fb)
152a38012Sejakowatz /***********************************************************************
2*95531d1eSJérôme Duval  * AUTHOR: Marcus Overhagen, Jérôme Duval
352a38012Sejakowatz  *   FILE: SoundPlayer.cpp
452a38012Sejakowatz  *  DESCR:
552a38012Sejakowatz  ***********************************************************************/
652a38012Sejakowatz #include <TimeSource.h>
7*95531d1eSJérôme Duval #include "SoundPlayer.h"
852a38012Sejakowatz #include <MediaRoster.h>
952a38012Sejakowatz #include <math.h>
1052a38012Sejakowatz 
1152a38012Sejakowatz #include "debug.h"
1252a38012Sejakowatz #include "SoundPlayNode.h"
1352a38012Sejakowatz 
1452a38012Sejakowatz /* this is the normal volume DB range of 16 bit integer */
1552a38012Sejakowatz const float minDB = -96;
1652a38012Sejakowatz const float maxDB = 0;
1752a38012Sejakowatz 
1852a38012Sejakowatz /*************************************************************
1952a38012Sejakowatz  * public sound_error
2052a38012Sejakowatz  *************************************************************/
2152a38012Sejakowatz 
2252a38012Sejakowatz //final
2352a38012Sejakowatz sound_error::sound_error(const char *str)
2452a38012Sejakowatz {
2552a38012Sejakowatz 	CALLED();
2652a38012Sejakowatz 	m_str_const = str;
2752a38012Sejakowatz }
2852a38012Sejakowatz 
2952a38012Sejakowatz //final
3052a38012Sejakowatz const char *
3152a38012Sejakowatz sound_error::what() const
3252a38012Sejakowatz {
3352a38012Sejakowatz 	CALLED();
3452a38012Sejakowatz 	return m_str_const;
3552a38012Sejakowatz }
3652a38012Sejakowatz 
3752a38012Sejakowatz /*************************************************************
3852a38012Sejakowatz  * public BSoundPlayer
3952a38012Sejakowatz  *************************************************************/
4052a38012Sejakowatz 
4152a38012Sejakowatz BSoundPlayer::BSoundPlayer(const char * name,
4252a38012Sejakowatz 						   void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
4352a38012Sejakowatz 						   void (*Notifier)(void *, sound_player_notification what, ...),
4452a38012Sejakowatz 						   void * cookie)
4552a38012Sejakowatz {
4652a38012Sejakowatz 	CALLED();
4752a38012Sejakowatz 
4852a38012Sejakowatz 	Init(NULL,&media_multi_audio_format::wildcard,name,NULL,PlayBuffer,Notifier,cookie);
4952a38012Sejakowatz }
5052a38012Sejakowatz 
5152a38012Sejakowatz BSoundPlayer::BSoundPlayer(const media_raw_audio_format * format,
5252a38012Sejakowatz 						   const char * name,
5352a38012Sejakowatz 						   void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
5452a38012Sejakowatz 						   void (*Notifier)(void *, sound_player_notification what, ...),
5552a38012Sejakowatz 						   void * cookie)
5652a38012Sejakowatz {
5752a38012Sejakowatz 	CALLED();
5852a38012Sejakowatz 	media_multi_audio_format fmt = media_multi_audio_format::wildcard;
5952a38012Sejakowatz 	memcpy(&fmt,format,sizeof(*format));
6052a38012Sejakowatz 	Init(NULL,&fmt,name,NULL,PlayBuffer,Notifier,cookie);
6152a38012Sejakowatz }
6252a38012Sejakowatz 
6352a38012Sejakowatz BSoundPlayer::BSoundPlayer(const media_node & toNode,
6452a38012Sejakowatz 						   const media_multi_audio_format * format,
6552a38012Sejakowatz 						   const char * name,
6652a38012Sejakowatz 						   const media_input * input,
6752a38012Sejakowatz 						   void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
6852a38012Sejakowatz 						   void (*Notifier)(void *, sound_player_notification what, ...),
6952a38012Sejakowatz 						   void * cookie)
7052a38012Sejakowatz {
7152a38012Sejakowatz 	CALLED();
7252a38012Sejakowatz 	if (toNode.kind & B_BUFFER_CONSUMER == 0)
7352a38012Sejakowatz 		debugger("BSoundPlayer: toNode must have B_BUFFER_CONSUMER kind!\n");
7452a38012Sejakowatz 	Init(&toNode,format,name,input,PlayBuffer,Notifier,cookie);
7552a38012Sejakowatz }
7652a38012Sejakowatz 
7752a38012Sejakowatz /* virtual */
7852a38012Sejakowatz BSoundPlayer::~BSoundPlayer()
7952a38012Sejakowatz {
8052a38012Sejakowatz 	CALLED();
81*95531d1eSJérôme Duval 	if (_m_node) {
82*95531d1eSJérôme Duval 		BMediaRoster *roster = BMediaRoster::Roster();
83*95531d1eSJérôme Duval 		if (!roster) {
84*95531d1eSJérôme Duval 			TRACE("BSoundPlayer::~BSoundPlayer: Couldn't get BMediaRoster\n");
85*95531d1eSJérôme Duval 		} else {
86*95531d1eSJérôme Duval 			status_t err;
87*95531d1eSJérôme Duval 
88*95531d1eSJérôme Duval 			// Ordinarily we'd stop *all* of the nodes in the chain at this point.  However,
89*95531d1eSJérôme Duval 			// one of the nodes is the System Mixer, and stopping the Mixer is a Bad Idea (tm).
90*95531d1eSJérôme Duval 			// So, we just disconnect from it, and release our references to the nodes that
91*95531d1eSJérôme Duval 			// we're using.  We *are* supposed to do that even for global nodes like the Mixer.
92*95531d1eSJérôme Duval 			Stop(true, false);
93*95531d1eSJérôme Duval 
94*95531d1eSJérôme Duval 			err = roster->Disconnect(m_input.node.node, m_input.source,
95*95531d1eSJérôme Duval 				m_output.node.node, m_output.destination);
96*95531d1eSJérôme Duval 			if (err) {
97*95531d1eSJérôme Duval 				fprintf(stderr, "* Error disconnecting nodes:  %ld (%s)\n", err, strerror(err));
98*95531d1eSJérôme Duval 			}
99*95531d1eSJérôme Duval 
100*95531d1eSJérôme Duval 			err = roster->ReleaseNode(m_input.node);
101*95531d1eSJérôme Duval 			if (err) {
102*95531d1eSJérôme Duval 				fprintf(stderr, "* Error releasing input node:  %ld (%s)\n", err, strerror(err));
103*95531d1eSJérôme Duval 			}
104*95531d1eSJérôme Duval 
105*95531d1eSJérôme Duval 			err = roster->ReleaseNode(m_output.node);
106*95531d1eSJérôme Duval 			if (err) {
107*95531d1eSJérôme Duval 				fprintf(stderr, "* Error releasing output node:  %ld (%s)\n", err, strerror(err));
108*95531d1eSJérôme Duval 			}
109*95531d1eSJérôme Duval 			_m_node = NULL;
110*95531d1eSJérôme Duval 		}
111*95531d1eSJérôme Duval 	}
11252a38012Sejakowatz 	delete [] _m_buf;
11352a38012Sejakowatz }
11452a38012Sejakowatz 
11552a38012Sejakowatz 
11652a38012Sejakowatz status_t
11752a38012Sejakowatz BSoundPlayer::InitCheck()
11852a38012Sejakowatz {
11952a38012Sejakowatz 	CALLED();
12052a38012Sejakowatz 	return _m_init_err;
12152a38012Sejakowatz }
12252a38012Sejakowatz 
12352a38012Sejakowatz 
12452a38012Sejakowatz media_raw_audio_format
12552a38012Sejakowatz BSoundPlayer::Format() const
12652a38012Sejakowatz {
12752a38012Sejakowatz 	CALLED();
12852a38012Sejakowatz 
12952a38012Sejakowatz 	media_raw_audio_format temp = media_raw_audio_format::wildcard;
13052a38012Sejakowatz 
13152a38012Sejakowatz 	if (_m_node) {
13252a38012Sejakowatz 		media_multi_audio_format fmt;
13352a38012Sejakowatz 		fmt = _m_node->Format();
13452a38012Sejakowatz 		memcpy(&temp,&fmt,sizeof(temp));
13552a38012Sejakowatz 	}
13652a38012Sejakowatz 
13752a38012Sejakowatz 	return temp;
13852a38012Sejakowatz }
13952a38012Sejakowatz 
14052a38012Sejakowatz 
14152a38012Sejakowatz status_t
14252a38012Sejakowatz BSoundPlayer::Start()
14352a38012Sejakowatz {
14452a38012Sejakowatz 	CALLED();
14552a38012Sejakowatz 
14652a38012Sejakowatz 	if (!_m_node)
14752a38012Sejakowatz 		return B_ERROR;
14852a38012Sejakowatz 
149*95531d1eSJérôme Duval 	BMediaRoster *roster = BMediaRoster::Roster();
150*95531d1eSJérôme Duval 	if (!roster) {
151*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n");
152*95531d1eSJérôme Duval 		return B_ERROR;
153*95531d1eSJérôme Duval 	}
154*95531d1eSJérôme Duval 
155*95531d1eSJérôme Duval 	BTimeSource *timeSource = roster->MakeTimeSourceFor(_m_node->Node());
156*95531d1eSJérôme Duval 
157*95531d1eSJérôme Duval 	// make sure we give the producer enough time to run buffers through
158*95531d1eSJérôme Duval 			// the node chain, otherwise it'll start up already late
159*95531d1eSJérôme Duval 	bigtime_t latency = 0;
160*95531d1eSJérôme Duval 	status_t err = roster->GetLatencyFor(_m_node->Node(), &latency);
161*95531d1eSJérôme Duval 
162*95531d1eSJérôme Duval 	err = roster->StartNode(_m_node->Node(), timeSource->Now() + latency);
163*95531d1eSJérôme Duval 
164*95531d1eSJérôme Duval 	timeSource->Release();
165*95531d1eSJérôme Duval 
166*95531d1eSJérôme Duval 	return err;
16752a38012Sejakowatz }
16852a38012Sejakowatz 
16952a38012Sejakowatz 
17052a38012Sejakowatz void
17152a38012Sejakowatz BSoundPlayer::Stop(bool block,
17252a38012Sejakowatz 				   bool flush)
17352a38012Sejakowatz {
17452a38012Sejakowatz 	CALLED();
17552a38012Sejakowatz 
17652a38012Sejakowatz 	if (!_m_node)
17752a38012Sejakowatz 		return;
17852a38012Sejakowatz 
179*95531d1eSJérôme Duval 	BMediaRoster *roster = BMediaRoster::Roster();
180*95531d1eSJérôme Duval 	if (!roster) {
181*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n");
182*95531d1eSJérôme Duval 		return;
183*95531d1eSJérôme Duval 	}
184*95531d1eSJérôme Duval 
185*95531d1eSJérôme Duval 	roster->StopNode(_m_node->Node(), 0, true);
186*95531d1eSJérôme Duval 
18752a38012Sejakowatz }
18852a38012Sejakowatz 
18952a38012Sejakowatz BSoundPlayer::BufferPlayerFunc
19052a38012Sejakowatz BSoundPlayer::BufferPlayer() const
19152a38012Sejakowatz {
19252a38012Sejakowatz 	CALLED();
19352a38012Sejakowatz 	return _PlayBuffer;
19452a38012Sejakowatz }
19552a38012Sejakowatz 
19652a38012Sejakowatz void BSoundPlayer::SetBufferPlayer(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format))
19752a38012Sejakowatz {
19852a38012Sejakowatz 	CALLED();
19952a38012Sejakowatz 	_m_lock.Lock();
20052a38012Sejakowatz 	_PlayBuffer = PlayBuffer;
20152a38012Sejakowatz 	_m_lock.Unlock();
20252a38012Sejakowatz }
20352a38012Sejakowatz 
20452a38012Sejakowatz BSoundPlayer::EventNotifierFunc
20552a38012Sejakowatz BSoundPlayer::EventNotifier() const
20652a38012Sejakowatz {
20752a38012Sejakowatz 	CALLED();
20852a38012Sejakowatz 	return _Notifier;
20952a38012Sejakowatz }
21052a38012Sejakowatz 
21152a38012Sejakowatz void BSoundPlayer::SetNotifier(void (*Notifier)(void *, sound_player_notification what, ...))
21252a38012Sejakowatz {
21352a38012Sejakowatz 	CALLED();
21452a38012Sejakowatz 	_m_lock.Lock();
21552a38012Sejakowatz 	_Notifier = Notifier;
21652a38012Sejakowatz 	_m_lock.Unlock();
21752a38012Sejakowatz }
21852a38012Sejakowatz 
21952a38012Sejakowatz void *
22052a38012Sejakowatz BSoundPlayer::Cookie() const
22152a38012Sejakowatz {
22252a38012Sejakowatz 	CALLED();
22352a38012Sejakowatz 	return _m_cookie;
22452a38012Sejakowatz }
22552a38012Sejakowatz 
22652a38012Sejakowatz void
22752a38012Sejakowatz BSoundPlayer::SetCookie(void *cookie)
22852a38012Sejakowatz {
22952a38012Sejakowatz 	CALLED();
23052a38012Sejakowatz 	_m_lock.Lock();
23152a38012Sejakowatz 	_m_cookie = cookie;
23252a38012Sejakowatz 	_m_lock.Unlock();
23352a38012Sejakowatz }
23452a38012Sejakowatz 
23552a38012Sejakowatz void BSoundPlayer::SetCallbacks(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
23652a38012Sejakowatz 								void (*Notifier)(void *, sound_player_notification what, ...),
23752a38012Sejakowatz 								void * cookie)
23852a38012Sejakowatz {
23952a38012Sejakowatz 	CALLED();
24052a38012Sejakowatz 	_m_lock.Lock();
24152a38012Sejakowatz 	SetBufferPlayer(PlayBuffer);
24252a38012Sejakowatz 	SetNotifier(Notifier);
24352a38012Sejakowatz 	SetCookie(cookie);
24452a38012Sejakowatz 	_m_lock.Unlock();
24552a38012Sejakowatz }
24652a38012Sejakowatz 
24752a38012Sejakowatz 
24852a38012Sejakowatz bigtime_t
24952a38012Sejakowatz BSoundPlayer::CurrentTime()
25052a38012Sejakowatz {
25152a38012Sejakowatz 	CALLED();
25252a38012Sejakowatz 	if (!_m_node)
25352a38012Sejakowatz 		return system_time();
254*95531d1eSJérôme Duval 
255*95531d1eSJérôme Duval 	return _m_node->TimeSource()->Now();
25652a38012Sejakowatz }
25752a38012Sejakowatz 
25852a38012Sejakowatz 
25952a38012Sejakowatz bigtime_t
26052a38012Sejakowatz BSoundPlayer::PerformanceTime()
26152a38012Sejakowatz {
26252a38012Sejakowatz 	CALLED();
26352a38012Sejakowatz 	if (!_m_node)
26452a38012Sejakowatz 		return (bigtime_t) B_ERROR;
265*95531d1eSJérôme Duval 
266*95531d1eSJérôme Duval 	return _m_node->TimeSource()->Now();
26752a38012Sejakowatz }
26852a38012Sejakowatz 
26952a38012Sejakowatz 
27052a38012Sejakowatz status_t
27152a38012Sejakowatz BSoundPlayer::Preroll()
27252a38012Sejakowatz {
273*95531d1eSJérôme Duval 	CALLED();
27452a38012Sejakowatz 
275*95531d1eSJérôme Duval 	BMediaRoster *roster = BMediaRoster::Roster();
276*95531d1eSJérôme Duval 	if (!roster) {
277*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n");
278*95531d1eSJérôme Duval 		return B_ERROR;
279*95531d1eSJérôme Duval 	}
280*95531d1eSJérôme Duval 
281*95531d1eSJérôme Duval 	status_t err = roster->PrerollNode(m_output.node);
282*95531d1eSJérôme Duval 
283*95531d1eSJérôme Duval 	if(err != B_OK) {
284*95531d1eSJérôme Duval 		fprintf(stderr, "Error while PrerollNode:  %ld (%s)\n", err, strerror(err));
285*95531d1eSJérôme Duval 	}
286*95531d1eSJérôme Duval 
287*95531d1eSJérôme Duval 	return err;
28852a38012Sejakowatz }
28952a38012Sejakowatz 
29052a38012Sejakowatz 
29152a38012Sejakowatz BSoundPlayer::play_id
29252a38012Sejakowatz BSoundPlayer::StartPlaying(BSound *sound,
29352a38012Sejakowatz 						   bigtime_t at_time)
29452a38012Sejakowatz {
29552a38012Sejakowatz 	UNIMPLEMENTED();
29652a38012Sejakowatz 	return 1;
29752a38012Sejakowatz }
29852a38012Sejakowatz 
29952a38012Sejakowatz 
30052a38012Sejakowatz BSoundPlayer::play_id
30152a38012Sejakowatz BSoundPlayer::StartPlaying(BSound *sound,
30252a38012Sejakowatz 						   bigtime_t at_time,
30352a38012Sejakowatz 						   float with_volume)
30452a38012Sejakowatz {
30552a38012Sejakowatz 	UNIMPLEMENTED();
30652a38012Sejakowatz 	return 1;
30752a38012Sejakowatz }
30852a38012Sejakowatz 
30952a38012Sejakowatz 
31052a38012Sejakowatz status_t
31152a38012Sejakowatz BSoundPlayer::SetSoundVolume(play_id sound,
31252a38012Sejakowatz 							 float new_volume)
31352a38012Sejakowatz {
31452a38012Sejakowatz 	UNIMPLEMENTED();
31552a38012Sejakowatz 
31652a38012Sejakowatz 	return B_OK;
31752a38012Sejakowatz }
31852a38012Sejakowatz 
31952a38012Sejakowatz 
32052a38012Sejakowatz bool
32152a38012Sejakowatz BSoundPlayer::IsPlaying(play_id id)
32252a38012Sejakowatz {
32352a38012Sejakowatz 	UNIMPLEMENTED();
32452a38012Sejakowatz 
32552a38012Sejakowatz 	return true;
32652a38012Sejakowatz }
32752a38012Sejakowatz 
32852a38012Sejakowatz 
32952a38012Sejakowatz status_t
33052a38012Sejakowatz BSoundPlayer::StopPlaying(play_id id)
33152a38012Sejakowatz {
33252a38012Sejakowatz 	UNIMPLEMENTED();
33352a38012Sejakowatz 
33452a38012Sejakowatz 	return B_OK;
33552a38012Sejakowatz }
33652a38012Sejakowatz 
33752a38012Sejakowatz 
33852a38012Sejakowatz status_t
33952a38012Sejakowatz BSoundPlayer::WaitForSound(play_id id)
34052a38012Sejakowatz {
34152a38012Sejakowatz 	UNIMPLEMENTED();
34252a38012Sejakowatz 
34352a38012Sejakowatz 	return B_OK;
34452a38012Sejakowatz }
34552a38012Sejakowatz 
34652a38012Sejakowatz 
34752a38012Sejakowatz float
34852a38012Sejakowatz BSoundPlayer::Volume()
34952a38012Sejakowatz {
35052a38012Sejakowatz 	CALLED();
35152a38012Sejakowatz 	return _m_volume;
35252a38012Sejakowatz }
35352a38012Sejakowatz 
35452a38012Sejakowatz 
35552a38012Sejakowatz void
35652a38012Sejakowatz BSoundPlayer::SetVolume(float new_volume)
35752a38012Sejakowatz {
35852a38012Sejakowatz 	CALLED();
35952a38012Sejakowatz 	_m_lock.Lock();
36052a38012Sejakowatz 	if (new_volume >= 0.0f)
36152a38012Sejakowatz 		_m_volume = new_volume;
36252a38012Sejakowatz 	_m_lock.Unlock();
36352a38012Sejakowatz }
36452a38012Sejakowatz 
36552a38012Sejakowatz 
36652a38012Sejakowatz float
36752a38012Sejakowatz BSoundPlayer::VolumeDB(bool forcePoll)
36852a38012Sejakowatz {
36952a38012Sejakowatz 	CALLED();
37052a38012Sejakowatz 	return 20.0f * log10(_m_volume);
37152a38012Sejakowatz }
37252a38012Sejakowatz 
37352a38012Sejakowatz 
37452a38012Sejakowatz void
37552a38012Sejakowatz BSoundPlayer::SetVolumeDB(float volume_dB)
37652a38012Sejakowatz {
37752a38012Sejakowatz 	CALLED();
37852a38012Sejakowatz 	_m_lock.Lock();
37952a38012Sejakowatz 	_m_volume = pow(10.0f,volume_dB / 20.0f);
38052a38012Sejakowatz 	_m_lock.Unlock();
38152a38012Sejakowatz }
38252a38012Sejakowatz 
38352a38012Sejakowatz 
38452a38012Sejakowatz status_t
38552a38012Sejakowatz BSoundPlayer::GetVolumeInfo(media_node *out_node,
38652a38012Sejakowatz 							int32 *out_parameter,
38752a38012Sejakowatz 							float *out_min_dB,
38852a38012Sejakowatz 							float *out_max_dB)
38952a38012Sejakowatz {
39052a38012Sejakowatz 	BROKEN();
39152a38012Sejakowatz 
39252a38012Sejakowatz 	*out_node = m_output.node;
39352a38012Sejakowatz 	*out_parameter = -1; /* is the parameter ID for the volume control */
39452a38012Sejakowatz 	*out_min_dB = minDB;
39552a38012Sejakowatz 	*out_max_dB = maxDB;
39652a38012Sejakowatz 
39752a38012Sejakowatz 	return B_OK;
39852a38012Sejakowatz }
39952a38012Sejakowatz 
40052a38012Sejakowatz 
40152a38012Sejakowatz bigtime_t
40252a38012Sejakowatz BSoundPlayer::Latency()
40352a38012Sejakowatz {
404*95531d1eSJérôme Duval 	CALLED();
405*95531d1eSJérôme Duval 
406*95531d1eSJérôme Duval 	BMediaRoster *roster = BMediaRoster::Roster();
407*95531d1eSJérôme Duval 	if (!roster) {
408*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Latency: Couldn't get BMediaRoster\n");
409*95531d1eSJérôme Duval 		return 0;
410*95531d1eSJérôme Duval 	}
411*95531d1eSJérôme Duval 
412*95531d1eSJérôme Duval 	bigtime_t latency = 0;
413*95531d1eSJérôme Duval 	status_t err = roster->GetLatencyFor(m_output.node, &latency);
414*95531d1eSJérôme Duval 
415*95531d1eSJérôme Duval 	if(err != B_OK) {
416*95531d1eSJérôme Duval 		fprintf(stderr, "Error while GetLatencyFor:  %ld (%s)\n", err, strerror(err));
417*95531d1eSJérôme Duval 	}
418*95531d1eSJérôme Duval 
419*95531d1eSJérôme Duval 	return latency;
42052a38012Sejakowatz }
42152a38012Sejakowatz 
42252a38012Sejakowatz 
42352a38012Sejakowatz /* virtual */ bool
42452a38012Sejakowatz BSoundPlayer::HasData()
42552a38012Sejakowatz {
42652a38012Sejakowatz 	CALLED();
42752a38012Sejakowatz 
42852a38012Sejakowatz 	return _m_has_data != 0;
42952a38012Sejakowatz }
43052a38012Sejakowatz 
43152a38012Sejakowatz 
43252a38012Sejakowatz void
43352a38012Sejakowatz BSoundPlayer::SetHasData(bool has_data)
43452a38012Sejakowatz {
43552a38012Sejakowatz 	CALLED();
43652a38012Sejakowatz 	_m_lock.Lock();
43752a38012Sejakowatz 	_m_has_data = has_data ? 1 : 0;
43852a38012Sejakowatz 	_m_lock.Unlock();
43952a38012Sejakowatz }
44052a38012Sejakowatz 
44152a38012Sejakowatz 
44252a38012Sejakowatz /*************************************************************
44352a38012Sejakowatz  * protected BSoundPlayer
44452a38012Sejakowatz  *************************************************************/
44552a38012Sejakowatz 
44652a38012Sejakowatz //final
44752a38012Sejakowatz void
44852a38012Sejakowatz BSoundPlayer::SetInitError(status_t in_error)
44952a38012Sejakowatz {
45052a38012Sejakowatz 	CALLED();
45152a38012Sejakowatz 	_m_init_err = in_error;
45252a38012Sejakowatz }
45352a38012Sejakowatz 
45452a38012Sejakowatz 
45552a38012Sejakowatz /*************************************************************
45652a38012Sejakowatz  * private BSoundPlayer
45752a38012Sejakowatz  *************************************************************/
45852a38012Sejakowatz 
45952a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_0(void *, ...) { return B_ERROR; }
46052a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_1(void *, ...) { return B_ERROR; }
46152a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_2(void *, ...) { return B_ERROR; }
46252a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_3(void *, ...) { return B_ERROR; }
46352a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_4(void *, ...) { return B_ERROR; }
46452a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_5(void *, ...) { return B_ERROR; }
46552a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_6(void *, ...) { return B_ERROR; }
46652a38012Sejakowatz status_t BSoundPlayer::_Reserved_SoundPlayer_7(void *, ...) { return B_ERROR; }
46752a38012Sejakowatz 
46852a38012Sejakowatz 
46952a38012Sejakowatz void
47052a38012Sejakowatz BSoundPlayer::NotifySoundDone(play_id sound,
47152a38012Sejakowatz 							  bool got_to_play)
47252a38012Sejakowatz {
47352a38012Sejakowatz 	UNIMPLEMENTED();
47452a38012Sejakowatz }
47552a38012Sejakowatz 
47652a38012Sejakowatz 
47752a38012Sejakowatz void
47852a38012Sejakowatz BSoundPlayer::get_volume_slider()
47952a38012Sejakowatz {
48052a38012Sejakowatz 	UNIMPLEMENTED();
48152a38012Sejakowatz }
48252a38012Sejakowatz 
48352a38012Sejakowatz void
48452a38012Sejakowatz BSoundPlayer::Init(
48552a38012Sejakowatz 					const media_node * node,
48652a38012Sejakowatz 					const media_multi_audio_format * format,
48752a38012Sejakowatz 					const char * name,
48852a38012Sejakowatz 					const media_input * input,
48952a38012Sejakowatz 					void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
49052a38012Sejakowatz 					void (*Notifier)(void *, sound_player_notification what, ...),
49152a38012Sejakowatz 					void * cookie)
49252a38012Sejakowatz {
49352a38012Sejakowatz 	BROKEN();
49452a38012Sejakowatz 	_m_node = NULL;
49552a38012Sejakowatz 	_m_sounds = NULL;
49652a38012Sejakowatz 	_m_waiting = NULL;
49752a38012Sejakowatz 	_PlayBuffer = PlayBuffer;
49852a38012Sejakowatz 	_Notifier = Notifier;
49952a38012Sejakowatz 	_m_volume = 0.0f;
50052a38012Sejakowatz 	_m_mix_buffer = 0;
50152a38012Sejakowatz 	_m_mix_buffer_size = 0;
50252a38012Sejakowatz 	_m_cookie = cookie;
50352a38012Sejakowatz 	_m_buf = NULL;
50452a38012Sejakowatz 	_m_bufsize = 0;
50552a38012Sejakowatz 	_m_has_data = 0;
50652a38012Sejakowatz 	_m_init_err = B_ERROR;
50752a38012Sejakowatz 	_m_perfTime = 0;
50852a38012Sejakowatz 	_m_volumeSlider = NULL;
50952a38012Sejakowatz 	_m_gotVolume = 0;
51052a38012Sejakowatz 
51152a38012Sejakowatz 	_m_node = 0;
51252a38012Sejakowatz 
513*95531d1eSJérôme Duval 	status_t err;
514*95531d1eSJérôme Duval 	media_node outputNode;
515*95531d1eSJérôme Duval 	media_output _output;
516*95531d1eSJérôme Duval 	media_input _input;
517*95531d1eSJérôme Duval 	int32 inputCount, outputCount;
518*95531d1eSJérôme Duval 	media_format tryFormat;
519*95531d1eSJérôme Duval 	media_multi_audio_format fmt;
520*95531d1eSJérôme Duval 	media_node timeSource;
521*95531d1eSJérôme Duval 
522*95531d1eSJérôme Duval 	BMediaRoster *roster = BMediaRoster::Roster();
52352a38012Sejakowatz 	if (!roster) {
52452a38012Sejakowatz 		TRACE("BSoundPlayer::Init: Couldn't get BMediaRoster\n");
52552a38012Sejakowatz 		return;
52652a38012Sejakowatz 	}
52752a38012Sejakowatz 
52852a38012Sejakowatz 	//connect our producer node either to the
52952a38012Sejakowatz 	//system mixer or to the supplied out node
53052a38012Sejakowatz 	if (!node) {
531*95531d1eSJérôme Duval 		err = roster->GetAudioMixer(&outputNode);
532*95531d1eSJérôme Duval 		if (err != B_OK) {
53352a38012Sejakowatz 			TRACE("BSoundPlayer::Init: Couldn't GetAudioMixer\n");
534*95531d1eSJérôme Duval 			goto the_end;
53552a38012Sejakowatz 		}
536*95531d1eSJérôme Duval 		node = &outputNode;
53752a38012Sejakowatz 	}
53852a38012Sejakowatz 
53952a38012Sejakowatz 	memcpy(&fmt,format,sizeof(fmt));
54052a38012Sejakowatz 
54152a38012Sejakowatz 	if (fmt.frame_rate == media_multi_audio_format::wildcard.frame_rate)
54252a38012Sejakowatz 		fmt.frame_rate = 44100.0f;
54352a38012Sejakowatz 	if (fmt.channel_count == media_multi_audio_format::wildcard.channel_count)
54452a38012Sejakowatz 		fmt.channel_count = 2;
54552a38012Sejakowatz 	if (fmt.format == media_multi_audio_format::wildcard.format)
54652a38012Sejakowatz 		fmt.format = media_raw_audio_format::B_AUDIO_FLOAT;
54752a38012Sejakowatz 	if (fmt.byte_order == media_multi_audio_format::wildcard.byte_order)
54852a38012Sejakowatz 		fmt.byte_order = B_MEDIA_HOST_ENDIAN;
54952a38012Sejakowatz 	if (fmt.buffer_size == media_multi_audio_format::wildcard.buffer_size)
55052a38012Sejakowatz 		fmt.buffer_size = 4096;
55152a38012Sejakowatz 
55252a38012Sejakowatz 	if (fmt.channel_count != 1 && fmt.channel_count != 2)
55352a38012Sejakowatz 		debugger("BSoundPlayer: not a 1 or 2 channel audio format\n");
55452a38012Sejakowatz 	if (fmt.frame_rate <= 0.0f)
55552a38012Sejakowatz 		debugger("BSoundPlayer: framerate must be > 0\n");
55652a38012Sejakowatz 
55752a38012Sejakowatz 	_m_bufsize = fmt.buffer_size;
55852a38012Sejakowatz 	_m_buf = new char[_m_bufsize];
55952a38012Sejakowatz 	_m_node = new _SoundPlayNode(name,&fmt,this);
56052a38012Sejakowatz 
561*95531d1eSJérôme Duval 	err = roster->RegisterNode(_m_node);
562*95531d1eSJérôme Duval 	if(err != B_OK) {
563*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Init: Couldn't RegisterNode\n");
564*95531d1eSJérôme Duval 		goto the_end;
565*95531d1eSJérôme Duval 	}
56652a38012Sejakowatz 
567*95531d1eSJérôme Duval 	// set the producer's time source to be the "default" time source, which
568*95531d1eSJérôme Duval 	// the Mixer uses too.
56952a38012Sejakowatz 
570*95531d1eSJérôme Duval 	roster->GetTimeSource(&timeSource);
571*95531d1eSJérôme Duval 	roster->SetTimeSourceFor(_m_node->Node().node, timeSource.node);
57252a38012Sejakowatz 
573*95531d1eSJérôme Duval 	if(!input) {
574*95531d1eSJérôme Duval 		err = roster->GetFreeInputsFor(*node, &_input, 1,
575*95531d1eSJérôme Duval 			&inputCount, B_MEDIA_RAW_AUDIO);
576*95531d1eSJérôme Duval 		if(err != B_OK) {
577*95531d1eSJérôme Duval 			TRACE("BSoundPlayer::Init: Couldn't GetFreeInputsFor\n");
578*95531d1eSJérôme Duval 			goto the_end;
579*95531d1eSJérôme Duval 		}
580*95531d1eSJérôme Duval 	} else {
581*95531d1eSJérôme Duval 		_input = *input;
582*95531d1eSJérôme Duval 	}
583*95531d1eSJérôme Duval 	err = roster->GetFreeOutputsFor(_m_node->Node(), &_output, 1, &outputCount, B_MEDIA_RAW_AUDIO);
584*95531d1eSJérôme Duval 	if(err != B_OK) {
585*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Init: Couldn't GetFreeOutputsFor\n");
586*95531d1eSJérôme Duval 		goto the_end;
587*95531d1eSJérôme Duval 	}
58852a38012Sejakowatz 
589*95531d1eSJérôme Duval 	//tryFormat.type = B_MEDIA_RAW_AUDIO;
590*95531d1eSJérôme Duval 	//tryformat.fileAudioOutput.format;
591*95531d1eSJérôme Duval 	tryFormat = _output.format;
592*95531d1eSJérôme Duval 	err = roster->Connect(_output.source, _input.destination, &tryFormat, &m_output, &m_input);
593*95531d1eSJérôme Duval 	if(err != B_OK) {
594*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Init: Couldn't Connect\n");
595*95531d1eSJérôme Duval 		goto the_end;
596*95531d1eSJérôme Duval 	}
59752a38012Sejakowatz 
598*95531d1eSJérôme Duval 	// Set an appropriate run mode for the producer
599*95531d1eSJérôme Duval 	err = roster->SetRunModeNode(_m_node->Node(), BMediaNode::B_INCREASE_LATENCY);
600*95531d1eSJérôme Duval 	if(err != B_OK) {
601*95531d1eSJérôme Duval 		TRACE("BSoundPlayer::Init: Couldn't SetRunModeNode\n");
602*95531d1eSJérôme Duval 		goto the_end;
603*95531d1eSJérôme Duval 	}
60452a38012Sejakowatz 
605*95531d1eSJérôme Duval the_end:
606*95531d1eSJérôme Duval 	TRACE("BSoundPlayer::Init: %s\n", strerror(err));
607*95531d1eSJérôme Duval 	SetInitError(err);
60852a38012Sejakowatz }
60952a38012Sejakowatz 
61052a38012Sejakowatz /* virtual */ void
61152a38012Sejakowatz BSoundPlayer::Notify(sound_player_notification what,
61252a38012Sejakowatz 					 ...)
61352a38012Sejakowatz {
61452a38012Sejakowatz 	CALLED();
61552a38012Sejakowatz 	_m_lock.Lock();
61652a38012Sejakowatz 	if (_Notifier)
61752a38012Sejakowatz 		(*_Notifier)(_m_cookie,what);
61852a38012Sejakowatz 	else {
61952a38012Sejakowatz 	}
62052a38012Sejakowatz 	_m_lock.Unlock();
62152a38012Sejakowatz }
62252a38012Sejakowatz 
62352a38012Sejakowatz 
62452a38012Sejakowatz /* virtual */ void
62552a38012Sejakowatz BSoundPlayer::PlayBuffer(void *buffer,
62652a38012Sejakowatz 						 size_t size,
62752a38012Sejakowatz 						 const media_raw_audio_format &format)
62852a38012Sejakowatz {
62952a38012Sejakowatz //	CALLED();
63052a38012Sejakowatz 	_m_lock.Lock();
63152a38012Sejakowatz 	if (_PlayBuffer)
63252a38012Sejakowatz 		(*_PlayBuffer)(_m_cookie,buffer,size,format);
63352a38012Sejakowatz 	else {
63452a38012Sejakowatz 	}
63552a38012Sejakowatz 	_m_lock.Unlock();
63652a38012Sejakowatz }
63752a38012Sejakowatz 
63852a38012Sejakowatz 
639