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