* 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:
@@ -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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user