* When you even already have the typedefs, why wouldn't you want to use them?

* Some cleanup, no functional change.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34474 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-12-03 19:48:11 +00:00
parent b69928b291
commit 812fde99a1
3 changed files with 704 additions and 661 deletions
+69 -94
View File
@@ -28,47 +28,40 @@ public:
class BSoundPlayer {
friend class _SoundPlayNode;
public:
enum sound_player_notification {
B_STARTED = 1,
B_STOPPED,
B_SOUND_DONE
};
enum sound_player_notification {
B_STARTED = 1,
B_STOPPED,
B_SOUND_DONE
};
typedef void (*BufferPlayerFunc)(void*, void* buffer, size_t size,
const media_raw_audio_format& format);
typedef void (*EventNotifierFunc)(void*, sound_player_notification what,
...);
public:
BSoundPlayer(const char* name = NULL,
void (*PlayBuffer)(void*, void* buffer,
size_t size,
const media_raw_audio_format& format)
= NULL,
void (*Notifier)(void*,
sound_player_notification what, ...)
= NULL,
BufferPlayerFunc playerFunction = NULL,
EventNotifierFunc
eventNotifierFunction = NULL,
void* cookie = NULL);
BSoundPlayer(
const media_raw_audio_format* format,
const char* name = NULL,
void (*PlayBuffer)(void*, void* buffer,
size_t size,
const media_raw_audio_format& format)
= NULL,
void (*Notifier)(void*,
sound_player_notification what, ...)
= NULL,
BufferPlayerFunc playerFunction = NULL,
EventNotifierFunc
eventNotifierFunction = NULL,
void* cookie = NULL);
BSoundPlayer(
const media_node& toNode,
const media_multi_audio_format* format
= NULL,
const media_multi_audio_format*
format = NULL,
const char* name = NULL,
const media_input* input = NULL,
void (*PlayBuffer)(void*, void* buffer,
size_t size,
const media_raw_audio_format& format)
= NULL,
void (*Notifier)(void*,
sound_player_notification what, ...)
= NULL,
BufferPlayerFunc playerFunction = NULL,
EventNotifierFunc
eventNotifierFunction = NULL,
void* cookie = NULL);
virtual ~BSoundPlayer();
@@ -78,27 +71,20 @@ public:
status_t Start();
void Stop(bool block = true, bool flush = true);
typedef void (*BufferPlayerFunc)(void*, void*, size_t,
const media_raw_audio_format&);
BufferPlayerFunc BufferPlayer() const;
void SetBufferPlayer(void (*PlayBuffer)(void*,
void* buffer, size_t size,
const media_raw_audio_format& format));
typedef void (*EventNotifierFunc)(void*, sound_player_notification what,
...);
EventNotifierFunc EventNotifier() const;
void SetNotifier(void (*Notifier)(void*,
sound_player_notification what, ...));
void SetNotifier(
EventNotifierFunc eventNotifierFunction);
void* Cookie() const;
void SetCookie(void* cookie);
void SetCallbacks(void (*PlayBuffer)(void*,
void* buffer, size_t size,
const media_raw_audio_format& format)
= NULL,
void (*Notifier)(void*,
sound_player_notification what, ...)
= NULL,
void SetCallbacks(
BufferPlayerFunc playerFunction = NULL,
EventNotifierFunc
eventNotifierFunction = NULL,
void* cookie = NULL);
typedef int32 play_id;
@@ -137,7 +123,7 @@ public:
protected:
void SetInitError(status_t inError);
void SetInitError(status_t error);
private:
static void _SoundPlayBufferFunc(void* cookie,
@@ -154,37 +140,50 @@ private:
virtual status_t _Reserved_SoundPlayer_6(void*, ...);
virtual status_t _Reserved_SoundPlayer_7(void*, ...);
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);
void _GetVolumeSlider();
void _NotifySoundDone(play_id sound, bool gotToPlay);
virtual void _Notify(sound_player_notification what, ...);
virtual void _PlayBuffer(void* buffer, size_t size,
const media_raw_audio_format& format);
private:
friend class _SoundPlayNode;
struct _playing_sound {
_playing_sound* next;
off_t current_offset;
BSound* sound;
play_id id;
int32 delta;
int32 rate;
sem_id wait_sem;
float volume;
};
struct _waiting_sound {
_waiting_sound* next;
bigtime_t start_time;
BSound* sound;
play_id id;
int32 rate;
float volume;
};
_SoundPlayNode* fPlayerNode;
struct _playing_sound {
_playing_sound* next;
off_t current_offset;
BSound* sound;
play_id id;
int32 delta;
int32 rate;
sem_id wait_sem;
float volume;
};
_playing_sound* fPlayingSounds;
struct _waiting_sound {
_waiting_sound* next;
bigtime_t start_time;
BSound* sound;
play_id id;
int32 rate;
float volume;
};
_waiting_sound* fWaitingSounds;
void (*fPlayBufferFunc)(void* cookie, void* buffer,
size_t size, const media_raw_audio_format& format);
void (*fNotifierFunc)(void* cookie, sound_player_notification what,
...);
BufferPlayerFunc fPlayBufferFunc;
EventNotifierFunc fNotifierFunc;
BLocker fLocker;
float fVolumeDB;
@@ -201,31 +200,7 @@ private:
bigtime_t fLastVolumeUpdate;
BParameterWeb* fParameterWeb;
uint32 _m_reserved[15];
private:
void NotifySoundDone(play_id sound, bool gotToPlay);
void get_volume_slider();
void 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);
// For B_STARTED and B_STOPPED, the argument is BSoundPlayer* (this).
// For B_SOUND_DONE, the arguments are play_id and true/false for
// whether it got to play data at all.
virtual void Notify(sound_player_notification what,
...);
// Get data into the buffer to play -- this version will use the
// queued BSound system.
virtual void PlayBuffer(void* buffer, size_t size,
const media_raw_audio_format& format);
uint32 _reserved[15];
};
#endif // _SOUND_PLAYER_H
+307 -235
View File
@@ -1,29 +1,42 @@
/***********************************************************************
* AUTHOR: Marcus Overhagen, Jérôme Duval
* FILE: SoundPlayNode.cpp
* DESCR: This is the BBufferProducer, used internally by BSoundPlayer
* This belongs into a private namespace, but isn't for
* compatibility reasons.
***********************************************************************/
/*
* Copyright 2002-2009, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
* Jérôme Duval
*/
/*! This is the BBufferProducer, used internally by BSoundPlayer
This belongs into a private namespace, but isn't for
compatibility reasons.
*/
#include "SoundPlayNode.h"
#include <TimeSource.h>
#include <MediaRoster.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "SoundPlayNode.h"
#include <TimeSource.h>
#include <MediaRoster.h>
#include "debug.h"
#define SEND_NEW_BUFFER_EVENT (BTimedEventQueue::B_USER_EVENT + 1)
_SoundPlayNode::_SoundPlayNode(const char *name, BSoundPlayer *player) :
_SoundPlayNode::_SoundPlayNode(const char* name, BSoundPlayer* player)
:
BMediaNode(name),
BBufferProducer(B_MEDIA_RAW_AUDIO),
BMediaEventLooper(),
mPlayer(player),
mInitCheckStatus(B_OK),
mOutputEnabled(true),
mBufferGroup(NULL),
mBufferGroup(NULL),
mFramesSent(0),
mTooEarlyCount(0)
{
@@ -39,60 +52,71 @@ _SoundPlayNode::~_SoundPlayNode()
Quit();
}
bool
_SoundPlayNode::IsPlaying()
{
return RunState() == B_STARTED;
}
bigtime_t
_SoundPlayNode::CurrentTime()
{
int frame_rate = (int)mOutput.format.u.raw_audio.frame_rate;
return frame_rate == 0 ? 0 : bigtime_t((1000000LL * mFramesSent) / frame_rate);
int frameRate = (int)mOutput.format.u.raw_audio.frame_rate;
return frameRate == 0 ? 0
: bigtime_t((1000000LL * mFramesSent) / frameRate);
}
media_multi_audio_format
media_multi_audio_format
_SoundPlayNode::Format() const
{
return mOutput.format.u.raw_audio;
}
// -------------------------------------------------------- //
// implementation of BMediaNode
// -------------------------------------------------------- //
BMediaAddOn * _SoundPlayNode::AddOn(int32 * internal_id) const
// #pragma mark - implementation of BMediaNode
BMediaAddOn*
_SoundPlayNode::AddOn(int32* _internalID) const
{
CALLED();
// BeBook says this only gets called if we were in an add-on.
// This only gets called if we are in an add-on.
return NULL;
}
void _SoundPlayNode::Preroll(void)
void
_SoundPlayNode::Preroll()
{
CALLED();
// XXX:Performance opportunity
// TODO: Performance opportunity
BMediaNode::Preroll();
}
status_t _SoundPlayNode::HandleMessage(int32 message, const void * data, size_t size)
status_t
_SoundPlayNode::HandleMessage(int32 message, const void* data, size_t size)
{
CALLED();
return B_ERROR;
}
void _SoundPlayNode::NodeRegistered(void)
void
_SoundPlayNode::NodeRegistered()
{
CALLED();
if (mInitCheckStatus != B_OK) {
ReportError(B_NODE_IN_DISTRESS);
return;
}
SetPriority(B_URGENT_PRIORITY);
mOutput.format.type = B_MEDIA_RAW_AUDIO;
mOutput.format.u.raw_audio = media_multi_audio_format::wildcard;
mOutput.destination = media_destination::null;
@@ -100,22 +124,27 @@ void _SoundPlayNode::NodeRegistered(void)
mOutput.source.id = 0;
mOutput.node = Node();
strcpy(mOutput.name, Name());
Run();
Run();
}
status_t _SoundPlayNode::RequestCompleted(const media_request_info &info)
status_t
_SoundPlayNode::RequestCompleted(const media_request_info& info)
{
CALLED();
return B_OK;
}
void _SoundPlayNode::SetTimeSource(BTimeSource *timeSource)
void
_SoundPlayNode::SetTimeSource(BTimeSource* timeSource)
{
CALLED();
BMediaNode::SetTimeSource(timeSource);
}
void
_SoundPlayNode::SetRunMode(run_mode mode)
{
@@ -123,16 +152,18 @@ _SoundPlayNode::SetRunMode(run_mode mode)
BMediaNode::SetRunMode(mode);
}
// -------------------------------------------------------- //
// implementation for BBufferProducer
// -------------------------------------------------------- //
status_t
_SoundPlayNode::FormatSuggestionRequested(media_type type, int32 /*quality*/, media_format* format)
// #pragma mark - implementation for BBufferProducer
status_t
_SoundPlayNode::FormatSuggestionRequested(media_type type, int32 /*quality*/,
media_format* format)
{
// FormatSuggestionRequested() is not necessarily part of the format negotiation
// process; it's simply an interrogation -- the caller wants to see what the node's
// preferred data format is, given a suggestion by the caller.
// FormatSuggestionRequested() is not necessarily part of the format
// negotiation process; it's simply an interrogation -- the caller wants
// to see what the node's preferred data format is, given a suggestion by
// the caller.
CALLED();
// a wildcard type is okay; but we only support raw audio
@@ -146,11 +177,13 @@ _SoundPlayNode::FormatSuggestionRequested(media_type type, int32 /*quality*/, me
return B_OK;
}
status_t
status_t
_SoundPlayNode::FormatProposal(const media_source& output, media_format* format)
{
// FormatProposal() is the first stage in the BMediaRoster::Connect() process. We hand
// out a suggested format, with wildcards for any variations we support.
// FormatProposal() is the first stage in the BMediaRoster::Connect()
// process. We hand out a suggested format, with wildcards for any
// variations we support.
CALLED();
// is this a proposal for our one output?
@@ -168,7 +201,7 @@ _SoundPlayNode::FormatProposal(const media_source& output, media_format* format)
TRACE("_SoundPlayNode::FormatProposal returning B_MEDIA_BAD_FORMAT\n");
return B_MEDIA_BAD_FORMAT;
}
#if DEBUG >0
char buf[100];
string_for_format(*format, buf, sizeof(buf));
@@ -178,8 +211,11 @@ _SoundPlayNode::FormatProposal(const media_source& output, media_format* format)
return B_OK;
}
status_t
_SoundPlayNode::FormatChangeRequested(const media_source& source, const media_destination& destination, media_format* io_format, int32* _deprecated_)
status_t
_SoundPlayNode::FormatChangeRequested(const media_source& source,
const media_destination& destination, media_format* _format,
int32* /* deprecated */)
{
CALLED();
@@ -187,13 +223,14 @@ _SoundPlayNode::FormatChangeRequested(const media_source& source, const media_de
return B_ERROR;
}
status_t
_SoundPlayNode::GetNextOutput(int32* cookie, media_output* out_output)
status_t
_SoundPlayNode::GetNextOutput(int32* cookie, media_output* _output)
{
CALLED();
if (*cookie == 0) {
*out_output = mOutput;
*_output = mOutput;
*cookie += 1;
return B_OK;
} else {
@@ -201,7 +238,8 @@ _SoundPlayNode::GetNextOutput(int32* cookie, media_output* out_output)
}
}
status_t
status_t
_SoundPlayNode::DisposeOutputCookie(int32 cookie)
{
CALLED();
@@ -209,13 +247,15 @@ _SoundPlayNode::DisposeOutputCookie(int32 cookie)
return B_OK;
}
status_t
_SoundPlayNode::SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup)
status_t
_SoundPlayNode::SetBufferGroup(const media_source& forSource,
BBufferGroup* newGroup)
{
CALLED();
// is this our output?
if (for_source != mOutput.source) {
if (forSource != mOutput.source) {
TRACE("_SoundPlayNode::SetBufferGroup returning B_MEDIA_BAD_SOURCE\n");
return B_MEDIA_BAD_SOURCE;
}
@@ -224,20 +264,18 @@ _SoundPlayNode::SetBufferGroup(const media_source& for_source, BBufferGroup* new
if (newGroup == mBufferGroup)
return B_OK;
// Ahh, someone wants us to use a different buffer group. At this point we delete
// the one we are using and use the specified one instead. If the specified group is
// NULL, we need to recreate one ourselves, and use *that*. Note that if we're
// caching a BBuffer that we requested earlier, we have to Recycle() that buffer
// *before* deleting the buffer group, otherwise we'll deadlock waiting for that
// buffer to be recycled!
delete mBufferGroup; // waits for all buffers to recycle
if (newGroup != NULL)
{
// Ahh, someone wants us to use a different buffer group. At this point we
// delete the one we are using and use the specified one instead.
// If the specified group is NULL, we need to recreate one ourselves, and
// use *that*. Note that if we're caching a BBuffer that we requested
// earlier, we have to Recycle() that buffer *before* deleting the buffer
// group, otherwise we'll deadlock waiting for that buffer to be recycled!
delete mBufferGroup;
// waits for all buffers to recycle
if (newGroup != NULL) {
// we were given a valid group; just use that one from now on
mBufferGroup = newGroup;
}
else
{
} else {
// we were passed a NULL group pointer; that means we construct
// our own buffer group to use from now on
size_t size = mOutput.format.u.raw_audio.buffer_size;
@@ -250,29 +288,35 @@ _SoundPlayNode::SetBufferGroup(const media_source& for_source, BBufferGroup* new
return B_OK;
}
status_t
_SoundPlayNode::GetLatency(bigtime_t* out_latency)
status_t
_SoundPlayNode::GetLatency(bigtime_t* _latency)
{
CALLED();
// report our *total* latency: internal plus downstream plus scheduling
*out_latency = EventLatency() + SchedulingLatency();
*_latency = EventLatency() + SchedulingLatency();
return B_OK;
}
status_t
_SoundPlayNode::PrepareToConnect(const media_source& what, const media_destination& where, media_format* format, media_source* out_source, char* out_name)
status_t
_SoundPlayNode::PrepareToConnect(const media_source& what,
const media_destination& where, media_format* format,
media_source* _source, char* _name)
{
// PrepareToConnect() is the second stage of format negotiations that happens
// inside BMediaRoster::Connect(). At this point, the consumer's AcceptFormat()
// method has been called, and that node has potentially changed the proposed
// format. It may also have left wildcards in the format. PrepareToConnect()
// *must* fully specialize the format before returning!
// PrepareToConnect() is the second stage of format negotiations that
// happens inside BMediaRoster::Connect(). At this point, the consumer's
// AcceptFormat() method has been called, and that node has potentially
// changed the proposed format. It may also have left wildcards in the
// format. PrepareToConnect() *must* fully specialize the format before
// returning!
CALLED();
// is this our output?
if (what != mOutput.source) {
TRACE("_SoundPlayNode::PrepareToConnect returning B_MEDIA_BAD_SOURCE\n");
TRACE("_SoundPlayNode::PrepareToConnect returning "
"B_MEDIA_BAD_SOURCE\n");
return B_MEDIA_BAD_SOURCE;
}
@@ -291,8 +335,10 @@ _SoundPlayNode::PrepareToConnect(const media_source& what, const media_destinati
#endif
// if not raw audio, we can't support it
if (format->type != B_MEDIA_UNKNOWN_TYPE && format->type != B_MEDIA_RAW_AUDIO) {
TRACE("_SoundPlayNode::PrepareToConnect: non raw format, returning B_MEDIA_BAD_FORMAT\n");
if (format->type != B_MEDIA_UNKNOWN_TYPE
&& format->type != B_MEDIA_RAW_AUDIO) {
TRACE("_SoundPlayNode::PrepareToConnect: non raw format, returning "
"B_MEDIA_BAD_FORMAT\n");
return B_MEDIA_BAD_FORMAT;
}
@@ -304,27 +350,30 @@ _SoundPlayNode::PrepareToConnect(const media_source& what, const media_destinati
uint32 channel_count = 0;
float frame_rate = 0;
if (format->user_data_type == FORMAT_USER_DATA_TYPE
&& *(uint32 *)&format->user_data[0] == FORMAT_USER_DATA_MAGIC_1
&& *(uint32 *)&format->user_data[44] == FORMAT_USER_DATA_MAGIC_2) {
&& *(uint32 *)&format->user_data[0] == FORMAT_USER_DATA_MAGIC_1
&& *(uint32 *)&format->user_data[44] == FORMAT_USER_DATA_MAGIC_2) {
channel_count = *(uint32 *)&format->user_data[4];
frame_rate = *(float *)&format->user_data[20];
TRACE("_SoundPlayNode::PrepareToConnect: found mixer info: channel_count %ld, frame_rate %.1f\n", channel_count, frame_rate);
TRACE("_SoundPlayNode::PrepareToConnect: found mixer info: "
"channel_count %ld, frame_rate %.1f\n", channel_count, frame_rate);
}
media_format default_format;
default_format.type = B_MEDIA_RAW_AUDIO;
default_format.u.raw_audio.frame_rate = frame_rate > 0 ? frame_rate : 44100;
default_format.u.raw_audio.channel_count = channel_count > 0 ? channel_count : 2;
default_format.u.raw_audio.channel_count = channel_count > 0
? channel_count : 2;
default_format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT;
default_format.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
default_format.u.raw_audio.buffer_size = 0;
format->SpecializeTo(&default_format);
if (format->u.raw_audio.buffer_size == 0)
format->u.raw_audio.buffer_size = BMediaRoster::Roster()->AudioBufferSizeFor(
format->u.raw_audio.channel_count,
format->u.raw_audio.format,
format->u.raw_audio.frame_rate);
if (format->u.raw_audio.buffer_size == 0) {
format->u.raw_audio.buffer_size
= BMediaRoster::Roster()->AudioBufferSizeFor(
format->u.raw_audio.channel_count, format->u.raw_audio.format,
format->u.raw_audio.frame_rate);
}
#if DEBUG > 0
string_for_format(*format, buf, sizeof(buf));
@@ -334,25 +383,28 @@ _SoundPlayNode::PrepareToConnect(const media_source& what, const media_destinati
// Now reserve the connection, and return information about it
mOutput.destination = where;
mOutput.format = *format;
*out_source = mOutput.source;
strcpy(out_name, Name());
*_source = mOutput.source;
strcpy(_name, Name());
return B_OK;
}
void
_SoundPlayNode::Connect(status_t error, const media_source& source, const media_destination& destination, const media_format& format, char* io_name)
void
_SoundPlayNode::Connect(status_t error, const media_source& source,
const media_destination& destination, const media_format& format,
char* name)
{
CALLED();
// is this our output?
if (source != mOutput.source) {
TRACE("_SoundPlayNode::Connect returning\n");
return;
}
// If something earlier failed, Connect() might still be called, but with a non-zero
// error code. When that happens we simply unreserve the connection and do
// nothing else.
// If something earlier failed, Connect() might still be called, but with
// a non-zero error code. When that happens we simply unreserve the
// connection and do nothing else.
if (error) {
mOutput.destination = media_destination::null;
mOutput.format.type = B_MEDIA_RAW_AUDIO;
@@ -360,11 +412,11 @@ _SoundPlayNode::Connect(status_t error, const media_source& source, const media_
return;
}
// Okay, the connection has been confirmed. Record the destination and format
// that we agreed on, and report our connection name again.
// Okay, the connection has been confirmed. Record the destination and
// format that we agreed on, and report our connection name again.
mOutput.destination = destination;
mOutput.format = format;
strcpy(io_name, Name());
strcpy(name, Name());
// Now that we're connected, we can determine our downstream latency.
// Do so, then make sure we get our events early enough.
@@ -374,83 +426,83 @@ _SoundPlayNode::Connect(status_t error, const media_source& source, const media_
// reset our buffer duration, etc. to avoid later calculations
bigtime_t duration = ((mOutput.format.u.raw_audio.buffer_size * 1000000LL)
/ ((mOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK) * mOutput.format.u.raw_audio.channel_count))
/ ((mOutput.format.u.raw_audio.format
& media_raw_audio_format::B_AUDIO_SIZE_MASK)
* mOutput.format.u.raw_audio.channel_count))
/ (int32)mOutput.format.u.raw_audio.frame_rate;
SetBufferDuration(duration);
TRACE("_SoundPlayNode::Connect: buffer duration is %Ld\n", duration);
mInternalLatency = (3 * BufferDuration()) / 4;
TRACE("_SoundPlayNode::Connect: using %Ld as internal latency\n", mInternalLatency);
TRACE("_SoundPlayNode::Connect: using %Ld as internal latency\n",
mInternalLatency);
SetEventLatency(mLatency + mInternalLatency);
// Set up the buffer group for our connection, as long as nobody handed us a
// buffer group (via SetBufferGroup()) prior to this. That can happen, for example,
// if the consumer calls SetOutputBuffersFor() on us from within its Connected()
// method.
if (!mBufferGroup)
// Set up the buffer group for our connection, as long as nobody handed us
// a buffer group (via SetBufferGroup()) prior to this.
// That can happen, for example, if the consumer calls SetOutputBuffersFor()
// on us from within its Connected() method.
if (!mBufferGroup)
AllocateBuffers();
}
void
_SoundPlayNode::Disconnect(const media_source& what, const media_destination& where)
void
_SoundPlayNode::Disconnect(const media_source& what,
const media_destination& where)
{
CALLED();
// is this our output?
if (what != mOutput.source)
{
if (what != mOutput.source) {
TRACE("_SoundPlayNode::Disconnect returning\n");
return;
}
// Make sure that our connection is the one being disconnected
if ((where == mOutput.destination) && (what == mOutput.source))
{
if (where == mOutput.destination && what == mOutput.source) {
mOutput.destination = media_destination::null;
mOutput.format.type = B_MEDIA_RAW_AUDIO;
mOutput.format.u.raw_audio = media_multi_audio_format::wildcard;
delete mBufferGroup;
mBufferGroup = NULL;
}
else
{
} else {
fprintf(stderr, "\tDisconnect() called with wrong source/destination (%ld/%ld), ours is (%ld/%ld)\n",
what.id, where.id, mOutput.source.id, mOutput.destination.id);
}
}
void
_SoundPlayNode::LateNoticeReceived(const media_source& what, bigtime_t how_much, bigtime_t performance_time)
void
_SoundPlayNode::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
bigtime_t performanceTime)
{
CALLED();
TRACE("_SoundPlayNode::LateNoticeReceived, %Ld too late at %Ld\n", how_much, performance_time);
TRACE("_SoundPlayNode::LateNoticeReceived, %Ld too late at %Ld\n", howMuch,
performanceTime);
// is this our output?
if (what != mOutput.source)
{
if (what != mOutput.source) {
TRACE("_SoundPlayNode::LateNoticeReceived returning\n");
return;
}
if (RunMode() != B_DROP_DATA)
{
if (RunMode() != B_DROP_DATA) {
// We're late, and our run mode dictates that we try to produce buffers
// earlier in order to catch up. This argues that the downstream nodes are
// not properly reporting their latency, but there's not much we can do about
// that at the moment, so we try to start producing buffers earlier to
// compensate.
mInternalLatency += how_much;
mInternalLatency += howMuch;
if (mInternalLatency > 30000) // avoid getting a too high latency
mInternalLatency = 30000;
SetEventLatency(mLatency + mInternalLatency);
TRACE("_SoundPlayNode::LateNoticeReceived: increasing latency to %Ld\n", mLatency + mInternalLatency);
}
else
{
} else {
// The other run modes dictate various strategies for sacrificing data quality
// in the interests of timely data delivery. The way *we* do this is to skip
// a buffer, which catches us up in time by one buffer duration.
@@ -465,61 +517,67 @@ _SoundPlayNode::LateNoticeReceived(const media_source& what, bigtime_t how_much,
}
}
void
_SoundPlayNode::EnableOutput(const media_source& what, bool enabled, int32* _deprecated_)
void
_SoundPlayNode::EnableOutput(const media_source& what, bool enabled,
int32* /* deprecated */)
{
CALLED();
// If I had more than one output, I'd have to walk my list of output records to see
// which one matched the given source, and then enable/disable that one. But this
// node only has one output, so I just make sure the given source matches, then set
// the enable state accordingly.
// If I had more than one output, I'd have to walk my list of output
// records to see which one matched the given source, and then
// enable/disable that one.
// But this node only has one output, so I just make sure the given source
// matches, then set the enable state accordingly.
// is this our output?
if (what != mOutput.source)
{
if (what != mOutput.source) {
fprintf(stderr, "_SoundPlayNode::EnableOutput returning\n");
return;
}
mOutputEnabled = enabled;
}
void
_SoundPlayNode::AdditionalBufferRequested(const media_source& source, media_buffer_id prev_buffer, bigtime_t prev_time, const media_seek_tag* prev_tag)
void
_SoundPlayNode::AdditionalBufferRequested(const media_source& source,
media_buffer_id previousBuffer, bigtime_t previousTime,
const media_seek_tag* previousTag)
{
CALLED();
// we don't support offline mode
return;
}
void
_SoundPlayNode::LatencyChanged(const media_source& source, const media_destination& destination, bigtime_t new_latency, uint32 flags)
void
_SoundPlayNode::LatencyChanged(const media_source& source,
const media_destination& destination, bigtime_t newLatency, uint32 flags)
{
CALLED();
TRACE("_SoundPlayNode::LatencyChanged: new_latency %Ld\n", new_latency);
TRACE("_SoundPlayNode::LatencyChanged: new_latency %Ld\n", newLatency);
// something downstream changed latency, so we need to start producing
// buffers earlier (or later) than we were previously. Make sure that the
// connection that changed is ours, and adjust to the new downstream
// latency if so.
if ((source == mOutput.source) && (destination == mOutput.destination))
{
mLatency = new_latency;
if (source == mOutput.source && destination == mOutput.destination) {
mLatency = newLatency;
SetEventLatency(mLatency + mInternalLatency);
} else {
TRACE("_SoundPlayNode::LatencyChanged: ignored\n");
}
}
// -------------------------------------------------------- //
// implementation for BMediaEventLooper
// -------------------------------------------------------- //
void _SoundPlayNode::HandleEvent(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
// #pragma mark - implementation for BMediaEventLooper
void
_SoundPlayNode::HandleEvent(const media_timed_event* event, bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
switch (event->type) {
@@ -539,9 +597,8 @@ void _SoundPlayNode::HandleEvent(
// we don't get any buffers
break;
case SEND_NEW_BUFFER_EVENT:
if (RunState() == BMediaEventLooper::B_STARTED) {
if (RunState() == BMediaEventLooper::B_STARTED)
SendNewBuffer(event, lateness, realTimeEvent);
}
break;
case BTimedEventQueue::B_DATA_STATUS:
HandleDataStatus(event,lateness,realTimeEvent);
@@ -550,35 +607,41 @@ void _SoundPlayNode::HandleEvent(
HandleParameter(event,lateness,realTimeEvent);
break;
default:
fprintf(stderr," unknown event type: %li\n",event->type);
fprintf(stderr," unknown event type: %li\n", event->type);
break;
}
}
// protected:
// #pragma mark - protected methods
// how should we handle late buffers? drop them?
// notify the producer?
status_t
_SoundPlayNode::SendNewBuffer(const media_timed_event *event, bigtime_t lateness, bool realTimeEvent)
status_t
_SoundPlayNode::SendNewBuffer(const media_timed_event* event,
bigtime_t lateness, bool realTimeEvent)
{
CALLED();
// printf("latency = %12Ld, event = %12Ld, sched = %5Ld, arrive at %12Ld, now %12Ld, current lateness %12Ld\n", EventLatency() + SchedulingLatency(), EventLatency(), SchedulingLatency(), event->event_time, TimeSource()->Now(), lateness);
// make sure we're both started *and* connected before delivering a buffer
if ((RunState() != BMediaEventLooper::B_STARTED) || (mOutput.destination == media_destination::null))
if (RunState() != BMediaEventLooper::B_STARTED
|| mOutput.destination == media_destination::null)
return B_OK;
// The event->event_time is the time at which the buffer we are preparing here should
// arrive at it's destination. The MediaEventLooper should have scheduled us early enough
// (based on EventLatency() and the SchedulingLatency()) to make this possible.
// The event->event_time is the time at which the buffer we are preparing
// here should arrive at it's destination. The MediaEventLooper should have
// scheduled us early enough (based on EventLatency() and the
// SchedulingLatency()) to make this possible.
// lateness is independent of EventLatency()!
if (lateness > (BufferDuration() / 3) ) {
printf("_SoundPlayNode::SendNewBuffer, event scheduled much too late, lateness is %Ld\n", lateness);
printf("_SoundPlayNode::SendNewBuffer, event scheduled much too late, "
"lateness is %Ld\n", lateness);
}
// skip buffer creation if output not enabled
// skip buffer creation if output not enabled
if (mOutputEnabled) {
// Get the next buffer of data
@@ -607,7 +670,8 @@ _SoundPlayNode::SendNewBuffer(const media_timed_event *event, bigtime_t lateness
if (B_OK != SendBuffer(buffer, mOutput.destination)) {
// we need to recycle the buffer
// if the call to SendBuffer() fails
printf("_SoundPlayNode::SendNewBuffer: Buffer sending failed\n");
printf("_SoundPlayNode::SendNewBuffer: Buffer sending "
"failed\n");
buffer->Recycle();
}
}
@@ -615,27 +679,31 @@ _SoundPlayNode::SendNewBuffer(const media_timed_event *event, bigtime_t lateness
// track how much media we've delivered so far
size_t nFrames = mOutput.format.u.raw_audio.buffer_size
/ ((mOutput.format.u.raw_audio.format & media_raw_audio_format::B_AUDIO_SIZE_MASK)
/ ((mOutput.format.u.raw_audio.format
& media_raw_audio_format::B_AUDIO_SIZE_MASK)
* mOutput.format.u.raw_audio.channel_count);
mFramesSent += nFrames;
// The buffer is on its way; now schedule the next one to go
// nextEvent is the time at which the buffer should arrive at it's destination
bigtime_t nextEvent = mStartTime + bigtime_t((1000000LL * mFramesSent) / (int32)mOutput.format.u.raw_audio.frame_rate);
// nextEvent is the time at which the buffer should arrive at it's
// destination
bigtime_t nextEvent = mStartTime + bigtime_t((1000000LL * mFramesSent)
/ (int32)mOutput.format.u.raw_audio.frame_rate);
media_timed_event nextBufferEvent(nextEvent, SEND_NEW_BUFFER_EVENT);
EventQueue()->AddEvent(nextBufferEvent);
return B_OK;
}
status_t
_SoundPlayNode::HandleDataStatus(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
status_t
_SoundPlayNode::HandleDataStatus(const media_timed_event* event,
bigtime_t lateness, bool realTimeEvent)
{
TRACE("_SoundPlayNode::HandleDataStatus status: %li, lateness: %Li\n", event->data, lateness);
switch(event->data) {
TRACE("_SoundPlayNode::HandleDataStatus status: %li, lateness: %Li\n",
event->data, lateness);
switch (event->data) {
case B_DATA_NOT_AVAILABLE:
break;
case B_DATA_AVAILABLE:
@@ -648,25 +716,24 @@ _SoundPlayNode::HandleDataStatus(
return B_OK;
}
status_t
_SoundPlayNode::HandleStart(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
status_t
_SoundPlayNode::HandleStart(const media_timed_event* event, bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
// don't do anything if we're already running
if (RunState() != B_STARTED)
{
// We want to start sending buffers now, so we set up the buffer-sending bookkeeping
// and fire off the first "produce a buffer" event.
mFramesSent = 0;
mStartTime = event->event_time;
media_timed_event firstBufferEvent(event->event_time, SEND_NEW_BUFFER_EVENT);
if (RunState() != B_STARTED) {
// We want to start sending buffers now, so we set up the buffer-sending
// bookkeeping and fire off the first "produce a buffer" event.
// Alternatively, we could call HandleEvent() directly with this event, to avoid a trip through
// the event queue, like this:
mFramesSent = 0;
mStartTime = event->event_time;
media_timed_event firstBufferEvent(event->event_time,
SEND_NEW_BUFFER_EVENT);
// Alternatively, we could call HandleEvent() directly with this event,
// to avoid a trip through the event queue, like this:
//
// this->HandleEvent(&firstBufferEvent, 0, false);
//
@@ -675,51 +742,50 @@ _SoundPlayNode::HandleStart(
return B_OK;
}
status_t
_SoundPlayNode::HandleSeek(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
status_t
_SoundPlayNode::HandleSeek(const media_timed_event* event, bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
TRACE("_SoundPlayNode::HandleSeek(t=%lld, d=%li, bd=%lld)\n", event->event_time, event->data, event->bigdata);
TRACE("_SoundPlayNode::HandleSeek(t=%lld, d=%li, bd=%lld)\n",
event->event_time, event->data, event->bigdata);
return B_OK;
}
status_t
_SoundPlayNode::HandleWarp(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
status_t
_SoundPlayNode::HandleWarp(const media_timed_event* event, bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
return B_OK;
}
status_t
_SoundPlayNode::HandleStop(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
status_t
_SoundPlayNode::HandleStop(const media_timed_event* event, bigtime_t lateness,
bool realTimeEvent)
{
CALLED();
// flush the queue so downstreamers don't get any more
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, SEND_NEW_BUFFER_EVENT);
EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true,
SEND_NEW_BUFFER_EVENT);
return B_OK;
}
status_t
_SoundPlayNode::HandleParameter(
const media_timed_event *event,
bigtime_t lateness,
bool realTimeEvent)
status_t
_SoundPlayNode::HandleParameter(const media_timed_event* event,
bigtime_t lateness, bool realTimeEvent)
{
CALLED();
return B_OK;
}
void
void
_SoundPlayNode::AllocateBuffers()
{
CALLED();
@@ -728,41 +794,47 @@ _SoundPlayNode::AllocateBuffers()
size_t size = mOutput.format.u.raw_audio.buffer_size;
int32 count = int32(mLatency / BufferDuration() + 1 + 1);
TRACE("_SoundPlayNode::AllocateBuffers: latency = %Ld, buffer duration = %Ld, count %ld\n", mLatency, BufferDuration(), count);
TRACE("_SoundPlayNode::AllocateBuffers: latency = %Ld, buffer duration "
"= %Ld, count %ld\n", mLatency, BufferDuration(), count);
if (count < 3)
count = 3;
TRACE("_SoundPlayNode::AllocateBuffers: creating group of %ld buffers, size = %lu\n", count, size);
TRACE("_SoundPlayNode::AllocateBuffers: creating group of %ld buffers, "
"size = %lu\n", count, size);
mBufferGroup = new BBufferGroup(size, count);
if (mBufferGroup->InitCheck() != B_OK) {
ERROR("_SoundPlayNode::AllocateBuffers: BufferGroup::InitCheck() failed\n");
}
ERROR("_SoundPlayNode::AllocateBuffers: BufferGroup::InitCheck() "
"failed\n");
}
}
BBuffer*
_SoundPlayNode::FillNextBuffer(bigtime_t event_time)
{
CALLED();
// get a buffer from our buffer group
BBuffer* buf = mBufferGroup->RequestBuffer(mOutput.format.u.raw_audio.buffer_size, BufferDuration() / 2);
BBuffer* buf = mBufferGroup->RequestBuffer(
mOutput.format.u.raw_audio.buffer_size, BufferDuration() / 2);
// if we fail to get a buffer (for example, if the request times out), we skip this
// buffer and go on to the next, to avoid locking up the control thread
// If we fail to get a buffer (for example, if the request times out), we
// skip this buffer and go on to the next, to avoid locking up the control
// thread
if (!buf) {
ERROR("_SoundPlayNode::FillNextBuffer: RequestBuffer failed\n");
return NULL;
}
if (mPlayer->HasData()) {
mPlayer->PlayBuffer(buf->Data(),
mPlayer->_PlayBuffer(buf->Data(),
mOutput.format.u.raw_audio.buffer_size, mOutput.format.u.raw_audio);
} else {
memset(buf->Data(), 0, mOutput.format.u.raw_audio.buffer_size);
}
// fill in the buffer header
media_header* hdr = buf->Header();
hdr->type = B_MEDIA_RAW_AUDIO;
+328 -332
View File
@@ -1,18 +1,27 @@
/***********************************************************************
* AUTHOR: Marcus Overhagen, Jérôme Duval
* FILE: SoundPlayer.cpp
* DESCR:
***********************************************************************/
#include <TimeSource.h>
#include <MediaRoster.h>
#include <ParameterWeb.h>
#include <Sound.h>
/*
* Copyright 2002-2009, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Marcus Overhagen
* Jérôme Duval
*/
#include <SoundPlayer.h>
#include <math.h>
#include <string.h>
#include "debug.h"
#include <Autolock.h>
#include <MediaRoster.h>
#include <ParameterWeb.h>
#include <Sound.h>
#include <TimeSource.h>
#include "SoundPlayNode.h"
#include "SoundPlayer.h"
#include "debug.h"
#define atomic_read(a) atomic_or(a, 0)
@@ -28,57 +37,47 @@ enum {
static BSoundPlayer::play_id sCurrentPlayID = 1;
/*************************************************************
* 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)
BSoundPlayer::BSoundPlayer(const char* name, BufferPlayerFunc playerFunction,
EventNotifierFunc eventNotifierFunction, void* cookie)
{
CALLED();
TRACE("BSoundPlayer::BSoundPlayer: default constructor used\n");
media_multi_audio_format fmt = media_multi_audio_format::wildcard;
media_multi_audio_format format = media_multi_audio_format::wildcard;
Init(NULL, &fmt, name, NULL, PlayBuffer, Notifier, cookie);
_Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction,
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)
BSoundPlayer::BSoundPlayer(const media_raw_audio_format* _format,
const char* name, BufferPlayerFunc playerFunction,
EventNotifierFunc eventNotifierFunction, void* cookie)
{
CALLED();
TRACE("BSoundPlayer::BSoundPlayer: raw audio format constructor used\n");
media_multi_audio_format fmt = media_multi_audio_format::wildcard;
*(media_raw_audio_format *)&fmt = *format;
media_multi_audio_format format = media_multi_audio_format::wildcard;
*(media_raw_audio_format*)&format = *_format;
#if DEBUG > 0
char buf[100];
media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = fmt;
media_format tmp; tmp.type = B_MEDIA_RAW_AUDIO; tmp.u.raw_audio = format;
string_for_format(tmp, buf, sizeof(buf));
TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf);
#endif
Init(NULL, &fmt, name, NULL, PlayBuffer, Notifier, cookie);
_Init(NULL, &format, name, NULL, playerFunction, eventNotifierFunction,
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)
BSoundPlayer::BSoundPlayer(const media_node& toNode,
const media_multi_audio_format* format, const char* name,
const media_input* input, BufferPlayerFunc playerFunction,
EventNotifierFunc eventNotifierFunction, void* cookie)
{
CALLED();
@@ -94,216 +93,66 @@ BSoundPlayer::BSoundPlayer(const media_node & toNode,
TRACE("BSoundPlayer::BSoundPlayer: format %s\n", buf);
#endif
Init(&toNode, format, name, input, PlayBuffer, Notifier, cookie);
_Init(&toNode, format, name, input, playerFunction, eventNotifierFunction,
cookie);
}
/*************************************************************
* private BSoundPlayer
*************************************************************/
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)
{
CALLED();
fPlayingSounds = NULL;
fWaitingSounds = NULL;
fPlayerNode = NULL;
fPlayBufferFunc = PlayBuffer;
if (fPlayBufferFunc == NULL) {
fPlayBufferFunc = _SoundPlayBufferFunc;
fCookie = this;
} else
fCookie = cookie;
fNotifierFunc = Notifier;
fVolumeDB = 0.0f;
fFlags = 0;
fInitStatus = B_ERROR;
fParameterWeb = NULL;
fVolumeSlider = NULL;
fLastVolumeUpdate = 0;
status_t err;
media_node timeSource;
media_node inputNode;
media_output _output;
media_input _input;
int32 inputCount;
int32 outputCount;
media_format tryFormat;
BMediaRoster *roster = BMediaRoster::Roster();
if (!roster) {
TRACE("BSoundPlayer::Init: Couldn't get BMediaRoster\n");
return;
}
// The inputNode that our player node will be
// connected with is either supplied by the user
// or the system audio mixer
if (node) {
inputNode = *node;
} else {
err = roster->GetAudioMixer(&inputNode);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't GetAudioMixer\n");
goto the_end;
}
fFlags |= F_MUST_RELEASE_MIXER;
}
// Create the player node and register it
fPlayerNode = new _SoundPlayNode(name, this);
err = roster->RegisterNode(fPlayerNode);
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 system audio mixer uses too.
err = roster->GetTimeSource(&timeSource);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't GetTimeSource\n");
goto the_end;
}
err = roster->SetTimeSourceFor(fPlayerNode->Node().node, timeSource.node);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't SetTimeSourceFor\n");
goto the_end;
}
// find a free media_input
if (!input) {
err = roster->GetFreeInputsFor(inputNode, &_input, 1, &inputCount, B_MEDIA_RAW_AUDIO);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't GetFreeInputsFor\n");
goto the_end;
}
if (inputCount < 1) {
TRACE("BSoundPlayer::Init: Couldn't find a free input\n");
err = B_ERROR;
goto the_end;
}
} else {
_input = *input;
}
// find a free media_output
err = roster->GetFreeOutputsFor(fPlayerNode->Node(), &_output, 1, &outputCount, B_MEDIA_RAW_AUDIO);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't GetFreeOutputsFor\n");
goto the_end;
}
if (outputCount < 1) {
TRACE("BSoundPlayer::Init: Couldn't find a free output\n");
err = B_ERROR;
goto the_end;
}
// Set an appropriate run mode for the producer
err = roster->SetRunModeNode(fPlayerNode->Node(), BMediaNode::B_INCREASE_LATENCY);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't SetRunModeNode\n");
goto the_end;
}
// setup our requested format (can still have many wildcards)
tryFormat.type = B_MEDIA_RAW_AUDIO;
tryFormat.u.raw_audio = *format;
#if DEBUG > 0
char buf[100];
string_for_format(tryFormat, buf, sizeof(buf));
TRACE("BSoundPlayer::Init: trying to connect with format %s\n", buf);
#endif
// and connect the nodes
err = roster->Connect(_output.source, _input.destination, &tryFormat, &fMediaOutput, &fMediaInput);
if (err != B_OK) {
TRACE("BSoundPlayer::Init: Couldn't Connect\n");
goto the_end;
}
fFlags |= F_NODES_CONNECTED;
get_volume_slider();
TRACE("BSoundPlayer node %ld has timesource %ld\n", fPlayerNode->Node().node, fPlayerNode->TimeSource()->Node().node);
the_end:
TRACE("BSoundPlayer::Init: %s\n", strerror(err));
SetInitError(err);
}
/*************************************************************
* public BSoundPlayer
*************************************************************/
/* virtual */
BSoundPlayer::~BSoundPlayer()
{
CALLED();
if (fFlags & F_IS_STARTED) {
Stop(true, false); // block, but don't flush
if ((fFlags & F_IS_STARTED) != 0) {
// block, but don't flush
Stop(true, false);
}
status_t err;
BMediaRoster *roster = BMediaRoster::Roster();
if (!roster) {
BMediaRoster* roster = BMediaRoster::Roster();
if (roster == NULL) {
TRACE("BSoundPlayer::~BSoundPlayer: Couldn't get BMediaRoster\n");
goto cleanup;
}
if (fFlags & F_NODES_CONNECTED) {
// Ordinarily we'd stop *all* of the nodes in the chain before disconnecting. However,
// our node is already stopped, and we can't stop the System Mixer.
// 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.
if ((fFlags & F_NODES_CONNECTED) != 0) {
// Ordinarily we'd stop *all* of the nodes in the chain before
// disconnecting. However, our node is already stopped, and we can't
// stop the System Mixer.
// 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.
err = roster->Disconnect(fMediaOutput, fMediaInput);
#if DEBUG >0
if (err) {
TRACE("BSoundPlayer::~BSoundPlayer: Error disconnecting nodes: %ld (%s)\n", err, strerror(err));
#if DEBUG > 0
if (err != B_OK) {
TRACE("BSoundPlayer::~BSoundPlayer: Error disconnecting nodes: "
"%ld (%s)\n", err, strerror(err));
}
#endif
}
if (fFlags & F_MUST_RELEASE_MIXER) {
if ((fFlags & F_MUST_RELEASE_MIXER) != 0) {
// Release the mixer as it was acquired
// through BMediaRoster::GetAudioMixer()
err = roster->ReleaseNode(fMediaInput.node);
#if DEBUG >0
if (err) {
TRACE("BSoundPlayer::~BSoundPlayer: Error releasing input node: %ld (%s)\n", err, strerror(err));
#if DEBUG > 0
if (err != B_OK) {
TRACE("BSoundPlayer::~BSoundPlayer: Error releasing input node: "
"%ld (%s)\n", err, strerror(err));
}
#endif
}
cleanup:
// Dispose of the player node
if (fPlayerNode) {
// We do not call BMediaRoster::ReleaseNode(), since
// the player was created by using "new". We could
// call BMediaRoster::UnregisterNode(), but this is
// supposed to be done by BMediaNode destructor automatically
delete fPlayerNode;
}
// We do not call BMediaRoster::ReleaseNode(), since
// the player was created by using "new". We could
// call BMediaRoster::UnregisterNode(), but this is
// supposed to be done by BMediaNode destructor automatically
delete fPlayerNode;
// do not delete fVolumeSlider, it belongs to the parameter web
delete fParameterWeb;
// do not delete fVolumeSlider, it belonged to the parameter web
}
@@ -335,10 +184,10 @@ BSoundPlayer::Start()
if ((fFlags & F_NODES_CONNECTED) == 0)
return B_NO_INIT;
if (fFlags & F_IS_STARTED)
if ((fFlags & F_IS_STARTED) != 0)
return B_OK;
BMediaRoster *roster = BMediaRoster::Roster();
BMediaRoster* roster = BMediaRoster::Roster();
if (!roster) {
TRACE("BSoundPlayer::Start: Couldn't get BMediaRoster\n");
return B_ERROR;
@@ -354,13 +203,14 @@ BSoundPlayer::Start()
// buffers through the node chain, otherwise it'll start
// up already late
status_t err = roster->StartNode(fPlayerNode->Node(), fPlayerNode->TimeSource()->Now() + Latency() + 5000);
status_t err = roster->StartNode(fPlayerNode->Node(),
fPlayerNode->TimeSource()->Now() + Latency() + 5000);
if (err != B_OK) {
TRACE("BSoundPlayer::Start: StartNode failed, %ld", err);
return err;
}
if (fNotifierFunc)
if (fNotifierFunc != NULL)
fNotifierFunc(fCookie, B_STARTED, this);
SetHasData(true);
@@ -371,8 +221,7 @@ BSoundPlayer::Start()
void
BSoundPlayer::Stop(bool block,
bool flush)
BSoundPlayer::Stop(bool block, bool flush)
{
CALLED();
@@ -381,12 +230,11 @@ BSoundPlayer::Stop(bool block,
if ((fFlags & F_NODES_CONNECTED) == 0)
return;
// XXX flush is ignored
// TODO: flush is ignored
if (fFlags & F_IS_STARTED) {
BMediaRoster *roster = BMediaRoster::Roster();
if (!roster) {
if ((fFlags & F_IS_STARTED) != 0) {
BMediaRoster* roster = BMediaRoster::Roster();
if (roster == NULL) {
TRACE("BSoundPlayer::Stop: Couldn't get BMediaRoster\n");
return;
}
@@ -398,13 +246,15 @@ BSoundPlayer::Stop(bool block,
if (block) {
// wait until the node is stopped
int maxtrys;
for (maxtrys = 250; fPlayerNode->IsPlaying() && maxtrys != 0; maxtrys--)
int tries;
for (tries = 250; fPlayerNode->IsPlaying() && tries != 0; tries--)
snooze(2000);
DEBUG_ONLY(if (maxtrys == 0) TRACE("BSoundPlayer::Stop: waiting for node stop failed\n"));
DEBUG_ONLY(if (maxtrys == 0)
TRACE("BSoundPlayer::Stop: waiting for node stop failed\n"));
// wait until all buffers on the way to the physical output have been played
// Wait until all buffers on the way to the physical output have been
// played
snooze(Latency() + 2000);
}
@@ -431,7 +281,8 @@ BSoundPlayer::Latency()
bigtime_t latency;
status_t err = roster->GetLatencyFor(fMediaOutput.node, &latency);
if (err != B_OK) {
TRACE("BSoundPlayer::Latency: GetLatencyFor failed %ld (%s)\n", err, strerror(err));
TRACE("BSoundPlayer::Latency: GetLatencyFor failed %ld (%s)\n", err,
strerror(err));
return 0;
}
@@ -452,7 +303,7 @@ BSoundPlayer::SetHasData(bool has_data)
}
/* virtual */ bool
bool
BSoundPlayer::HasData()
{
CALLED();
@@ -469,12 +320,12 @@ BSoundPlayer::BufferPlayer() const
void
BSoundPlayer::SetBufferPlayer(void (*PlayBuffer)(void *, void * buffer, size_t size, const media_raw_audio_format & format))
BSoundPlayer::SetBufferPlayer(BufferPlayerFunc playerFunction)
{
CALLED();
fLocker.Lock();
fPlayBufferFunc = PlayBuffer;
fLocker.Unlock();
BAutolock _(fLocker);
fPlayBufferFunc = playerFunction;
}
@@ -486,16 +337,17 @@ BSoundPlayer::EventNotifier() const
}
void BSoundPlayer::SetNotifier(void (*Notifier)(void *, sound_player_notification what, ...))
void
BSoundPlayer::SetNotifier(EventNotifierFunc eventNotifierFunction)
{
CALLED();
fLocker.Lock();
fNotifierFunc = Notifier;
fLocker.Unlock();
BAutolock _(fLocker);
fNotifierFunc = eventNotifierFunction;
}
void *
void*
BSoundPlayer::Cookie() const
{
CALLED();
@@ -507,31 +359,30 @@ void
BSoundPlayer::SetCookie(void *cookie)
{
CALLED();
fLocker.Lock();
BAutolock _(fLocker);
fCookie = cookie;
fLocker.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)
BSoundPlayer::SetCallbacks(BufferPlayerFunc playerFunction,
EventNotifierFunc eventNotifierFunction, void* cookie)
{
CALLED();
fLocker.Lock();
SetBufferPlayer(PlayBuffer);
SetNotifier(Notifier);
BAutolock _(fLocker);
SetBufferPlayer(playerFunction);
SetNotifier(eventNotifierFunction);
SetCookie(cookie);
fLocker.Unlock();
}
/* The BeBook is inaccurate about the meaning of this function.
* The probably best interpretation is to return the time that
* has elapsed since playing was started, whichs seems to match
* " CurrentTime() returns the current media time "
*/
/*! The BeBook is inaccurate about the meaning of this function.
The probably best interpretation is to return the time that
has elapsed since playing was started, whichs seems to match
"CurrentTime() returns the current media time"
*/
bigtime_t
BSoundPlayer::CurrentTime()
{
@@ -542,10 +393,10 @@ BSoundPlayer::CurrentTime()
}
/* Returns the current performance time of the sound player node
* being used by the BSoundPlayer. Will return B_ERROR if the
* BSoundPlayer object hasn't been properly initialized.
*/
/*! Returns the current performance time of the sound player node
being used by the BSoundPlayer. Will return B_ERROR if the
BSoundPlayer object hasn't been properly initialized.
*/
bigtime_t
BSoundPlayer::PerformanceTime()
{
@@ -564,15 +415,16 @@ BSoundPlayer::Preroll()
if ((fFlags & F_NODES_CONNECTED) == 0)
return B_NO_INIT;
BMediaRoster *roster = BMediaRoster::Roster();
if (!roster) {
BMediaRoster* roster = BMediaRoster::Roster();
if (roster == NULL) {
TRACE("BSoundPlayer::Preroll: Couldn't get BMediaRoster\n");
return B_ERROR;
}
status_t err = roster->PrerollNode(fMediaOutput.node);
if (err != B_OK) {
TRACE("BSoundPlayer::Preroll: Error while PrerollNode: %ld (%s)\n", err, strerror(err));
TRACE("BSoundPlayer::Preroll: Error while PrerollNode: %ld (%s)\n",
err, strerror(err));
return err;
}
@@ -581,14 +433,14 @@ BSoundPlayer::Preroll()
BSoundPlayer::play_id
BSoundPlayer::StartPlaying(BSound *sound, bigtime_t atTime)
BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime)
{
return StartPlaying(sound, atTime, 1.0);
}
BSoundPlayer::play_id
BSoundPlayer::StartPlaying(BSound *sound, bigtime_t atTime, float withVolume)
BSoundPlayer::StartPlaying(BSound* sound, bigtime_t atTime, float withVolume)
{
CALLED();
@@ -671,9 +523,10 @@ BSoundPlayer::StopPlaying(play_id id)
if (!fLocker.Lock())
return B_ERROR;
_playing_sound **link = &fPlayingSounds;
_playing_sound *item = fPlayingSounds;
while (item) {
_playing_sound** link = &fPlayingSounds;
_playing_sound* item = fPlayingSounds;
while (item != NULL) {
if (item->id == id) {
*link = item->next;
sem_id waitSem = item->wait_sem;
@@ -681,7 +534,7 @@ BSoundPlayer::StopPlaying(play_id id)
free(item);
fLocker.Unlock();
NotifySoundDone(id, true);
_NotifySoundDone(id, true);
if (waitSem >= 0)
release_sem(waitSem);
@@ -704,8 +557,8 @@ BSoundPlayer::WaitForSound(play_id id)
if (!fLocker.Lock())
return B_ERROR;
_playing_sound *item = fPlayingSounds;
while (item) {
_playing_sound* item = fPlayingSounds;
while (item != NULL) {
if (item->id == id) {
sem_id waitSem = item->wait_sem;
if (waitSem < 0)
@@ -732,10 +585,10 @@ BSoundPlayer::Volume()
void
BSoundPlayer::SetVolume(float new_volume)
BSoundPlayer::SetVolume(float newVolume)
{
CALLED();
SetVolumeDB(20.0 * log10(new_volume));
SetVolumeDB(20.0 * log10(newVolume));
}
@@ -746,7 +599,7 @@ BSoundPlayer::VolumeDB(bool forcePoll)
if (!fVolumeSlider)
return -94.0f; // silence
if (!forcePoll && (system_time() - fLastVolumeUpdate < 500000))
if (!forcePoll && system_time() - fLastVolumeUpdate < 500000)
return fVolumeDB;
int32 count = fVolumeSlider->CountChannels();
@@ -761,69 +614,64 @@ BSoundPlayer::VolumeDB(bool forcePoll)
void
BSoundPlayer::SetVolumeDB(float volume_dB)
BSoundPlayer::SetVolumeDB(float volumeDB)
{
CALLED();
if (!fVolumeSlider)
return;
float min_dB = fVolumeSlider->MinValue();
float max_dB = fVolumeSlider->MaxValue();
if (volume_dB < min_dB)
volume_dB = min_dB;
if (volume_dB > max_dB)
volume_dB = max_dB;
float minDB = fVolumeSlider->MinValue();
float maxDB = fVolumeSlider->MaxValue();
if (volumeDB < minDB)
volumeDB = minDB;
if (volumeDB > maxDB)
volumeDB = maxDB;
int count = fVolumeSlider->CountChannels();
float values[count];
for (int i = 0; i < count; i++)
values[i] = volume_dB;
values[i] = volumeDB;
fVolumeSlider->SetValue(values, sizeof(float) * count, 0);
fVolumeDB = volume_dB;
fVolumeDB = volumeDB;
fLastVolumeUpdate = system_time();
}
status_t
BSoundPlayer::GetVolumeInfo(media_node *out_node,
int32 *out_parameter_id,
float *out_min_dB,
float *out_max_dB)
BSoundPlayer::GetVolumeInfo(media_node* _node, int32* _parameterID,
float* _minDB, float* _maxDB)
{
CALLED();
if (!fVolumeSlider)
if (fVolumeSlider == NULL)
return B_NO_INIT;
if (out_node)
*out_node = fMediaInput.node;
if (out_parameter_id)
*out_parameter_id = fVolumeSlider->ID();
if (out_min_dB)
*out_min_dB = fVolumeSlider->MinValue();
if (out_max_dB)
*out_max_dB = fVolumeSlider->MaxValue();
if (_node != NULL)
*_node = fMediaInput.node;
if (_parameterID != NULL)
*_parameterID = fVolumeSlider->ID();
if (_minDB != NULL)
*_minDB = fVolumeSlider->MinValue();
if (_maxDB != NULL)
*_maxDB = fVolumeSlider->MaxValue();
return B_OK;
}
/*************************************************************
* protected BSoundPlayer
*************************************************************/
// #pragma mark - protected BSoundPlayer
void
BSoundPlayer::SetInitError(status_t in_error)
BSoundPlayer::SetInitError(status_t error)
{
CALLED();
fInitStatus = in_error;
fInitStatus = error;
}
/*************************************************************
* private BSoundPlayer
*************************************************************/
// #pragma mark - private BSoundPlayer
void
BSoundPlayer::_SoundPlayBufferFunc(void *cookie, void *buffer, size_t size,
@@ -861,26 +709,175 @@ BSoundPlayer::_SoundPlayBufferFunc(void *cookie, void *buffer, size_t size,
}
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; }
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 id, bool gotToPlay)
BSoundPlayer::_Init(const media_node* node,
const media_multi_audio_format* format, const char* name,
const media_input* input, BufferPlayerFunc playerFunction,
EventNotifierFunc eventNotifierFunction, void* cookie)
{
CALLED();
Notify(B_SOUND_DONE, id, gotToPlay);
fPlayingSounds = NULL;
fWaitingSounds = NULL;
fPlayerNode = NULL;
if (playerFunction == NULL) {
fPlayBufferFunc = _SoundPlayBufferFunc;
fCookie = this;
} else {
fPlayBufferFunc = playerFunction;
fCookie = cookie;
}
fNotifierFunc = eventNotifierFunction;
fVolumeDB = 0.0f;
fFlags = 0;
fInitStatus = B_ERROR;
fParameterWeb = NULL;
fVolumeSlider = NULL;
fLastVolumeUpdate = 0;
BMediaRoster* roster = BMediaRoster::Roster();
if (roster == NULL) {
TRACE("BSoundPlayer::_Init: Couldn't get BMediaRoster\n");
return;
}
// The inputNode that our player node will be
// connected with is either supplied by the user
// or the system audio mixer
media_node inputNode;
if (node) {
inputNode = *node;
} else {
fInitStatus = roster->GetAudioMixer(&inputNode);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't GetAudioMixer\n");
return;
}
fFlags |= F_MUST_RELEASE_MIXER;
}
media_output _output;
media_input _input;
int32 inputCount;
int32 outputCount;
media_format tryFormat;
// Create the player node and register it
fPlayerNode = new _SoundPlayNode(name, this);
fInitStatus = roster->RegisterNode(fPlayerNode);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't RegisterNode: %s\n",
strerror(fInitStatus));
return;
}
// set the producer's time source to be the "default" time source,
// which the system audio mixer uses too.
media_node timeSource;
fInitStatus = roster->GetTimeSource(&timeSource);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't GetTimeSource: %s\n",
strerror(fInitStatus));
return;
}
fInitStatus = roster->SetTimeSourceFor(fPlayerNode->Node().node,
timeSource.node);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't SetTimeSourceFor: %s\n",
strerror(fInitStatus));
return;
}
// find a free media_input
if (!input) {
fInitStatus = roster->GetFreeInputsFor(inputNode, &_input, 1,
&inputCount, B_MEDIA_RAW_AUDIO);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't GetFreeInputsFor: %s\n",
strerror(fInitStatus));
return;
}
if (inputCount < 1) {
TRACE("BSoundPlayer::_Init: Couldn't find a free input\n");
fInitStatus = B_ERROR;
return;
}
} else {
_input = *input;
}
// find a free media_output
fInitStatus = roster->GetFreeOutputsFor(fPlayerNode->Node(), &_output, 1,
&outputCount, B_MEDIA_RAW_AUDIO);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't GetFreeOutputsFor: %s\n",
strerror(fInitStatus));
return;
}
if (outputCount < 1) {
TRACE("BSoundPlayer::_Init: Couldn't find a free output\n");
fInitStatus = B_ERROR;
return;
}
// Set an appropriate run mode for the producer
fInitStatus = roster->SetRunModeNode(fPlayerNode->Node(),
BMediaNode::B_INCREASE_LATENCY);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't SetRunModeNode: %s\n",
strerror(fInitStatus));
return;
}
// setup our requested format (can still have many wildcards)
tryFormat.type = B_MEDIA_RAW_AUDIO;
tryFormat.u.raw_audio = *format;
#if DEBUG > 0
char buf[100];
string_for_format(tryFormat, buf, sizeof(buf));
TRACE("BSoundPlayer::_Init: trying to connect with format %s\n", buf);
#endif
// and connect the nodes
fInitStatus = roster->Connect(_output.source, _input.destination,
&tryFormat, &fMediaOutput, &fMediaInput);
if (fInitStatus != B_OK) {
TRACE("BSoundPlayer::_Init: Couldn't Connect: %s\n",
strerror(fInitStatus));
return;
}
fFlags |= F_NODES_CONNECTED;
_GetVolumeSlider();
TRACE("BSoundPlayer node %ld has timesource %ld\n",
fPlayerNode->Node().node, fPlayerNode->TimeSource()->Node().node);
}
void
BSoundPlayer::get_volume_slider()
BSoundPlayer::_NotifySoundDone(play_id id, bool gotToPlay)
{
CALLED();
_Notify(B_SOUND_DONE, id, gotToPlay);
}
void
BSoundPlayer::_GetVolumeSlider()
{
CALLED();
@@ -888,12 +885,12 @@ BSoundPlayer::get_volume_slider()
BMediaRoster *roster = BMediaRoster::CurrentRoster();
if (!roster) {
TRACE("BSoundPlayer::get_volume_slider failed to get BMediaRoster");
TRACE("BSoundPlayer::_GetVolumeSlider failed to get BMediaRoster");
return;
}
if (!fParameterWeb && roster->GetParameterWebFor(fMediaInput.node, &fParameterWeb) < B_OK) {
TRACE("BSoundPlayer::get_volume_slider couldn't get parameter web");
TRACE("BSoundPlayer::_GetVolumeSlider couldn't get parameter web");
return;
}
@@ -912,14 +909,14 @@ BSoundPlayer::get_volume_slider()
#if DEBUG >0
if (!fVolumeSlider) {
TRACE("BSoundPlayer::get_volume_slider couldn't find volume control");
TRACE("BSoundPlayer::_GetVolumeSlider couldn't find volume control");
}
#endif
}
/* virtual */ void
BSoundPlayer::Notify(sound_player_notification what, ...)
void
BSoundPlayer::_Notify(sound_player_notification what, ...)
{
CALLED();
if (fLocker.Lock()) {
@@ -930,8 +927,9 @@ BSoundPlayer::Notify(sound_player_notification what, ...)
}
/* virtual */ void
BSoundPlayer::PlayBuffer(void *buffer, size_t size, const media_raw_audio_format &format)
void
BSoundPlayer::_PlayBuffer(void* buffer, size_t size,
const media_raw_audio_format& format)
{
if (fLocker.Lock()) {
if (fPlayBufferFunc)
@@ -941,19 +939,17 @@ BSoundPlayer::PlayBuffer(void *buffer, size_t size, const media_raw_audio_format
}
/*************************************************************
* public sound_error
*************************************************************/
// #pragma mark - public sound_error
sound_error::sound_error(const char *str)
sound_error::sound_error(const char* string)
{
m_str_const = str;
m_str_const = string;
}
const char *
sound_error::what() const throw ()
const char*
sound_error::what() const throw()
{
return m_str_const;
}