xref: /haiku/src/apps/cortex/RouteApp/ConnectionIO.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 // ConnectionIO.cpp
2 
3 #include "ConnectionIO.h"
4 #include "LiveNodeIO.h"
5 #include "NodeManager.h"
6 #include "NodeSetIOContext.h"
7 
8 #include "MediaFormatIO.h"
9 #include "route_app_io.h"
10 
11 #include <vector>
12 #include <Debug.h>
13 
14 __USE_CORTEX_NAMESPACE
15 
16 // -------------------------------------------------------- //
17 // *** ctor/dtor
18 // -------------------------------------------------------- //
19 
20 ConnectionIO::~ConnectionIO() {
21 	if(m_inputNodeIO) delete m_inputNodeIO;
22 	if(m_outputNodeIO) delete m_outputNodeIO;
23 }
24 
25 // initialize for import
26 ConnectionIO::ConnectionIO() :
27 	m_inputNodeIO(0),
28 	m_outputNodeIO(0),
29 	m_flags(0),
30 	m_exportValid(false),
31 	m_importState(IMPORT_NONE) {
32 
33 	m_outputFormat.type = B_MEDIA_NO_TYPE;
34 	m_inputFormat.type = B_MEDIA_NO_TYPE;
35 	m_requestedFormat.type = B_MEDIA_NO_TYPE;
36 }
37 
38 // initialize for export
39 ConnectionIO::ConnectionIO(
40 	const Connection*				con,
41 	const NodeManager*			manager,
42 	const NodeSetIOContext*	context) :
43 
44 	m_inputNodeIO(0),
45 	m_outputNodeIO(0),
46 	m_exportValid(false),
47 	m_importState(IMPORT_NONE) {
48 
49 	ASSERT(con);
50 	ASSERT(manager);
51 	ASSERT(context);
52 	status_t err;
53 
54 	if(!con->isValid()) {
55 		PRINT((
56 			"!!! ConnectionIO(): invalid connection\n"));
57 		return;
58 	}
59 
60 	m_outputNodeIO = new LiveNodeIO(
61 		manager,
62 		context,
63 		con->sourceNode());
64 
65 	// fetch output (connection-point) description
66 	const char* name;
67 	if(con->getOutputHint(
68 		&name,
69 		&m_outputFormat) == B_OK)
70 		m_outputName = name;
71 	else {
72 		m_outputName = con->outputName();
73 	}
74 
75 	m_inputNodeIO = new LiveNodeIO(
76 		manager,
77 		context,
78 		con->destinationNode());
79 
80 	// fetch input (connection-point) description
81 	if(con->getInputHint(
82 		&name,
83 		&m_inputFormat) == B_OK)
84 		m_inputName = name;
85 
86 	else {
87 		m_inputName = con->inputName();
88 	}
89 
90 	m_requestedFormat = con->requestedFormat();
91 	m_flags = con->flags();
92 
93 	m_exportValid = true;
94 }
95 
96 // -------------------------------------------------------- //
97 // *** operations
98 // -------------------------------------------------------- //
99 
100 // call when object imported to create the described
101 // connection
102 
103 // +++++ to do
104 // smarter input/output matching -- if no name/format provided,
105 // pick the first available endpoint.  otherwise, make two passes:
106 // 1) match all nodes w/ given name (pass wildcards through to roster)
107 // 2) filter by format
108 
109 status_t ConnectionIO::instantiate(
110 	NodeManager*						manager,
111 	const NodeSetIOContext*	context,
112 	Connection*							outCon) {
113 
114 	// sanity checks
115 	ASSERT(manager);
116 	if(!m_inputNodeIO || !m_outputNodeIO)
117 		return B_NOT_ALLOWED;
118 
119 	status_t err;
120 	media_node_id node;
121 
122 	// find output node
123 	NodeRef* outputRef;
124 	err = m_outputNodeIO->getNode(manager, context, &node);
125 	if(err < B_OK)
126 		return err;
127 	err = manager->getNodeRef(
128 		node,
129 		&outputRef);
130 	if(err < B_OK)
131 		return err;
132 
133 	// find output +++++ currently matches by name only
134 	const int32 outputBufferSize = 16;
135 	media_output outputs[outputBufferSize];
136 	int32 count = outputBufferSize;
137 
138 	//vector<media_output> outputs;
139 //	err = outputRef->getFreeOutputs(
140 //		outputs/*,
141 //		m_outputFormat.type*/);
142 
143 	err = outputRef->getFreeOutputs(
144 		outputs,
145 		outputBufferSize,
146 		&count);
147 	if(err < B_OK)
148 		return err;
149 
150 	media_output output;
151 	bool found = false;
152 	for(int n = 0; n < count; ++n) {
153 		if(m_outputName == outputs[n].name) {
154 			output = outputs[n];
155 			found = true;
156 			break;
157 		}
158 	}
159 	if(!found) {
160 		PRINT(("!!! output '%s' of node '%s' not found\n",
161 			m_outputName.String(),
162 			outputRef->name()));
163 		return B_NAME_NOT_FOUND;
164 	}
165 
166 	// find input node
167 	NodeRef* inputRef;
168 	err = m_inputNodeIO->getNode(manager, context, &node);
169 	if(err < B_OK)
170 		return err;
171 	err = manager->getNodeRef(
172 		node,
173 		&inputRef);
174 	if(err < B_OK)
175 		return err;
176 
177 	// find input +++++ currently matches by name only
178 	vector<media_input> inputs;
179 	err = inputRef->getFreeInputs(
180 		inputs /*,
181 		m_inputFormat.type*/);
182 	if(err < B_OK)
183 		return err;
184 
185 	media_input input;
186 	found = false;
187 	for(unsigned int n = 0; n < inputs.size(); ++n) {
188 		if(m_inputName == inputs[n].name) {
189 			input = inputs[n];
190 			found = true;
191 			break;
192 		}
193 	}
194 	if(!found) {
195 		PRINT(("!!! input '%s' of node '%s' not found\n",
196 			m_inputName.String(),
197 			inputRef->name()));
198 		return B_NAME_NOT_FOUND;
199 	}
200 
201 	// connect
202 	Connection con;
203 	if(m_requestedFormat.type != B_MEDIA_NO_TYPE)
204 		err = manager->connect(
205 			output,
206 			input,
207 			m_requestedFormat,
208 			&con);
209 	else
210 		err = manager->connect(
211 			output,
212 			input,
213 			&con);
214 
215 	if(err < B_OK)
216 		return err;
217 
218 	if(outCon)
219 		*outCon = con;
220 	return B_OK;
221 }
222 
223 // -------------------------------------------------------- //
224 // *** document-type setup
225 // -------------------------------------------------------- //
226 
227 /*static*/
228 void ConnectionIO::AddTo(
229 	XML::DocumentType*			docType) {
230 
231 	// map self
232 	docType->addMapping(new Mapping<ConnectionIO>(_CONNECTION_ELEMENT));
233 
234 	// map simple (content-only) elements
235 	// +++++ should these be added at a higher level, since they're
236 	//       shared?  no harm is done if one is added more than once,
237 	//       since they'll always map to StringContent -- but it's way
238 	//       messy!
239 	// +++++
240 	//docType->addMapping(new Mapping<StringContent>(_LIVE_NODE_ELEMENT));
241 //	docType->addMapping(new Mapping<StringContent>(_NAME_ELEMENT));
242 //	docType->addMapping(new Mapping<StringContent>(_KIND_ELEMENT));
243 //	docType->addMapping(new Mapping<StringContent>(_FLAG_ELEMENT));
244 }
245 
246 // -------------------------------------------------------- //
247 // *** IPersistent
248 // -------------------------------------------------------- //
249 
250 // -------------------------------------------------------- //
251 // EXPORT:
252 // -------------------------------------------------------- //
253 
254 
255 // -------------------------------------------------------- //
256 void ConnectionIO::xmlExportBegin(
257 	ExportContext&						context) const {
258 
259 	if(!m_exportValid) {
260 		context.reportError(
261 			"ConnectionIO::xmlExportBegin():\n"
262 			"*** invalid ***\n");
263 		return;
264 	}
265 
266 	context.beginElement(_CONNECTION_ELEMENT);
267 }
268 
269 void ConnectionIO::xmlExportAttributes(
270 	ExportContext&						context) const { TOUCH(context); }
271 
272 void ConnectionIO::xmlExportContent(
273 	ExportContext&						context) const {
274 
275 	context.beginContent();
276 
277 	// write output
278 	{
279 		context.beginElement(_OUTPUT_ELEMENT);
280 		context.beginContent();
281 
282 		// describe the node
283 //		LiveNodeIO nodeIO(
284 //			m_manager,
285 //			dynamic_cast<NodeSetIOContext*>(&context),
286 //			m_outputNode);
287 		context.writeObject(m_outputNodeIO);
288 
289 //		context.beginElement(_LIVE_NODE_ELEMENT);
290 //		if(m_outputNodeKey.Length()) {
291 //			context.writeAttr("key", m_outputNodeKey);
292 //		}
293 //		else {
294 //			_write_simple("name", m_outputNodeName.String(), context);
295 //			_write_node_kinds(m_outputNodeKind, context);
296 //		}
297 //		context.endElement(); // _LIVE_NODE_ELEMENT
298 
299 		// describe the output
300 
301 		_write_simple("name", m_outputName.String(), context);
302 
303 		if(m_outputFormat.type > B_MEDIA_UNKNOWN_TYPE) {
304 			MediaFormatIO io(m_outputFormat);
305 			context.writeObject(&io);
306 		}
307 
308 		context.endElement(); // _OUTPUT_ELEMENT
309 	}
310 
311 	// write input
312 	{
313 		context.beginElement(_INPUT_ELEMENT);
314 		context.beginContent();
315 
316 		// describe the node
317 //		LiveNodeIO nodeIO(
318 //			m_manager,
319 //			dynamic_cast<NodeSetIOContext*>(&context),
320 //			m_inputNode);
321 		context.writeObject(m_inputNodeIO);
322 
323 //		context.beginElement(_LIVE_NODE_ELEMENT);
324 //		if(m_inputNodeKey.Length()) {
325 //			context.writeAttr("key", m_inputNodeKey);
326 //		}
327 //		else {
328 //			_write_simple("name", m_inputNodeName.String(), context);
329 //			_write_node_kinds(m_inputNodeKind, context);
330 //		}
331 //		context.endElement(); // _LIVE_NODE_ELEMENT
332 
333 		// describe the input
334 
335 		_write_simple("name", m_inputName.String(), context);
336 
337 		if(m_inputFormat.type > B_MEDIA_UNKNOWN_TYPE) {
338 			MediaFormatIO io(m_inputFormat);
339 			context.writeObject(&io);
340 		}
341 
342 		context.endElement(); // _INPUT_ELEMENT
343 	}
344 
345 	// write requested format
346 	if(m_requestedFormat.type > B_MEDIA_UNKNOWN_TYPE) {
347 		MediaFormatIO io(m_requestedFormat);
348 		BString comment = "\n";
349 		comment << context.indentString();
350 		comment << "<!-- initial requested format -->";
351 		context.writeString(comment);
352 		context.writeObject(&io);
353 	}
354 }
355 
356 void ConnectionIO::xmlExportEnd(
357 	ExportContext&						context) const {
358 
359 	context.endElement(); // _CONNECTION_ELEMENT
360 }
361 
362 // -------------------------------------------------------- //
363 // IMPORT:
364 // -------------------------------------------------------- //
365 
366 void ConnectionIO::xmlImportBegin(
367 	ImportContext&						context) { TOUCH(context); }
368 
369 void ConnectionIO::xmlImportAttribute(
370 	const char*								key,
371 	const char*								value,
372 	ImportContext&						context) { TOUCH(key); TOUCH(value); TOUCH(context); }
373 
374 void ConnectionIO::xmlImportContent(
375 	const char*								data,
376 	uint32										length,
377 	ImportContext&						context) { TOUCH(data); TOUCH(length); TOUCH(context); }
378 
379 void ConnectionIO::xmlImportChild(
380 	IPersistent*							child,
381 	ImportContext&						context) {
382 
383 	status_t err;
384 
385 	if(!strcmp(context.element(), _LIVE_NODE_ELEMENT)) {
386 		LiveNodeIO* nodeIO = dynamic_cast<LiveNodeIO*>(child);
387 		ASSERT(nodeIO);
388 
389 		// store the LiveNodeIO for now; it will be used in
390 		// instantiate()
391 
392 		switch(m_importState) {
393 			case IMPORT_OUTPUT:
394 				m_outputNodeIO = nodeIO;
395 				child = 0; // don't delete child object
396 				break;
397 
398 			case IMPORT_INPUT:
399 				m_inputNodeIO = nodeIO;
400 				child = 0; // don't delete child object
401 				break;
402 
403 			case IMPORT_NONE:
404 				context.reportError("Unexpected node description.\n");
405 				delete child;
406 				return;
407 		}
408 	}
409 	else if(!strcmp(context.element(), _NAME_ELEMENT)) {
410 		StringContent* c = dynamic_cast<StringContent*>(child);
411 		ASSERT(c);
412 
413 		switch(m_importState) {
414 			case IMPORT_OUTPUT:
415 				m_outputName = c->content;
416 				break;
417 
418 			case IMPORT_INPUT:
419 				m_inputName = c->content;
420 				break;
421 
422 			case IMPORT_NONE:
423 				context.reportError("Unexpected node name.\n");
424 				delete child;
425 				return;
426 		}
427 	}
428 	else {
429 		MediaFormatIO* io = dynamic_cast<MediaFormatIO*>(child);
430 		if(!io) {
431 			context.reportError("Unexpected element.\n");
432 			delete child;
433 			return;
434 		}
435 
436 		media_format f;
437 		err = io->getFormat(f);
438 		if(err < B_OK) {
439 			context.reportError("Malformed format.\n");
440 			delete child;
441 			return;
442 		}
443 
444 		switch(m_importState) {
445 			case IMPORT_OUTPUT:
446 				m_outputFormat = f;
447 				break;
448 
449 			case IMPORT_INPUT:
450 				m_inputFormat = f;
451 				break;
452 
453 			case IMPORT_NONE:
454 				m_requestedFormat = f;
455 				break;
456 		}
457 	}
458 
459 	if(child)
460 		delete child;
461 }
462 
463 void ConnectionIO::xmlImportComplete(
464 	ImportContext&						context) {
465 
466 	// +++++
467 }
468 
469 void ConnectionIO::xmlImportChildBegin(
470 	const char*								name,
471 	ImportContext&						context) {
472 
473 	if(!strcmp(name, "input")) {
474 		if(m_importState != IMPORT_NONE) {
475 			context.reportError("ConnectionIO: unexpected nested child element\n");
476 			return;
477 		}
478 		m_importState = IMPORT_INPUT;
479 	}
480 	else if(!strcmp(name, "output")) {
481 		if(m_importState != IMPORT_NONE) {
482 			context.reportError("ConnectionIO: unexpected nested child element\n");
483 			return;
484 		}
485 		m_importState = IMPORT_OUTPUT;
486 	}
487 	else
488 		context.reportError("ConnectionIO: unexpected child element\n");
489 }
490 
491 void ConnectionIO::xmlImportChildComplete(
492 	const char*								name,
493 	ImportContext&						context) {
494 	TOUCH(name); TOUCH(context);
495 
496 	m_importState = IMPORT_NONE;
497 }
498 
499 // END -- ConnectionIO.cpp --