BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / cortex / NodeManager / NodeRef.cpp
blob94aba19c92351d4b6f7b2beb4691f55b448edf0d
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
32 // NodeRef.cpp
34 #include "NodeRef.h"
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"
44 #include <Entry.h>
45 #include <MediaRoster.h>
46 #include <TimeSource.h>
48 #include <algorithm>
49 #include <functional>
50 #include <iterator>
51 #include <stdexcept>
53 #include "functional_tools.h"
54 #include "node_manager_impl.h"
55 #include "SoundUtils.h"
57 // -------------------------------------------------------- //
59 using namespace std;
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 // -------------------------------------------------------- //
69 // addon_hint
71 // Contains information that can be used to reconstruct this
72 // node later on.
73 // -------------------------------------------------------- //
75 // [e.moon 29sep99] added 'file'
77 struct NodeRef::addon_hint {
79 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) {}
85 ~addon_hint() {
86 if(file) delete file;
89 void setFile(
90 const entry_ref* _file) {
91 ASSERT(_file);
92 if(file) delete file;
93 file = new entry_ref(*_file);
96 dormant_node_info dormantInfo;
97 entry_ref* file;
100 // -------------------------------------------------------- //
101 // *** ctor/dtor
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
125 if(m_positionThread)
126 _stopPositionThread();
128 if(m_addonHint) {
129 delete m_addonHint;
130 m_addonHint = 0;
133 // close Media Roster connection [e.moon 11oct99]
134 BMediaRoster* r = BMediaRoster::Roster();
135 if(m_watching) {
136 r->StopWatching(
137 BMessenger(this),
138 node(),
139 B_MEDIA_WILDCARD);
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 // -------------------------------------------------------- //
156 // *** member access
157 // -------------------------------------------------------- //
159 // turn cycle mode (looping) on or off
161 void NodeRef::setCycling(
162 bool cycle) {
163 Autolock _l(this);
165 D_METHOD((
166 "NodeRef::setCycling(%s)\n",
167 cycle ? "true" : "false"));
169 if(cycle == m_cycle)
170 return;
172 m_cycle = cycle;
174 if(m_group) {
175 m_group->_refCycleChanged(this);
177 // +++++ if running, get started...
180 // notify
181 BMessage m(M_CYCLING_CHANGED);
182 m.AddBool("cycling", cycle);
183 notify(&m);
186 bool NodeRef::isCycling() const {
187 return m_cycle;
191 // is the node running?
193 bool NodeRef::isRunning() const {
194 return m_running;
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 {
205 Autolock _l(this);
206 return m_group;
209 // flag access
210 uint32 NodeRef::flags() const {
211 Autolock _l(this);
212 return m_flags;
215 void NodeRef::setFlags(
216 uint32 flags) {
217 Autolock _l(this);
218 m_flags = flags;
221 //// has this reference been released?
222 //bool NodeRef::isReleased() const {
223 // // no lock necessary for bool access -- right? +++++
224 // return m_released;
228 // [e.moon 29sep99]
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) {
235 if(!m_addonHint)
236 return B_BAD_VALUE;
238 *outInfo = m_addonHint->dormantInfo;
239 return B_OK;
242 // [e.moon 29sep99]
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) {
250 Autolock _l(this);
252 if(!m_addonHint || !m_addonHint->file)
253 return B_BAD_VALUE;
255 *outFile = *(m_addonHint->file);
256 return B_OK;
259 // [e.moon 8dec99]
260 // set file to play
262 status_t NodeRef::setFile(
263 const entry_ref& file,
264 bigtime_t* outDuration) {
266 Autolock _l(this);
268 bigtime_t dur;
269 status_t err = m_manager->roster->SetRefFor(
270 node(),
271 file,
272 false,
273 &dur);
274 if(err == B_OK) {
275 if(outDuration)
276 *outDuration = dur;
277 if(m_addonHint)
278 m_addonHint->setFile(&file);
281 return err;
284 // [e.moon 23oct99]
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(
297 uint32 runMode,
298 bigtime_t delay) {
299 Autolock _l(this);
301 ASSERT(runMode <= BMediaNode::B_RECORDING);
302 m_runMode = runMode;
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);
314 notify(&m);
316 // update real run mode
317 if(m_group)
318 _setRunMode(m_group->runMode(), m_recordingDelay);
321 uint32 NodeRef::runMode() const {
322 Autolock _l(this);
323 return m_runMode;
326 bigtime_t NodeRef::recordingDelay() const {
327 Autolock _l(this);
328 return m_recordingDelay;
331 // calculates the minimum amount of delay needed for
332 // B_RECORDING mode
333 // +++++ 15sep99: returns biggest_output_buffer_duration * 2
334 // +++++ 28sep99: adds downstream latency
336 bigtime_t NodeRef::calculateRecordingModeDelay() {
337 PRINT((
338 "NodeRef::calculateRecordingModeDelay()\n"));
339 status_t err;
341 bigtime_t maxBufferDur = 0LL;
343 vector<Connection> outputConnections;
344 err = getOutputConnections(outputConnections);
345 for(
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(
356 node(), &latency);
358 PRINT((
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 {
374 Autolock _l(this);
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));
388 return B_OK;
392 status_t NodeRef::getOutputConnections(
393 vector<Connection>& ioConnections,
394 media_type filterType) const {
395 Autolock _l(this);
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));
409 return B_OK;
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 {
419 Autolock _l(this);
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);
425 int32 count = 0;
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;
437 return B_OK;
440 status_t NodeRef::getOutputConnections(
441 Connection* outConnections,
442 int32 maxConnections,
443 int32* outNumConnections,
444 media_type filterType) const {
445 Autolock _l(this);
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);
451 int32 count = 0;
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;
463 return B_OK;
466 // -------------------------------------------------------- //
467 // *** position reporting/listening
468 // -------------------------------------------------------- //
470 bool NodeRef::positionReportsEnabled() const {
471 return m_positionReportsEnabled;
474 // start thread if necessary
475 void NodeRef::enablePositionReports() {
476 Autolock _l(this);
478 if(m_flags & NO_POSITION_REPORTING)
479 return;
481 if(m_positionReportsEnabled)
482 return;
484 m_positionReportsEnabled = true;
485 if(m_running) {
486 // start the thread
487 _startPositionThread();
491 // stop thread if necessary
492 void NodeRef::disablePositionReports() {
493 Autolock _l(this);
495 if(!m_positionReportsEnabled)
496 return;
498 m_positionReportsEnabled = false;
499 if(m_running) {
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 {
516 Autolock _l(this);
518 if(!m_positionReportsEnabled)
519 return B_NOT_ALLOWED;
521 *outPosition = m_lastPosition;
522 *outPerfTime = m_tpLastPositionUpdate;
523 return B_OK;
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(
532 BHandler* handler) {
533 ASSERT(handler);
535 // try to create messenger
536 status_t error;
537 BMessenger m(handler, NULL, &error);
538 if(error < B_OK) {
539 PRINT((
540 "* NodeRef::addPositionListener(): BMessenger() failed:\n"
541 " %s\n"
542 " handler %p\n",
543 strerror(error), handler));
544 return error;
547 // add to the invoker
548 Autolock _l(this);
549 m_positionInvoker.AddTarget(handler);
551 // enable position updates:
552 if(!m_positionReportsEnabled)
553 enablePositionReports();
555 return B_OK;
558 status_t NodeRef::removePositionObserver(
559 BHandler* handler) {
560 ASSERT(handler);
562 Autolock _l(this);
564 // look for listener
565 int32 index = m_positionInvoker.IndexOfTarget(handler);
566 if(index == -1)
567 return B_ERROR;
569 // remove it
570 m_positionInvoker.RemoveTarget(index);
572 // last observer removed? kill thread. [e.moon 12oct99]
573 if(m_positionReportsEnabled && !m_positionInvoker.CountTargets())
574 disablePositionReports();
576 return B_OK;
579 // Set how often position updates will be sent:
580 // Realistically, period should be > 10000 or so.
582 status_t NodeRef::setPositionUpdatePeriod(
583 bigtime_t period) {
585 Autolock _l(this);
586 if(period < 1000LL)
587 return B_BAD_VALUE;
588 m_positionUpdatePeriod = period;
589 return B_OK;
592 bigtime_t NodeRef::positionUpdatePeriod() const{
593 Autolock _l(this);
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() {
605 D_METHOD((
606 "NodeRef[%s]::releaseNode()\n", name()));
607 status_t err;
609 Autolock _l(m_manager);
611 if(isReleased() || m_nodeReleased)
612 return B_NOT_ALLOWED;
614 if(m_group)
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
626 // NodeManager
627 vector<Connection> c_set;
628 getInputConnections(c_set);
629 getOutputConnections(c_set);
631 // [e.moon 13oct99] making PPC compiler happy
632 // for_each(
633 // c_set.begin(),
634 // c_set.end(),
635 // bound_method(
636 // *m_manager,
637 // &NodeManager::disconnect
638 // )
639 // );
641 for(vector<Connection>::iterator it = c_set.begin();
642 it != c_set.end(); ++it) {
643 err = m_manager->disconnect(*it);
644 if(err < B_OK) {
645 PRINT((
646 "! NodeRef('%s')::releaseNode():\n"
647 " NodeManager::disconnect('%s'->'%s') failed:\n"
648 " %s\n",
649 name(),
650 (*it).outputName(), (*it).inputName(),
651 strerror(err)));
655 // +++++ ensure that the connections were really broken?
658 err = B_OK;
659 if(!(m_implFlags & _NO_RELEASE)) {
661 // PRINT((
662 // "### releasing node %ld\n",
663 // id()));
665 // free the node
666 D_ROSTER(("# roster->ReleaseNode(%ld)\n", m_info.node.node));
667 err = BMediaRoster::Roster()->ReleaseNode(
668 m_info.node);
670 if(err < B_OK) {
671 PRINT((
672 "!!! ReleaseNode(%" B_PRId32 ") failed:\n"
673 " %s\n",
674 m_info.node.node,
675 strerror(err)));
679 (m_implFlags & _INTERNAL) &&
680 m_manager->m_useAddOnHost) {
682 // ask add-on host to release the node
683 err = AddOnHost::ReleaseInternalNode(m_info);
684 if(err < B_OK) {
685 PRINT((
686 "!!! AddOnHost::ReleaseInternalNode(%" B_PRId32
687 ") failed:\n"
688 " %s\n",
689 m_info.node.node,
690 strerror(err)));
694 else {
695 // PRINT(("- not releasing node\n"));
698 m_nodeReleased = true;
699 return err;
703 // calculate total (internal + downstream) latency for this node
705 status_t NodeRef::totalLatency(
706 bigtime_t* outLatency) const {
708 return BMediaRoster::Roster()->GetLatencyFor(
709 m_info.node,
710 outLatency);
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 {
737 status_t err;
739 vector<media_input> inputs;
740 vector<media_input>::const_iterator it;
741 inputs.reserve(32);
743 // check free inputs
744 err = getFreeInputs(inputs);
745 if(err < B_OK)
746 return err;
748 it = find_if(
749 inputs.begin(), inputs.end(),
750 match_input_destination(forDestination));
752 if(it != inputs.end()) {
753 *outInput = *it;
754 return B_OK;
757 // check connected inputs
758 inputs.clear();
759 err = getConnectedInputs(inputs);
760 if(err < B_OK)
761 return err;
763 it = find_if(
764 inputs.begin(), inputs.end(),
765 match_input_destination(forDestination));
767 if(it != inputs.end()) {
768 *outInput = *it;
769 return B_OK;
771 return B_MEDIA_BAD_DESTINATION;
774 status_t NodeRef::findOutput(
775 const media_source& forSource,
776 media_output* outOutput) const {
778 status_t err;
780 vector<media_output> outputs;
781 vector<media_output>::const_iterator it;
782 outputs.reserve(32);
784 // check free outputs
785 err = getFreeOutputs(outputs);
786 if(err < B_OK)
787 return err;
789 it = find_if(
790 outputs.begin(), outputs.end(),
791 match_output_source(forSource));
793 if(it != outputs.end()) {
794 *outOutput = *it;
795 return B_OK;
798 // check connected outputs
799 outputs.clear();
800 err = getConnectedOutputs(outputs);
801 if(err < B_OK)
802 return err;
804 it = find_if(
805 outputs.begin(), outputs.end(),
806 match_output_source(forSource));
808 if(it != outputs.end()) {
809 *outOutput = *it;
810 return B_OK;
813 return B_MEDIA_BAD_SOURCE;
817 // endpoint matching (given name and/or format as 'hints')
819 template <class T>
820 class match_endpoint_name_format : public unary_function<T, bool> {
821 public:
822 const char* name;
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)
830 return false;
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))
835 return false;
836 return true;
840 template <class T>
841 class match_endpoint_name_type : public unary_function<T, bool> {
842 public:
843 const char* name;
844 media_type type;
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)
851 return false;
852 // test type, if given
853 if(type != B_MEDIA_UNKNOWN_TYPE &&
854 type != endpoint.format.type)
855 return false;
857 return true;
861 template <class T>
862 class match_endpoint_type : public unary_function<T, bool> {
863 public:
864 media_type type;
866 match_endpoint_type(media_type _type) :
867 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)
872 return false;
874 return true;
878 status_t NodeRef::findFreeInput(
879 media_input* outInput,
880 const media_format* format /*=0*/,
881 const char* name /*=0*/) const {
883 status_t err;
885 vector<media_input> inputs;
886 vector<media_input>::const_iterator it;
887 inputs.reserve(32);
889 err = getFreeInputs(inputs);
890 if(err < B_OK)
891 return err;
893 it = find_if(
894 inputs.begin(),
895 inputs.end(),
896 match_endpoint_name_format<media_input>(name, format));
898 if(it != inputs.end()) {
899 *outInput = *it;
900 return B_OK;
902 return B_ERROR;
905 status_t NodeRef::findFreeInput(
906 media_input* outInput,
907 media_type type /*=B_MEDIA_UNKNOWN_TYPE*/,
908 const char* name /*=0*/) const {
910 status_t err;
912 vector<media_input> inputs;
913 vector<media_input>::const_iterator it;
914 inputs.reserve(32);
916 err = getFreeInputs(inputs);
917 if(err < B_OK)
918 return err;
920 it = find_if(
921 inputs.begin(),
922 inputs.end(),
923 match_endpoint_name_type<media_input>(name, type));
924 if(it != inputs.end()) {
925 *outInput = *it;
926 return B_OK;
928 return B_ERROR;
931 status_t NodeRef::findFreeOutput(
932 media_output* outOutput,
933 const media_format* format /*=0*/,
934 const char* name /*=0*/) const {
936 status_t err;
938 vector<media_output> outputs;
939 vector<media_output>::const_iterator it;
940 outputs.reserve(32);
942 err = getFreeOutputs(outputs);
943 if(err < B_OK)
944 return err;
946 it = find_if(
947 outputs.begin(),
948 outputs.end(),
949 match_endpoint_name_format<media_output>(name, format));
950 if(it != outputs.end()) {
951 *outOutput = *it;
952 return B_OK;
954 return B_ERROR;
957 status_t NodeRef::findFreeOutput(
958 media_output* outOutput,
959 media_type type /*=B_MEDIA_UNKNOWN_TYPE*/,
960 const char* name /*=0*/) const {
962 status_t err;
964 vector<media_output> outputs;
965 vector<media_output>::const_iterator it;
966 outputs.reserve(32);
968 err = getFreeOutputs(outputs);
969 if(err < B_OK)
970 return err;
972 it = find_if(
973 outputs.begin(),
974 outputs.end(),
975 match_endpoint_name_type<media_output>(name, type));
976 if(it != outputs.end()) {
977 *outOutput = *it;
978 return B_OK;
980 return B_ERROR;
984 // node endpoint access: vector versions (wrappers for BMediaRoster
985 // calls.)
987 status_t NodeRef::getFreeInputs(
988 vector<media_input>& ioInputs,
989 media_type filterType) const {
991 BMediaRoster* r = BMediaRoster::Roster();
992 status_t err;
994 int32 count;
995 int32 bufferInc = 16;
996 int32 inputBufferSize = 16;
997 media_input* inputBuffer = new media_input[inputBufferSize];
999 while (true) {
1000 err = r->GetFreeInputsFor(
1001 m_info.node, inputBuffer, inputBufferSize, &count, filterType);
1002 if (err < B_OK) {
1003 delete [] inputBuffer;
1004 return err;
1007 if (count == inputBufferSize) {
1008 // buffer too small; increase & try again
1009 inputBufferSize += bufferInc;
1010 delete [] inputBuffer;
1011 inputBuffer = new media_input[inputBufferSize];
1012 continue;
1015 if (count)
1016 // copy found inputs into vector
1017 copy(inputBuffer, inputBuffer + count,
1018 back_inserter(ioInputs));
1020 break;
1023 // fix missing node info
1024 _fixInputs(ioInputs);
1026 delete [] inputBuffer;
1027 return B_OK;
1030 // +++++ broken?
1031 status_t NodeRef::getConnectedInputs(
1032 vector<media_input>& ioInputs,
1033 media_type filterType) const {
1035 BMediaRoster* r = BMediaRoster::Roster();
1036 status_t err;
1038 int32 count;
1039 int32 bufferInc = 16;
1040 int32 inputBufferSize = 16;
1041 media_input* inputBuffer = new media_input[inputBufferSize];
1043 while (true) {
1044 err = r->GetConnectedInputsFor(
1045 m_info.node, inputBuffer, inputBufferSize, &count);
1046 if (err < B_OK) {
1047 delete [] inputBuffer;
1048 return err;
1051 if (count == inputBufferSize) {
1052 // buffer too small; increase & try again
1053 inputBufferSize += bufferInc;
1054 delete [] inputBuffer;
1055 inputBuffer = new media_input[inputBufferSize];
1056 continue;
1059 if (count)
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)));
1065 break;
1068 // fix missing node info
1069 _fixInputs(ioInputs);
1071 delete [] inputBuffer;
1072 return B_OK;
1075 status_t NodeRef::getFreeOutputs(
1076 vector<media_output>& ioOutputs,
1077 media_type filterType) const {
1079 BMediaRoster* r = BMediaRoster::Roster();
1080 status_t err;
1082 int32 count;
1083 int32 bufferInc = 16;
1084 int32 outputBufferSize = 16;
1085 media_output* outputBuffer = new media_output[outputBufferSize];
1087 while (true) {
1088 err = r->GetFreeOutputsFor(
1089 m_info.node, outputBuffer, outputBufferSize, &count, filterType);
1090 if (err < B_OK) {
1091 delete [] outputBuffer;
1092 return err;
1095 if (count == outputBufferSize) {
1096 // buffer too small; increase & try again
1097 outputBufferSize += bufferInc;
1098 delete [] outputBuffer;
1099 outputBuffer = new media_output[outputBufferSize];
1100 continue;
1103 if (count)
1104 // copy found outputs into vector
1105 copy(outputBuffer, outputBuffer + count,
1106 back_inserter(ioOutputs));
1108 break;
1111 // fix missing node info
1112 _fixOutputs(ioOutputs);
1114 delete [] outputBuffer;
1115 return B_OK;
1118 status_t NodeRef::getConnectedOutputs(
1119 vector<media_output>& ioOutputs,
1120 media_type filterType) const {
1122 BMediaRoster* r = BMediaRoster::Roster();
1123 status_t err;
1125 int32 count;
1126 int32 bufferInc = 16;
1127 int32 outputBufferSize = 16;
1128 media_output* outputBuffer = new media_output[outputBufferSize];
1130 while (true) {
1131 err = r->GetConnectedOutputsFor(
1132 m_info.node, outputBuffer, outputBufferSize, &count);
1133 if (err < B_OK) {
1134 delete [] outputBuffer;
1135 return err;
1138 if (count == outputBufferSize) {
1139 // buffer too small; increase & try again
1140 outputBufferSize += bufferInc;
1141 delete [] outputBuffer;
1142 outputBuffer = new media_output[outputBufferSize];
1143 continue;
1146 if (count)
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)));
1152 break;
1155 // fix missing node info
1156 _fixOutputs(ioOutputs);
1158 delete [] outputBuffer;
1159 return B_OK;
1163 // node endpoint access: array versions (wrappers for BMediaRoster
1164 // calls.)
1166 status_t NodeRef::getFreeInputs(
1167 media_input* outInputs,
1168 int32 maxInputs,
1169 int32* outNumInputs,
1170 media_type filterType) const {
1172 status_t err = BMediaRoster::Roster()->GetFreeInputsFor(
1173 m_info.node, outInputs, maxInputs, outNumInputs, filterType);
1175 if(err < B_OK)
1176 return err;
1178 // fix missing node info
1179 _fixInputs(outInputs, *outNumInputs);
1180 return err;
1184 status_t NodeRef::getConnectedInputs(
1185 media_input* outInputs,
1186 int32 maxInputs,
1187 int32* outNumInputs) const {
1189 status_t err = BMediaRoster::Roster()->GetConnectedInputsFor(
1190 m_info.node, outInputs, maxInputs, outNumInputs);
1192 if(err < B_OK)
1193 return err;
1195 // fix missing node info
1196 _fixInputs(outInputs, *outNumInputs);
1197 return err;
1200 status_t NodeRef::getFreeOutputs(
1201 media_output* outOutputs,
1202 int32 maxOutputs,
1203 int32* outNumOutputs,
1204 media_type filterType) const {
1206 status_t err = BMediaRoster::Roster()->GetFreeOutputsFor(
1207 m_info.node, outOutputs, maxOutputs, outNumOutputs, filterType);
1209 if(err < B_OK)
1210 return err;
1212 // fix missing node info
1213 _fixOutputs(outOutputs, *outNumOutputs);
1214 return err;
1217 status_t NodeRef::getConnectedOutputs(
1218 media_output* outOutputs,
1219 int32 maxOutputs,
1220 int32* outNumOutputs) const {
1222 status_t err = BMediaRoster::Roster()->GetConnectedOutputsFor(
1223 m_info.node, outOutputs, maxOutputs, outNumOutputs);
1225 if(err < B_OK)
1226 return err;
1228 // fix missing node info
1229 _fixOutputs(outOutputs, *outNumOutputs);
1230 return err;
1234 // -------------------------------------------------------- //
1235 // *** IPersistent
1236 // -------------------------------------------------------- //
1238 // !
1239 #if CORTEX_XML
1240 // !
1242 // +++++
1244 // !
1245 #endif /*CORTEX_XML*/
1246 // !
1248 // -------------------------------------------------------- //
1249 // *** BHandler:
1250 // -------------------------------------------------------- //
1252 void NodeRef::MessageReceived(
1253 BMessage* message) {
1255 D_MESSAGE((
1256 "NodeRef['%s']::MessageReceived(): %c%c%c%c\n",
1257 name(),
1258 message->what >> 24,
1259 (message->what >> 16) & 0xff,
1260 (message->what >> 8) & 0xff,
1261 (message->what) & 0xff));
1262 status_t err;
1264 switch(message->what) {
1265 case M_SET_RUN_MODE:
1267 // set run mode & delay (if given)
1268 int32 runMode;
1269 bigtime_t delay = 0LL;
1270 err = message->FindInt32("runMode", &runMode);
1271 if(err < B_OK) {
1272 PRINT((
1273 "! NodeRef::MessageReceived(M_SET_RUN_MODE): no value found.\n"));
1274 break;
1276 if(runMode == BMediaNode::B_RECORDING)
1277 message->FindInt64("delay", &delay); // optional
1279 setRunMode(runMode, delay);
1281 break;
1284 case M_PREROLL:
1285 // +++++
1286 break;
1288 case M_SET_CYCLING:
1290 bool cycling;
1291 err = message->FindBool("cycling", &cycling);
1292 if(err < B_OK) {
1293 int32 val;
1294 err = message->FindInt32("be:value", &val);
1295 if(err < B_OK) {
1296 PRINT((
1297 "! NodeRef::MessageReceived(M_SET_CYCLING): no value found.\n"));
1298 break;
1300 cycling = val;
1303 setCycling(cycling);
1305 break;
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]
1311 if(m_running) {
1312 m_running = false;
1313 m_stopQueued = false;
1315 if(m_group) {
1316 Autolock _l(m_group);
1317 m_group->_refStopped(this);
1321 break;
1323 case NodeSyncThread::M_SYNC_COMPLETE: {
1324 // [e.moon 14oct99] position-report messages are now sent
1325 // by the NodeSyncThread.
1327 Autolock _l(this);
1329 // unpack message
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);
1337 break;
1340 default:
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));
1372 notify(&m);
1375 void NodeRef::releaseComplete() {
1376 // +++++
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)
1392 // Notes:
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.
1401 bool NodeRef::lock(
1402 lock_t type,
1403 bigtime_t timeout) {
1405 D_LOCK(("*** NodeRef::lock(): %ld\n", find_thread(0)));
1407 ASSERT(type == WRITE);
1408 ASSERT(m_manager);
1410 // lock manager
1411 if(!m_manager->lock(type, timeout))
1412 return false;
1414 // transfer lock to group, if any
1415 NodeGroup* group = m_group;
1416 if(!group)
1417 return true;
1419 bool ret = m_group->lock(type, timeout);
1421 m_manager->unlock();
1423 D_LOCK(("*** NodeRef::lock() ACQUIRED: %ld\n", find_thread(0)));
1425 return ret;
1428 bool NodeRef::unlock(
1429 lock_t type) {
1431 D_LOCK(("*** NodeRef::unlock(): %ld\n", find_thread(0)));
1433 ASSERT(type == WRITE);
1434 ASSERT(m_manager);
1436 NodeGroup* group = m_group;
1437 if(group) {
1438 bool ret = m_group->unlock(type);
1439 D_LOCK(("*** NodeRef::unlock() RELEASED: %ld\n", find_thread(0)));
1440 return ret;
1443 bool ret = m_manager->unlock(type);
1445 D_LOCK(("*** NodeRef::unlock() RELEASED: %ld\n", find_thread(0)));
1446 return ret;
1449 bool NodeRef::isLocked(
1450 lock_t type) const {
1452 ASSERT(type == WRITE);
1453 ASSERT(m_manager);
1455 NodeGroup* group = m_group;
1456 if(group)
1457 return m_group->isLocked(type);
1459 return m_manager->isLocked(type);
1462 // -------------------------------------------------------- //
1463 // *** ctor
1464 // -------------------------------------------------------- //
1466 NodeRef::NodeRef(
1467 const media_node& node,
1468 NodeManager* manager,
1469 uint32 userFlags,
1470 uint32 implFlags) :
1472 m_manager(manager),
1473 m_group(0),
1474 m_flags(userFlags),
1475 m_implFlags(implFlags),
1476 m_runMode(0),
1477 m_recordingDelay(0LL),
1478 m_watching(false),
1479 m_addonHint(0),
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),
1486 m_running(false),
1487 m_nodeReleased(false),
1488 m_cycle(false),
1489 m_prerolled(false),
1490 // m_cycleSyncThread(0),
1491 m_stopQueued(false),
1492 m_latency(0LL) {
1494 ASSERT(manager);
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(
1505 node,
1506 &m_info);
1508 if(err < B_OK) {
1509 PRINT((
1510 "!!! NodeRef(): BMediaRoster::GetLiveNodeInfo(%" B_PRId32
1511 ") failed:\n"
1512 " %s\n",
1513 node.node,
1514 strerror(err)));
1515 // at least store node info
1516 m_info.node = node;
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)) {
1524 r->StartWatching(
1525 BMessenger(this),
1526 m_info.node,
1527 B_MEDIA_NODE_STOPPED);
1528 m_watching = true;
1531 // -------------------------------------------------------- //
1532 // *** endpoint-fixing operations (no lock required)
1533 // -------------------------------------------------------- //
1535 template <class T>
1536 class fixEndpointFn : public unary_function<T&, void> {
1537 const media_node& node;
1538 public:
1539 fixEndpointFn(const media_node& _n) : node(_n) {}
1540 void operator()(T& endpoint) {
1541 // PRINT((
1542 // "fixEndpointFn(): endpoint '%s', node ID %ld\n",
1543 // endpoint.name, endpoint.node.node));
1544 if(endpoint.node != node) {
1545 PRINT((
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 {
1557 D_METHOD((
1558 "NodeRef[%s]::fixInputs()\n", m_info.name));
1560 for_each(
1561 inputs,
1562 inputs+count,
1563 fixEndpointFn<media_input>(node()));
1566 void NodeRef::_fixInputs(
1567 vector<media_input>& inputs) const {
1569 D_METHOD((
1570 "NodeRef[%s]::fixInputs()\n", m_info.name));
1572 for_each(
1573 inputs.begin(),
1574 inputs.end(),
1575 fixEndpointFn<media_input>(node()));
1578 void NodeRef::_fixOutputs(
1579 media_output* outputs,
1580 int32 count) const {
1582 D_METHOD((
1583 "NodeRef[%s]::fixOutputs()\n", m_info.name));
1585 for_each(
1586 outputs,
1587 outputs+count,
1588 fixEndpointFn<media_output>(node()));
1591 void NodeRef::_fixOutputs(
1592 vector<media_output>& outputs) const {
1594 D_METHOD((
1595 "NodeRef[%s]::fixOutputs()\n", m_info.name));
1597 for_each(
1598 outputs.begin(),
1599 outputs.end(),
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);
1616 if(m_addonHint)
1617 delete m_addonHint;
1619 m_addonHint = new addon_hint(info, file);
1622 // call to set a new group; if 0, the node must have no
1623 // connections
1624 void NodeRef::_setGroup(
1625 NodeGroup* group) {
1626 assert_locked(this);
1628 m_group = group;
1630 if(!LockLooper()) {
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);
1636 notify(&m);
1637 UnlockLooper();
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);
1650 D_METHOD((
1651 "NodeRef('%s')::_initTransportState()\n",
1652 name()));
1654 // init transport state for this node
1655 m_prerolled = false;
1656 m_tpStart = 0LL;
1657 m_tpLastSeek = 0LL;
1658 m_lastSeekPos = 0LL;
1660 // +++++ init position reporting stuff here?
1662 return B_OK;
1665 status_t NodeRef::_setTimeSource(
1666 media_node_id timeSourceID) {
1667 assert_locked(this);
1669 D_METHOD((
1670 "NodeRef('%s')::_setTimeSource(%ld)\n",
1671 name(), timeSourceID));
1672 status_t err;
1674 // set time source
1675 ASSERT(timeSourceID != media_node::null.node);
1676 D_ROSTER(("# roster->SetTimeSourceFor()\n"));
1677 err = m_manager->roster->SetTimeSourceFor(
1678 id(), timeSourceID);
1680 if(err < B_OK) {
1681 PRINT((
1682 "* NodeRef('%s')::_setTimeSource(%" B_PRId32 "):\n"
1683 " SetTimeSourceFor() failed: %s\n",
1684 name(), timeSourceID, strerror(err)));
1687 return err;
1690 status_t NodeRef::_setRunMode(
1691 const uint32 runMode,
1692 bigtime_t delay) {
1693 assert_locked(this);
1695 D_METHOD((
1696 "NodeRef('%s')::_setRunMode(%ld : %Ld)\n",
1697 name(), runMode, delay));
1698 status_t err;
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
1706 (m_runMode > 0) ?
1707 (BMediaNode::run_mode)m_runMode :
1708 (BMediaNode::run_mode)runMode;
1709 ASSERT(m > 0);
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(
1719 node(), delay, m);
1720 if(err < B_OK) {
1721 PRINT((
1722 "NodeRef('%s')::_setRunMode(): SetProducerRunModeDelay(%"
1723 B_PRIdBIGTIME ") failed: %s\n",
1724 name(), delay, strerror(err)));
1726 } else {
1728 D_ROSTER(("# roster->SetRunModeNode()\n"));
1729 err = m_manager->roster->SetRunModeNode(
1730 node(), m);
1731 if(err < B_OK) {
1732 PRINT((
1733 "NodeRef('%s')::_setRunMode(): SetRunModeNode(%d) failed: %s\n",
1734 name(), m, strerror(err)));
1738 return err;
1741 status_t NodeRef::_setRunModeAuto(
1742 const uint32 runMode) {
1745 kind() && B_BUFFER_PRODUCER &&
1746 runMode == BMediaNode::B_RECORDING) {
1748 return _setRunMode(
1749 runMode,
1750 calculateRecordingModeDelay());
1752 } else
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
1762 // error.
1764 status_t NodeRef::_preroll(
1765 bigtime_t position) {
1766 assert_locked(this);
1768 D_METHOD((
1769 "NodeRef('%s')::_preroll(%Ld)\n",
1770 name(), position));
1771 status_t err;
1773 // make sure the node can be and wants to be prerolled
1774 if(m_running ||
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(
1781 node(),
1782 position,
1783 0LL);
1785 if(err < B_OK) {
1786 PRINT((
1787 "*** NodeRef('%s')::_preroll(%" B_PRIdBIGTIME
1788 "): BMediaRoster::SeekNode():\n"
1789 " %s\n",
1790 name(), position, strerror(err)));
1791 return err;
1795 // preroll the node (*** this blocks until the node's Preroll()
1796 // implementation returns ***)
1798 err = BMediaRoster::Roster()->PrerollNode(
1799 node());
1801 if(err < B_OK) {
1802 PRINT((
1803 "*** NodeRef('%s')::_preroll(%" B_PRIdBIGTIME
1804 "): BMediaRoster::PrerollNode():\n"
1805 " %s\n",
1806 name(), position, strerror(err)));
1807 return err;
1810 m_prerolled = true;
1811 m_tpLastSeek = 0LL;
1812 m_lastSeekPos = position;
1814 return B_OK;
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(
1822 bigtime_t position,
1823 bigtime_t when) {
1824 assert_locked(this);
1826 D_METHOD((
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
1832 return B_OK;
1834 if(m_prerolled && m_lastSeekPos == position)
1835 // the node has already been advanced to the proper position
1836 return B_OK;
1838 // do it
1839 status_t err = BMediaRoster::Roster()->SeekNode(
1840 node(), position, when);
1842 if(err < B_OK) {
1843 PRINT((
1844 "*** NodeRef('%s')::_seek(to %" B_PRIdBIGTIME ", at %"
1845 B_PRIdBIGTIME "): BMediaRoster::SeekNode():\n"
1846 " %s\n",
1847 name(), position, when, strerror(err)));
1848 return 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;
1858 return B_OK;
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);
1869 D_METHOD((
1870 "NodeRef('%s')::_seekStopped(to %Ld)\n",
1871 name(), position));
1873 if(m_running)
1874 return B_NOT_ALLOWED;
1876 return _seek(position, 0LL);
1880 // start the given node, if possible & necessary, at
1881 // the given time
1882 // (this may be called from the transport thread or from
1883 // an API-implementation method.)
1885 status_t NodeRef::_start(
1886 bigtime_t when) {
1887 assert_locked(this);
1889 D_METHOD((
1890 "NodeRef('%s')::_start(at %Ld)\n",
1891 name(), when));
1893 if(isRunning()) {
1894 D_METHOD((
1895 " * node already running; aborting\n"));
1896 return B_OK; // +++++ is this technically an error?
1899 // +++++ is this proper?
1900 ASSERT(m_group);
1901 ASSERT(
1902 m_group->m_transportState == NodeGroup::TRANSPORT_RUNNING ||
1903 m_group->m_transportState == NodeGroup::TRANSPORT_STARTING);
1905 if(m_flags & NO_START_STOP) {
1906 D_METHOD((
1907 " * NO_START_STOP; aborting\n"));
1908 return B_OK;
1911 D_ROSTER(("# roster->StartNode(%ld)\n", id()));
1912 status_t err = BMediaRoster::Roster()->StartNode(
1913 node(), when);
1915 if(err < B_OK) {
1916 PRINT((
1917 " * StartNode(%" B_PRId32 ") failed: '%s'\n",
1918 id(), strerror(err)));
1919 return err;
1922 // update state
1923 m_running = true;
1924 m_tpStart = when;
1926 // fetch new node latency
1927 _updateLatency();
1929 // start position tracking thread if needed
1930 m_positionReportsStarted = false;
1931 if(m_positionReportsEnabled)
1932 _startPositionThread();
1934 return B_OK;
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);
1945 D_METHOD((
1946 "NodeRef('%s')::_stop()\n",
1947 name()));
1949 if(!isRunning())
1950 return B_OK; // +++++ error?
1952 if(m_flags & NO_START_STOP || m_flags & NO_STOP)
1953 return B_OK;
1955 D_ROSTER(("# roster->StopNode(%ld)\n", id()));
1956 status_t err = BMediaRoster::Roster()->StopNode(
1957 node(), 0, true);
1959 if(err < B_OK)
1960 return err;
1962 // 9aug99: refuse further position notification
1963 _stopPositionThread();
1965 // clear node's state
1966 m_running = false;
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(
1975 bigtime_t start,
1976 bigtime_t stop,
1977 bigtime_t position) {
1978 assert_locked(this);
1980 D_METHOD((
1981 "NodeRef('%s')::_roll(%Ld to %Ld, from %Ld)\n",
1982 name(), start, stop, position));
1983 status_t err;
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;
1993 if(isRunning())
1994 return B_NOT_ALLOWED;
1996 ASSERT(m_group);
1997 ASSERT(
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);
2005 else
2006 err = BMediaRoster::Roster()->RollNode(
2007 node(), start, stop, position);
2009 if(err < B_OK) {
2010 PRINT((
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)));
2015 return err;
2018 // update state
2019 m_running = true;
2020 m_stopQueued = true; // remember that node will stop on its own [e.moon 11oct99]
2021 m_tpStart = start;
2023 // fetch new node latency
2024 _updateLatency();
2026 // start position tracking thread if needed
2027 m_positionReportsStarted = false;
2028 if(m_positionReportsEnabled)
2029 _startPositionThread();
2031 return B_OK;
2034 // [28sep99 e.moon]
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)) {
2043 m_latency = 0LL;
2044 return B_OK;
2047 bigtime_t latency;
2048 status_t err = BMediaRoster::Roster()->GetLatencyFor(
2049 node(),
2050 &latency);
2051 if(err < B_OK) {
2052 PRINT((
2053 "* NodeRef('%s')::_updateLatency(): GetLatencyFor() failed:\n"
2054 " %s\n",
2055 name(), strerror(err)));
2057 return err;
2060 // success
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);
2069 return B_OK;
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
2076 // start position.
2077 // Pass the estimated amount of time needed to prepare the
2078 // node for playback (ie. preroll & a little fudge factor) in
2079 // startDelay.
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,
2086 bigtime_t* outTime,
2087 bigtime_t* outPosition) {
2088 assert_locked(this);
2090 // +++++
2092 return B_ERROR;
2096 // -------------------------------------------------------- //
2097 // *** Position and cycle thread management *** (LOCK REQUIRED)
2098 // -------------------------------------------------------- //
2100 status_t NodeRef::_startPositionThread() {
2101 assert_locked(this);
2102 ASSERT(m_group);
2103 status_t err;
2105 if(!m_positionReportsEnabled)
2106 return B_NOT_ALLOWED;
2108 if(m_positionThread)
2109 _stopPositionThread();
2111 m_positionThread = new NodeSyncThread(
2112 m_info.node,
2113 new BMessenger(this));
2115 // send an initial position report if necessary
2116 if(!m_positionReportsStarted) {
2117 m_positionReportsStarted = true;
2119 err = _handlePositionUpdate(
2120 m_tpStart,
2121 m_lastSeekPos);
2123 if(err < B_OK) {
2124 PRINT((
2125 "* NodeRef::_startPositionThread(): _handlePositionUpdate() failed:\n"
2126 " %s\\n",
2127 strerror(err)));
2128 return err;
2131 else {
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(
2146 tpTarget,
2147 targetPosition);
2149 if(err < B_OK) {
2150 PRINT((
2151 "* NodeRef::_createPositionThread(): _schedulePositionUpdate() failed:\n"
2152 " %s\\n",
2153 strerror(err)));
2154 return err;
2158 return B_OK;
2161 status_t NodeRef::_handlePositionUpdate(
2162 bigtime_t perfTime,
2163 bigtime_t position) {
2164 assert_locked(this);
2165 status_t err;
2167 if(!m_running) {
2168 PRINT((
2169 "* NodeRef::_handlePositionUpdate(): not running.\n"));
2170 return B_NOT_ALLOWED;
2173 if(!m_positionReportsEnabled) {
2174 PRINT((
2175 "* NodeRef::_handlePositionUpdate(): position reports disabled.\n"));
2176 return B_NOT_ALLOWED;
2179 // store info
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);
2191 if(err < B_OK) {
2192 PRINT((
2193 "* NodeRef::_handlePositionUpdate(): _schedulePositionUpdate() failed:\n"
2194 " %s\n",
2195 strerror(err)));
2197 return err;
2200 status_t NodeRef::_schedulePositionUpdate(
2201 bigtime_t when,
2202 bigtime_t position) {
2203 assert_locked(this);
2204 status_t err;
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 = {
2219 //// id(),
2220 //// m_group->id(),
2221 //// when,
2222 //// position
2223 //// };
2225 //// PRINT((
2226 //// "NodeRef::_schedulePositionUpdate():\n"
2227 //// " when = %Ld\n"
2228 //// " position = %Ld\n",
2229 //// when, position));
2231 // m_positionSyncThread->setPosition(position);
2233 // if(first)
2234 // err = m_positionSyncThread->go(when);
2235 // else
2236 // err = m_positionSyncThread->reschedule(when);
2238 err = m_positionThread->sync(when, position, B_INFINITE_TIMEOUT);
2240 if(err < B_OK) {
2241 PRINT((
2242 "! NodeRef::_schedulePositionUpdate(): m_positionThread->sync() failed:\n"
2243 " %s\n", strerror(err)));
2245 return 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;
2257 return B_OK;
2261 // Send a message to all position listeners
2262 status_t NodeRef::_notifyPosition(
2263 bigtime_t when,
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);
2278 return err;
2281 // END -- NodeRef.cpp --