2 * Copyright (c) 1999-2000, Eric Moon.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions, and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include "Connection.h"
37 #include "NodeGroup.h"
38 //#include "NodeGroup_transport_thread.h"
39 #include "NodeManager.h"
40 #include "NodeSyncThread.h"
42 #include "AddOnHost.h"
45 #include <MediaRoster.h>
46 #include <TimeSource.h>
53 #include "functional_tools.h"
54 #include "node_manager_impl.h"
55 #include "SoundUtils.h"
57 // -------------------------------------------------------- //
61 __USE_CORTEX_NAMESPACE
63 #define D_METHOD(x) //PRINT (x)
64 #define D_MESSAGE(x) //PRINT (x)
65 #define D_ROSTER(x) //PRINT (x)
66 #define D_LOCK(x) //PRINT (x)
68 // -------------------------------------------------------- //
71 // Contains information that can be used to reconstruct this
73 // -------------------------------------------------------- //
75 // [e.moon 29sep99] added 'file'
77 struct NodeRef::addon_hint
{
80 const dormant_node_info
* _dormantInfo
,
81 const entry_ref
* _file
=0) :
82 dormantInfo(*_dormantInfo
),
83 file(_file
? new entry_ref(*_file
) : 0) {}
90 const entry_ref
* _file
) {
93 file
= new entry_ref(*_file
);
96 dormant_node_info dormantInfo
;
100 // -------------------------------------------------------- //
102 // -------------------------------------------------------- //
104 // free the node (this call will result in the eventual
105 // deletion of the object.)
107 status_t
NodeRef::release() {
109 // release the node, if possible:
110 status_t err
= releaseNode();
112 // hand off to parent release() implementation
113 status_t parentErr
= _inherited::release();
114 return (parentErr
< B_OK
) ? parentErr
: err
;
117 NodeRef::~NodeRef() {
118 D_METHOD(("~NodeRef[%s]\n", name()));
119 Autolock
_l(m_manager
);
121 // remove from NodeManager
122 m_manager
->_removeRef(id());
124 // [14oct99 e.moon] kill position-report thread if necessary
126 _stopPositionThread();
133 // close Media Roster connection [e.moon 11oct99]
134 BMediaRoster
* r
= BMediaRoster::Roster();
143 // -------------------------------------------------------- //
144 // *** const accessors
145 // -------------------------------------------------------- //
147 // [e.moon 13oct99] moved to header
149 //inline const media_node& NodeRef::node() const { return m_info.node; }
150 //inline uint32 NodeRef::kind() const { return m_info.node.kind; }
151 //inline const live_node_info& NodeRef::nodeInfo() const { return m_info; }
152 //inline media_node_id NodeRef::id() const { return m_info.node.node; }
153 //inline const char* NodeRef::name() const { return m_info.name; }
155 // -------------------------------------------------------- //
157 // -------------------------------------------------------- //
159 // turn cycle mode (looping) on or off
161 void NodeRef::setCycling(
166 "NodeRef::setCycling(%s)\n",
167 cycle
? "true" : "false"));
175 m_group
->_refCycleChanged(this);
177 // +++++ if running, get started...
181 BMessage
m(M_CYCLING_CHANGED
);
182 m
.AddBool("cycling", cycle
);
186 bool NodeRef::isCycling() const {
191 // is the node running?
193 bool NodeRef::isRunning() const {
197 // was the node created via NodeManager::instantiate()?
198 bool NodeRef::isInternal() const {
199 return m_implFlags
& _INTERNAL
;
203 // fetch the group; may return 0 if the node has no connections
204 NodeGroup
* NodeRef::group() const {
210 uint32
NodeRef::flags() const {
215 void NodeRef::setFlags(
221 //// has this reference been released?
222 //bool NodeRef::isReleased() const {
223 // // no lock necessary for bool access -- right? +++++
224 // return m_released;
229 // access addon-hint info
230 // - returns B_BAD_VALUE if not an add-on node created by this NodeManager
232 status_t
NodeRef::getDormantNodeInfo(
233 dormant_node_info
* outInfo
) {
238 *outInfo
= m_addonHint
->dormantInfo
;
243 // access file being played
244 // - returns B_BAD_VALUE if not an add-on node created by this NodeManager,
245 // or if the node has no associated file
247 status_t
NodeRef::getFile(
248 entry_ref
* outFile
) {
252 if(!m_addonHint
|| !m_addonHint
->file
)
255 *outFile
= *(m_addonHint
->file
);
262 status_t
NodeRef::setFile(
263 const entry_ref
& file
,
264 bigtime_t
* outDuration
) {
269 status_t err
= m_manager
->roster
->SetRefFor(
278 m_addonHint
->setFile(&file
);
285 // returns true if the media_node has been released (call releaseNode() to
286 // make this happen.)
288 bool NodeRef::isNodeReleased() const {
289 return m_nodeReleased
;
292 // -------------------------------------------------------- //
293 // *** run-mode operations
294 // -------------------------------------------------------- //
296 void NodeRef::setRunMode(
301 ASSERT(runMode
<= BMediaNode::B_RECORDING
);
303 if(runMode
== BMediaNode::B_RECORDING
)
304 m_recordingDelay
= delay
;
306 // send notification to all observers
307 BMessage
m(M_RUN_MODE_CHANGED
);
308 m
.AddInt32("nodeID", id());
309 m
.AddInt32("runMode", runMode
);
311 if(runMode
== BMediaNode::B_RECORDING
&& m_recordingDelay
!= 0)
312 m
.AddInt64("delay", m_recordingDelay
);
316 // update real run mode
318 _setRunMode(m_group
->runMode(), m_recordingDelay
);
321 uint32
NodeRef::runMode() const {
326 bigtime_t
NodeRef::recordingDelay() const {
328 return m_recordingDelay
;
331 // calculates the minimum amount of delay needed for
333 // +++++ 15sep99: returns biggest_output_buffer_duration * 2
334 // +++++ 28sep99: adds downstream latency
336 bigtime_t
NodeRef::calculateRecordingModeDelay() {
338 "NodeRef::calculateRecordingModeDelay()\n"));
341 bigtime_t maxBufferDur
= 0LL;
343 vector
<Connection
> outputConnections
;
344 err
= getOutputConnections(outputConnections
);
346 vector
<Connection
>::iterator it
= outputConnections
.begin();
347 it
!= outputConnections
.end(); ++it
) {
349 bigtime_t bufferDur
= buffer_duration((*it
).format().u
.raw_audio
);
350 if(bufferDur
> maxBufferDur
)
351 maxBufferDur
= bufferDur
;
354 bigtime_t latency
= 0LL;
355 err
= m_manager
->roster
->GetLatencyFor(
359 " %" B_PRIdBIGTIME
"\n", latency
));
361 return latency
; // +++++ stab in the dark 28sep99
362 // return maxBufferDur + latency;
365 // -------------------------------------------------------- //
366 // *** connection access
367 // -------------------------------------------------------- //
369 // connection access: vector versions
371 status_t
NodeRef::getInputConnections(
372 vector
<Connection
>& ioConnections
,
373 media_type filterType
) const {
376 NodeManager::con_map::iterator it
, itEnd
;
377 it
= m_manager
->m_conDestinationMap
.lower_bound(m_info
.node
.node
);
378 itEnd
= m_manager
->m_conDestinationMap
.upper_bound(m_info
.node
.node
);
380 for(; it
!= itEnd
; ++it
) {
381 if(filterType
== B_MEDIA_UNKNOWN_TYPE
||
382 (*it
).second
->format().type
== filterType
) {
384 ioConnections
.push_back(*((*it
).second
));
392 status_t
NodeRef::getOutputConnections(
393 vector
<Connection
>& ioConnections
,
394 media_type filterType
) const {
397 NodeManager::con_map::iterator it
, itEnd
;
398 it
= m_manager
->m_conSourceMap
.lower_bound(m_info
.node
.node
);
399 itEnd
= m_manager
->m_conSourceMap
.upper_bound(m_info
.node
.node
);
401 for(; it
!= itEnd
; ++it
) {
402 if(filterType
== B_MEDIA_UNKNOWN_TYPE
||
403 (*it
).second
->format().type
== filterType
) {
405 ioConnections
.push_back(*((*it
).second
));
412 // connection access: flat array versions
414 status_t
NodeRef::getInputConnections(
415 Connection
* outConnections
,
416 int32 maxConnections
,
417 int32
* outNumConnections
,
418 media_type filterType
) const {
421 NodeManager::con_map::iterator it
, itEnd
;
422 it
= m_manager
->m_conDestinationMap
.lower_bound(m_info
.node
.node
);
423 itEnd
= m_manager
->m_conDestinationMap
.upper_bound(m_info
.node
.node
);
427 for(; it
!= itEnd
&& count
< maxConnections
; ++it
) {
428 if(filterType
== B_MEDIA_UNKNOWN_TYPE
||
429 (*it
).second
->format().type
== filterType
) {
431 outConnections
[count
++] = *((*it
).second
);
435 *outNumConnections
= count
;
440 status_t
NodeRef::getOutputConnections(
441 Connection
* outConnections
,
442 int32 maxConnections
,
443 int32
* outNumConnections
,
444 media_type filterType
) const {
447 NodeManager::con_map::iterator it
, itEnd
;
448 it
= m_manager
->m_conSourceMap
.lower_bound(m_info
.node
.node
);
449 itEnd
= m_manager
->m_conSourceMap
.upper_bound(m_info
.node
.node
);
453 for(; it
!= itEnd
&& count
< maxConnections
; ++it
) {
454 if(filterType
== B_MEDIA_UNKNOWN_TYPE
||
455 (*it
).second
->format().type
== filterType
) {
457 outConnections
[count
++] = *((*it
).second
);
461 *outNumConnections
= count
;
466 // -------------------------------------------------------- //
467 // *** position reporting/listening
468 // -------------------------------------------------------- //
470 bool NodeRef::positionReportsEnabled() const {
471 return m_positionReportsEnabled
;
474 // start thread if necessary
475 void NodeRef::enablePositionReports() {
478 if(m_flags
& NO_POSITION_REPORTING
)
481 if(m_positionReportsEnabled
)
484 m_positionReportsEnabled
= true;
487 _startPositionThread();
491 // stop thread if necessary
492 void NodeRef::disablePositionReports() {
495 if(!m_positionReportsEnabled
)
498 m_positionReportsEnabled
= false;
500 // shut down the thread
501 _stopPositionThread();
505 // Fetch the approximate current position:
506 // Returns the last reported position, and the
507 // performance time at which that position was reached. If the
508 // transport has never been started, the start position and
509 // a performance time of 0 will be returned. If position updating
510 // isn't currently enabled, returns B_NOT_ALLOWED.
512 status_t
NodeRef::getLastPosition(
513 bigtime_t
* outPosition
,
514 bigtime_t
* outPerfTime
) const {
518 if(!m_positionReportsEnabled
)
519 return B_NOT_ALLOWED
;
521 *outPosition
= m_lastPosition
;
522 *outPerfTime
= m_tpLastPositionUpdate
;
526 // Subscribe to regular position reports:
527 // Position reporting isn't rolled into the regular IObservable
528 // interface because a large number of messages are generated
529 // (the frequency can be changed; see below.)
531 status_t
NodeRef::addPositionObserver(
535 // try to create messenger
537 BMessenger
m(handler
, NULL
, &error
);
540 "* NodeRef::addPositionListener(): BMessenger() failed:\n"
543 strerror(error
), handler
));
547 // add to the invoker
549 m_positionInvoker
.AddTarget(handler
);
551 // enable position updates:
552 if(!m_positionReportsEnabled
)
553 enablePositionReports();
558 status_t
NodeRef::removePositionObserver(
565 int32 index
= m_positionInvoker
.IndexOfTarget(handler
);
570 m_positionInvoker
.RemoveTarget(index
);
572 // last observer removed? kill thread. [e.moon 12oct99]
573 if(m_positionReportsEnabled
&& !m_positionInvoker
.CountTargets())
574 disablePositionReports();
579 // Set how often position updates will be sent:
580 // Realistically, period should be > 10000 or so.
582 status_t
NodeRef::setPositionUpdatePeriod(
588 m_positionUpdatePeriod
= period
;
592 bigtime_t
NodeRef::positionUpdatePeriod() const{
594 return m_positionUpdatePeriod
;
597 // -------------------------------------------------------- //
598 // *** BMediaRoster wrappers & convenience methods
599 // -------------------------------------------------------- //
601 // release the media node
602 // (if allowed, will trigger the release/deletion of this object)
603 status_t
NodeRef::releaseNode() {
606 "NodeRef[%s]::releaseNode()\n", name()));
609 Autolock
_l(m_manager
);
611 if(isReleased() || m_nodeReleased
)
612 return B_NOT_ALLOWED
;
615 m_group
->removeNode(this);
617 // kill off sync thread
618 if(m_positionThread
) {
619 delete m_positionThread
;
620 m_positionThread
= 0;
623 if(m_implFlags
& _INTERNAL
) {
625 // tear down all connections if the node was created by
627 vector
<Connection
> c_set
;
628 getInputConnections(c_set
);
629 getOutputConnections(c_set
);
631 // [e.moon 13oct99] making PPC compiler happy
637 // &NodeManager::disconnect
641 for(vector
<Connection
>::iterator it
= c_set
.begin();
642 it
!= c_set
.end(); ++it
) {
643 err
= m_manager
->disconnect(*it
);
646 "! NodeRef('%s')::releaseNode():\n"
647 " NodeManager::disconnect('%s'->'%s') failed:\n"
650 (*it
).outputName(), (*it
).inputName(),
655 // +++++ ensure that the connections were really broken?
659 if(!(m_implFlags
& _NO_RELEASE
)) {
662 // "### releasing node %ld\n",
666 D_ROSTER(("# roster->ReleaseNode(%ld)\n", m_info
.node
.node
));
667 err
= BMediaRoster::Roster()->ReleaseNode(
672 "!!! ReleaseNode(%" B_PRId32
") failed:\n"
679 (m_implFlags
& _INTERNAL
) &&
680 m_manager
->m_useAddOnHost
) {
682 // ask add-on host to release the node
683 err
= AddOnHost::ReleaseInternalNode(m_info
);
686 "!!! AddOnHost::ReleaseInternalNode(%" B_PRId32
695 // PRINT(("- not releasing node\n"));
698 m_nodeReleased
= true;
703 // calculate total (internal + downstream) latency for this node
705 status_t
NodeRef::totalLatency(
706 bigtime_t
* outLatency
) const {
708 return BMediaRoster::Roster()->GetLatencyFor(
713 // retrieve input/output matching the given destination/source.
714 // returns B_MEDIA_BAD_[SOURCE | DESTINATION] if the destination
715 // or source don't correspond to this node.
717 class match_input_destination
{ public:
718 const media_destination
& dest
;
719 match_input_destination(const media_destination
& _dest
) : dest(_dest
) {}
720 bool operator()(const media_input
& input
) const {
721 return input
.destination
== dest
;
725 class match_output_source
{ public:
726 const media_source
& source
;
727 match_output_source(const media_source
& _source
) : source(_source
) {}
728 bool operator()(const media_output
& output
) const {
729 return output
.source
== source
;
733 status_t
NodeRef::findInput(
734 const media_destination
& forDestination
,
735 media_input
* outInput
) const {
739 vector
<media_input
> inputs
;
740 vector
<media_input
>::const_iterator it
;
744 err
= getFreeInputs(inputs
);
749 inputs
.begin(), inputs
.end(),
750 match_input_destination(forDestination
));
752 if(it
!= inputs
.end()) {
757 // check connected inputs
759 err
= getConnectedInputs(inputs
);
764 inputs
.begin(), inputs
.end(),
765 match_input_destination(forDestination
));
767 if(it
!= inputs
.end()) {
771 return B_MEDIA_BAD_DESTINATION
;
774 status_t
NodeRef::findOutput(
775 const media_source
& forSource
,
776 media_output
* outOutput
) const {
780 vector
<media_output
> outputs
;
781 vector
<media_output
>::const_iterator it
;
784 // check free outputs
785 err
= getFreeOutputs(outputs
);
790 outputs
.begin(), outputs
.end(),
791 match_output_source(forSource
));
793 if(it
!= outputs
.end()) {
798 // check connected outputs
800 err
= getConnectedOutputs(outputs
);
805 outputs
.begin(), outputs
.end(),
806 match_output_source(forSource
));
808 if(it
!= outputs
.end()) {
813 return B_MEDIA_BAD_SOURCE
;
817 // endpoint matching (given name and/or format as 'hints')
820 class match_endpoint_name_format
: public unary_function
<T
, bool> {
823 const media_format
* format
;
825 match_endpoint_name_format(const char* _name
, const media_format
* _format
) :
826 name(_name
), format(_format
) {}
827 bool operator()(const T
& endpoint
) const {
828 // test name, if given
829 if(name
&& strcmp(endpoint
.name
, name
) != 0)
831 // test format, if given
832 media_format
* f1
= const_cast<media_format
*>(format
);
833 media_format
* f2
= const_cast<media_format
*>(&endpoint
.format
);
834 if(format
&& !f1
->Matches(f2
))
841 class match_endpoint_name_type
: public unary_function
<T
, bool> {
846 match_endpoint_name_type(const char* _name
, media_type _type
) :
847 name(_name
), type(_type
) {}
848 bool operator()(const T
& endpoint
) const {
849 // test name, if given
850 if(name
&& strcmp(endpoint
.name
, name
) != 0)
852 // test type, if given
853 if(type
!= B_MEDIA_UNKNOWN_TYPE
&&
854 type
!= endpoint
.format
.type
)
862 class match_endpoint_type
: public unary_function
<T
, bool> {
866 match_endpoint_type(media_type _type
) :
868 bool operator()(const T
& endpoint
) const {
869 // test type, if given
870 if(type
!= B_MEDIA_UNKNOWN_TYPE
&&
871 type
!= endpoint
.format
.type
)
878 status_t
NodeRef::findFreeInput(
879 media_input
* outInput
,
880 const media_format
* format
/*=0*/,
881 const char* name
/*=0*/) const {
885 vector
<media_input
> inputs
;
886 vector
<media_input
>::const_iterator it
;
889 err
= getFreeInputs(inputs
);
896 match_endpoint_name_format
<media_input
>(name
, format
));
898 if(it
!= inputs
.end()) {
905 status_t
NodeRef::findFreeInput(
906 media_input
* outInput
,
907 media_type type
/*=B_MEDIA_UNKNOWN_TYPE*/,
908 const char* name
/*=0*/) const {
912 vector
<media_input
> inputs
;
913 vector
<media_input
>::const_iterator it
;
916 err
= getFreeInputs(inputs
);
923 match_endpoint_name_type
<media_input
>(name
, type
));
924 if(it
!= inputs
.end()) {
931 status_t
NodeRef::findFreeOutput(
932 media_output
* outOutput
,
933 const media_format
* format
/*=0*/,
934 const char* name
/*=0*/) const {
938 vector
<media_output
> outputs
;
939 vector
<media_output
>::const_iterator it
;
942 err
= getFreeOutputs(outputs
);
949 match_endpoint_name_format
<media_output
>(name
, format
));
950 if(it
!= outputs
.end()) {
957 status_t
NodeRef::findFreeOutput(
958 media_output
* outOutput
,
959 media_type type
/*=B_MEDIA_UNKNOWN_TYPE*/,
960 const char* name
/*=0*/) const {
964 vector
<media_output
> outputs
;
965 vector
<media_output
>::const_iterator it
;
968 err
= getFreeOutputs(outputs
);
975 match_endpoint_name_type
<media_output
>(name
, type
));
976 if(it
!= outputs
.end()) {
984 // node endpoint access: vector versions (wrappers for BMediaRoster
987 status_t
NodeRef::getFreeInputs(
988 vector
<media_input
>& ioInputs
,
989 media_type filterType
) const {
991 BMediaRoster
* r
= BMediaRoster::Roster();
995 int32 bufferInc
= 16;
996 int32 inputBufferSize
= 16;
997 media_input
* inputBuffer
= new media_input
[inputBufferSize
];
1000 err
= r
->GetFreeInputsFor(
1001 m_info
.node
, inputBuffer
, inputBufferSize
, &count
, filterType
);
1003 delete [] inputBuffer
;
1007 if (count
== inputBufferSize
) {
1008 // buffer too small; increase & try again
1009 inputBufferSize
+= bufferInc
;
1010 delete [] inputBuffer
;
1011 inputBuffer
= new media_input
[inputBufferSize
];
1016 // copy found inputs into vector
1017 copy(inputBuffer
, inputBuffer
+ count
,
1018 back_inserter(ioInputs
));
1023 // fix missing node info
1024 _fixInputs(ioInputs
);
1026 delete [] inputBuffer
;
1031 status_t
NodeRef::getConnectedInputs(
1032 vector
<media_input
>& ioInputs
,
1033 media_type filterType
) const {
1035 BMediaRoster
* r
= BMediaRoster::Roster();
1039 int32 bufferInc
= 16;
1040 int32 inputBufferSize
= 16;
1041 media_input
* inputBuffer
= new media_input
[inputBufferSize
];
1044 err
= r
->GetConnectedInputsFor(
1045 m_info
.node
, inputBuffer
, inputBufferSize
, &count
);
1047 delete [] inputBuffer
;
1051 if (count
== inputBufferSize
) {
1052 // buffer too small; increase & try again
1053 inputBufferSize
+= bufferInc
;
1054 delete [] inputBuffer
;
1055 inputBuffer
= new media_input
[inputBufferSize
];
1060 // copy found inputs matching the given type into vector
1061 remove_copy_if(inputBuffer
, inputBuffer
+ count
,
1062 back_inserter(ioInputs
),
1063 not1(match_endpoint_type
<media_input
>(filterType
)));
1068 // fix missing node info
1069 _fixInputs(ioInputs
);
1071 delete [] inputBuffer
;
1075 status_t
NodeRef::getFreeOutputs(
1076 vector
<media_output
>& ioOutputs
,
1077 media_type filterType
) const {
1079 BMediaRoster
* r
= BMediaRoster::Roster();
1083 int32 bufferInc
= 16;
1084 int32 outputBufferSize
= 16;
1085 media_output
* outputBuffer
= new media_output
[outputBufferSize
];
1088 err
= r
->GetFreeOutputsFor(
1089 m_info
.node
, outputBuffer
, outputBufferSize
, &count
, filterType
);
1091 delete [] outputBuffer
;
1095 if (count
== outputBufferSize
) {
1096 // buffer too small; increase & try again
1097 outputBufferSize
+= bufferInc
;
1098 delete [] outputBuffer
;
1099 outputBuffer
= new media_output
[outputBufferSize
];
1104 // copy found outputs into vector
1105 copy(outputBuffer
, outputBuffer
+ count
,
1106 back_inserter(ioOutputs
));
1111 // fix missing node info
1112 _fixOutputs(ioOutputs
);
1114 delete [] outputBuffer
;
1118 status_t
NodeRef::getConnectedOutputs(
1119 vector
<media_output
>& ioOutputs
,
1120 media_type filterType
) const {
1122 BMediaRoster
* r
= BMediaRoster::Roster();
1126 int32 bufferInc
= 16;
1127 int32 outputBufferSize
= 16;
1128 media_output
* outputBuffer
= new media_output
[outputBufferSize
];
1131 err
= r
->GetConnectedOutputsFor(
1132 m_info
.node
, outputBuffer
, outputBufferSize
, &count
);
1134 delete [] outputBuffer
;
1138 if (count
== outputBufferSize
) {
1139 // buffer too small; increase & try again
1140 outputBufferSize
+= bufferInc
;
1141 delete [] outputBuffer
;
1142 outputBuffer
= new media_output
[outputBufferSize
];
1147 // copy found outputs matching the given type into vector
1148 remove_copy_if(outputBuffer
, outputBuffer
+ count
,
1149 back_inserter(ioOutputs
),
1150 not1(match_endpoint_type
<media_output
>(filterType
)));
1155 // fix missing node info
1156 _fixOutputs(ioOutputs
);
1158 delete [] outputBuffer
;
1163 // node endpoint access: array versions (wrappers for BMediaRoster
1166 status_t
NodeRef::getFreeInputs(
1167 media_input
* outInputs
,
1169 int32
* outNumInputs
,
1170 media_type filterType
) const {
1172 status_t err
= BMediaRoster::Roster()->GetFreeInputsFor(
1173 m_info
.node
, outInputs
, maxInputs
, outNumInputs
, filterType
);
1178 // fix missing node info
1179 _fixInputs(outInputs
, *outNumInputs
);
1184 status_t
NodeRef::getConnectedInputs(
1185 media_input
* outInputs
,
1187 int32
* outNumInputs
) const {
1189 status_t err
= BMediaRoster::Roster()->GetConnectedInputsFor(
1190 m_info
.node
, outInputs
, maxInputs
, outNumInputs
);
1195 // fix missing node info
1196 _fixInputs(outInputs
, *outNumInputs
);
1200 status_t
NodeRef::getFreeOutputs(
1201 media_output
* outOutputs
,
1203 int32
* outNumOutputs
,
1204 media_type filterType
) const {
1206 status_t err
= BMediaRoster::Roster()->GetFreeOutputsFor(
1207 m_info
.node
, outOutputs
, maxOutputs
, outNumOutputs
, filterType
);
1212 // fix missing node info
1213 _fixOutputs(outOutputs
, *outNumOutputs
);
1217 status_t
NodeRef::getConnectedOutputs(
1218 media_output
* outOutputs
,
1220 int32
* outNumOutputs
) const {
1222 status_t err
= BMediaRoster::Roster()->GetConnectedOutputsFor(
1223 m_info
.node
, outOutputs
, maxOutputs
, outNumOutputs
);
1228 // fix missing node info
1229 _fixOutputs(outOutputs
, *outNumOutputs
);
1234 // -------------------------------------------------------- //
1236 // -------------------------------------------------------- //
1245 #endif /*CORTEX_XML*/
1248 // -------------------------------------------------------- //
1250 // -------------------------------------------------------- //
1252 void NodeRef::MessageReceived(
1253 BMessage
* message
) {
1256 "NodeRef['%s']::MessageReceived(): %c%c%c%c\n",
1258 message
->what
>> 24,
1259 (message
->what
>> 16) & 0xff,
1260 (message
->what
>> 8) & 0xff,
1261 (message
->what
) & 0xff));
1264 switch(message
->what
) {
1265 case M_SET_RUN_MODE
:
1267 // set run mode & delay (if given)
1269 bigtime_t delay
= 0LL;
1270 err
= message
->FindInt32("runMode", &runMode
);
1273 "! NodeRef::MessageReceived(M_SET_RUN_MODE): no value found.\n"));
1276 if(runMode
== BMediaNode::B_RECORDING
)
1277 message
->FindInt64("delay", &delay
); // optional
1279 setRunMode(runMode
, delay
);
1291 err
= message
->FindBool("cycling", &cycling
);
1294 err
= message
->FindInt32("be:value", &val
);
1297 "! NodeRef::MessageReceived(M_SET_CYCLING): no value found.\n"));
1303 setCycling(cycling
);
1307 case B_MEDIA_NODE_STOPPED
:
1308 // PRINT(("### B_MEDIA_NODE_STOPPED\n"));
1310 // if still marked running, let the group know [e.moon 11oct99]
1313 m_stopQueued
= false;
1316 Autolock
_l(m_group
);
1317 m_group
->_refStopped(this);
1323 case NodeSyncThread::M_SYNC_COMPLETE
: {
1324 // [e.moon 14oct99] position-report messages are now sent
1325 // by the NodeSyncThread.
1330 bigtime_t when
, position
;
1331 err
= message
->FindInt64("perfTime", &when
);
1332 ASSERT(err
== B_OK
);
1333 err
= message
->FindInt64("position", &position
);
1334 ASSERT(err
== B_OK
);
1336 _handlePositionUpdate(when
, position
);
1341 _inherited::MessageReceived(message
);
1345 // -------------------------------------------------------- //
1346 // *** IObservable: [20aug99]
1347 // -------------------------------------------------------- //
1349 void NodeRef::observerAdded(
1350 const BMessenger
& observer
) {
1352 BMessage
m(M_OBSERVER_ADDED
);
1353 m
.AddInt32("nodeID", id());
1354 m
.AddMessenger("target", BMessenger(this));
1355 observer
.SendMessage(&m
);
1358 void NodeRef::observerRemoved(
1359 const BMessenger
& observer
) {
1361 BMessage
m(M_OBSERVER_REMOVED
);
1362 m
.AddInt32("nodeID", id());
1363 m
.AddMessenger("target", BMessenger(this));
1364 observer
.SendMessage(&m
);
1367 void NodeRef::notifyRelease() {
1369 BMessage
m(M_RELEASED
);
1370 m
.AddInt32("nodeID", id());
1371 m
.AddMessenger("target", BMessenger(this));
1375 void NodeRef::releaseComplete() {
1379 // -------------------------------------------------------- //
1380 // *** ILockable: pass lock requests to parent group,
1381 // or manager if no group found
1382 // -------------------------------------------------------- //
1384 // this is hideous. [24aug99]
1385 // it must die soon.
1387 // The two-stage lock appears safe UNLESS it's multiply acquired
1388 // (and the NodeManager is locked somewhere in between.) Then
1389 // it's deadlocks all around...
1391 // safe two-stage lock (only WRITE locking is supported)
1393 // a) a NodeRef either belongs to a group (m_group != 0) or
1394 // is free. If the ref is free, the NodeManager is the
1395 // target for locking; otherwise the group is the 'lockee'.
1396 // b) operations which affect a NodeRef's group affiliation
1397 // (ie. adding or removing a node to/from a group) must
1398 // lock first the NodeManager, then the NodeGroup. The
1399 // locks should be released in the opposite order.
1403 bigtime_t timeout
) {
1405 D_LOCK(("*** NodeRef::lock(): %ld\n", find_thread(0)));
1407 ASSERT(type
== WRITE
);
1411 if(!m_manager
->lock(type
, timeout
))
1414 // transfer lock to group, if any
1415 NodeGroup
* group
= m_group
;
1419 bool ret
= m_group
->lock(type
, timeout
);
1421 m_manager
->unlock();
1423 D_LOCK(("*** NodeRef::lock() ACQUIRED: %ld\n", find_thread(0)));
1428 bool NodeRef::unlock(
1431 D_LOCK(("*** NodeRef::unlock(): %ld\n", find_thread(0)));
1433 ASSERT(type
== WRITE
);
1436 NodeGroup
* group
= m_group
;
1438 bool ret
= m_group
->unlock(type
);
1439 D_LOCK(("*** NodeRef::unlock() RELEASED: %ld\n", find_thread(0)));
1443 bool ret
= m_manager
->unlock(type
);
1445 D_LOCK(("*** NodeRef::unlock() RELEASED: %ld\n", find_thread(0)));
1449 bool NodeRef::isLocked(
1450 lock_t type
) const {
1452 ASSERT(type
== WRITE
);
1455 NodeGroup
* group
= m_group
;
1457 return m_group
->isLocked(type
);
1459 return m_manager
->isLocked(type
);
1462 // -------------------------------------------------------- //
1464 // -------------------------------------------------------- //
1467 const media_node
& node
,
1468 NodeManager
* manager
,
1475 m_implFlags(implFlags
),
1477 m_recordingDelay(0LL),
1480 m_positionReportsEnabled(false),
1481 m_positionReportsStarted(false),
1482 m_positionUpdatePeriod(s_defaultPositionUpdatePeriod
),
1483 m_tpLastPositionUpdate(0LL),
1484 m_lastPosition(0LL),
1485 m_positionThread(0),
1487 m_nodeReleased(false),
1490 // m_cycleSyncThread(0),
1491 m_stopQueued(false),
1496 if(!m_manager
->Lock()) {
1497 ASSERT(!"m_manager->Lock() failed");
1499 m_manager
->AddHandler(this);
1500 m_manager
->Unlock();
1502 // fetch node details
1503 BMediaRoster
* r
= BMediaRoster::Roster();
1504 status_t err
= r
->GetLiveNodeInfo(
1510 "!!! NodeRef(): BMediaRoster::GetLiveNodeInfo(%" B_PRId32
1515 // at least store node info
1519 // name self after node
1520 SetName(m_info
.name
);
1522 // init Media Roster connection [e.moon 11oct99]
1523 if(!(m_flags
& NO_ROSTER_WATCH
)) {
1527 B_MEDIA_NODE_STOPPED
);
1531 // -------------------------------------------------------- //
1532 // *** endpoint-fixing operations (no lock required)
1533 // -------------------------------------------------------- //
1536 class fixEndpointFn
: public unary_function
<T
&, void> {
1537 const media_node
& node
;
1539 fixEndpointFn(const media_node
& _n
) : node(_n
) {}
1540 void operator()(T
& endpoint
) {
1542 // "fixEndpointFn(): endpoint '%s', node ID %ld\n",
1543 // endpoint.name, endpoint.node.node));
1544 if(endpoint
.node
!= node
) {
1546 " fixing '%s'\n", endpoint
.name
));
1547 endpoint
.node
= node
;
1552 // 'fix' (fill in node if needed) sets of inputs/outputs
1553 void NodeRef::_fixInputs(
1554 media_input
* inputs
,
1555 int32 count
) const {
1558 "NodeRef[%s]::fixInputs()\n", m_info
.name
));
1563 fixEndpointFn
<media_input
>(node()));
1566 void NodeRef::_fixInputs(
1567 vector
<media_input
>& inputs
) const {
1570 "NodeRef[%s]::fixInputs()\n", m_info
.name
));
1575 fixEndpointFn
<media_input
>(node()));
1578 void NodeRef::_fixOutputs(
1579 media_output
* outputs
,
1580 int32 count
) const {
1583 "NodeRef[%s]::fixOutputs()\n", m_info
.name
));
1588 fixEndpointFn
<media_output
>(node()));
1591 void NodeRef::_fixOutputs(
1592 vector
<media_output
>& outputs
) const {
1595 "NodeRef[%s]::fixOutputs()\n", m_info
.name
));
1600 fixEndpointFn
<media_output
>(node()));
1603 // -------------------------------------------------------- //
1604 // *** internal/NodeManager operations (LOCK REQUIRED)
1605 // -------------------------------------------------------- //
1607 // call after instantiation to register the dormant_node_info
1608 // used to select this add-on node
1610 void NodeRef::_setAddonHint(
1611 const dormant_node_info
* info
,
1612 const entry_ref
* file
) {
1614 assert_locked(this);
1619 m_addonHint
= new addon_hint(info
, file
);
1622 // call to set a new group; if 0, the node must have no
1624 void NodeRef::_setGroup(
1626 assert_locked(this);
1631 ASSERT(!"LockLooper() failed.");
1633 BMessage
m(M_GROUP_CHANGED
);
1634 m
.AddInt32("nodeID", (int32
)m_info
.node
.node
);
1635 m
.AddInt32("groupID", m_group
? (int32
)m_group
->id() : 0);
1640 // *** NodeGroup API ***
1641 // 9aug99: moved from NodeGroup
1643 // initialize the given node's transport-state members
1644 // (this may be called from the transport thread or from
1645 // an API-implementation method.)
1647 status_t
NodeRef::_initTransportState() {
1648 assert_locked(this);
1651 "NodeRef('%s')::_initTransportState()\n",
1654 // init transport state for this node
1655 m_prerolled
= false;
1658 m_lastSeekPos
= 0LL;
1660 // +++++ init position reporting stuff here?
1665 status_t
NodeRef::_setTimeSource(
1666 media_node_id timeSourceID
) {
1667 assert_locked(this);
1670 "NodeRef('%s')::_setTimeSource(%ld)\n",
1671 name(), timeSourceID
));
1675 ASSERT(timeSourceID
!= media_node::null
.node
);
1676 D_ROSTER(("# roster->SetTimeSourceFor()\n"));
1677 err
= m_manager
->roster
->SetTimeSourceFor(
1678 id(), timeSourceID
);
1682 "* NodeRef('%s')::_setTimeSource(%" B_PRId32
"):\n"
1683 " SetTimeSourceFor() failed: %s\n",
1684 name(), timeSourceID
, strerror(err
)));
1690 status_t
NodeRef::_setRunMode(
1691 const uint32 runMode
,
1693 assert_locked(this);
1696 "NodeRef('%s')::_setRunMode(%ld : %Ld)\n",
1697 name(), runMode
, delay
));
1701 BMediaNode::run_mode m
=
1702 // if group is in offline mode, so are all its nodes
1703 (runMode
== BMediaNode::B_OFFLINE
) ?
1704 (BMediaNode::run_mode
)runMode
:
1705 // if non-0, the node's setting is used
1707 (BMediaNode::run_mode
)m_runMode
:
1708 (BMediaNode::run_mode
)runMode
;
1711 // +++++ additional producer run-mode delay support here?
1714 kind() & B_BUFFER_PRODUCER
&&
1715 runMode
== BMediaNode::B_RECORDING
) {
1717 D_ROSTER(("# roster->SetProducerRunModeDelay()\n"));
1718 err
= m_manager
->roster
->SetProducerRunModeDelay(
1722 "NodeRef('%s')::_setRunMode(): SetProducerRunModeDelay(%"
1723 B_PRIdBIGTIME
") failed: %s\n",
1724 name(), delay
, strerror(err
)));
1728 D_ROSTER(("# roster->SetRunModeNode()\n"));
1729 err
= m_manager
->roster
->SetRunModeNode(
1733 "NodeRef('%s')::_setRunMode(): SetRunModeNode(%d) failed: %s\n",
1734 name(), m
, strerror(err
)));
1741 status_t
NodeRef::_setRunModeAuto(
1742 const uint32 runMode
) {
1745 kind() && B_BUFFER_PRODUCER
&&
1746 runMode
== BMediaNode::B_RECORDING
) {
1750 calculateRecordingModeDelay());
1753 return _setRunMode(runMode
);
1756 // seek and preroll the given node.
1757 // *** this method should not be called from the transport thread
1758 // (since preroll operations can block for a relatively long time.)
1760 // returns B_NOT_ALLOWED if the node is running, or if its NO_PREROLL
1761 // flag is set; otherwise, returns B_OK on success or a Media Roster
1764 status_t
NodeRef::_preroll(
1765 bigtime_t position
) {
1766 assert_locked(this);
1769 "NodeRef('%s')::_preroll(%Ld)\n",
1773 // make sure the node can be and wants to be prerolled
1775 m_flags
& NO_PREROLL
)
1776 return B_NOT_ALLOWED
;
1778 if(!(m_flags
& NO_SEEK
)) {
1779 // seek the node first
1780 err
= BMediaRoster::Roster()->SeekNode(
1787 "*** NodeRef('%s')::_preroll(%" B_PRIdBIGTIME
1788 "): BMediaRoster::SeekNode():\n"
1790 name(), position
, strerror(err
)));
1795 // preroll the node (*** this blocks until the node's Preroll()
1796 // implementation returns ***)
1798 err
= BMediaRoster::Roster()->PrerollNode(
1803 "*** NodeRef('%s')::_preroll(%" B_PRIdBIGTIME
1804 "): BMediaRoster::PrerollNode():\n"
1806 name(), position
, strerror(err
)));
1812 m_lastSeekPos
= position
;
1817 // seek the given node if possible
1818 // (this may be called from the transport thread or from
1819 // an API-implementation method.)
1821 status_t
NodeRef::_seek(
1824 assert_locked(this);
1827 "NodeRef('%s')::_seek(to %" B_PRIdBIGTIME
", at %" B_PRIdBIGTIME
")\n",
1828 name(), position
, when
));
1830 if(m_flags
& NO_SEEK
)
1831 // the node should not be seek'd
1834 if(m_prerolled
&& m_lastSeekPos
== position
)
1835 // the node has already been advanced to the proper position
1839 status_t err
= BMediaRoster::Roster()->SeekNode(
1840 node(), position
, when
);
1844 "*** NodeRef('%s')::_seek(to %" B_PRIdBIGTIME
", at %"
1845 B_PRIdBIGTIME
"): BMediaRoster::SeekNode():\n"
1847 name(), position
, when
, strerror(err
)));
1851 // update node state
1852 m_tpLastSeek
= when
;
1853 m_lastSeekPos
= position
;
1855 // node can't be considered prerolled after a seek
1856 m_prerolled
= false;
1861 // seek the given (stopped) node
1862 // (this may be called from the transport thread or from
1863 // an API-implementation method.)
1865 status_t
NodeRef::_seekStopped(
1866 bigtime_t position
) {
1867 assert_locked(this);
1870 "NodeRef('%s')::_seekStopped(to %Ld)\n",
1874 return B_NOT_ALLOWED
;
1876 return _seek(position
, 0LL);
1880 // start the given node, if possible & necessary, at
1882 // (this may be called from the transport thread or from
1883 // an API-implementation method.)
1885 status_t
NodeRef::_start(
1887 assert_locked(this);
1890 "NodeRef('%s')::_start(at %Ld)\n",
1895 " * node already running; aborting\n"));
1896 return B_OK
; // +++++ is this technically an error?
1899 // +++++ is this proper?
1902 m_group
->m_transportState
== NodeGroup::TRANSPORT_RUNNING
||
1903 m_group
->m_transportState
== NodeGroup::TRANSPORT_STARTING
);
1905 if(m_flags
& NO_START_STOP
) {
1907 " * NO_START_STOP; aborting\n"));
1911 D_ROSTER(("# roster->StartNode(%ld)\n", id()));
1912 status_t err
= BMediaRoster::Roster()->StartNode(
1917 " * StartNode(%" B_PRId32
") failed: '%s'\n",
1918 id(), strerror(err
)));
1926 // fetch new node latency
1929 // start position tracking thread if needed
1930 m_positionReportsStarted
= false;
1931 if(m_positionReportsEnabled
)
1932 _startPositionThread();
1937 // stop the given node (which may or may not still be
1938 // a member of this group.)
1939 // (this may be called from the transport thread or from
1940 // an API-implementation method.)
1942 status_t
NodeRef::_stop() {
1943 assert_locked(this);
1946 "NodeRef('%s')::_stop()\n",
1950 return B_OK
; // +++++ error?
1952 if(m_flags
& NO_START_STOP
|| m_flags
& NO_STOP
)
1955 D_ROSTER(("# roster->StopNode(%ld)\n", id()));
1956 status_t err
= BMediaRoster::Roster()->StopNode(
1962 // 9aug99: refuse further position notification
1963 _stopPositionThread();
1965 // clear node's state
1967 m_stopQueued
= false; // asked for immediate stop [e.moon 11oct99]
1968 return _initTransportState();
1971 // roll the given node, if possible
1972 // (this may be called from the transport thread or from
1973 // an API-implementation method.)
1974 status_t
NodeRef::_roll(
1977 bigtime_t position
) {
1978 assert_locked(this);
1981 "NodeRef('%s')::_roll(%Ld to %Ld, from %Ld)\n",
1982 name(), start
, stop
, position
));
1985 // roll only if the node can be started & stopped,
1986 // AND if this NodeRef is watching the Media Roster.
1988 m_flags
& NO_START_STOP
||
1989 m_flags
& NO_STOP
||
1990 m_flags
& NO_ROSTER_WATCH
)
1991 return B_NOT_ALLOWED
;
1994 return B_NOT_ALLOWED
;
1998 m_group
->m_transportState
== NodeGroup::TRANSPORT_RUNNING
||
1999 m_group
->m_transportState
== NodeGroup::TRANSPORT_STARTING
);
2001 D_ROSTER(("# roster->RollNode(%" B_PRId32
")\n", id()));
2002 if(m_flags
& NO_SEEK
)
2003 err
= BMediaRoster::Roster()->RollNode(
2004 node(), start
, stop
);
2006 err
= BMediaRoster::Roster()->RollNode(
2007 node(), start
, stop
, position
);
2011 "NodeRef('%s')::_roll(%" B_PRIdBIGTIME
" to %" B_PRIdBIGTIME
2012 ", from %" B_PRIdBIGTIME
")\n"
2013 "!!! BMediaRoster::RollNode(%" B_PRId32
") failed: '%s'\n",
2014 name(), start
, stop
, position
, id(), strerror(err
)));
2020 m_stopQueued
= true; // remember that node will stop on its own [e.moon 11oct99]
2023 // fetch new node latency
2026 // start position tracking thread if needed
2027 m_positionReportsStarted
= false;
2028 if(m_positionReportsEnabled
)
2029 _startPositionThread();
2035 // refresh the node's current latency; if I reference
2036 // a B_RECORDING node, update its 'producer delay'.
2038 status_t
NodeRef::_updateLatency() {
2039 assert_locked(this);
2041 // [11nov99 e.moon] don't bother if it's not a producer:
2042 if(!(kind() & B_BUFFER_PRODUCER
)) {
2048 status_t err
= BMediaRoster::Roster()->GetLatencyFor(
2053 "* NodeRef('%s')::_updateLatency(): GetLatencyFor() failed:\n"
2055 name(), strerror(err
)));
2061 m_latency
= latency
;
2063 // update run-mode & delay if necessary
2065 m_runMode
== BMediaNode::B_RECORDING
||
2066 (m_runMode
== 0 && m_group
&& m_group
->runMode() == BMediaNode::B_RECORDING
))
2067 _setRunModeAuto(BMediaNode::B_RECORDING
);
2072 // Figure the earliest time at which the given node can be started.
2073 // Also calculates the position at which it should start from to
2074 // play in sync with other nodes in the group, if the transport is
2075 // running; if stopped, *outPosition will be set to the current
2077 // Pass the estimated amount of time needed to prepare the
2078 // node for playback (ie. preroll & a little fudge factor) in
2081 // (this may be called from the transport thread or from
2082 // an API-implementation method.)
2084 status_t
NodeRef::_calcStartTime(
2085 bigtime_t startDelay
,
2087 bigtime_t
* outPosition
) {
2088 assert_locked(this);
2096 // -------------------------------------------------------- //
2097 // *** Position and cycle thread management *** (LOCK REQUIRED)
2098 // -------------------------------------------------------- //
2100 status_t
NodeRef::_startPositionThread() {
2101 assert_locked(this);
2105 if(!m_positionReportsEnabled
)
2106 return B_NOT_ALLOWED
;
2108 if(m_positionThread
)
2109 _stopPositionThread();
2111 m_positionThread
= new NodeSyncThread(
2113 new BMessenger(this));
2115 // send an initial position report if necessary
2116 if(!m_positionReportsStarted
) {
2117 m_positionReportsStarted
= true;
2119 err
= _handlePositionUpdate(
2125 "* NodeRef::_startPositionThread(): _handlePositionUpdate() failed:\n"
2133 // figure when the last jump in position occurred
2134 bigtime_t tpFrom
= (m_tpLastSeek
> m_tpStart
) ? m_tpLastSeek
: m_tpStart
;
2136 // figure the corresponding position
2137 bigtime_t lastPosition
= m_lastSeekPos
;
2139 // figure the next time for a position report
2140 BTimeSource
* ts
= m_group
->m_timeSourceObj
;
2142 bigtime_t tpTarget
= ts
->Now() + m_positionUpdatePeriod
;
2143 bigtime_t targetPosition
= lastPosition
+ (tpTarget
-tpFrom
);
2145 err
= _schedulePositionUpdate(
2151 "* NodeRef::_createPositionThread(): _schedulePositionUpdate() failed:\n"
2161 status_t
NodeRef::_handlePositionUpdate(
2163 bigtime_t position
) {
2164 assert_locked(this);
2169 "* NodeRef::_handlePositionUpdate(): not running.\n"));
2170 return B_NOT_ALLOWED
;
2173 if(!m_positionReportsEnabled
) {
2175 "* NodeRef::_handlePositionUpdate(): position reports disabled.\n"));
2176 return B_NOT_ALLOWED
;
2180 m_tpLastPositionUpdate
= perfTime
;
2181 m_lastPosition
= position
;
2183 // relay notification to all 'position listeners'
2184 _notifyPosition(perfTime
, position
);
2186 // schedule next update
2187 err
= _schedulePositionUpdate(
2188 perfTime
+ m_positionUpdatePeriod
,
2189 position
+ m_positionUpdatePeriod
);
2193 "* NodeRef::_handlePositionUpdate(): _schedulePositionUpdate() failed:\n"
2200 status_t
NodeRef::_schedulePositionUpdate(
2202 bigtime_t position
) {
2203 assert_locked(this);
2206 if(!m_positionReportsEnabled
)
2207 return B_NOT_ALLOWED
;
2208 ASSERT(m_positionThread
);
2210 if(m_cycle
&& m_group
->_cycleValid()) {
2211 if(position
>= m_group
->endPosition()) {
2212 // snap to start of next cycle
2213 when
= m_group
->_cycleBoundary();
2214 position
= m_group
->startPosition();
2218 //// position_sync_msg m = {
2226 //// "NodeRef::_schedulePositionUpdate():\n"
2227 //// " when = %Ld\n"
2228 //// " position = %Ld\n",
2229 //// when, position));
2231 // m_positionSyncThread->setPosition(position);
2234 // err = m_positionSyncThread->go(when);
2236 // err = m_positionSyncThread->reschedule(when);
2238 err
= m_positionThread
->sync(when
, position
, B_INFINITE_TIMEOUT
);
2242 "! NodeRef::_schedulePositionUpdate(): m_positionThread->sync() failed:\n"
2243 " %s\n", strerror(err
)));
2248 status_t
NodeRef::_stopPositionThread() {
2249 assert_locked(this);
2251 if(!m_positionThread
)
2252 return B_NOT_ALLOWED
;
2254 delete m_positionThread
;
2255 m_positionThread
= 0;
2261 // Send a message to all position listeners
2262 status_t
NodeRef::_notifyPosition(
2264 bigtime_t position
) {
2265 assert_locked(this);
2266 status_t err
= B_OK
;
2268 if(!m_positionReportsEnabled
)
2269 return B_NOT_ALLOWED
;
2271 BMessage
message(M_POSITION
);
2272 message
.AddInt32("nodeID", id());
2273 message
.AddInt64("when", when
);
2274 message
.AddInt64("position", position
);
2276 m_positionInvoker
.Invoke(&message
);
2281 // END -- NodeRef.cpp --