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