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