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