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// MediaIcon.cpp
33
34#include "MediaIcon.h"
35#include "MediaIconBits.h"
36#include "AddOnHostProtocol.h"
37
38// Application Kit
39#include <Application.h>
40#include <Roster.h>
41// Media Kit
42#include <MediaDefs.h>
43#include <MediaNode.h>
44#include <MediaRoster.h>
45#include <MediaAddOn.h>
46// Storage Kit
47#include <NodeInfo.h>
48// Support Kit
49#include <String.h>
50// Interface Kit
51#include <IconUtils.h>
52
53
54__USE_CORTEX_NAMESPACE
55
56#include <Debug.h>
57#define D_ALLOC(x) //PRINT (x)
58#define D_INTERNAL(x) //PRINT (x)
59
60// -------------------------------------------------------- //
61// *** ctor/dtor
62// -------------------------------------------------------- //
63
64MediaIcon::MediaIcon(
65	const live_node_info &nodeInfo,
66	icon_size size)
67	: BBitmap(BRect(0.0, 0.0, size - 1.0, size - 1.0), B_RGBA32),
68	  m_size(size),
69	  m_nodeKind(nodeInfo.node.kind) {
70	D_ALLOC(("MediaIcon::MediaIcon(live_node_info '%s')\n", nodeInfo.name));
71
72	_findIconFor(nodeInfo);
73}
74
75MediaIcon::MediaIcon(
76	const dormant_node_info &nodeInfo,
77	icon_size size)
78	: BBitmap(BRect(0.0, 0.0, size - 1.0, size - 1.0), B_RGBA32),
79	  m_size(size),
80	  m_nodeKind(0) {
81	D_ALLOC(("MediaIcon::MediaIcon(dormant_node_info '%s')\n", nodeInfo.name));
82
83	_findIconFor(nodeInfo);
84}
85
86MediaIcon::~MediaIcon() {
87	D_ALLOC(("MediaIcon::~MediaIcon()\n"));
88
89}
90
91// -------------------------------------------------------- //
92// *** internal accessors (private)
93// -------------------------------------------------------- //
94
95bool MediaIcon::_isPhysicalInput() const {
96	D_INTERNAL(("MediaIcon::_isPhysicalInput()\n"));
97
98	return ((m_nodeKind & B_PHYSICAL_INPUT)
99	     && (m_nodeKind & B_BUFFER_PRODUCER));
100}
101
102bool MediaIcon::_isPhysicalOutput() const {
103	D_INTERNAL(("MediaIcon::_isPhysicalOutput()\n"));
104
105	return ((m_nodeKind & B_PHYSICAL_OUTPUT)
106	     && (m_nodeKind & B_BUFFER_CONSUMER));;
107}
108
109bool MediaIcon::_isProducer() const {
110	D_INTERNAL(("MediaIcon::_isProducer()\n"));
111
112	return (!(m_nodeKind & B_BUFFER_CONSUMER) &&
113			 (m_nodeKind & B_BUFFER_PRODUCER) &&
114			!(m_nodeKind & B_PHYSICAL_INPUT)  &&
115			!(m_nodeKind & B_PHYSICAL_OUTPUT));
116}
117
118bool MediaIcon::_isFilter() const {
119	D_INTERNAL(("MediaIcon::_isFilter()\n"));
120
121	return ( (m_nodeKind & B_BUFFER_CONSUMER) &&
122			 (m_nodeKind & B_BUFFER_PRODUCER) &&
123		    !(m_nodeKind & B_PHYSICAL_INPUT)  &&
124		    !(m_nodeKind & B_PHYSICAL_OUTPUT));
125}
126
127bool MediaIcon::_isConsumer() const {
128	D_INTERNAL(("MediaIcon::_isConsumer()\n"));
129
130	return ( (m_nodeKind & B_BUFFER_CONSUMER) &&
131		    !(m_nodeKind & B_BUFFER_PRODUCER) &&
132		    !(m_nodeKind & B_PHYSICAL_INPUT)  &&
133		    !(m_nodeKind & B_PHYSICAL_OUTPUT));
134}
135
136bool MediaIcon::_isSystemMixer() const {
137	D_INTERNAL(("MediaIcon::_isSystemMixer()\n"));
138
139	return (m_nodeKind & B_SYSTEM_MIXER);
140}
141
142bool MediaIcon::_isTimeSource() const {
143	D_INTERNAL(("MediaIcon::_isTimeSource()\n"));
144
145	return ((m_nodeKind & B_TIME_SOURCE) &&
146		   !(m_nodeKind & B_PHYSICAL_INPUT) &&
147		   !(m_nodeKind & B_PHYSICAL_OUTPUT));
148}
149
150// -------------------------------------------------------- //
151// *** internal operations (private)
152// -------------------------------------------------------- //
153
154void MediaIcon::_findIconFor(
155	const live_node_info &nodeInfo) {
156	D_INTERNAL(("MediaIcon::_findIconFor(live_node_info)\n"));
157
158	BMediaRoster *roster = BMediaRoster::CurrentRoster();
159	if (m_nodeKind & B_FILE_INTERFACE) {
160		entry_ref ref;
161		if ((roster && (roster->GetRefFor(nodeInfo.node, &ref) == B_OK))
162		 && (BNodeInfo::GetTrackerIcon(&ref, this, m_size) == B_OK)) {
163			return;
164		}
165	}
166	dormant_node_info dormantNodeInfo;
167	if  (roster
168	 && (roster->GetDormantNodeFor(nodeInfo.node, &dormantNodeInfo) == B_OK)) {
169		D_INTERNAL((" -> instantiated from dormant node\n"));
170		_findIconFor(dormantNodeInfo);
171	}
172	else {
173		D_INTERNAL((" -> application internal node\n"));
174		port_info portInfo;
175		app_info appInfo;
176		if ((get_port_info(nodeInfo.node.port, &portInfo) == B_OK)
177		 && (be_roster->GetRunningAppInfo(portInfo.team, &appInfo) == B_OK)) {
178			D_INTERNAL((" -> application info found: %s\n", appInfo.signature));
179			app_info thisAppInfo;
180			if ((be_app->GetAppInfo(&thisAppInfo) != B_OK)
181			 || ((strcmp(appInfo.signature, thisAppInfo.signature) != 0)
182			 && (strcmp(appInfo.signature, addon_host::g_appSignature) != 0))) {
183				// only use app icon if the node doesn't belong to our team
184				// or the addon-host
185				BNodeInfo::GetTrackerIcon(&appInfo.ref, this, m_size);
186				return;
187			}
188		}
189		bool audioIn = false, audioOut = false, videoIn = false, videoOut = false;
190		_getMediaTypesFor(nodeInfo, &audioIn, &audioOut, &videoIn, &videoOut);
191		_findDefaultIconFor(audioIn, audioOut, videoIn, videoOut);
192	}
193}
194
195
196void
197MediaIcon::_findIconFor(const dormant_node_info &nodeInfo)
198{
199	D_INTERNAL(("MediaIcon::_findIconFor(dormant_node_info)\n"));
200
201	dormant_flavor_info flavorInfo;
202	BMediaRoster *roster = BMediaRoster::CurrentRoster();
203	status_t error = roster->GetDormantFlavorInfoFor(nodeInfo, &flavorInfo);
204	if (error == B_OK) {
205		m_nodeKind = flavorInfo.kinds;
206		bool audioIn = false, audioOut = false;
207		bool videoIn = false, videoOut = false;
208		_getMediaTypesFor(flavorInfo, &audioIn, &audioOut, &videoIn, &videoOut);
209		_findDefaultIconFor(audioIn, audioOut, videoIn, videoOut);
210	} else if (BString(nodeInfo.name).Compare("System clock") == 0) {
211		BIconUtils::GetVectorIcon(M_TIME_SOURCE_ICON,
212			sizeof(M_TIME_SOURCE_ICON), this);
213	} else {
214		// use generic icon in case we couldn't get any info
215		BIconUtils::GetVectorIcon(M_GENERIC_ICON,
216			sizeof(M_GENERIC_ICON), this);
217	}
218}
219
220
221void
222MediaIcon::_getMediaTypesFor(const live_node_info &nodeInfo, bool *audioIn,
223	bool *audioOut, bool *videoIn, bool *videoOut)
224{
225	D_INTERNAL(("MediaIcon::_getMediaTypeFor(live_node_info)\n"));
226
227	// get the media_types supported by this node
228	const int32 numberOfInputs = 4;
229	int32 numberOfFreeInputs, numberOfConnectedInputs;
230	media_input inputs[numberOfInputs];
231	const int32 numberOfOutputs = 4;
232	int32 numberOfFreeOutputs, numberOfConnectedOutputs;
233	media_output outputs[numberOfOutputs];
234	BMediaRoster *roster = BMediaRoster::CurrentRoster();
235	if (roster->GetFreeInputsFor(nodeInfo.node, inputs, numberOfInputs,
236			&numberOfFreeInputs) == B_OK) {
237		for (int32 i = 0; i < numberOfFreeInputs; i++) {
238			if ((inputs[i].format.type == B_MEDIA_RAW_AUDIO)
239			 || (inputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
240				*audioIn = true;
241				continue;
242			}
243			if ((inputs[i].format.type == B_MEDIA_RAW_VIDEO)
244			 || (inputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
245				*videoIn = true;
246			}
247		}
248	}
249	if (roster->GetConnectedInputsFor(nodeInfo.node, inputs, numberOfInputs,
250			&numberOfConnectedInputs) == B_OK) {
251		for (int32 i = 0; i < numberOfConnectedInputs; i++) {
252			if ((inputs[i].format.type == B_MEDIA_RAW_AUDIO)
253			 || (inputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
254				*audioIn = true;
255				continue;
256			}
257			if ((inputs[i].format.type == B_MEDIA_RAW_VIDEO)
258			 || (inputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
259				*videoIn = true;
260			}
261		}
262	}
263	if (roster->GetFreeOutputsFor(nodeInfo.node, outputs, numberOfOutputs,
264			&numberOfFreeOutputs) == B_OK) {
265		for (int32 i = 0; i < numberOfFreeOutputs; i++) {
266			if ((outputs[i].format.type == B_MEDIA_RAW_AUDIO)
267			 || (outputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
268				*audioOut = true;
269				continue;
270			}
271			if ((outputs[i].format.type == B_MEDIA_RAW_VIDEO)
272			 || (outputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
273				*videoOut = true;
274			}
275		}
276	}
277	if (roster->GetConnectedOutputsFor(nodeInfo.node, outputs, numberOfOutputs,
278			&numberOfConnectedOutputs) == B_OK) {
279		for (int32 i = 0; i < numberOfConnectedOutputs; i++) {
280			if ((outputs[i].format.type == B_MEDIA_RAW_AUDIO)
281			 || (outputs[i].format.type == B_MEDIA_ENCODED_AUDIO)) {
282				*audioOut = true;
283				continue;
284			}
285			if ((outputs[i].format.type == B_MEDIA_RAW_VIDEO)
286			 || (outputs[i].format.type == B_MEDIA_ENCODED_VIDEO)) {
287				*videoOut = true;
288			}
289		}
290	}
291}
292
293void MediaIcon::_getMediaTypesFor(
294	const dormant_flavor_info &flavorInfo,
295	bool *audioIn,
296	bool *audioOut,
297	bool *videoIn,
298	bool *videoOut) {
299	D_INTERNAL(("MediaIcon::_getMediaTypeFor(dormant_flavor_info)\n"));
300
301	for (int32 i = 0; i < flavorInfo.in_format_count; i++) {
302		if ((flavorInfo.in_formats[i].type == B_MEDIA_RAW_AUDIO)
303		 || (flavorInfo.in_formats[i].type == B_MEDIA_ENCODED_AUDIO)) {
304			*audioIn = true;
305			continue;
306		}
307		if ((flavorInfo.in_formats[i].type == B_MEDIA_RAW_VIDEO)
308		 || (flavorInfo.in_formats[i].type == B_MEDIA_ENCODED_VIDEO)) {
309			*videoIn = true;
310		}
311	}
312	for (int32 i = 0; i < flavorInfo.out_format_count; i++)	{
313		if ((flavorInfo.out_formats[i].type == B_MEDIA_RAW_AUDIO)
314		 || (flavorInfo.out_formats[i].type == B_MEDIA_ENCODED_AUDIO)) {
315			*audioOut = true;
316			continue;
317		}
318		if ((flavorInfo.out_formats[i].type == B_MEDIA_RAW_VIDEO)
319		 || (flavorInfo.out_formats[i].type == B_MEDIA_ENCODED_VIDEO)) {
320			*videoOut = true;
321		}
322	}
323}
324
325void MediaIcon::_findDefaultIconFor(
326	bool audioIn,
327	bool audioOut,
328	bool videoIn,
329	bool videoOut) {
330	D_INTERNAL(("MediaIcon::_findDefaultIcon()\n"));
331
332	if (_isTimeSource()) {
333		BIconUtils::GetVectorIcon(M_TIME_SOURCE_ICON,
334			sizeof(M_TIME_SOURCE_ICON), this);
335		return;
336	}
337
338	if (_isSystemMixer()) {
339		BIconUtils::GetVectorIcon(M_AUDIO_MIXER_ICON,
340			sizeof(M_AUDIO_MIXER_ICON), this);
341		return;
342	}
343
344	if (m_nodeKind & B_FILE_INTERFACE) {
345		if (_isProducer()) {
346			BIconUtils::GetVectorIcon(M_FILE_READER_ICON,
347				sizeof(M_FILE_READER_ICON), this);
348			return;
349		} else {
350			BIconUtils::GetVectorIcon(M_FILE_WRITER_ICON,
351				sizeof(M_FILE_WRITER_ICON), this);
352			return;
353		}
354	}
355
356	if (_isPhysicalInput()) {
357		if (audioIn) {
358			BIconUtils::GetVectorIcon(M_AUDIO_DEVICE_ICON,
359				sizeof(M_AUDIO_DEVICE_ICON), this);
360			return;
361		} else if (audioOut) {
362			BIconUtils::GetVectorIcon(M_AUDIO_INPUT_ICON,
363				sizeof(M_AUDIO_INPUT_ICON), this);
364			return;
365		} else if (videoOut) {
366			BIconUtils::GetVectorIcon(M_VIDEO_INPUT_ICON,
367				sizeof(M_VIDEO_INPUT_ICON), this);
368			return;
369		}
370	}
371
372	if (_isPhysicalOutput()) {
373		if (audioIn) {
374			BIconUtils::GetVectorIcon(M_AUDIO_OUTPUT_ICON,
375				sizeof(M_AUDIO_OUTPUT_ICON), this);
376			return;
377		} else if (videoIn) {
378			BIconUtils::GetVectorIcon(M_VIDEO_OUTPUT_ICON,
379				sizeof(M_VIDEO_OUTPUT_ICON), this);
380			return;
381		}
382	}
383
384	if (_isProducer()) {
385		if (audioOut) {
386			BIconUtils::GetVectorIcon(M_AUDIO_PRODUCER_ICON,
387				sizeof(M_AUDIO_PRODUCER_ICON), this);
388			return;
389		} else if (videoOut) {
390			BIconUtils::GetVectorIcon(M_VIDEO_PRODUCER_ICON,
391				sizeof(M_VIDEO_PRODUCER_ICON), this);
392			return;
393		}
394	}
395
396	if (_isFilter()) {
397		if (audioIn && audioOut && !videoIn && !videoOut) {
398			BIconUtils::GetVectorIcon(M_AUDIO_FILTER_ICON,
399				sizeof(M_AUDIO_FILTER_ICON), this);
400			return;
401		} else if (audioIn && !videoIn && videoOut) {
402			BIconUtils::GetVectorIcon(M_AUDIO_CONSUMER_ICON,
403				sizeof(M_AUDIO_CONSUMER_ICON), this);
404			return;
405		} else if (!audioIn && !audioOut && videoIn && videoOut) {
406			BIconUtils::GetVectorIcon(M_VIDEO_FILTER_ICON,
407				sizeof(M_VIDEO_FILTER_ICON), this);
408			return;
409		}
410	}
411
412	if (_isConsumer()) {
413		if (audioIn) {
414			BIconUtils::GetVectorIcon(M_AUDIO_CONSUMER_ICON,
415				sizeof(M_AUDIO_CONSUMER_ICON), this);
416			return;
417		} else if (videoIn) {
418			BIconUtils::GetVectorIcon(M_VIDEO_CONSUMER_ICON,
419				sizeof(M_VIDEO_CONSUMER_ICON), this);
420			return;
421		}
422	}
423
424	// assign a default icon
425	BIconUtils::GetVectorIcon(M_GENERIC_ICON, sizeof(M_GENERIC_ICON), this);
426}
427