1 // DormantNodeIO.cpp 2 3 #include "DormantNodeIO.h" 4 #include "ImportContext.h" 5 #include "ExportContext.h" 6 #include "StringContent.h" 7 8 #include "NodeManager.h" 9 10 #include <Debug.h> 11 #include <MediaAddOn.h> 12 #include <MediaDefs.h> 13 #include <MediaRoster.h> 14 #include <Path.h> 15 16 #include <cstdlib> 17 18 #include "route_app_io.h" 19 20 __USE_CORTEX_NAMESPACE 21 22 // -------------------------------------------------------- // 23 // *** ctor/dtor 24 // -------------------------------------------------------- // 25 26 DormantNodeIO::~DormantNodeIO() {} 27 28 // initialize for import (to defaults) 29 DormantNodeIO::DormantNodeIO() : 30 m_kinds(0LL), 31 m_flavorID(0), 32 m_flags(0), 33 m_runMode(0), 34 m_recordingDelay(0), 35 m_cycle(false), 36 m_exportValid(false) {} 37 38 // initialize for export 39 DormantNodeIO::DormantNodeIO( 40 NodeRef* ref, 41 const char* nodeKey) : 42 m_exportValid(false) { 43 44 ASSERT(ref); 45 ASSERT(nodeKey); 46 status_t err; 47 48 m_nodeKey = nodeKey; 49 50 // * extract dormant-node info 51 dormant_node_info info; 52 err = ref->getDormantNodeInfo(&info); 53 if(err < B_OK) { 54 PRINT(( 55 "!!! DormantNodeIO(): getDormantNodeInfo() failed:\n" 56 " %s\n", 57 strerror(err))); 58 return; 59 } 60 61 dormant_flavor_info flavorInfo; 62 err = BMediaRoster::Roster()->GetDormantFlavorInfoFor( 63 info, &flavorInfo); 64 if(err < B_OK) { 65 PRINT(( 66 "!!! DormantNodeIO(): GetDormantFlavorInfoFor() failed:\n" 67 " %s\n", 68 strerror(err))); 69 return; 70 } 71 72 m_dormantName = flavorInfo.name; 73 m_flavorID = info.flavor_id; 74 m_kinds = flavorInfo.kinds; 75 76 m_flags = ref->flags(); 77 entry_ref file; 78 if(ref->getFile(&file) == B_OK) 79 m_entry.SetTo(&file); 80 81 m_runMode = ref->runMode(); 82 m_recordingDelay = ref->recordingDelay(); 83 m_cycle = ref->isCycling(); 84 85 // done extracting node info; ready for export 86 m_exportValid = true; 87 } 88 89 // -------------------------------------------------------- // 90 // *** document-type setup 91 // -------------------------------------------------------- // 92 93 /*static*/ 94 void DormantNodeIO::AddTo( 95 XML::DocumentType* docType) { 96 97 // map self 98 docType->addMapping(new Mapping<DormantNodeIO>(_DORMANT_NODE_ELEMENT)); 99 100 // // map simple (content-only) elements 101 // // +++++ should these be added at a higher level, since they're 102 // // shared? no harm is done if one is added more than once, 103 // // since they'll always map to StringContent. 104 // // +++++ 105 // docType->addMapping(new Mapping<StringContent>(_NAME_ELEMENT)); 106 // docType->addMapping(new Mapping<StringContent>(_KIND_ELEMENT)); 107 // docType->addMapping(new Mapping<StringContent>(_FLAVOR_ID_ELEMENT)); 108 // docType->addMapping(new Mapping<StringContent>(_FLAG_ELEMENT)); 109 // docType->addMapping(new Mapping<StringContent>(_RUN_MODE_ELEMENT)); 110 // docType->addMapping(new Mapping<StringContent>(_RECORDING_DELAY_ELEMENT)); 111 // docType->addMapping(new Mapping<StringContent>(_CYCLE_ELEMENT)); 112 // docType->addMapping(new Mapping<StringContent>(_REF_ELEMENT)); 113 } 114 115 // -------------------------------------------------------- // 116 // *** operations 117 // -------------------------------------------------------- // 118 119 // call when object imported to create the described node 120 121 // +++++ 122 123 status_t DormantNodeIO::instantiate( 124 NodeManager* manager, 125 NodeRef** outRef) { 126 127 status_t err; 128 BPath p; 129 if(m_entry.InitCheck() == B_OK) 130 m_entry.GetPath(&p); 131 132 // PRINT(( 133 // "DormantNodeIO:\n" 134 // " key: %s\n" 135 // " name: %s\n" 136 // " flavor: %ld\n" 137 // " kinds: %Lx\n" 138 // " flags: %lx\n" 139 // " runMode: %ld\n" 140 // " recDelay: %Ld\n" 141 // " cycle: %s\n" 142 // " entry: %s\n\n", 143 // m_nodeKey.String(), 144 // m_dormantName.String(), 145 // m_flavorID, 146 // m_kinds, 147 // m_flags, 148 // m_runMode, 149 // m_recordingDelay, 150 // m_cycle ? "true" : "false", 151 // p.Path())); 152 153 // find matching dormant node 154 dormant_node_info info; 155 err = _matchDormantNode(&info); 156 if(err < B_OK) { 157 PRINT(( 158 "!!! _matchDormantNode() failed: %s\n", strerror(err))); 159 return err; 160 } 161 162 // instantiate node 163 err = manager->instantiate( 164 info, 165 outRef, 166 B_INFINITE_TIMEOUT, 167 m_flags); 168 if(err < B_OK) { 169 PRINT(( 170 "!!! instantiate() failed: %s\n", strerror(err))); 171 return err; 172 } 173 174 entry_ref mediaRef; 175 if(m_entry.InitCheck() == B_OK && m_entry.GetRef(&mediaRef) == B_OK) { 176 // set ref 177 err = (*outRef)->setFile(mediaRef); 178 if(err < B_OK) { 179 PRINT(( 180 "!!! WARNING: setFile() failed: %s\n", strerror(err))); 181 } 182 } 183 184 // set run mode 185 if(m_runMode) 186 (*outRef)->setRunMode(m_runMode, m_recordingDelay); 187 188 // set cycle state 189 if(m_cycle) 190 (*outRef)->setCycling(true); 191 192 return B_OK; 193 } 194 195 status_t DormantNodeIO::_matchDormantNode( 196 dormant_node_info* outInfo) { 197 198 status_t err; 199 200 // fetch all dormant nodes matching the signature 201 const int32 bufferSize = 32; 202 dormant_node_info buffer[bufferSize]; 203 int32 count = bufferSize; 204 err = BMediaRoster::Roster()->GetDormantNodes( 205 buffer, 206 &count, 207 0, 208 0, 209 m_dormantName.String(), 210 m_kinds, 211 0 /*~m_kinds*/); 212 if(err < B_OK) 213 return err; 214 215 if(!count) 216 return B_NAME_NOT_FOUND; 217 218 for(int32 n = 0; n < count; ++n) { 219 if(buffer[n].flavor_id == m_flavorID) { 220 *outInfo = buffer[n]; 221 return B_OK; 222 } 223 } 224 225 // didn't match flavor id 226 return B_BAD_INDEX; 227 } 228 229 230 // -------------------------------------------------------- // 231 // *** IPersistent 232 // -------------------------------------------------------- // 233 234 // -------------------------------------------------------- // 235 // EXPORT: 236 // -------------------------------------------------------- // 237 238 //inline void _write_simple( 239 // const char* element, 240 // const char* value, 241 // ExportContext& context) { 242 // 243 // context.beginElement(element); 244 // context.beginContent(); 245 // context.writeString(value); 246 // context.endElement(); 247 //} 248 249 // -------------------------------------------------------- // 250 251 void DormantNodeIO::xmlExportBegin( 252 ExportContext& context) const { 253 254 if(!m_exportValid) { 255 context.reportError( 256 "DormantNodeIO::xmlExportBegin():\n" 257 "*** invalid ***\n"); 258 return; 259 } 260 261 context.beginElement(_DORMANT_NODE_ELEMENT); 262 } 263 264 void DormantNodeIO::xmlExportAttributes( 265 ExportContext& context) const { 266 267 context.writeAttr("key", m_nodeKey); 268 } 269 270 void DormantNodeIO::xmlExportContent( 271 ExportContext& context) const { 272 273 context.beginContent(); 274 BString buffer; 275 276 // write dormant-node description 277 context.beginElement(_NAME_ELEMENT); 278 context.beginContent(); 279 context.writeString(m_dormantName); 280 context.endElement(); 281 282 if(m_flavorID > 0) { 283 buffer = ""; 284 buffer << m_flavorID; 285 context.beginElement(_FLAVOR_ID_ELEMENT); 286 context.beginContent(); 287 context.writeString(buffer); 288 context.endElement(); 289 } 290 291 _write_node_kinds(m_kinds, context); 292 // if(m_kinds & B_BUFFER_PRODUCER) 293 // _write_simple(_KIND_ELEMENT, "B_BUFFER_PRODUCER", context); 294 // if(m_kinds & B_BUFFER_CONSUMER) 295 // _write_simple(_KIND_ELEMENT, "B_BUFFER_CONSUMER", context); 296 // if(m_kinds & B_TIME_SOURCE) 297 // _write_simple(_KIND_ELEMENT, "B_TIME_SOURCE", context); 298 // if(m_kinds & B_CONTROLLABLE) 299 // _write_simple(_KIND_ELEMENT, "B_CONTROLLABLE", context); 300 // if(m_kinds & B_FILE_INTERFACE) 301 // _write_simple(_KIND_ELEMENT, "B_FILE_INTERFACE", context); 302 // if(m_kinds & B_ENTITY_INTERFACE) 303 // _write_simple(_KIND_ELEMENT, "B_ENTITY_INTERFACE", context); 304 // if(m_kinds & B_PHYSICAL_INPUT) 305 // _write_simple(_KIND_ELEMENT, "B_PHYSICAL_INPUT", context); 306 // if(m_kinds & B_PHYSICAL_OUTPUT) 307 // _write_simple(_KIND_ELEMENT, "B_PHYSICAL_OUTPUT", context); 308 // if(m_kinds & B_SYSTEM_MIXER) 309 // _write_simple(_KIND_ELEMENT, "B_SYSTEM_MIXER", context); 310 311 // write NodeRef flags 312 if(m_flags & NodeRef::NO_START_STOP) 313 _write_simple(_FLAG_ELEMENT, "NO_START_STOP", context); 314 if(m_flags & NodeRef::NO_SEEK) 315 _write_simple(_FLAG_ELEMENT, "NO_SEEK", context); 316 if(m_flags & NodeRef::NO_PREROLL) 317 _write_simple(_FLAG_ELEMENT, "NO_PREROLL", context); 318 if(m_flags & NodeRef::NO_STOP) 319 _write_simple(_FLAG_ELEMENT, "NO_STOP", context); 320 if(m_flags & NodeRef::NO_ROSTER_WATCH) 321 _write_simple(_FLAG_ELEMENT, "NO_ROSTER_WATCH", context); 322 if(m_flags & NodeRef::NO_POSITION_REPORTING) 323 _write_simple(_FLAG_ELEMENT, "NO_POSITION_REPORTING", context); 324 325 // write transport settings 326 if(m_runMode > 0) { 327 switch(m_runMode) { 328 case BMediaNode::B_OFFLINE: 329 _write_simple(_RUN_MODE_ELEMENT, "B_OFFLINE", context); 330 break; 331 case BMediaNode::B_DECREASE_PRECISION: 332 _write_simple(_RUN_MODE_ELEMENT, "B_DECREASE_PRECISION", context); 333 break; 334 case BMediaNode::B_INCREASE_LATENCY: 335 _write_simple(_RUN_MODE_ELEMENT, "B_INCREASE_LATENCY", context); 336 break; 337 case BMediaNode::B_DROP_DATA: 338 _write_simple(_RUN_MODE_ELEMENT, "B_DROP_DATA", context); 339 break; 340 case BMediaNode::B_RECORDING: 341 _write_simple(_RUN_MODE_ELEMENT, "B_RECORDING", context); 342 buffer = ""; 343 buffer << m_recordingDelay; 344 _write_simple(_RECORDING_DELAY_ELEMENT, buffer.String(), context); 345 break; 346 default: 347 buffer = ""; 348 buffer << m_runMode; 349 _write_simple(_RUN_MODE_ELEMENT, buffer.String(), context); 350 } 351 } 352 353 if(m_cycle) { 354 context.beginElement(_CYCLE_ELEMENT); 355 context.endElement(); 356 } 357 358 BPath p; 359 if( 360 m_entry.InitCheck() == B_OK && 361 m_entry.GetPath(&p) == B_OK) 362 _write_simple(_REF_ELEMENT, p.Path(), context); 363 364 } 365 366 void DormantNodeIO::xmlExportEnd( 367 ExportContext& context) const { 368 369 // finish 370 context.endElement(); 371 } 372 373 374 // -------------------------------------------------------- // 375 // IMPORT: 376 // -------------------------------------------------------- // 377 378 //inline void _read_node_kind( 379 // int64& ioKind, 380 // const char* data, 381 // ImportContext& context) { 382 // 383 // if(!strcmp(data, "B_BUFFER_PRODUCER")) 384 // ioKind |= B_BUFFER_PRODUCER; 385 // else if(!strcmp(data, "B_BUFFER_CONSUMER")) 386 // ioKind |= B_BUFFER_CONSUMER; 387 // else if(!strcmp(data, "B_TIME_SOURCE")) 388 // ioKind |= B_TIME_SOURCE; 389 // else if(!strcmp(data, "B_CONTROLLABLE")) 390 // ioKind |= B_CONTROLLABLE; 391 // else if(!strcmp(data, "B_FILE_INTERFACE")) 392 // ioKind |= B_FILE_INTERFACE; 393 // else if(!strcmp(data, "B_ENTITY_INTERFACE")) 394 // ioKind |= B_ENTITY_INTERFACE; 395 // else if(!strcmp(data, "B_PHYSICAL_INPUT")) 396 // ioKind |= B_PHYSICAL_INPUT; 397 // else if(!strcmp(data, "B_PHYSICAL_OUTPUT")) 398 // ioKind |= B_PHYSICAL_OUTPUT; 399 // else if(!strcmp(data, "B_SYSTEM_MIXER")) 400 // ioKind |= B_SYSTEM_MIXER; 401 // else { 402 // BString err; 403 // err << "_read_noderef_kind(): unknown node kind '" << data << "'\n"; 404 // context.reportWarning(err.String()); 405 // } 406 //} 407 408 inline void _read_noderef_flag( 409 int32& ioFlags, 410 const char* data, 411 ImportContext& context) { 412 413 if(!strcmp(data, "NO_START_STOP")) 414 ioFlags |= NodeRef::NO_START_STOP; 415 else if(!strcmp(data, "NO_SEEK")) 416 ioFlags |= NodeRef::NO_SEEK; 417 else if(!strcmp(data, "NO_PREROLL")) 418 ioFlags |= NodeRef::NO_PREROLL; 419 else if(!strcmp(data, "NO_STOP")) 420 ioFlags |= NodeRef::NO_STOP; 421 else if(!strcmp(data, "NO_ROSTER_WATCH")) 422 ioFlags |= NodeRef::NO_ROSTER_WATCH; 423 else if(!strcmp(data, "NO_POSITION_REPORTING")) 424 ioFlags |= NodeRef::NO_POSITION_REPORTING; 425 else { 426 BString err; 427 err << "_read_noderef_flag(): unknown node flag '" << data << "'\n"; 428 context.reportWarning(err.String()); 429 } 430 } 431 432 inline void _read_run_mode( 433 int32& runMode, 434 const char* data, 435 ImportContext& context) { 436 437 if(!strcmp(data, "B_OFFLINE")) 438 runMode = BMediaNode::B_OFFLINE; 439 else if(!strcmp(data, "B_DECREASE_PRECISION")) 440 runMode = BMediaNode::B_DECREASE_PRECISION; 441 else if(!strcmp(data, "B_INCREASE_LATENCY")) 442 runMode = BMediaNode::B_INCREASE_LATENCY; 443 else if(!strcmp(data, "B_DROP_DATA")) 444 runMode = BMediaNode::B_DROP_DATA; 445 else if(!strcmp(data, "B_RECORDING")) 446 runMode = BMediaNode::B_RECORDING; 447 else { 448 BString err; 449 err << "_read_run_mode(): unknown run mode '" << data << "'\n"; 450 context.reportWarning(err.String()); 451 } 452 } 453 454 inline void _read_entry( 455 BEntry& entry, 456 const char* data, 457 ImportContext& context) { 458 459 entry_ref r; 460 status_t err = get_ref_for_path(data, &r); 461 if(err < B_OK) { 462 BString text; 463 text << "_read_entry_ref(): get_ref_for_path('" << data << "') failed:\n" 464 " " << strerror(err) << "\n"; 465 context.reportWarning(text.String()); 466 } 467 468 entry.SetTo(&r); 469 } 470 471 472 void DormantNodeIO::xmlImportBegin( 473 ImportContext& context) { TOUCH(context); } 474 475 void DormantNodeIO::xmlImportAttribute( 476 const char* key, 477 const char* value, 478 ImportContext& context) { 479 480 if(!strcmp(key, "key")) { 481 m_nodeKey = value; 482 } 483 else { 484 BString err; 485 err << "DormantNodeIO: unknown attribute '" << key << "'\n"; 486 context.reportError(err.String()); 487 } 488 } 489 490 void DormantNodeIO::xmlImportContent( 491 const char* data, 492 uint32 length, 493 ImportContext& context) { TOUCH(data); TOUCH(length); TOUCH(context); } 494 495 void DormantNodeIO::xmlImportChild( 496 IPersistent* child, 497 ImportContext& context) { 498 499 StringContent* obj = dynamic_cast<StringContent*>(child); 500 if(!obj) { 501 BString err; 502 err << "DormantNodeIO: unexpected element '" << 503 context.element() << "'\n"; 504 context.reportError(err.String()); 505 return; 506 } 507 508 if(!strcmp(context.element(), _NAME_ELEMENT)) 509 m_dormantName = obj->content; 510 else if(!strcmp(context.element(), _KIND_ELEMENT)) 511 _read_node_kind(m_kinds, obj->content.String(), context); 512 else if(!strcmp(context.element(), _FLAVOR_ID_ELEMENT)) 513 m_flavorID = atol(obj->content.String()); 514 else if(!strcmp(context.element(), _FLAG_ELEMENT)) 515 _read_noderef_flag(m_flags, obj->content.String(), context); 516 else if(!strcmp(context.element(), _RUN_MODE_ELEMENT)) 517 _read_run_mode(m_runMode, obj->content.String(), context); 518 else if(!strcmp(context.element(), _RECORDING_DELAY_ELEMENT)) 519 m_recordingDelay = strtoll(obj->content.String(), 0, 10); 520 else if(!strcmp(context.element(), _CYCLE_ELEMENT)) 521 m_cycle = true; 522 else if(!strcmp(context.element(), _REF_ELEMENT)) 523 _read_entry(m_entry, obj->content.String(), context); 524 else { 525 BString err; 526 err << "DormantNodeIO: unexpected element '" << 527 context.element() << "'\n"; 528 context.reportError(err.String()); 529 } 530 531 delete child; 532 } 533 534 void DormantNodeIO::xmlImportComplete( 535 ImportContext& context) { TOUCH(context); } //nyi; +++++ final checks? 536 537 538 // END -- DormantNodeIO.cpp -- 539 540