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