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