/* * Copyright (c) 1999-2000, Eric Moon. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions, and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // ConnectionIO.cpp #include "ConnectionIO.h" #include "LiveNodeIO.h" #include "NodeManager.h" #include "NodeSetIOContext.h" #include "MediaFormatIO.h" #include "route_app_io.h" #include #include using namespace std; __USE_CORTEX_NAMESPACE // -------------------------------------------------------- // // *** ctor/dtor // -------------------------------------------------------- // ConnectionIO::~ConnectionIO() { if(m_inputNodeIO) delete m_inputNodeIO; if(m_outputNodeIO) delete m_outputNodeIO; } // initialize for import ConnectionIO::ConnectionIO() : m_inputNodeIO(0), m_outputNodeIO(0), m_flags(0), m_exportValid(false), m_importState(IMPORT_NONE) { m_outputFormat.type = B_MEDIA_NO_TYPE; m_inputFormat.type = B_MEDIA_NO_TYPE; m_requestedFormat.type = B_MEDIA_NO_TYPE; } // initialize for export ConnectionIO::ConnectionIO( const Connection* con, const NodeManager* manager, const NodeSetIOContext* context) : m_inputNodeIO(0), m_outputNodeIO(0), m_exportValid(false), m_importState(IMPORT_NONE) { ASSERT(con); ASSERT(manager); ASSERT(context); if(!con->isValid()) { PRINT(( "!!! ConnectionIO(): invalid connection\n")); return; } m_outputNodeIO = new LiveNodeIO( manager, context, con->sourceNode()); // fetch output (connection-point) description const char* name; if(con->getOutputHint( &name, &m_outputFormat) == B_OK) m_outputName = name; else { m_outputName = con->outputName(); } m_inputNodeIO = new LiveNodeIO( manager, context, con->destinationNode()); // fetch input (connection-point) description if(con->getInputHint( &name, &m_inputFormat) == B_OK) m_inputName = name; else { m_inputName = con->inputName(); } m_requestedFormat = con->requestedFormat(); m_flags = con->flags(); m_exportValid = true; } // -------------------------------------------------------- // // *** operations // -------------------------------------------------------- // // call when object imported to create the described // connection // +++++ to do // smarter input/output matching -- if no name/format provided, // pick the first available endpoint. otherwise, make two passes: // 1) match all nodes w/ given name (pass wildcards through to roster) // 2) filter by format status_t ConnectionIO::instantiate( NodeManager* manager, const NodeSetIOContext* context, Connection* outCon) { // sanity checks ASSERT(manager); if(!m_inputNodeIO || !m_outputNodeIO) return B_NOT_ALLOWED; status_t err; media_node_id node; // find output node NodeRef* outputRef; err = m_outputNodeIO->getNode(manager, context, &node); if(err < B_OK) return err; err = manager->getNodeRef( node, &outputRef); if(err < B_OK) return err; // find output +++++ currently matches by name only const int32 outputBufferSize = 16; media_output outputs[outputBufferSize]; int32 count = outputBufferSize; //vector outputs; // err = outputRef->getFreeOutputs( // outputs/*, // m_outputFormat.type*/); err = outputRef->getFreeOutputs( outputs, outputBufferSize, &count); if(err < B_OK) return err; media_output output; bool found = false; for(int n = 0; n < count; ++n) { if(m_outputName == outputs[n].name) { output = outputs[n]; found = true; break; } } if(!found) { PRINT(("!!! output '%s' of node '%s' not found\n", m_outputName.String(), outputRef->name())); return B_NAME_NOT_FOUND; } // find input node NodeRef* inputRef; err = m_inputNodeIO->getNode(manager, context, &node); if(err < B_OK) return err; err = manager->getNodeRef( node, &inputRef); if(err < B_OK) return err; // find input +++++ currently matches by name only vector inputs; err = inputRef->getFreeInputs( inputs /*, m_inputFormat.type*/); if(err < B_OK) return err; media_input input; found = false; for(unsigned int n = 0; n < inputs.size(); ++n) { if(m_inputName == inputs[n].name) { input = inputs[n]; found = true; break; } } if(!found) { PRINT(("!!! input '%s' of node '%s' not found\n", m_inputName.String(), inputRef->name())); return B_NAME_NOT_FOUND; } // connect Connection con; if(m_requestedFormat.type != B_MEDIA_NO_TYPE) err = manager->connect( output, input, m_requestedFormat, &con); else err = manager->connect( output, input, &con); if(err < B_OK) return err; if(outCon) *outCon = con; return B_OK; } // -------------------------------------------------------- // // *** document-type setup // -------------------------------------------------------- // /*static*/ void ConnectionIO::AddTo( XML::DocumentType* docType) { // map self docType->addMapping(new Mapping(_CONNECTION_ELEMENT)); // map simple (content-only) elements // +++++ should these be added at a higher level, since they're // shared? no harm is done if one is added more than once, // since they'll always map to StringContent -- but it's way // messy! // +++++ //docType->addMapping(new Mapping(_LIVE_NODE_ELEMENT)); // docType->addMapping(new Mapping(_NAME_ELEMENT)); // docType->addMapping(new Mapping(_KIND_ELEMENT)); // docType->addMapping(new Mapping(_FLAG_ELEMENT)); } // -------------------------------------------------------- // // *** IPersistent // -------------------------------------------------------- // // -------------------------------------------------------- // // EXPORT: // -------------------------------------------------------- // // -------------------------------------------------------- // void ConnectionIO::xmlExportBegin( ExportContext& context) const { if(!m_exportValid) { context.reportError( "ConnectionIO::xmlExportBegin():\n" "*** invalid ***\n"); return; } context.beginElement(_CONNECTION_ELEMENT); } void ConnectionIO::xmlExportAttributes( ExportContext& context) const { TOUCH(context); } void ConnectionIO::xmlExportContent( ExportContext& context) const { context.beginContent(); // write output { context.beginElement(_OUTPUT_ELEMENT); context.beginContent(); // describe the node // LiveNodeIO nodeIO( // m_manager, // dynamic_cast(&context), // m_outputNode); context.writeObject(m_outputNodeIO); // context.beginElement(_LIVE_NODE_ELEMENT); // if(m_outputNodeKey.Length()) { // context.writeAttr("key", m_outputNodeKey); // } // else { // _write_simple("name", m_outputNodeName.String(), context); // _write_node_kinds(m_outputNodeKind, context); // } // context.endElement(); // _LIVE_NODE_ELEMENT // describe the output _write_simple("name", m_outputName.String(), context); if(m_outputFormat.type > B_MEDIA_UNKNOWN_TYPE) { MediaFormatIO io(m_outputFormat); context.writeObject(&io); } context.endElement(); // _OUTPUT_ELEMENT } // write input { context.beginElement(_INPUT_ELEMENT); context.beginContent(); // describe the node // LiveNodeIO nodeIO( // m_manager, // dynamic_cast(&context), // m_inputNode); context.writeObject(m_inputNodeIO); // context.beginElement(_LIVE_NODE_ELEMENT); // if(m_inputNodeKey.Length()) { // context.writeAttr("key", m_inputNodeKey); // } // else { // _write_simple("name", m_inputNodeName.String(), context); // _write_node_kinds(m_inputNodeKind, context); // } // context.endElement(); // _LIVE_NODE_ELEMENT // describe the input _write_simple("name", m_inputName.String(), context); if(m_inputFormat.type > B_MEDIA_UNKNOWN_TYPE) { MediaFormatIO io(m_inputFormat); context.writeObject(&io); } context.endElement(); // _INPUT_ELEMENT } // write requested format if(m_requestedFormat.type > B_MEDIA_UNKNOWN_TYPE) { MediaFormatIO io(m_requestedFormat); BString comment = "\n"; comment << context.indentString(); comment << ""; context.writeString(comment); context.writeObject(&io); } } void ConnectionIO::xmlExportEnd( ExportContext& context) const { context.endElement(); // _CONNECTION_ELEMENT } // -------------------------------------------------------- // // IMPORT: // -------------------------------------------------------- // void ConnectionIO::xmlImportBegin( ImportContext& context) { TOUCH(context); } void ConnectionIO::xmlImportAttribute( const char* key, const char* value, ImportContext& context) { TOUCH(key); TOUCH(value); TOUCH(context); } void ConnectionIO::xmlImportContent( const char* data, uint32 length, ImportContext& context) { TOUCH(data); TOUCH(length); TOUCH(context); } void ConnectionIO::xmlImportChild( IPersistent* child, ImportContext& context) { status_t err; if(!strcmp(context.element(), _LIVE_NODE_ELEMENT)) { LiveNodeIO* nodeIO = dynamic_cast(child); ASSERT(nodeIO); // store the LiveNodeIO for now; it will be used in // instantiate() switch(m_importState) { case IMPORT_OUTPUT: m_outputNodeIO = nodeIO; child = 0; // don't delete child object break; case IMPORT_INPUT: m_inputNodeIO = nodeIO; child = 0; // don't delete child object break; case IMPORT_NONE: context.reportError("Unexpected node description.\n"); delete child; return; } } else if(!strcmp(context.element(), _NAME_ELEMENT)) { StringContent* c = dynamic_cast(child); ASSERT(c); switch(m_importState) { case IMPORT_OUTPUT: m_outputName = c->content; break; case IMPORT_INPUT: m_inputName = c->content; break; case IMPORT_NONE: context.reportError("Unexpected node name.\n"); delete child; return; } } else { MediaFormatIO* io = dynamic_cast(child); if(!io) { context.reportError("Unexpected element.\n"); delete child; return; } media_format f; err = io->getFormat(f); if(err < B_OK) { context.reportError("Malformed format.\n"); delete child; return; } switch(m_importState) { case IMPORT_OUTPUT: m_outputFormat = f; break; case IMPORT_INPUT: m_inputFormat = f; break; case IMPORT_NONE: m_requestedFormat = f; break; } } if(child) delete child; } void ConnectionIO::xmlImportComplete( ImportContext& context) { // +++++ } void ConnectionIO::xmlImportChildBegin( const char* name, ImportContext& context) { if(!strcmp(name, "input")) { if(m_importState != IMPORT_NONE) { context.reportError("ConnectionIO: unexpected nested child element\n"); return; } m_importState = IMPORT_INPUT; } else if(!strcmp(name, "output")) { if(m_importState != IMPORT_NONE) { context.reportError("ConnectionIO: unexpected nested child element\n"); return; } m_importState = IMPORT_OUTPUT; } else context.reportError("ConnectionIO: unexpected child element\n"); } void ConnectionIO::xmlImportChildComplete( const char* name, ImportContext& context) { TOUCH(name); TOUCH(context); m_importState = IMPORT_NONE; } // END -- ConnectionIO.cpp --