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