diff --git a/headers/os/media/MediaNode.h b/headers/os/media/MediaNode.h index e5b18b2740..657a796d9b 100644 --- a/headers/os/media/MediaNode.h +++ b/headers/os/media/MediaNode.h @@ -325,7 +325,7 @@ virtual status_t _Reserved_MediaNode_15(void *); int32 _mChangeCount; // deprecated int32 _mChangeCountReserved; // deprecated uint64 fKinds; - media_node_id _unused; + media_node_id fTimeSourceID; BBufferProducer * fProducerThis; BBufferConsumer * fConsumerThis; diff --git a/headers/private/media/DataExchange.h b/headers/private/media/DataExchange.h index 84f2aaa6a3..fab5ccfd4c 100644 --- a/headers/private/media/DataExchange.h +++ b/headers/private/media/DataExchange.h @@ -109,6 +109,7 @@ enum { NODE_TIME_WARP, NODE_PREROLL, NODE_SET_TIMESOURCE, + NODE_GET_TIMESOURCE, NODE_REQUEST_COMPLETED, NODE_FINAL_RELEASE, @@ -840,6 +841,15 @@ struct node_set_timesource_command : public command_data media_node_id timesource_id; }; +struct node_get_timesource_request : public request_data +{ +}; + +struct node_get_timesource_reply : public reply_data +{ + media_node_id timesource_id; +}; + struct node_final_release_command : public command_data { }; diff --git a/headers/private/media/MediaMisc.h b/headers/private/media/MediaMisc.h index 3dd1453b32..ae300e1fce 100644 --- a/headers/private/media/MediaMisc.h +++ b/headers/private/media/MediaMisc.h @@ -13,7 +13,9 @@ #define IS_INVALID_SOURCE(_src) ((_src).port <= 0) #define IS_INVALID_DESTINATION(_dest) ((_dest).port <= 0) -#define NODE_UNREGISTERED_ID -2 +#define NODE_JUST_CREATED_ID -1 +#define NODE_UNREGISTERED_ID -2 +#define NODE_SYSTEM_TIMESOURCE_ID 1 #define BAD_MEDIA_SERVER_PORT -222 #define BAD_MEDIA_ADDON_SERVER_PORT -444 diff --git a/headers/private/media/MediaRosterEx.h b/headers/private/media/MediaRosterEx.h index 55a6fdd692..b4430f07b4 100644 --- a/headers/private/media/MediaRosterEx.h +++ b/headers/private/media/MediaRosterEx.h @@ -49,6 +49,8 @@ public: status_t GetAllInputs(const media_node & node, List *list); status_t PublishOutputs(const media_node & node, List *list); status_t PublishInputs(const media_node & node, List *list); + + BTimeSource *MakeTimeSourceObject(media_node_id timesource_id); private: friend class BMediaRoster; diff --git a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp index aef922bf69..ef45ea5b45 100644 --- a/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp +++ b/src/add-ons/media/media-add-ons/mixer/AudioMixer.cpp @@ -531,7 +531,7 @@ AudioMixer::BufferReceived(BBuffer *buffer) bigtime_t now = system_time(); // XXX debugging bigtime_t send = buffer->Header()->file_pos; // XXX debugging - printf("buffer received at %10Ld, was send at %10Ld, delta %7Ld # ", now, send, now - send); +// printf("buffer received at %10Ld, was send at %10Ld, delta %7Ld # ", now, send, now - send); // printf("2) should arrive at %20Ld, now %20Ld\n", buffer->Header()->start_time, TimeSource()->Now()); @@ -544,6 +544,9 @@ AudioMixer::BufferReceived(BBuffer *buffer) buffer, BTimedEventQueue::B_RECYCLE_BUFFER); EventQueue()->AddEvent(event); + + uint32 dummy; + write_port(ControlPort(), -1, &dummy, sizeof(dummy)); } @@ -552,13 +555,13 @@ AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness) { media_header *hdr = buffer->Header(); - printf("latency = %12Ld, event = %12Ld, sched = %5Ld, arrive at %12Ld, now %12Ld, current lateness %12Ld\n", EventLatency() + SchedulingLatency(), EventLatency(), SchedulingLatency(), buffer->Header()->start_time, TimeSource()->Now(), lateness); +// printf("latency = %12Ld, event = %12Ld, sched = %5Ld, arrive at %12Ld, now %12Ld, current lateness %12Ld\n", EventLatency() + SchedulingLatency(), EventLatency(), SchedulingLatency(), buffer->Header()->start_time, TimeSource()->Now(), lateness); // printf("3) should arrive at %20Ld, now %20Ld\n", buffer->Header()->start_time, TimeSource()->Now()); - bigtime_t now = TimeSource()->Now(); - bigtime_t perf_time = hdr->start_time; - bigtime_t how_late = now - perf_time - fLatency; +// bigtime_t now = TimeSource()->Now(); +// bigtime_t perf_time = hdr->start_time; +// bigtime_t how_late = now - perf_time - fLatency; // check input int inputcount = fMixerInputs.CountItems(); @@ -570,11 +573,11 @@ AudioMixer::HandleInputBuffer(BBuffer *buffer, bigtime_t lateness) if (channel->fInput.destination.id != hdr->destination) continue; - if (how_late > 0) { - printf("Received buffer %Ld usecs late, lateness %Ld\n", how_late, lateness); + if (lateness > 5000) { + printf("Received buffer with lateness %Ld\n", lateness); if (RunMode() != B_OFFLINE && RunMode() != B_RECORDING) { - printf("sending notify\n"); - NotifyLateProducer(channel->fInput.source, how_late, perf_time); +// printf("sending notify\n"); +// NotifyLateProducer(channel->fInput.source, lateness, TimeSource()->Now()); } else if (RunMode() == B_DROP_DATA) { printf("dropping buffer\n"); return; @@ -618,7 +621,7 @@ void AudioMixer::SendNewBuffer(bigtime_t event_time) { bigtime_t start = system_time(); - BBuffer *outbuffer = fBufferGroup->RequestBuffer(fOutput.format.u.raw_audio.buffer_size, BufferDuration()); + BBuffer *outbuffer = fBufferGroup->RequestBuffer(fOutput.format.u.raw_audio.buffer_size, BufferDuration() / 4); bigtime_t delta = system_time() - start; if (delta > 200) printf("RequestBuffer took %Ld usec\n", delta); @@ -657,6 +660,8 @@ AudioMixer::ProducerDataStatus( const media_destination &for_whom, media_timed_event event(at_performance_time, BTimedEventQueue::B_DATA_STATUS, (void *)(&for_whom), BTimedEventQueue::B_NO_CLEANUP, status, 0, NULL); EventQueue()->AddEvent(event); + uint32 dummy; + write_port(ControlPort(), -1, &dummy, sizeof(dummy)); // FIX_THIS // the for_whom destination is not being sent correctly - verify in HandleEvent loop @@ -680,7 +685,7 @@ AudioMixer::GetLatencyFor( const media_destination &for_whom, bigtime_t *out_lat *out_latency = EventLatency(); *out_timesource = TimeSource()->ID(); - printf("AudioMixer::GetLatencyFor %Ld\n", EventLatency()); + printf("AudioMixer::GetLatencyFor %Ld, timesource is %ld\n", *out_latency, *out_timesource); return B_OK; @@ -1085,6 +1090,7 @@ AudioMixer::Connect( status_t error, const media_source &source, const media_des media_node_id id; FindLatencyFor(fOutput.destination, &fLatency, &id); printf("Downstream Latency is %Ld usecs\n", fLatency); + fLatency += 6000; // we need at least the length of a full output buffer's latency (I think?) @@ -1102,8 +1108,6 @@ AudioMixer::Connect( status_t error, const media_source &source, const media_des fInternalLatency = latency_end - latency_start; printf("Internal latency is %Ld usecs\n", fInternalLatency); - fInternalLatency += 15000; - printf("Internal latency is %Ld usecs\n", fInternalLatency); delete mouse; @@ -1248,7 +1252,7 @@ AudioMixer::HandleEvent( const media_timed_event *event, bigtime_t lateness, boo // if this is the first buffer, mark with the start time // we need this to calculate the other buffer times if (fStartTime == 0) { - fStartTime = event->event_time; + fStartTime = TimeSource()->RealTimeFor(event->event_time, 0); } // count frames that have been played @@ -1258,9 +1262,11 @@ AudioMixer::HandleEvent( const media_timed_event *event, bigtime_t lateness, boo fFramesSent += framesperbuffer; // calculate the start time for the next event and add the event - bigtime_t nextevent = bigtime_t(fStartTime + double(fFramesSent / fOutput.format.u.raw_audio.frame_rate) * 1000000.0); + bigtime_t nextevent = TimeSource()->PerformanceTimeFor(bigtime_t(fStartTime + double(fFramesSent / fOutput.format.u.raw_audio.frame_rate) * 1000000.0)); media_timed_event nextBufferEvent(nextevent, SEND_NEW_BUFFER_EVENT); EventQueue()->AddEvent(nextBufferEvent); + uint32 dummy; + write_port(ControlPort(), -1, &dummy, sizeof(dummy)); break; } @@ -1283,6 +1289,8 @@ AudioMixer::HandleEvent( const media_timed_event *event, bigtime_t lateness, boo // this->HandleEvent(&firstBufferEvent, 0, false); // EventQueue()->AddEvent(firstBufferEvent); + uint32 dummy; + write_port(ControlPort(), -1, &dummy, sizeof(dummy)); // fStartTime = event->event_time; diff --git a/src/kits/media/MediaEventLooper.cpp b/src/kits/media/MediaEventLooper.cpp index fea1caa453..5c24ed4f60 100644 --- a/src/kits/media/MediaEventLooper.cpp +++ b/src/kits/media/MediaEventLooper.cpp @@ -224,9 +224,11 @@ BMediaEventLooper::ControlLoop() // (see SetEventLatency()) and the scheduling latency (or, for real-time events, // only the scheduling latency). // XXX well, fix this later - latency = fEventLatency + fSchedulingLatency; + latency = fEventLatency + fSchedulingLatency; +// printf("node %02d, latency %Ld\n", ID(), latency); if (fEventQueue.HasEvents() && (TimeSource()->Now() - latency) >= fEventQueue.FirstEventTime()) { +// printf("node %02d waiting for %12Ld that has already happened, now %12Ld\n", ID(), fEventQueue.FirstEventTime(), system_time()); is_realtime = false; break; } @@ -237,6 +239,7 @@ BMediaEventLooper::ControlLoop() waituntil = B_INFINITE_TIMEOUT; if (fEventQueue.HasEvents()) { waituntil = TimeSource()->RealTimeFor(fEventQueue.FirstEventTime(), latency); +// printf("node %02d waiting for %12Ld that will happen at %12Ld\n", ID(), fEventQueue.FirstEventTime(), waituntil); is_realtime = false; } if (fRealTimeQueue.HasEvents()) { @@ -251,7 +254,6 @@ BMediaEventLooper::ControlLoop() if (err == B_TIMED_OUT) break; } - /// we have timed out - so handle the next event media_timed_event event; if (is_realtime) @@ -259,10 +261,12 @@ BMediaEventLooper::ControlLoop() else err = fEventQueue.RemoveFirstEvent(&event); +// printf("node %02d handling %12Ld at %12Ld\n", ID(), event.event_time, system_time()); + if (err == B_OK) { bigtime_t lateness; if (is_realtime) - lateness = TimeSource()->RealTime() + fEventLatency - event.event_time; + lateness = TimeSource()->RealTime() - event.event_time; else lateness = TimeSource()->Now() + fEventLatency - event.event_time; DispatchEvent(&event, lateness, is_realtime); diff --git a/src/kits/media/MediaNode.cpp b/src/kits/media/MediaNode.cpp index 42c3200d95..d6d1142ffd 100644 --- a/src/kits/media/MediaNode.cpp +++ b/src/kits/media/MediaNode.cpp @@ -39,11 +39,13 @@ static char __copyright[] = "Copyright (c) 2002, 2003 Marcus Overhagen #include #include "debug.h" +#include "MediaMisc.h" #include "MediaRosterEx.h" #include "DataExchange.h" #include "ServerInterface.h" #include "Notifications.h" #include "TimeSourceObject.h" +#include "TimeSourceObjectManager.h" // don't rename this one, it's used and exported for binary compatibility int32 BMediaNode::_m_changeTag = 0; @@ -207,8 +209,8 @@ BMediaNode::Node() const { CALLED(); media_node temp; - temp.node = ID(); - temp.port = ControlPort(); + temp.node = fNodeID; + temp.port = fControlPort; temp.kind = Kinds(); return temp; } @@ -230,35 +232,30 @@ BMediaNode::TimeSource() const // return the currently assigned time source if (fTimeSource != 0) return fTimeSource; + + printf("BMediaNode::TimeSource node %ld enter\n", ID()); - // If the node hasn't been assigned a time source - // so far, we assign the system time source. This - // can't be done in the BMediaNode constructor, since - // a BTimeSource is also a BMediaNode and that would be - // an infinite loop... loop... loop... loop... - - BMediaRoster *roster = BMediaRoster::Roster(); - status_t rv; - media_node clone; - rv = roster->GetSystemTimeSource(&clone); - if (rv != B_OK) { - FATAL("BMediaNode::TimeSource: Error, GetSystemTimeSource failed\n"); - return NULL; - } + // If the node doesn't have a time source object, we need to create one. + // If the node is still unregistered, we can't call MakeTimeSourceFor(), + // but since the node does still have the default system time source, we + // can use GetSystemTimeSource BMediaNode *self = const_cast(this); - self->fTimeSource = roster->MakeTimeSourceFor(clone); + if (fTimeSourceID == NODE_SYSTEM_TIMESOURCE_ID) { + self->fTimeSource = _TimeSourceObjectManager->GetSystemTimeSource(); + } else { + self->fTimeSource = MediaRosterEx(BMediaRoster::Roster())->MakeTimeSourceObject(fTimeSourceID); + } ASSERT(fTimeSource == self->fTimeSource); + if (fTimeSource == 0) { FATAL("BMediaNode::TimeSource: Error, MakeTimeSourceFor failed\n"); } else { + ASSERT(fTimeSourceID == fTimeSource->ID()); fTimeSource->AddMe(self); } -// rv = roster->ReleaseNode(clone); -// if (rv != B_OK) { -// FATAL("BMediaNode::TimeSource: Error, ReleaseNode failed\n"); -// } + printf("BMediaNode::TimeSource node %ld leave\n", ID()); return fTimeSource; } @@ -339,7 +336,7 @@ BMediaNode::TimerExpired(bigtime_t notifyPoint, BMediaNode::BMediaNode(const char *name) { TRACE("BMediaNode::BMediaNode: name '%s'\n", name); - _InitObject(name, -1, 0); + _InitObject(name, NODE_JUST_CREATED_ID, 0); } @@ -365,6 +362,11 @@ BMediaNode::WaitForMessage(bigtime_t waitUntil, return size; // returns the error code } + if (message == -1) { + //printf("BMediaNode::WaitForMessage dummy received\n"); + return B_OK; + } + TRACE("BMediaNode::WaitForMessage %#lx, node %ld, this %p\n", message, fNodeID, this); if (message > NODE_MESSAGE_START && message < NODE_MESSAGE_END) { @@ -512,32 +514,6 @@ BMediaNode::SetTimeSource(BTimeSource *time_source) // we just trip into debugger, code that tries to do this is broken. debugger("BMediaNode::SetTimeSource() can't be used to set a timesource, use BMediaRoster::SetTimeSourceFor()!\n"); - - /* - FATAL("BMediaNode::SetTimeSource used to set a time source for this node\n"); - - // the functionality here is only to - // support those people that don't - // use the roster to set a time source - - // some stupid code to do a stupid thing that should not be done - BMediaNode *newnode = time_source->Acquire(); - BTimeSource *newsource = dynamic_cast(newnode); - if (newsource == NULL) { - FATAL("BMediaNode::SetTimeSource can't dynamic_cast into timesource\n"); - newnode->Release(); - return; - } - if (fTimeSource) { - fTimeSource->RemoveMe(this); - fTimeSource->Release(); - newsource->AddMe(this); - printf("#### BMediaNode::SetTimeSource: node %ld has been assigned time source %ld\n", ID(), time_source->ID()); - - } - fTimeSource = newsource; - //BMediaRoster::Roster()->StartTimeSource(fTimeSource->Node(), fTimeSource->RealTime()); - */ } /************************************************************* @@ -553,7 +529,7 @@ BMediaNode::HandleMessage(int32 message, switch (message) { case NODE_FINAL_RELEASE: { - const node_final_release_command *command = static_cast(data); + // const node_final_release_command *command = static_cast(data); // This is called by the media server to delete the object // after is has been released by all nodes that are using it. // We forward the function to the BMediaRoster, since the @@ -619,51 +595,39 @@ BMediaNode::HandleMessage(int32 message, case NODE_SET_TIMESOURCE: { const node_set_timesource_command *command = static_cast(data); - BMediaRoster *roster; - BTimeSource *newsource; - media_node clone; - status_t rv; TRACE("NODE_SET_TIMESOURCE, node %ld, timesource %ld\n", fNodeID, command->timesource_id); - roster = BMediaRoster::Roster(); + + printf("NODE_SET_TIMESOURCE, node %ld, timesource %ld enter\n", fNodeID, command->timesource_id); + + fTimeSourceID = command->timesource_id; - // Time sources are not reference counted. But since - // BMediaRoster::GetNodeFor() will create a clone of - // any node, we will need to release it! - rv = roster->GetNodeFor(command->timesource_id, &clone); - if (rv != B_OK) { - FATAL("NODE_SET_TIMESOURCE: Error, GetNodeFor failed\n"); - return B_OK; - } - newsource = roster->MakeTimeSourceFor(clone); - if (newsource == 0) { - FATAL("NODE_SET_TIMESOURCE: Error, MakeTimeSourceFor failed\n"); - roster->ReleaseNode(clone); // release cloned node - return B_OK; - } - roster->ReleaseNode(clone); // release cloned node if (fTimeSource) { // as this node already had a timesource, we need // we need to remove this node from time source control fTimeSource->RemoveMe(this); - // Then released the time source + // Then release the time source fTimeSource->Release(); - // now the new one is assigned - fTimeSource = newsource; - // we add this node to the time source controll - fTimeSource->AddMe(this); - // and call the SetTimeSource hook function to notify - // any derived class - SetTimeSource(fTimeSource); - } else { - // the new time source is assigned to this node - fTimeSource = newsource; - // we add this node to the time source controll - fTimeSource->AddMe(this); + // force next call to TimeSource() to create a new object + fTimeSource = 0; } - TRACE("BMediaNode::HandleMessage NODE_SET_TIMESOURCE: node %ld has been assigned time source %ld\n", ID(), fTimeSource->ID()); - printf("BMediaNode::HandleMessage NODE_SET_TIMESOURCE: node %ld has been assigned time source %ld\n", ID(), fTimeSource->ID()); - - //roster->StartTimeSource(fTimeSource->Node(), fTimeSource->RealTime()); + + // create new time source object + fTimeSource = TimeSource(); + // and call the SetTimeSource hook function to notify + // any derived class + SetTimeSource(fTimeSource); + + printf("NODE_SET_TIMESOURCE, node %ld, timesource %ld leave\n", fNodeID, command->timesource_id); + + return B_OK; + } + + case NODE_GET_TIMESOURCE: + { + const node_get_timesource_request *request = static_cast(data); + node_get_timesource_reply reply; + reply.timesource_id = fTimeSourceID; + request->SendReply(B_OK, &reply, sizeof(reply)); return B_OK; } @@ -888,7 +852,6 @@ BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds) TRACE("BMediaNode::_InitObject: nodeid %ld, this %p\n", id, this); fNodeID = id; - fTimeSource = NULL; fRefCount = 1; fName[0] = 0; if (name) { @@ -907,6 +870,14 @@ BMediaNode::_InitObject(const char *name, media_node_id id, uint64 kinds) // create control port fControlPort = create_port(64, fName); + + // nodes are assigned the system time source by default + fTimeSourceID = NODE_SYSTEM_TIMESOURCE_ID; + + // We can't create the timesource object here, because + // every timesource is a BMediaNode, which would result + // in infinite recursions + fTimeSource = NULL; } diff --git a/src/kits/media/MediaRoster.cpp b/src/kits/media/MediaRoster.cpp index 4ddadc4f1c..e7ec77d903 100644 --- a/src/kits/media/MediaRoster.cpp +++ b/src/kits/media/MediaRoster.cpp @@ -563,24 +563,54 @@ BTimeSource * BMediaRoster::MakeTimeSourceFor(const media_node & for_node) { CALLED(); - - BTimeSource *source; - - TRACE("BMediaRoster::MakeTimeSourceFor enter, node %ld, port %ld, kind %#lx\n", for_node.node, for_node.port, for_node.kind); - - if (0 == (for_node.kind & B_TIME_SOURCE)) { - //FATAL("BMediaRoster::MakeTimeSourceFor, node %ld is not a timesource!\n", for_node.node); - // XXX It appears that Cortex calls this function on every node, and expects - // XXX to be returned a system time source if the for_node is not a timesource - media_node clone; - GetSystemTimeSource(&clone); - source = _TimeSourceObjectManager->GetTimeSource(clone); -// ReleaseNode(clone); - } else { - source = _TimeSourceObjectManager->GetTimeSource(for_node); + if (IS_INVALID_NODE(for_node)) { + FATAL("BMediaRoster::MakeTimeSourceFor: for_node invalid\n"); + return NULL; } - TRACE("BMediaRoster::MakeTimeSourceFor leave, node %ld, port %ld, kind %#lx\n", source->Node().node, source->Node().port, source->Node().kind); + printf("BMediaRoster::MakeTimeSourceFor: node %ld enter\n", for_node.node); + + // MakeTimeSourceFor() returns a BTimeSource object + // corresponding to the specified node's time source. + + node_get_timesource_request request; + node_get_timesource_reply reply; + BTimeSource *source; + status_t rv; + + rv = QueryPort(for_node.port, NODE_GET_TIMESOURCE, &request, sizeof(request), &reply, sizeof(reply)); + if (rv != B_OK) { + FATAL("BMediaRoster::MakeTimeSourceFor: request failed\n"); + return NULL; + } + + source = MediaRosterEx(this)->MakeTimeSourceObject(reply.timesource_id); + + printf("BMediaRoster::MakeTimeSourceFor: node %ld leave\n", for_node.node); + + return source; +} + +BTimeSource * +BMediaRosterEx::MakeTimeSourceObject(media_node_id timesource_id) +{ + BTimeSource *source; + media_node clone; + status_t rv; + + rv = GetNodeFor(timesource_id, &clone); + if (rv != B_OK) { + FATAL("BMediaRosterEx::MakeTimeSourceObject: GetNodeFor failed\n"); + return NULL; + } + + source = _TimeSourceObjectManager->GetTimeSource(clone); + if (source == NULL) { + FATAL("BMediaRosterEx::MakeTimeSourceObject: GetTimeSource failed\n"); + return NULL; + } + + //ReleaseNode(clone); return source; } @@ -1686,6 +1716,10 @@ BMediaRoster::SetTimeSourceFor(media_node_id node, media_node clone; status_t rv, result; + TRACE("BMediaRoster::SetTimeSourceFor: node %ld will be assigned time source %ld\n", node, time_source); + + printf("BMediaRoster::SetTimeSourceFor: node %ld time source %ld enter\n", node, time_source); + // we need to get a clone of the node to have a port id rv = GetNodeFor(node, &clone); if (rv != B_OK) { @@ -1693,8 +1727,6 @@ BMediaRoster::SetTimeSourceFor(media_node_id node, return B_ERROR; } - TRACE("BMediaRoster::SetTimeSourceFor: node %ld will be assigned time source %ld\n", node, time_source); - // we just send the request to set time_source-id as timesource to the node, // the NODE_SET_TIMESOURCE handler code will do the real assignment result = B_OK; @@ -1713,6 +1745,8 @@ BMediaRoster::SetTimeSourceFor(media_node_id node, result = B_ERROR; } + printf("BMediaRoster::SetTimeSourceFor: node %ld time source %ld leave\n", node, time_source); + return result; } diff --git a/src/kits/media/SoundPlayNode.cpp b/src/kits/media/SoundPlayNode.cpp index 7983ce76aa..dff1634814 100644 --- a/src/kits/media/SoundPlayNode.cpp +++ b/src/kits/media/SoundPlayNode.cpp @@ -452,14 +452,16 @@ _SoundPlayNode::LateNoticeReceived(const media_source& what, bigtime_t how_much, // 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 += how_much; // if (mInternalLatency > 50000) // mInternalLatency = 50000; - SetEventLatency(mLatency + mInternalLatency); +// SetEventLatency(mLatency + mInternalLatency); - fprintf(stderr, "\tincreasing latency to %Ld\n", mLatency + mInternalLatency); +// fprintf(stderr, "\tincreasing latency to %Ld\n", mLatency + mInternalLatency); } else { @@ -574,7 +576,7 @@ _SoundPlayNode::SendNewBuffer( 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); +// 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("1) should arrive at %20Ld, now %20Ld\n", event->event_time, TimeSource()->Now()); @@ -586,12 +588,12 @@ _SoundPlayNode::SendNewBuffer( // arrive at it's destination. The MediaEventLooper should have scheduled us early enough // (based on EventLatency() and the SchedulingLatency()) to make this possible. - bigtime_t scheduling_latency = SchedulingLatency(); +// bigtime_t scheduling_latency = SchedulingLatency(); - if (lateness > 0) { + if (lateness > 5000) { printf("_SoundPlayNode::SendNewBuffer, event sheduled too late, lateness is %Ld\n", lateness); - mInternalLatency += 1000; - SetEventLatency(mLatency + mInternalLatency); +// mInternalLatency += 1000; +// SetEventLatency(mLatency + mInternalLatency); } // skip buffer creation if output not enabled @@ -642,13 +644,12 @@ _SoundPlayNode::SendNewBuffer( // 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) / mOutput.format.u.raw_audio.frame_rate); + bigtime_t nextEvent = TimeSource()->PerformanceTimeFor(mStartTime + bigtime_t((1000000LL * mFramesSent) / mOutput.format.u.raw_audio.frame_rate)); media_timed_event nextBufferEvent(nextEvent, SEND_NEW_BUFFER_EVENT); - if (TimeSource()->Now() + mLatency > nextEvent) { - printf("SendNewBuffer: already %Ld usec too late for new buffer\n", TimeSource()->Now() + mLatency - nextEvent); - } // printf("0) should arrive at %20Ld, now %20Ld\n", nextEvent, TimeSource()->Now()); EventQueue()->AddEvent(nextBufferEvent); + uint32 dummy; + write_port(ControlPort(), -1, &dummy, sizeof(dummy)); return B_OK; } @@ -688,8 +689,8 @@ _SoundPlayNode::HandleStart( // and fire off the first "produce a buffer" event. mFramesSent = 0; - mStartTime = event->event_time; - media_timed_event firstBufferEvent(mStartTime, SEND_NEW_BUFFER_EVENT); + mStartTime = TimeSource()->RealTimeFor(event->event_time, 0); + 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: @@ -697,6 +698,8 @@ _SoundPlayNode::HandleStart( // this->HandleEvent(&firstBufferEvent, 0, false); // EventQueue()->AddEvent(firstBufferEvent); + uint32 dummy; + write_port(ControlPort(), -1, &dummy, sizeof(dummy)); } return B_OK; } @@ -758,7 +761,7 @@ _SoundPlayNode::AllocateBuffers() DPRINTF("\tcreating group of %ld buffers, size = %lu\n", count, size); if (count < 3) - count == 3; + count = 3; mBufferGroup = new BBufferGroup(size, count); } @@ -770,7 +773,7 @@ _SoundPlayNode::FillNextBuffer(bigtime_t event_time) // get a buffer from our buffer group bigtime_t start = system_time(); - BBuffer* buf = mBufferGroup->RequestBuffer(mOutput.format.u.raw_audio.buffer_size, BufferDuration()); + BBuffer* buf = mBufferGroup->RequestBuffer(mOutput.format.u.raw_audio.buffer_size, BufferDuration() / 4); bigtime_t delta = system_time() - start; if (delta > 200) printf("RequestBuffer took %Ld usec\n", delta); @@ -779,6 +782,7 @@ _SoundPlayNode::FillNextBuffer(bigtime_t event_time) // buffer and go on to the next, to avoid locking up the control thread if (!buf) { + printf("RequestBuffer failed\n"); return NULL; } diff --git a/src/kits/media/SoundPlayer.cpp b/src/kits/media/SoundPlayer.cpp index 255adc584a..7f498b24d3 100644 --- a/src/kits/media/SoundPlayer.cpp +++ b/src/kits/media/SoundPlayer.cpp @@ -563,8 +563,16 @@ BSoundPlayer::Init( // set the producer's time source to be the "default" time source, which // the Mixer uses too. - roster->GetTimeSource(&timeSource); - roster->SetTimeSourceFor(_m_node->Node().node, timeSource.node); + err = roster->GetTimeSource(&timeSource); + if(err != B_OK) { + TRACE("BSoundPlayer::Init: Couldn't GetTimeSource\n"); + goto the_end; + } + err = roster->SetTimeSourceFor(_m_node->Node().node, timeSource.node); + if(err != B_OK) { + TRACE("BSoundPlayer::Init: Couldn't SetTimeSourceFor\n"); + goto the_end; + } if(!input) { err = roster->GetFreeInputsFor(*node, &_input, 1, @@ -598,6 +606,8 @@ BSoundPlayer::Init( goto the_end; } + printf("BSoundPlayer node %ld has timesource %ld\n", _m_node->Node().node, _m_node->TimeSource()->Node().node); + the_end: TRACE("BSoundPlayer::Init: %s\n", strerror(err)); SetInitError(err); diff --git a/src/kits/media/TimeSource.cpp b/src/kits/media/TimeSource.cpp index 73a6b29836..a2fa018405 100644 --- a/src/kits/media/TimeSource.cpp +++ b/src/kits/media/TimeSource.cpp @@ -96,7 +96,7 @@ BTimeSource::PerformanceTimeFor(bigtime_t real_time) while (GetTime(&last_perf_time, &last_real_time, &last_drift) != B_OK) snooze(1); - return (bigtime_t)(last_perf_time + (real_time - last_real_time) * last_drift); + return last_perf_time + (bigtime_t)((real_time - last_real_time) * last_drift); } @@ -117,7 +117,7 @@ BTimeSource::RealTimeFor(bigtime_t performance_time, while (GetTime(&last_perf_time, &last_real_time, &last_drift) != B_OK) snooze(1); - return (bigtime_t)(last_real_time + (performance_time - last_perf_time) / last_drift) - with_latency; + return last_real_time - with_latency + (bigtime_t)((performance_time - last_perf_time) / last_drift); } @@ -168,7 +168,7 @@ BTimeSource::GetTime(bigtime_t *performance_time, // *drift = 1.0f; // return B_OK; // } - //printf("BTimeSource::GetTime timesource %ld, index %ld, perf %16Ld, real %16Ld, drift %2.2f\n", ID(), index, *performance_time, *real_time, *drift); +// printf("BTimeSource::GetTime timesource %ld, index %ld, perf %16Ld, real %16Ld, drift %2.2f\n", ID(), index, *performance_time, *real_time, *drift); TRACE_TIMESOURCE("BTimeSource::GetTime timesource %ld, perf %16Ld, real %16Ld, drift %2.2f\n", ID(), *performance_time, *real_time, *drift); return B_OK; diff --git a/src/kits/media/TimeSourceObject.cpp b/src/kits/media/TimeSourceObject.cpp index c2442d244b..9a84e6f8e1 100644 --- a/src/kits/media/TimeSourceObject.cpp +++ b/src/kits/media/TimeSourceObject.cpp @@ -18,25 +18,30 @@ TimeSourceObject::TimeSourceObject(const media_node &node) : BMediaNode("some timesource object", node.node, node.kind), BTimeSource(node.node) { -// printf("TimeSourceObject::TimeSourceObject enter, id = %ld\n", id); + printf("TimeSourceObject::TimeSourceObject enter, id = %ld\n", node.node); if (fControlPort > 0) delete_port(fControlPort); fControlPort = node.port; ASSERT(fNodeID == node.node); ASSERT(fKinds == node.kind); + +if (node.node == NODE_SYSTEM_TIMESOURCE_ID) { + strcpy(fName, "System Clock"); +} else { live_node_info lni; if (B_OK == BMediaRoster::Roster()->GetLiveNodeInfo(node, &lni)) { strcpy(fName, lni.name); } else { sprintf(fName, "timesource %ld", node.node); } +} AddNodeKind(NODE_KIND_SHADOW_TIMESOURCE); AddNodeKind(NODE_KIND_NO_REFCOUNTING); fControlPort = SHADOW_TIMESOURCE_CONTROL_PORT; // XXX if we don't do this, we get a infinite loop somewhere. This needs to be debugged -// printf("TimeSourceObject::TimeSourceObject leave, node id %ld\n", fNodeID); + printf("TimeSourceObject::TimeSourceObject leave, node id %ld\n", fNodeID); } /* virtual */ status_t @@ -66,9 +71,8 @@ TimeSourceObject::DeleteHook(BMediaNode *node) return status; } - SystemTimeSourceObject::SystemTimeSourceObject(const media_node &node) - : BMediaNode("System Clock", node.node, node.kind), + : BMediaNode("System Clock", node.node, node.kind), TimeSourceObject(node) { // printf("SystemTimeSourceObject::SystemTimeSourceObject enter, id = %ld\n", id); diff --git a/src/kits/media/TimeSourceObjectManager.cpp b/src/kits/media/TimeSourceObjectManager.cpp index d1be278adc..20fd2807c3 100644 --- a/src/kits/media/TimeSourceObjectManager.cpp +++ b/src/kits/media/TimeSourceObjectManager.cpp @@ -13,6 +13,7 @@ #include #include "TimeSourceObjectManager.h" #include "TimeSourceObject.h" +#include "MediaMisc.h" #include "debug.h" @@ -23,8 +24,7 @@ namespace BPrivate { namespace media { TimeSourceObjectManager::TimeSourceObjectManager() - : fSystemTimeSource(0), - fSystemTimeSourceID(0) + : fSystemTimeSource(0) { CALLED(); fLock = new BLocker("timesource object manager locker"); @@ -50,6 +50,38 @@ TimeSourceObjectManager::~TimeSourceObjectManager() delete fMap; } +void +TimeSourceObjectManager::InitSystemTimeSource() +{ + BAutolock lock(fLock); + + if (fSystemTimeSource != 0) + return; + + printf("TimeSourceObjectManager::InitSystemTimeSource enter\n"); + + media_node node; + node.node = NODE_SYSTEM_TIMESOURCE_ID; + node.port = SYSTEM_TIMESOURCE_CONTROL_PORT; + node.kind = B_TIME_SOURCE; + + fSystemTimeSource = new SystemTimeSourceObject(node); + + printf("TimeSourceObjectManager::InitSystemTimeSource leave\n"); +} + + +BTimeSource * +TimeSourceObjectManager::GetSystemTimeSource() +{ + BAutolock lock(fLock); + + if (fSystemTimeSource == 0) + InitSystemTimeSource(); + + return dynamic_cast(fSystemTimeSource->Acquire()); +} + /* BMediaRoster::MakeTimeSourceFor does use this function to request * a time source object. If it is already in memory, it will be * Acquired(), if not, a new TimeSourceObject will be created. @@ -62,20 +94,10 @@ TimeSourceObjectManager::GetTimeSource(const media_node &node) // printf("TimeSourceObjectManager::GetTimeSource, node id %ld\n", node.node); - if (fSystemTimeSource == 0) { - media_node clone; - status_t rv; - // XXX this clone is never released - rv = BMediaRoster::Roster()->GetSystemTimeSource(&clone); - if (rv != B_OK) { - FATAL("TimeSourceObjectManager::GetTimeSource, GetSystemTimeSource failed\n"); - return NULL; - } - fSystemTimeSource = new SystemTimeSourceObject(clone); - fSystemTimeSourceID = fSystemTimeSource->ID(); - } + if (fSystemTimeSource == 0) + InitSystemTimeSource(); - if (node.node == fSystemTimeSourceID) + if (NODE_SYSTEM_TIMESOURCE_ID == node.node) return dynamic_cast(fSystemTimeSource->Acquire()); BTimeSource **pts; diff --git a/src/kits/media/TimeSourceObjectManager.h b/src/kits/media/TimeSourceObjectManager.h index 20a5fb50b6..b7a51ad579 100644 --- a/src/kits/media/TimeSourceObjectManager.h +++ b/src/kits/media/TimeSourceObjectManager.h @@ -18,13 +18,16 @@ public: ~TimeSourceObjectManager(); BTimeSource *GetTimeSource(const media_node &node); + BTimeSource *GetSystemTimeSource(); void ObjectDeleted(BTimeSource *timesource); +private: + void InitSystemTimeSource(); + private: Map *fMap; BLocker *fLock; BTimeSource *fSystemTimeSource; - media_node_id fSystemTimeSourceID; }; }; // namespace media diff --git a/src/kits/media/TimedEventQueuePrivate.cpp b/src/kits/media/TimedEventQueuePrivate.cpp index 7de3cd621b..fdd1f70aca 100644 --- a/src/kits/media/TimedEventQueuePrivate.cpp +++ b/src/kits/media/TimedEventQueuePrivate.cpp @@ -69,6 +69,8 @@ status_t _event_queue_imp::AddEvent(const media_timed_event &event) { BAutolock lock(fLock); + +// printf(" adding %12Ld at %12Ld\n", event.event_time, system_time()); if (event.type <= 0) { return B_BAD_VALUE; diff --git a/src/servers/media/DefaultManager.cpp b/src/servers/media/DefaultManager.cpp index a6b5f102de..136e1529af 100644 --- a/src/servers/media/DefaultManager.cpp +++ b/src/servers/media/DefaultManager.cpp @@ -463,7 +463,7 @@ DefaultManager::ConnectMixerToOutput() roster->PrerollNode(mixer); roster->PrerollNode(soundcard); - ts = roster->MakeTimeSourceFor(timesource); + ts = roster->MakeTimeSourceFor(mixer); start_at = ts->Now() + 50000; roster->StartNode(mixer, start_at); roster->StartNode(soundcard, start_at); diff --git a/src/servers/media/NodeManager.cpp b/src/servers/media/NodeManager.cpp index 1e7cc70c88..9352e47c61 100644 --- a/src/servers/media/NodeManager.cpp +++ b/src/servers/media/NodeManager.cpp @@ -211,7 +211,6 @@ NodeManager::SetNodeCreator(media_node_id nodeid, team_id creator) BAutolock lock(fLocker); registered_node *rn; bool b; - status_t rv; TRACE("NodeManager::SetNodeCreator node %ld, creator %ld\n", nodeid, creator); diff --git a/src/servers/media/media_server.cpp b/src/servers/media/media_server.cpp index e6fb0881da..862aff5f21 100644 --- a/src/servers/media/media_server.cpp +++ b/src/servers/media/media_server.cpp @@ -181,8 +181,10 @@ ServerApp::StartSystemTimeSource() // register a dummy node media_node node; - rv = gNodeManager->RegisterNode(&node.node, -1, 0, "System Clock", B_TIME_SOURCE, SYSTEM_TIMESOURCE_CONTROL_PORT, BPrivate::media::team); + rv = gNodeManager->RegisterNode(&node.node, -1, 0, "System Clock", B_TIME_SOURCE, SYSTEM_TIMESOURCE_CONTROL_PORT, BPrivate::media::team); ASSERT(rv == B_OK); + + ASSERT(node.node == NODE_SYSTEM_TIMESOURCE_ID); printf("StartSystemTimeSource setting as default\n"); diff --git a/src/servers/media_addon/main.cpp b/src/servers/media_addon/main.cpp index ec3a307f0e..a774eb4aea 100644 --- a/src/servers/media_addon/main.cpp +++ b/src/servers/media_addon/main.cpp @@ -336,7 +336,7 @@ MediaAddonServer::AddOnAdded(const char *path, ino_t file_node) return; } - TRACE("MediaAddonServer::AddOnAdded: loading addon %d now...\n", id); + TRACE("MediaAddonServer::AddOnAdded: loading addon %ld now...\n", id); addon = _DormantNodeManager->GetAddon(id); if (addon == NULL) { @@ -455,7 +455,7 @@ MediaAddonServer::InstantiateAutostartFlavors(AddOnInfo *info) printf("trying autostart of node %ld, index %ld\n", info->id, index); rv = info->addon->AutoStart(index, &outNode, &outInternalID, &outHasMore); if (rv == B_OK) { - printf("started node\n",index); + printf("started node %ld\n",index); // XXX IncrementAddonFlavorInstancesCount @@ -483,7 +483,6 @@ MediaAddonServer::AddOnRemoved(ino_t file_node) media_addon_id *tempid; media_addon_id id; AddOnInfo *info; - int32 *tempflavorcount; int32 oldflavorcount; // XXX locking?