Working SoundPlayer and SoundPlayerNode, it lacks volume methods

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@3210 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Jérôme Duval 2003-05-11 17:41:38 +00:00
parent 7f879cccff
commit 95531d1e1b
3 changed files with 985 additions and 499 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,91 +1,174 @@
#ifndef _SOUND_PLAY_NODE_
#define _SOUND_PLAY_NODE_
#include <BufferProducer.h>
#include <MediaEventLooper.h>
#include <Buffer.h>
#include <BufferGroup.h>
#include "SoundPlayer.h"
/***********************************************************************
* AUTHOR: Marcus Overhagen
* AUTHOR: Marcus Overhagen, Jérôme Duval
* FILE: SoundPlayNode.h
* DESCR: This is the BBufferProducer, used internally by BSoundPlayer
* This belongs into a private namespace, but isn't for
* compatibility reasons.
***********************************************************************/
class _SoundPlayNode : public BBufferProducer
class _SoundPlayNode
: public BBufferProducer, public BMediaEventLooper
{
public:
_SoundPlayNode(const char *name, const media_multi_audio_format *format, BSoundPlayer *player);
~_SoundPlayNode();
media_multi_audio_format Format() const;
private:
/*************************/
/* begin from BMediaNode */
public:
virtual BMediaAddOn* AddOn(
int32 * internal_id) const; /* Who instantiated you -- or NULL for app class */
virtual status_t FormatSuggestionRequested(
media_type type,
int32 quality,
media_format * format);
virtual status_t FormatProposal(
const media_source & output,
media_format * format);
virtual status_t FormatChangeRequested(
const media_source & source,
const media_destination & destination,
media_format * io_format,
int32 * _deprecated_);
virtual status_t GetNextOutput( /* cookie starts as 0 */
int32 * cookie,
media_output * out_output);
virtual status_t DisposeOutputCookie(
int32 cookie);
virtual status_t SetBufferGroup(
const media_source & for_source,
BBufferGroup * group);
virtual status_t VideoClippingChanged(
const media_source & for_source,
int16 num_shorts,
int16 * clip_data,
const media_video_display_info & display,
int32 * _deprecated_);
virtual status_t GetLatency(
bigtime_t * out_lantency);
virtual status_t PrepareToConnect(
const media_source & what,
const media_destination & where,
media_format * format,
media_source * out_source,
char * out_name);
virtual void Connect(
status_t error,
const media_source & source,
const media_destination & destination,
const media_format & format,
char * io_name);
virtual void Disconnect(
const media_source & what,
const media_destination & where);
virtual void LateNoticeReceived(
const media_source & what,
bigtime_t how_much,
bigtime_t performance_time);
virtual void EnableOutput(
const media_source & what,
bool enabled,
int32 * _deprecated_);
virtual BMediaAddOn* AddOn(
int32 * internal_id) const;
protected:
/* These don't return errors; instead, they use the global error condition reporter. */
/* A node is required to have a queue of at least one pending command (plus TimeWarp) */
/* and is recommended to allow for at least one pending command of each type. */
/* Allowing an arbitrary number of outstanding commands might be nice, but apps */
/* cannot depend on that happening. */
virtual void Preroll(void);
public:
void Start();
void Stop();
virtual status_t HandleMessage(
int32 message,
const void * data,
size_t size);
protected:
virtual void NodeRegistered(void); /* reserved 2 */
virtual status_t RequestCompleted(const media_request_info &info);
virtual void SetTimeSource(BTimeSource *timeSource);
virtual void SetRunMode(run_mode mode);
/* end from BMediaNode */
/***********************/
/******************************/
/* begin from BBufferProducer */
virtual status_t FormatSuggestionRequested( media_type type,
int32 quality,
media_format* format);
virtual status_t FormatProposal( const media_source& output,
media_format* format);
virtual status_t FormatChangeRequested( const media_source& source,
const media_destination& destination,
media_format* io_format,
int32* _deprecated_);
virtual status_t GetNextOutput( int32* cookie,
media_output* out_output);
virtual status_t DisposeOutputCookie( int32 cookie);
virtual status_t SetBufferGroup( const media_source& for_source,
BBufferGroup* group);
virtual status_t GetLatency( bigtime_t * out_latency);
virtual status_t PrepareToConnect( const media_source& what,
const media_destination& where,
media_format* format,
media_source* out_source,
char* out_name);
virtual void Connect( status_t error,
const media_source& source,
const media_destination& destination,
const media_format& format,
char* io_name);
virtual void Disconnect( const media_source& what,
const media_destination& where);
virtual void LateNoticeReceived( const media_source& what,
bigtime_t how_much,
bigtime_t performance_time);
virtual void EnableOutput( const media_source & what,
bool enabled,
int32* _deprecated_);
virtual void AdditionalBufferRequested( const media_source& source,
media_buffer_id prev_buffer,
bigtime_t prev_time,
const media_seek_tag* prev_tag);
virtual void LatencyChanged( const media_source& source,
const media_destination& destination,
bigtime_t new_latency,
uint32 flags);
/* end from BBufferProducer */
/****************************/
/********************************/
/* start from BMediaEventLooper */
protected:
/* you must override to handle your events! */
/* you should not call HandleEvent directly */
virtual void HandleEvent( const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
/* end from BMediaEventLooper */
/******************************/
public:
media_multi_audio_format Format() const;
protected:
virtual status_t HandleStart(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
virtual status_t HandleSeek(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
virtual status_t HandleWarp(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
virtual status_t HandleStop(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
virtual status_t HandleBuffer(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
virtual status_t HandleDataStatus(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
virtual status_t HandleParameter(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent = false);
void AllocateBuffers();
BBuffer* FillNextBuffer(bigtime_t event_time);
private:
int fFramesPerBuffer;
thread_id fThreadId;
volatile bool fStopThread;
static int32 threadstart(void *arg);
void PlayThread();
media_multi_audio_format fFormat;
BSoundPlayer *fPlayer;
BSoundPlayer *mPlayer;
status_t mInitCheckStatus;
bool mOutputEnabled;
media_output mOutput;
BBufferGroup *mBufferGroup;
media_format mPreferredFormat;
media_format mFormat;
bigtime_t mLatency;
bigtime_t mInternalLatency;
bigtime_t mStartTime;
uint64 mFramesSent;
};
#endif

View File

@ -1,10 +1,10 @@
/***********************************************************************
* AUTHOR: Marcus Overhagen
* AUTHOR: Marcus Overhagen, Jérôme Duval
* FILE: SoundPlayer.cpp
* DESCR:
***********************************************************************/
#include <TimeSource.h>
#include <SoundPlayer.h>
#include "SoundPlayer.h"
#include <MediaRoster.h>
#include <math.h>
@ -78,9 +78,37 @@ BSoundPlayer::BSoundPlayer(const media_node & toNode,
BSoundPlayer::~BSoundPlayer()
{
CALLED();
if (_m_node)
_m_node->Release();
delete _m_node;
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;
}
}
delete [] _m_buf;
}
@ -117,9 +145,25 @@ BSoundPlayer::Start()
if (!_m_node)
return B_ERROR;
BMediaRoster *roster = BMediaRoster::Roster();
if (!roster) {
TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n");
return B_ERROR;
}
_m_node->Start();
return B_OK;
BTimeSource *timeSource = roster->MakeTimeSourceFor(_m_node->Node());
// make sure we give the producer enough time to run buffers through
// the node chain, otherwise it'll start up already late
bigtime_t latency = 0;
status_t err = roster->GetLatencyFor(_m_node->Node(), &latency);
err = roster->StartNode(_m_node->Node(), timeSource->Now() + latency);
timeSource->Release();
return err;
}
@ -131,8 +175,15 @@ BSoundPlayer::Stop(bool block,
if (!_m_node)
return;
BMediaRoster *roster = BMediaRoster::Roster();
if (!roster) {
TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n");
return;
}
roster->StopNode(_m_node->Node(), 0, true);
_m_node->Stop();
}
BSoundPlayer::BufferPlayerFunc
@ -200,10 +251,8 @@ BSoundPlayer::CurrentTime()
CALLED();
if (!_m_node)
return system_time();
#if 0 /* we don't have a media roster, or real media nodes yet */
return _m_node->TimeSource()->Now(); /* either this one is wrong */
#endif
return system_time();
return _m_node->TimeSource()->Now();
}
@ -213,19 +262,29 @@ BSoundPlayer::PerformanceTime()
CALLED();
if (!_m_node)
return (bigtime_t) B_ERROR;
#if 0 /* we don't have a media roster, or real media nodes yet */
return _m_node->TimeSource()->Now(); /* or this one is wrong */
#endif
return system_time();
return _m_node->TimeSource()->Now();
}
status_t
BSoundPlayer::Preroll()
{
UNIMPLEMENTED();
CALLED();
return B_OK;
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;
}
@ -342,8 +401,22 @@ BSoundPlayer::GetVolumeInfo(media_node *out_node,
bigtime_t
BSoundPlayer::Latency()
{
BROKEN();
return 50000;
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;
}
@ -423,10 +496,7 @@ BSoundPlayer::Init(
_m_waiting = NULL;
_PlayBuffer = PlayBuffer;
_Notifier = Notifier;
//_m_lock;
_m_volume = 0.0f;
//m_input;
//m_output;
_m_mix_buffer = 0;
_m_mix_buffer_size = 0;
_m_cookie = cookie;
@ -440,11 +510,16 @@ BSoundPlayer::Init(
_m_node = 0;
#if 0 /* we don't have a media roster, or real media nodes yet */
status_t status;
BMediaRoster *roster;
media_node outnode;
roster = BMediaRoster::Roster();
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();
if (!roster) {
TRACE("BSoundPlayer::Init: Couldn't get BMediaRoster\n");
return;
@ -453,17 +528,14 @@ BSoundPlayer::Init(
//connect our producer node either to the
//system mixer or to the supplied out node
if (!node) {
status = roster->GetAudioMixer(&outnode);
if (status != B_OK) {
err = roster->GetAudioMixer(&outputNode);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't GetAudioMixer\n");
SetInitError(status);
return;
goto the_end;
}
node = &outnode;
node = &outputNode;
}
#endif
media_multi_audio_format fmt;
memcpy(&fmt,format,sizeof(fmt));
if (fmt.frame_rate == media_multi_audio_format::wildcard.frame_rate)
@ -485,29 +557,54 @@ BSoundPlayer::Init(
_m_bufsize = fmt.buffer_size;
_m_buf = new char[_m_bufsize];
_m_node = new _SoundPlayNode(name,&fmt,this);
/*
m_input = ;
m_output = ;
tryFormat = fileAudioOutput.format;
   err = roster->Connect(fileAudioOutput.source, audioInput.destination,
               &tryFormat, &m_output, &m_input);
 err = roster->GetStartLatencyFor(timeSourceNode, &startTime);
   startTime += b_timesource->PerformanceTimeFor(BTimeSource::RealTime()
               + 1000000 / 50);
   
   err = roster->StartNode(mediaFileNode, startTime);
   err = roster->StartNode(codecNode, startTime);
   err = roster->StartNode(videoNode, startTime);
*/
err = roster->RegisterNode(_m_node);
if(err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't RegisterNode\n");
goto the_end;
}
SetInitError(B_OK);
// set the producer's time source to be the "default" time source, which
// the Mixer uses too.
roster->GetTimeSource(&timeSource);
roster->SetTimeSourceFor(_m_node->Node().node, timeSource.node);
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;
}
//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;
}
// 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;
}
the_end:
TRACE("BSoundPlayer::Init: %s\n", strerror(err));
SetInitError(err);
}
/* virtual */ void