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
~DormantNodeIO()57 DormantNodeIO::~DormantNodeIO() {}
58
59 // initialize for import (to defaults)
DormantNodeIO()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
DormantNodeIO(NodeRef * ref,const char * nodeKey)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*/
AddTo(XML::DocumentType * docType)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
instantiate(NodeManager * manager,NodeRef ** outRef)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
_matchDormantNode(dormant_node_info * outInfo)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
xmlExportBegin(ExportContext & context) const282 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
xmlExportAttributes(ExportContext & context) const295 void DormantNodeIO::xmlExportAttributes(
296 ExportContext& context) const {
297
298 context.writeAttr("key", m_nodeKey);
299 }
300
xmlExportContent(ExportContext & context) const301 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
xmlExportEnd(ExportContext & context) const397 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
_read_noderef_flag(int32 & ioFlags,const char * data,ImportContext & context)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
_read_run_mode(int32 & runMode,const char * data,ImportContext & context)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
_read_entry(BEntry & entry,const char * data,ImportContext & context)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
xmlImportBegin(ImportContext & context)503 void DormantNodeIO::xmlImportBegin(
504 ImportContext& context) { TOUCH(context); }
505
xmlImportAttribute(const char * key,const char * value,ImportContext & context)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
xmlImportContent(const char * data,uint32 length,ImportContext & context)521 void DormantNodeIO::xmlImportContent(
522 const char* data,
523 uint32 length,
524 ImportContext& context) { TOUCH(data); TOUCH(length); TOUCH(context); }
525
xmlImportChild(IPersistent * child,ImportContext & context)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
xmlImportComplete(ImportContext & context)565 void DormantNodeIO::xmlImportComplete(
566 ImportContext& context) { TOUCH(context); } //nyi; +++++ final checks?
567
568
569 // END -- DormantNodeIO.cpp --
570
571