1 /* 2 * Copyright (c) 1999-2000, Eric Moon. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer. 11 * 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. 15 * 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. 18 * 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. 29 */ 30 31 32 // ConnectionIO.cpp 33 34 #include "ConnectionIO.h" 35 #include "LiveNodeIO.h" 36 #include "NodeManager.h" 37 #include "NodeSetIOContext.h" 38 39 #include "MediaFormatIO.h" 40 #include "route_app_io.h" 41 42 #include <vector> 43 #include <Debug.h> 44 45 using namespace std; 46 47 __USE_CORTEX_NAMESPACE 48 49 // -------------------------------------------------------- // 50 // *** ctor/dtor 51 // -------------------------------------------------------- // 52 53 ConnectionIO::~ConnectionIO() { 54 if(m_inputNodeIO) delete m_inputNodeIO; 55 if(m_outputNodeIO) delete m_outputNodeIO; 56 } 57 58 // initialize for import 59 ConnectionIO::ConnectionIO() : 60 m_inputNodeIO(0), 61 m_outputNodeIO(0), 62 m_flags(0), 63 m_exportValid(false), 64 m_importState(IMPORT_NONE) { 65 66 m_outputFormat.type = B_MEDIA_NO_TYPE; 67 m_inputFormat.type = B_MEDIA_NO_TYPE; 68 m_requestedFormat.type = B_MEDIA_NO_TYPE; 69 } 70 71 // initialize for export 72 ConnectionIO::ConnectionIO( 73 const Connection* con, 74 const NodeManager* manager, 75 const NodeSetIOContext* context) : 76 77 m_inputNodeIO(0), 78 m_outputNodeIO(0), 79 m_exportValid(false), 80 m_importState(IMPORT_NONE) { 81 82 ASSERT(con); 83 ASSERT(manager); 84 ASSERT(context); 85 86 if(!con->isValid()) { 87 PRINT(( 88 "!!! ConnectionIO(): invalid connection\n")); 89 return; 90 } 91 92 m_outputNodeIO = new LiveNodeIO( 93 manager, 94 context, 95 con->sourceNode()); 96 97 // fetch output (connection-point) description 98 const char* name; 99 if(con->getOutputHint( 100 &name, 101 &m_outputFormat) == B_OK) 102 m_outputName = name; 103 else { 104 m_outputName = con->outputName(); 105 } 106 107 m_inputNodeIO = new LiveNodeIO( 108 manager, 109 context, 110 con->destinationNode()); 111 112 // fetch input (connection-point) description 113 if(con->getInputHint( 114 &name, 115 &m_inputFormat) == B_OK) 116 m_inputName = name; 117 118 else { 119 m_inputName = con->inputName(); 120 } 121 122 m_requestedFormat = con->requestedFormat(); 123 m_flags = con->flags(); 124 125 m_exportValid = true; 126 } 127 128 // -------------------------------------------------------- // 129 // *** operations 130 // -------------------------------------------------------- // 131 132 // call when object imported to create the described 133 // connection 134 135 // +++++ to do 136 // smarter input/output matching -- if no name/format provided, 137 // pick the first available endpoint. otherwise, make two passes: 138 // 1) match all nodes w/ given name (pass wildcards through to roster) 139 // 2) filter by format 140 141 status_t ConnectionIO::instantiate( 142 NodeManager* manager, 143 const NodeSetIOContext* context, 144 Connection* outCon) { 145 146 // sanity checks 147 ASSERT(manager); 148 if(!m_inputNodeIO || !m_outputNodeIO) 149 return B_NOT_ALLOWED; 150 151 status_t err; 152 media_node_id node; 153 154 // find output node 155 NodeRef* outputRef; 156 err = m_outputNodeIO->getNode(manager, context, &node); 157 if(err < B_OK) 158 return err; 159 err = manager->getNodeRef( 160 node, 161 &outputRef); 162 if(err < B_OK) 163 return err; 164 165 // find output +++++ currently matches by name only 166 const int32 outputBufferSize = 16; 167 media_output outputs[outputBufferSize]; 168 int32 count = outputBufferSize; 169 170 //vector<media_output> outputs; 171 // err = outputRef->getFreeOutputs( 172 // outputs/*, 173 // m_outputFormat.type*/); 174 175 err = outputRef->getFreeOutputs( 176 outputs, 177 outputBufferSize, 178 &count); 179 if(err < B_OK) 180 return err; 181 182 media_output output; 183 bool found = false; 184 for(int n = 0; n < count; ++n) { 185 if(m_outputName == outputs[n].name) { 186 output = outputs[n]; 187 found = true; 188 break; 189 } 190 } 191 if(!found) { 192 PRINT(("!!! output '%s' of node '%s' not found\n", 193 m_outputName.String(), 194 outputRef->name())); 195 return B_NAME_NOT_FOUND; 196 } 197 198 // find input node 199 NodeRef* inputRef; 200 err = m_inputNodeIO->getNode(manager, context, &node); 201 if(err < B_OK) 202 return err; 203 err = manager->getNodeRef( 204 node, 205 &inputRef); 206 if(err < B_OK) 207 return err; 208 209 // find input +++++ currently matches by name only 210 vector<media_input> inputs; 211 err = inputRef->getFreeInputs( 212 inputs /*, 213 m_inputFormat.type*/); 214 if(err < B_OK) 215 return err; 216 217 media_input input; 218 found = false; 219 for(unsigned int n = 0; n < inputs.size(); ++n) { 220 if(m_inputName == inputs[n].name) { 221 input = inputs[n]; 222 found = true; 223 break; 224 } 225 } 226 if(!found) { 227 PRINT(("!!! input '%s' of node '%s' not found\n", 228 m_inputName.String(), 229 inputRef->name())); 230 return B_NAME_NOT_FOUND; 231 } 232 233 // connect 234 Connection con; 235 if(m_requestedFormat.type != B_MEDIA_NO_TYPE) 236 err = manager->connect( 237 output, 238 input, 239 m_requestedFormat, 240 &con); 241 else 242 err = manager->connect( 243 output, 244 input, 245 &con); 246 247 if(err < B_OK) 248 return err; 249 250 if(outCon) 251 *outCon = con; 252 return B_OK; 253 } 254 255 // -------------------------------------------------------- // 256 // *** document-type setup 257 // -------------------------------------------------------- // 258 259 /*static*/ 260 void ConnectionIO::AddTo( 261 XML::DocumentType* docType) { 262 263 // map self 264 docType->addMapping(new Mapping<ConnectionIO>(_CONNECTION_ELEMENT)); 265 266 // map simple (content-only) elements 267 // +++++ should these be added at a higher level, since they're 268 // shared? no harm is done if one is added more than once, 269 // since they'll always map to StringContent -- but it's way 270 // messy! 271 // +++++ 272 //docType->addMapping(new Mapping<StringContent>(_LIVE_NODE_ELEMENT)); 273 // docType->addMapping(new Mapping<StringContent>(_NAME_ELEMENT)); 274 // docType->addMapping(new Mapping<StringContent>(_KIND_ELEMENT)); 275 // docType->addMapping(new Mapping<StringContent>(_FLAG_ELEMENT)); 276 } 277 278 // -------------------------------------------------------- // 279 // *** IPersistent 280 // -------------------------------------------------------- // 281 282 // -------------------------------------------------------- // 283 // EXPORT: 284 // -------------------------------------------------------- // 285 286 287 // -------------------------------------------------------- // 288 void ConnectionIO::xmlExportBegin( 289 ExportContext& context) const { 290 291 if(!m_exportValid) { 292 context.reportError( 293 "ConnectionIO::xmlExportBegin():\n" 294 "*** invalid ***\n"); 295 return; 296 } 297 298 context.beginElement(_CONNECTION_ELEMENT); 299 } 300 301 void ConnectionIO::xmlExportAttributes( 302 ExportContext& context) const { TOUCH(context); } 303 304 void ConnectionIO::xmlExportContent( 305 ExportContext& context) const { 306 307 context.beginContent(); 308 309 // write output 310 { 311 context.beginElement(_OUTPUT_ELEMENT); 312 context.beginContent(); 313 314 // describe the node 315 // LiveNodeIO nodeIO( 316 // m_manager, 317 // dynamic_cast<NodeSetIOContext*>(&context), 318 // m_outputNode); 319 context.writeObject(m_outputNodeIO); 320 321 // context.beginElement(_LIVE_NODE_ELEMENT); 322 // if(m_outputNodeKey.Length()) { 323 // context.writeAttr("key", m_outputNodeKey); 324 // } 325 // else { 326 // _write_simple("name", m_outputNodeName.String(), context); 327 // _write_node_kinds(m_outputNodeKind, context); 328 // } 329 // context.endElement(); // _LIVE_NODE_ELEMENT 330 331 // describe the output 332 333 _write_simple("name", m_outputName.String(), context); 334 335 if(m_outputFormat.type > B_MEDIA_UNKNOWN_TYPE) { 336 MediaFormatIO io(m_outputFormat); 337 context.writeObject(&io); 338 } 339 340 context.endElement(); // _OUTPUT_ELEMENT 341 } 342 343 // write input 344 { 345 context.beginElement(_INPUT_ELEMENT); 346 context.beginContent(); 347 348 // describe the node 349 // LiveNodeIO nodeIO( 350 // m_manager, 351 // dynamic_cast<NodeSetIOContext*>(&context), 352 // m_inputNode); 353 context.writeObject(m_inputNodeIO); 354 355 // context.beginElement(_LIVE_NODE_ELEMENT); 356 // if(m_inputNodeKey.Length()) { 357 // context.writeAttr("key", m_inputNodeKey); 358 // } 359 // else { 360 // _write_simple("name", m_inputNodeName.String(), context); 361 // _write_node_kinds(m_inputNodeKind, context); 362 // } 363 // context.endElement(); // _LIVE_NODE_ELEMENT 364 365 // describe the input 366 367 _write_simple("name", m_inputName.String(), context); 368 369 if(m_inputFormat.type > B_MEDIA_UNKNOWN_TYPE) { 370 MediaFormatIO io(m_inputFormat); 371 context.writeObject(&io); 372 } 373 374 context.endElement(); // _INPUT_ELEMENT 375 } 376 377 // write requested format 378 if(m_requestedFormat.type > B_MEDIA_UNKNOWN_TYPE) { 379 MediaFormatIO io(m_requestedFormat); 380 BString comment = "\n"; 381 comment << context.indentString(); 382 comment << "<!-- initial requested format -->"; 383 context.writeString(comment); 384 context.writeObject(&io); 385 } 386 } 387 388 void ConnectionIO::xmlExportEnd( 389 ExportContext& context) const { 390 391 context.endElement(); // _CONNECTION_ELEMENT 392 } 393 394 // -------------------------------------------------------- // 395 // IMPORT: 396 // -------------------------------------------------------- // 397 398 void ConnectionIO::xmlImportBegin( 399 ImportContext& context) { TOUCH(context); } 400 401 void ConnectionIO::xmlImportAttribute( 402 const char* key, 403 const char* value, 404 ImportContext& context) { TOUCH(key); TOUCH(value); TOUCH(context); } 405 406 void ConnectionIO::xmlImportContent( 407 const char* data, 408 uint32 length, 409 ImportContext& context) { TOUCH(data); TOUCH(length); TOUCH(context); } 410 411 void ConnectionIO::xmlImportChild( 412 IPersistent* child, 413 ImportContext& context) { 414 415 status_t err; 416 417 if(!strcmp(context.element(), _LIVE_NODE_ELEMENT)) { 418 LiveNodeIO* nodeIO = dynamic_cast<LiveNodeIO*>(child); 419 ASSERT(nodeIO); 420 421 // store the LiveNodeIO for now; it will be used in 422 // instantiate() 423 424 switch(m_importState) { 425 case IMPORT_OUTPUT: 426 m_outputNodeIO = nodeIO; 427 child = 0; // don't delete child object 428 break; 429 430 case IMPORT_INPUT: 431 m_inputNodeIO = nodeIO; 432 child = 0; // don't delete child object 433 break; 434 435 case IMPORT_NONE: 436 context.reportError("Unexpected node description.\n"); 437 delete child; 438 return; 439 } 440 } 441 else if(!strcmp(context.element(), _NAME_ELEMENT)) { 442 StringContent* c = dynamic_cast<StringContent*>(child); 443 ASSERT(c); 444 445 switch(m_importState) { 446 case IMPORT_OUTPUT: 447 m_outputName = c->content; 448 break; 449 450 case IMPORT_INPUT: 451 m_inputName = c->content; 452 break; 453 454 case IMPORT_NONE: 455 context.reportError("Unexpected node name.\n"); 456 delete child; 457 return; 458 } 459 } 460 else { 461 MediaFormatIO* io = dynamic_cast<MediaFormatIO*>(child); 462 if(!io) { 463 context.reportError("Unexpected element.\n"); 464 delete child; 465 return; 466 } 467 468 media_format f; 469 err = io->getFormat(f); 470 if(err < B_OK) { 471 context.reportError("Malformed format.\n"); 472 delete child; 473 return; 474 } 475 476 switch(m_importState) { 477 case IMPORT_OUTPUT: 478 m_outputFormat = f; 479 break; 480 481 case IMPORT_INPUT: 482 m_inputFormat = f; 483 break; 484 485 case IMPORT_NONE: 486 m_requestedFormat = f; 487 break; 488 } 489 } 490 491 if(child) 492 delete child; 493 } 494 495 void ConnectionIO::xmlImportComplete( 496 ImportContext& context) { 497 498 // +++++ 499 } 500 501 void ConnectionIO::xmlImportChildBegin( 502 const char* name, 503 ImportContext& context) { 504 505 if(!strcmp(name, "input")) { 506 if(m_importState != IMPORT_NONE) { 507 context.reportError("ConnectionIO: unexpected nested child element\n"); 508 return; 509 } 510 m_importState = IMPORT_INPUT; 511 } 512 else if(!strcmp(name, "output")) { 513 if(m_importState != IMPORT_NONE) { 514 context.reportError("ConnectionIO: unexpected nested child element\n"); 515 return; 516 } 517 m_importState = IMPORT_OUTPUT; 518 } 519 else 520 context.reportError("ConnectionIO: unexpected child element\n"); 521 } 522 523 void ConnectionIO::xmlImportChildComplete( 524 const char* name, 525 ImportContext& context) { 526 TOUCH(name); TOUCH(context); 527 528 m_importState = IMPORT_NONE; 529 } 530 531 // END -- ConnectionIO.cpp -- 532