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