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