xref: /haiku/src/apps/cortex/RouteApp/DormantNodeIO.cpp (revision 1e36cfc2721ef13a187c6f7354dc9cbc485e89d3)
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