2002-07-09 12:24:59 +00:00
|
|
|
/***********************************************************************
|
2003-05-11 17:41:38 +00:00
|
|
|
* AUTHOR: Marcus Overhagen, Jérôme Duval
|
2002-07-09 12:24:59 +00:00
|
|
|
* FILE: SoundPlayer.cpp
|
|
|
|
|
* DESCR:
|
|
|
|
|
***********************************************************************/
|
|
|
|
|
#include <TimeSource.h>
|
2003-05-11 17:41:38 +00:00
|
|
|
#include "SoundPlayer.h"
|
2002-07-09 12:24:59 +00:00
|
|
|
#include <MediaRoster.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "debug.h"
|
|
|
|
|
#include "SoundPlayNode.h"
|
|
|
|
|
|
|
|
|
|
/* this is the normal volume DB range of 16 bit integer */
|
|
|
|
|
const float minDB = -96;
|
|
|
|
|
const float maxDB = 0;
|
|
|
|
|
|
|
|
|
|
/*************************************************************
|
|
|
|
|
* public sound_error
|
|
|
|
|
*************************************************************/
|
|
|
|
|
|
|
|
|
|
//final
|
|
|
|
|
sound_error::sound_error(const char *str)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
m_str_const = str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//final
|
|
|
|
|
const char *
|
|
|
|
|
sound_error::what() const
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
return m_str_const;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************
|
|
|
|
|
* public BSoundPlayer
|
|
|
|
|
*************************************************************/
|
|
|
|
|
|
|
|
|
|
BSoundPlayer::BSoundPlayer(const char * name,
|
|
|
|
|
void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
|
|
|
|
|
void (*Notifier)(void *, sound_player_notification what, ...),
|
|
|
|
|
void * cookie)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
|
|
|
|
|
Init(NULL,&media_multi_audio_format::wildcard,name,NULL,PlayBuffer,Notifier,cookie);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BSoundPlayer::BSoundPlayer(const media_raw_audio_format * format,
|
|
|
|
|
const char * name,
|
|
|
|
|
void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
|
|
|
|
|
void (*Notifier)(void *, sound_player_notification what, ...),
|
|
|
|
|
void * cookie)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
media_multi_audio_format fmt = media_multi_audio_format::wildcard;
|
|
|
|
|
memcpy(&fmt,format,sizeof(*format));
|
|
|
|
|
Init(NULL,&fmt,name,NULL,PlayBuffer,Notifier,cookie);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BSoundPlayer::BSoundPlayer(const media_node & toNode,
|
|
|
|
|
const media_multi_audio_format * format,
|
|
|
|
|
const char * name,
|
|
|
|
|
const media_input * input,
|
|
|
|
|
void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
|
|
|
|
|
void (*Notifier)(void *, sound_player_notification what, ...),
|
|
|
|
|
void * cookie)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
if (toNode.kind & B_BUFFER_CONSUMER == 0)
|
|
|
|
|
debugger("BSoundPlayer: toNode must have B_BUFFER_CONSUMER kind!\n");
|
|
|
|
|
Init(&toNode,format,name,input,PlayBuffer,Notifier,cookie);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* virtual */
|
|
|
|
|
BSoundPlayer::~BSoundPlayer()
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
2003-05-11 17:41:38 +00:00
|
|
|
if (_m_node) {
|
|
|
|
|
BMediaRoster *roster = BMediaRoster::Roster();
|
|
|
|
|
if (!roster) {
|
|
|
|
|
TRACE("BSoundPlayer::~BSoundPlayer: Couldn't get BMediaRoster\n");
|
|
|
|
|
} else {
|
|
|
|
|
status_t err;
|
|
|
|
|
|
|
|
|
|
// Ordinarily we'd stop *all* of the nodes in the chain at this point. However,
|
|
|
|
|
// one of the nodes is the System Mixer, and stopping the Mixer is a Bad Idea (tm).
|
|
|
|
|
// So, we just disconnect from it, and release our references to the nodes that
|
|
|
|
|
// we're using. We *are* supposed to do that even for global nodes like the Mixer.
|
|
|
|
|
Stop(true, false);
|
|
|
|
|
|
|
|
|
|
err = roster->Disconnect(m_input.node.node, m_input.source,
|
|
|
|
|
m_output.node.node, m_output.destination);
|
|
|
|
|
if (err) {
|
|
|
|
|
fprintf(stderr, "* Error disconnecting nodes: %ld (%s)\n", err, strerror(err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = roster->ReleaseNode(m_input.node);
|
|
|
|
|
if (err) {
|
|
|
|
|
fprintf(stderr, "* Error releasing input node: %ld (%s)\n", err, strerror(err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = roster->ReleaseNode(m_output.node);
|
|
|
|
|
if (err) {
|
|
|
|
|
fprintf(stderr, "* Error releasing output node: %ld (%s)\n", err, strerror(err));
|
|
|
|
|
}
|
|
|
|
|
_m_node = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-07-09 12:24:59 +00:00
|
|
|
delete [] _m_buf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
BSoundPlayer::InitCheck()
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
return _m_init_err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
media_raw_audio_format
|
|
|
|
|
BSoundPlayer::Format() const
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
|
|
|
|
|
media_raw_audio_format temp = media_raw_audio_format::wildcard;
|
|
|
|
|
|
|
|
|
|
if (_m_node) {
|
|
|
|
|
media_multi_audio_format fmt;
|
|
|
|
|
fmt = _m_node->Format();
|
|
|
|
|
memcpy(&temp,&fmt,sizeof(temp));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
BSoundPlayer::Start()
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
|
|
|
|
|
if (!_m_node)
|
|
|
|
|
return B_ERROR;
|
2003-06-03 21:02:38 +00:00
|
|
|
|
2003-05-11 17:41:38 +00:00
|
|
|
BMediaRoster *roster = BMediaRoster::Roster();
|
|
|
|
|
if (!roster) {
|
|
|
|
|
TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n");
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
2002-07-09 12:24:59 +00:00
|
|
|
|
2003-05-11 17:41:38 +00:00
|
|
|
// make sure we give the producer enough time to run buffers through
|
2003-05-29 17:28:11 +00:00
|
|
|
// the node chain, otherwise it'll start up already late
|
2003-05-11 17:41:38 +00:00
|
|
|
bigtime_t latency = 0;
|
|
|
|
|
status_t err = roster->GetLatencyFor(_m_node->Node(), &latency);
|
|
|
|
|
|
2003-05-30 20:41:04 +00:00
|
|
|
err = roster->StartNode(_m_node->Node(), _m_node->TimeSource()->Now() + latency + 5000);
|
2003-05-11 17:41:38 +00:00
|
|
|
|
|
|
|
|
return err;
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::Stop(bool block,
|
|
|
|
|
bool flush)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
|
|
|
|
|
if (!_m_node)
|
|
|
|
|
return;
|
2003-06-03 21:02:38 +00:00
|
|
|
|
|
|
|
|
// XXX flush is ignored
|
|
|
|
|
|
|
|
|
|
TRACE("BSoundPlayer::Stop: block %d, flush %d\n", (int)block, (int)flush);
|
2003-05-11 17:41:38 +00:00
|
|
|
|
|
|
|
|
BMediaRoster *roster = BMediaRoster::Roster();
|
|
|
|
|
if (!roster) {
|
|
|
|
|
TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
roster->StopNode(_m_node->Node(), 0, true);
|
2003-06-03 21:02:38 +00:00
|
|
|
|
|
|
|
|
if (block) {
|
|
|
|
|
// wait until the node is stopped
|
|
|
|
|
int maxtrys;
|
|
|
|
|
for (maxtrys = 250; _m_node->IsPlaying() && maxtrys != 0; maxtrys--)
|
|
|
|
|
snooze(2000);
|
|
|
|
|
|
|
|
|
|
DEBUG_ONLY(if (maxtrys == 0) printf("BSoundPlayer::Stop: waiting for node stop failed\n"));
|
|
|
|
|
|
|
|
|
|
// wait until all buffers on the way to the physical output have been played
|
|
|
|
|
snooze(_m_node->Latency() + 2000);
|
|
|
|
|
}
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BSoundPlayer::BufferPlayerFunc
|
|
|
|
|
BSoundPlayer::BufferPlayer() const
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
return _PlayBuffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BSoundPlayer::SetBufferPlayer(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format))
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
_m_lock.Lock();
|
|
|
|
|
_PlayBuffer = PlayBuffer;
|
|
|
|
|
_m_lock.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BSoundPlayer::EventNotifierFunc
|
|
|
|
|
BSoundPlayer::EventNotifier() const
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
return _Notifier;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BSoundPlayer::SetNotifier(void (*Notifier)(void *, sound_player_notification what, ...))
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
_m_lock.Lock();
|
|
|
|
|
_Notifier = Notifier;
|
|
|
|
|
_m_lock.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
BSoundPlayer::Cookie() const
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
return _m_cookie;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::SetCookie(void *cookie)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
_m_lock.Lock();
|
|
|
|
|
_m_cookie = cookie;
|
|
|
|
|
_m_lock.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BSoundPlayer::SetCallbacks(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
|
|
|
|
|
void (*Notifier)(void *, sound_player_notification what, ...),
|
|
|
|
|
void * cookie)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
_m_lock.Lock();
|
|
|
|
|
SetBufferPlayer(PlayBuffer);
|
|
|
|
|
SetNotifier(Notifier);
|
|
|
|
|
SetCookie(cookie);
|
|
|
|
|
_m_lock.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bigtime_t
|
|
|
|
|
BSoundPlayer::CurrentTime()
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
if (!_m_node)
|
|
|
|
|
return system_time();
|
2003-05-11 17:41:38 +00:00
|
|
|
|
|
|
|
|
return _m_node->TimeSource()->Now();
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bigtime_t
|
|
|
|
|
BSoundPlayer::PerformanceTime()
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
if (!_m_node)
|
|
|
|
|
return (bigtime_t) B_ERROR;
|
2003-05-11 17:41:38 +00:00
|
|
|
|
|
|
|
|
return _m_node->TimeSource()->Now();
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
BSoundPlayer::Preroll()
|
|
|
|
|
{
|
2003-05-11 17:41:38 +00:00
|
|
|
CALLED();
|
2002-07-09 12:24:59 +00:00
|
|
|
|
2003-05-11 17:41:38 +00:00
|
|
|
BMediaRoster *roster = BMediaRoster::Roster();
|
|
|
|
|
if (!roster) {
|
|
|
|
|
TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n");
|
|
|
|
|
return B_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
status_t err = roster->PrerollNode(m_output.node);
|
|
|
|
|
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
fprintf(stderr, "Error while PrerollNode: %ld (%s)\n", err, strerror(err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err;
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BSoundPlayer::play_id
|
|
|
|
|
BSoundPlayer::StartPlaying(BSound *sound,
|
|
|
|
|
bigtime_t at_time)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BSoundPlayer::play_id
|
|
|
|
|
BSoundPlayer::StartPlaying(BSound *sound,
|
|
|
|
|
bigtime_t at_time,
|
|
|
|
|
float with_volume)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
BSoundPlayer::SetSoundVolume(play_id sound,
|
|
|
|
|
float new_volume)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
BSoundPlayer::IsPlaying(play_id id)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
BSoundPlayer::StopPlaying(play_id id)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
BSoundPlayer::WaitForSound(play_id id)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
BSoundPlayer::Volume()
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
2003-06-06 14:22:26 +00:00
|
|
|
|
|
|
|
|
return pow(10.0, VolumeDB(true)/20.0);
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::SetVolume(float new_volume)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
2003-06-06 14:22:26 +00:00
|
|
|
SetVolumeDB(20.0 * log10(new_volume));
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float
|
|
|
|
|
BSoundPlayer::VolumeDB(bool forcePoll)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
2003-06-06 13:56:44 +00:00
|
|
|
if(_m_volumeSlider==NULL)
|
|
|
|
|
get_volume_slider();
|
|
|
|
|
if(_m_volumeSlider==NULL)
|
|
|
|
|
return 0.0;
|
2003-06-06 14:22:26 +00:00
|
|
|
|
|
|
|
|
if(!forcePoll && (system_time() - _m_gotVolume < 500000))
|
|
|
|
|
return _m_volume;
|
2003-06-06 13:56:44 +00:00
|
|
|
|
2003-06-06 14:22:26 +00:00
|
|
|
bigtime_t lastChange;
|
|
|
|
|
int32 count = _m_volumeSlider->CountChannels();
|
|
|
|
|
float values[count];
|
|
|
|
|
size_t size = count * sizeof(float);
|
|
|
|
|
_m_volumeSlider->GetValue(&values, &size, &lastChange);
|
|
|
|
|
_m_gotVolume = system_time();
|
2003-06-06 13:56:44 +00:00
|
|
|
_m_volume = values[0];
|
2003-06-06 14:22:26 +00:00
|
|
|
|
|
|
|
|
return values[0];
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::SetVolumeDB(float volume_dB)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
2003-06-06 13:56:44 +00:00
|
|
|
if(_m_volumeSlider==NULL)
|
|
|
|
|
get_volume_slider();
|
|
|
|
|
if(_m_volumeSlider==NULL)
|
|
|
|
|
return;
|
2003-06-06 14:22:26 +00:00
|
|
|
|
|
|
|
|
if(volume_dB < _m_volumeSlider->MinValue())
|
|
|
|
|
volume_dB = _m_volumeSlider->MinValue();
|
|
|
|
|
if(volume_dB > _m_volumeSlider->MaxValue())
|
|
|
|
|
volume_dB = _m_volumeSlider->MaxValue();
|
|
|
|
|
|
2003-06-06 13:56:44 +00:00
|
|
|
int32 count = _m_volumeSlider->CountChannels();
|
|
|
|
|
float values[count];
|
|
|
|
|
for(int32 i=0; i<count; i++)
|
2003-06-06 14:22:26 +00:00
|
|
|
values[i] = volume_dB;
|
2003-06-06 13:56:44 +00:00
|
|
|
_m_volumeSlider->SetValue(values, sizeof(float) * count, 0);
|
2003-06-06 14:22:26 +00:00
|
|
|
_m_volume = volume_dB;
|
|
|
|
|
_m_gotVolume = system_time();
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
|
BSoundPlayer::GetVolumeInfo(media_node *out_node,
|
|
|
|
|
int32 *out_parameter,
|
|
|
|
|
float *out_min_dB,
|
|
|
|
|
float *out_max_dB)
|
|
|
|
|
{
|
2003-06-06 13:56:44 +00:00
|
|
|
CALLED();
|
|
|
|
|
if(_m_volumeSlider==NULL)
|
|
|
|
|
get_volume_slider();
|
|
|
|
|
if(_m_volumeSlider==NULL
|
|
|
|
|
|| out_node == NULL
|
|
|
|
|
|| out_parameter == NULL
|
|
|
|
|
|| out_min_dB == NULL
|
|
|
|
|
|| out_max_dB == NULL)
|
|
|
|
|
return B_ERROR;
|
2002-07-09 12:24:59 +00:00
|
|
|
|
2003-06-06 13:56:44 +00:00
|
|
|
*out_node = m_input.node;
|
|
|
|
|
*out_parameter = _m_volumeSlider->ID(); /* is the parameter ID for the volume control */
|
|
|
|
|
*out_min_dB = _m_volumeSlider->MinValue();
|
|
|
|
|
*out_max_dB = _m_volumeSlider->MaxValue();
|
2002-07-09 12:24:59 +00:00
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bigtime_t
|
|
|
|
|
BSoundPlayer::Latency()
|
|
|
|
|
{
|
2003-05-11 17:41:38 +00:00
|
|
|
CALLED();
|
|
|
|
|
|
|
|
|
|
BMediaRoster *roster = BMediaRoster::Roster();
|
|
|
|
|
if (!roster) {
|
|
|
|
|
TRACE("BSoundPlayer::Latency: Couldn't get BMediaRoster\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bigtime_t latency = 0;
|
|
|
|
|
status_t err = roster->GetLatencyFor(m_output.node, &latency);
|
|
|
|
|
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
fprintf(stderr, "Error while GetLatencyFor: %ld (%s)\n", err, strerror(err));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return latency;
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* virtual */ bool
|
|
|
|
|
BSoundPlayer::HasData()
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
|
|
|
|
|
return _m_has_data != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::SetHasData(bool has_data)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
_m_lock.Lock();
|
|
|
|
|
_m_has_data = has_data ? 1 : 0;
|
|
|
|
|
_m_lock.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************
|
|
|
|
|
* protected BSoundPlayer
|
|
|
|
|
*************************************************************/
|
|
|
|
|
|
|
|
|
|
//final
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::SetInitError(status_t in_error)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
_m_init_err = in_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************************************
|
|
|
|
|
* private BSoundPlayer
|
|
|
|
|
*************************************************************/
|
|
|
|
|
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_0(void *, ...) { return B_ERROR; }
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_1(void *, ...) { return B_ERROR; }
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_2(void *, ...) { return B_ERROR; }
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_3(void *, ...) { return B_ERROR; }
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_4(void *, ...) { return B_ERROR; }
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_5(void *, ...) { return B_ERROR; }
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_6(void *, ...) { return B_ERROR; }
|
|
|
|
|
status_t BSoundPlayer::_Reserved_SoundPlayer_7(void *, ...) { return B_ERROR; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::NotifySoundDone(play_id sound,
|
|
|
|
|
bool got_to_play)
|
|
|
|
|
{
|
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::get_volume_slider()
|
|
|
|
|
{
|
2003-06-06 14:22:26 +00:00
|
|
|
CALLED();
|
|
|
|
|
|
2003-06-06 13:56:44 +00:00
|
|
|
BMediaRoster *roster = BMediaRoster::CurrentRoster();
|
|
|
|
|
if(roster==NULL)
|
|
|
|
|
return;
|
|
|
|
|
BParameterWeb *web = NULL;
|
|
|
|
|
if(roster->GetParameterWebFor(m_input.node, &web) < B_OK)
|
|
|
|
|
return;
|
|
|
|
|
for(int32 i=0; i<web->CountParameters(); i++) {
|
|
|
|
|
BParameter *parameter = web->ParameterAt(i);
|
|
|
|
|
if(parameter->Type() != BParameter::B_CONTINUOUS_PARAMETER
|
2003-06-06 14:22:26 +00:00
|
|
|
|| strcmp(parameter->Kind(), B_GAIN) != 0
|
2003-06-06 13:56:44 +00:00
|
|
|
|| (parameter->ID() >> 16) != m_input.destination.id)
|
|
|
|
|
continue;
|
|
|
|
|
_m_volumeSlider = (BContinuousParameter*)parameter;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
BSoundPlayer::Init(
|
|
|
|
|
const media_node * node,
|
|
|
|
|
const media_multi_audio_format * format,
|
|
|
|
|
const char * name,
|
|
|
|
|
const media_input * input,
|
|
|
|
|
void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format),
|
|
|
|
|
void (*Notifier)(void *, sound_player_notification what, ...),
|
|
|
|
|
void * cookie)
|
|
|
|
|
{
|
2003-06-03 19:00:34 +00:00
|
|
|
CALLED();
|
2002-07-09 12:24:59 +00:00
|
|
|
_m_node = NULL;
|
|
|
|
|
_m_sounds = NULL;
|
|
|
|
|
_m_waiting = NULL;
|
|
|
|
|
_PlayBuffer = PlayBuffer;
|
|
|
|
|
_Notifier = Notifier;
|
|
|
|
|
_m_volume = 0.0f;
|
|
|
|
|
_m_mix_buffer = 0;
|
|
|
|
|
_m_mix_buffer_size = 0;
|
|
|
|
|
_m_cookie = cookie;
|
|
|
|
|
_m_buf = NULL;
|
|
|
|
|
_m_bufsize = 0;
|
|
|
|
|
_m_has_data = 0;
|
|
|
|
|
_m_init_err = B_ERROR;
|
|
|
|
|
_m_perfTime = 0;
|
|
|
|
|
_m_volumeSlider = NULL;
|
|
|
|
|
_m_gotVolume = 0;
|
|
|
|
|
|
|
|
|
|
_m_node = 0;
|
|
|
|
|
|
2003-05-11 17:41:38 +00:00
|
|
|
status_t err;
|
|
|
|
|
media_node outputNode;
|
|
|
|
|
media_output _output;
|
|
|
|
|
media_input _input;
|
|
|
|
|
int32 inputCount, outputCount;
|
|
|
|
|
media_format tryFormat;
|
|
|
|
|
media_multi_audio_format fmt;
|
|
|
|
|
media_node timeSource;
|
|
|
|
|
|
|
|
|
|
BMediaRoster *roster = BMediaRoster::Roster();
|
2002-07-09 12:24:59 +00:00
|
|
|
if (!roster) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't get BMediaRoster\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//connect our producer node either to the
|
|
|
|
|
//system mixer or to the supplied out node
|
|
|
|
|
if (!node) {
|
2003-05-11 17:41:38 +00:00
|
|
|
err = roster->GetAudioMixer(&outputNode);
|
|
|
|
|
if (err != B_OK) {
|
2002-07-09 12:24:59 +00:00
|
|
|
TRACE("BSoundPlayer::Init: Couldn't GetAudioMixer\n");
|
2003-05-11 17:41:38 +00:00
|
|
|
goto the_end;
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
2003-05-11 17:41:38 +00:00
|
|
|
node = &outputNode;
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
2003-05-11 17:41:38 +00:00
|
|
|
|
2002-07-09 12:24:59 +00:00
|
|
|
memcpy(&fmt,format,sizeof(fmt));
|
|
|
|
|
|
|
|
|
|
if (fmt.frame_rate == media_multi_audio_format::wildcard.frame_rate)
|
|
|
|
|
fmt.frame_rate = 44100.0f;
|
|
|
|
|
if (fmt.channel_count == media_multi_audio_format::wildcard.channel_count)
|
|
|
|
|
fmt.channel_count = 2;
|
|
|
|
|
if (fmt.format == media_multi_audio_format::wildcard.format)
|
|
|
|
|
fmt.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
|
|
|
|
if (fmt.byte_order == media_multi_audio_format::wildcard.byte_order)
|
|
|
|
|
fmt.byte_order = B_MEDIA_HOST_ENDIAN;
|
|
|
|
|
if (fmt.buffer_size == media_multi_audio_format::wildcard.buffer_size)
|
|
|
|
|
fmt.buffer_size = 4096;
|
|
|
|
|
|
|
|
|
|
if (fmt.channel_count != 1 && fmt.channel_count != 2)
|
2003-06-03 19:00:34 +00:00
|
|
|
FATAL("BSoundPlayer: not a 1 or 2 channel audio format\n");
|
2002-07-09 12:24:59 +00:00
|
|
|
if (fmt.frame_rate <= 0.0f)
|
2003-06-03 19:00:34 +00:00
|
|
|
FATAL("BSoundPlayer: framerate must be > 0\n");
|
2002-07-09 12:24:59 +00:00
|
|
|
|
|
|
|
|
_m_bufsize = fmt.buffer_size;
|
|
|
|
|
_m_buf = new char[_m_bufsize];
|
|
|
|
|
_m_node = new _SoundPlayNode(name,&fmt,this);
|
|
|
|
|
|
2003-05-11 17:41:38 +00:00
|
|
|
err = roster->RegisterNode(_m_node);
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't RegisterNode\n");
|
|
|
|
|
goto the_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// set the producer's time source to be the "default" time source, which
|
|
|
|
|
// the Mixer uses too.
|
|
|
|
|
|
2003-06-01 17:18:24 +00:00
|
|
|
err = roster->GetTimeSource(&timeSource);
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't GetTimeSource\n");
|
|
|
|
|
goto the_end;
|
|
|
|
|
}
|
|
|
|
|
err = roster->SetTimeSourceFor(_m_node->Node().node, timeSource.node);
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't SetTimeSourceFor\n");
|
|
|
|
|
goto the_end;
|
|
|
|
|
}
|
2003-05-11 17:41:38 +00:00
|
|
|
|
|
|
|
|
if(!input) {
|
|
|
|
|
err = roster->GetFreeInputsFor(*node, &_input, 1,
|
|
|
|
|
&inputCount, B_MEDIA_RAW_AUDIO);
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't GetFreeInputsFor\n");
|
|
|
|
|
goto the_end;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
_input = *input;
|
|
|
|
|
}
|
|
|
|
|
err = roster->GetFreeOutputsFor(_m_node->Node(), &_output, 1, &outputCount, B_MEDIA_RAW_AUDIO);
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't GetFreeOutputsFor\n");
|
|
|
|
|
goto the_end;
|
|
|
|
|
}
|
2003-06-03 19:00:34 +00:00
|
|
|
|
|
|
|
|
// Set an appropriate run mode for the producer
|
|
|
|
|
err = roster->SetRunModeNode(_m_node->Node(), BMediaNode::B_INCREASE_LATENCY);
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't SetRunModeNode\n");
|
|
|
|
|
goto the_end;
|
|
|
|
|
}
|
2003-05-11 17:41:38 +00:00
|
|
|
|
|
|
|
|
//tryFormat.type = B_MEDIA_RAW_AUDIO;
|
|
|
|
|
//tryformat.fileAudioOutput.format;
|
|
|
|
|
tryFormat = _output.format;
|
|
|
|
|
err = roster->Connect(_output.source, _input.destination, &tryFormat, &m_output, &m_input);
|
|
|
|
|
if(err != B_OK) {
|
|
|
|
|
TRACE("BSoundPlayer::Init: Couldn't Connect\n");
|
|
|
|
|
goto the_end;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-09 12:24:59 +00:00
|
|
|
|
2003-06-01 17:18:24 +00:00
|
|
|
printf("BSoundPlayer node %ld has timesource %ld\n", _m_node->Node().node, _m_node->TimeSource()->Node().node);
|
|
|
|
|
|
2003-05-11 17:41:38 +00:00
|
|
|
the_end:
|
|
|
|
|
TRACE("BSoundPlayer::Init: %s\n", strerror(err));
|
|
|
|
|
SetInitError(err);
|
2002-07-09 12:24:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* virtual */ void
|
|
|
|
|
BSoundPlayer::Notify(sound_player_notification what,
|
|
|
|
|
...)
|
|
|
|
|
{
|
|
|
|
|
CALLED();
|
|
|
|
|
_m_lock.Lock();
|
|
|
|
|
if (_Notifier)
|
|
|
|
|
(*_Notifier)(_m_cookie,what);
|
|
|
|
|
else {
|
|
|
|
|
}
|
|
|
|
|
_m_lock.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* virtual */ void
|
|
|
|
|
BSoundPlayer::PlayBuffer(void *buffer,
|
|
|
|
|
size_t size,
|
|
|
|
|
const media_raw_audio_format &format)
|
|
|
|
|
{
|
|
|
|
|
// CALLED();
|
2003-06-03 21:02:38 +00:00
|
|
|
|
2002-07-09 12:24:59 +00:00
|
|
|
_m_lock.Lock();
|
|
|
|
|
if (_PlayBuffer)
|
|
|
|
|
(*_PlayBuffer)(_m_cookie,buffer,size,format);
|
|
|
|
|
else {
|
|
|
|
|
}
|
|
|
|
|
_m_lock.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|