2 * Copyright (C) 2011, BMW AG
4 * GeniviAudioMananger AudioManagerDaemon
8 * \date 20-Oct-2011 3:42:04 PM
9 * \author Christian Mueller (christian.ei.mueller@bmw.de)
12 * GNU Lesser General Public License, version 2.1, with special exception (GENIVI clause)
13 * Copyright (C) 2011, BMW AG Christian Mueller Christian.ei.mueller@bmw.de
15 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License, version 2.1, as published by the Free Software Foundation.
16 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License, version 2.1, for more details.
17 * You should have received a copy of the GNU Lesser General Public License, version 2.1, along with this program; if not, see <http://www.gnu.org/licenses/lgpl-2.1.html>.
18 * Note that the copyright holders assume that the GNU Lesser General Public License, version 2.1, may also be applicable to programs even in cases in which the program is not a library in the technical sense.
19 * Linking AudioManager statically or dynamically with other modules is making a combined work based on AudioManager. You may license such other modules under the GNU Lesser General Public License, version 2.1. If you do not want to license your linked modules under the GNU Lesser General Public License, version 2.1, you may use the program under the following exception.
20 * As a special exception, the copyright holders of AudioManager give you permission to combine AudioManager with software programs or libraries that are released under any license unless such a combination is not permitted by the license of such a software program or library. You may copy and distribute such a system following the terms of the GNU Lesser General Public License, version 2.1, including this special exception, for AudioManager and the licenses of the other code concerned.
21 * Note that people who make modified versions of AudioManager are not obligated to grant this special exception for their modified versions; it is their choice whether to do so. The GNU Lesser General Public License, version 2.1, gives permission to release a modified version without this exception; this exception also makes it possible to release a modified version which carries forward this exception.
25 #include "CAmRouter.h"
30 #include "CAmDatabaseHandler.h"
31 #include "CAmControlSender.h"
35 CAmRouter::CAmRouter(CAmDatabaseHandler* iDatabaseHandler, CAmControlSender* iSender) :
36 mDatabaseHandler(iDatabaseHandler), //
37 mControlSender(iSender)
39 assert(mDatabaseHandler);
40 assert(mControlSender);
43 am_Error_e CAmRouter::getRoute(const bool onlyfree, const am_sourceID_t sourceID, const am_sinkID_t sinkID, std::vector<am_Route_s> & returnList)
46 //first find out in which domains the source and sink are
47 am_domainID_t sourceDomainID;
48 am_domainID_t sinkDomainID;
49 if (mDatabaseHandler->getDomainOfSource(sourceID, sourceDomainID) != E_OK)
50 return (E_NON_EXISTENT);
51 if (mDatabaseHandler->getDomainOfSink(sinkID, sinkDomainID) != E_OK)
52 return (E_NON_EXISTENT);
54 if (sourceDomainID == sinkDomainID) //shortcut if the domains are the same...
56 //first get the list of possible connection formats
57 std::vector<am_ConnectionFormat_e> listFormats, listPriorityConnectionFormats;
58 listPossibleConnectionFormats(sourceID, sinkID, listFormats);
62 route.sinkID = sinkID;
63 route.sourceID = sourceID;
66 //get the prio of the Controller:
67 mControlSender->getConnectionFormatChoice(sourceID, sinkID, route, listFormats, listPriorityConnectionFormats);
69 //no possible connection, so no route ! But we report OK since there is no fault ...
70 if (listPriorityConnectionFormats.empty())
73 //return the first item as route:
74 am_RoutingElement_s routingElement;
75 routingElement.sourceID = sourceID;
76 routingElement.sinkID = sinkID;
77 routingElement.connectionFormat = listPriorityConnectionFormats[0];
78 routingElement.domainID = sourceDomainID;
81 am_Route_s actualRoute;
82 actualRoute.route.push_back(routingElement);
83 actualRoute.sourceID = sourceID;
84 actualRoute.sinkID = sinkID;
86 //push it to the return list - we are done here ...
87 returnList.push_back(actualRoute);
91 CAmRoutingTree routingtree(sourceDomainID); //Build up a Tree from the Source_Domain to every other domain.
92 std::vector<CAmRoutingTreeItem*> flattree; //This list is the flat tree
93 std::vector<CAmRoutingTreeItem*> matchtree;
94 std::vector<am_gatewayID_t> listGatewayID; //holds all gateway ids of the route
95 am_RoutingElement_s routingElement;
96 am_Route_s actualRoute; //holds the actual Route
97 am_sourceID_t lastSource = 0;
99 mDatabaseHandler->getRoutingTree(onlyfree, routingtree, flattree); //Build up the tree out of the database as
101 //we go through the returned flattree and look for our sink, after that flattree holds only treeItems that match
102 std::vector<CAmRoutingTreeItem*>::iterator iterator = flattree.begin();
103 for (; iterator != flattree.end(); ++iterator)
105 if ((*iterator)->returnDomainID() == sinkDomainID)
107 matchtree.push_back(*iterator);
111 //No we need to trace back the routes for each entry in matchtree
112 iterator = matchtree.begin();
113 for (; iterator != matchtree.end(); ++iterator)
115 std::vector<am_RoutingElement_s> actualRoutingElement; //intermediate list of current routing pairs
116 //getting the route for the actual item
117 routingtree.getRoute(*iterator, listGatewayID); //This gives only the Gateway IDs we need more
119 //go throught the gatewayids and get more information
120 std::vector<am_gatewayID_t>::iterator gatewayIterator = listGatewayID.begin();
121 for (; gatewayIterator != listGatewayID.end(); ++gatewayIterator)
123 am_Gateway_s gatewayData;
124 if (mDatabaseHandler->getGatewayInfoDB(*gatewayIterator, gatewayData) != E_OK)
127 //at the beginning of the route, we connect first the source to the first gateway
128 if (gatewayIterator == listGatewayID.begin())
130 routingElement.sourceID = sourceID;
131 routingElement.domainID = sourceDomainID;
135 routingElement.sourceID = lastSource;
136 routingElement.domainID = gatewayData.domainSinkID;
138 routingElement.sinkID = gatewayData.sinkID;
139 actualRoutingElement.push_back(routingElement);
140 lastSource = gatewayData.sourceID;
142 //at the end of the route, connect to the sink !
143 routingElement.sourceID = lastSource;
144 routingElement.sinkID = sinkID;
145 routingElement.domainID = sinkDomainID;
146 actualRoutingElement.push_back(routingElement);
148 //So now we got the route, what is missing are the connectionFormats...
150 //Step through the routes and try to use always the best connectionFormat
151 std::vector<am_RoutingElement_s>::iterator routingInterator = actualRoutingElement.begin();
152 gatewayIterator = listGatewayID.begin();
153 if (findBestWay(sinkID, sourceID, actualRoutingElement, routingInterator, gatewayIterator) != E_OK)
158 //add the route to the list of routes...
159 actualRoute.sourceID = sourceID;
160 actualRoute.sinkID = sinkID;
161 actualRoute.route = actualRoutingElement;
162 returnList.push_back(actualRoute);
167 void CAmRouter::listPossibleConnectionFormats(const am_sourceID_t sourceID, const am_sinkID_t sinkID, std::vector<am_ConnectionFormat_e>& listFormats) const
169 std::vector<am_ConnectionFormat_e> listSourceFormats;
170 std::vector<am_ConnectionFormat_e> listSinkFormats;
171 mDatabaseHandler->getListSinkConnectionFormats(sinkID, listSinkFormats);
172 mDatabaseHandler->getListSourceConnectionFormats(sourceID, listSourceFormats);
173 std::sort(listSinkFormats.begin(), listSinkFormats.end()); //todo: this might be not needed if we use strictly sorted input
174 std::sort(listSourceFormats.begin(), listSourceFormats.end()); //todo: this might be not needed if we use strictly sorted input
175 std::insert_iterator<std::vector<am_ConnectionFormat_e> > inserter(listFormats, listFormats.begin());
176 set_intersection(listSourceFormats.begin(), listSourceFormats.end(), listSinkFormats.begin(), listSinkFormats.end(), inserter);
179 am_Error_e CAmRouter::findBestWay(am_sinkID_t sinkID, am_sourceID_t sourceID, std::vector<am_RoutingElement_s> & listRoute, std::vector<am_RoutingElement_s>::iterator routeIterator, std::vector<am_gatewayID_t>::iterator gatewayIterator)
181 am_Error_e returnError = E_NOT_POSSIBLE;
182 std::vector<am_ConnectionFormat_e> listConnectionFormats;
183 std::vector<am_ConnectionFormat_e> listMergeConnectionFormats;
184 std::vector<am_ConnectionFormat_e> listPriorityConnectionFormats;
185 std::vector<am_RoutingElement_s>::iterator nextIterator = routeIterator + 1;
186 //get best connection format
187 listPossibleConnectionFormats(routeIterator->sourceID, routeIterator->sinkID, listConnectionFormats);
189 //if we have not just started, we need to take care about the gateways...
190 if (routeIterator != listRoute.begin())
192 //since we have to deal with Gateways, there are restrictions what connectionFormat we can take. So we need to take the subset of connections that are restricted:
193 std::vector<am_ConnectionFormat_e> listRestrictedConnectionFormats;
194 std::insert_iterator<std::vector<am_ConnectionFormat_e> > inserter(listMergeConnectionFormats, listMergeConnectionFormats.begin());
195 std::vector<am_RoutingElement_s>::iterator tempIterator(routeIterator);
197 listRestrictedOutputFormatsGateways(*gatewayIterator, (tempIterator)->connectionFormat, listRestrictedConnectionFormats);
198 std::sort(listRestrictedConnectionFormats.begin(), listRestrictedConnectionFormats.end()); //todo: this might be not needed if we use strictly sorted input
199 set_intersection(listConnectionFormats.begin(), listConnectionFormats.end(), listRestrictedConnectionFormats.begin(), listRestrictedConnectionFormats.end(), inserter);
204 listMergeConnectionFormats = listConnectionFormats;
208 route.sinkID = sinkID;
209 route.sourceID = sourceID;
210 route.route = listRoute;
212 //let the controller decide:
213 mControlSender->getConnectionFormatChoice(routeIterator->sourceID, routeIterator->sinkID, route, listMergeConnectionFormats, listPriorityConnectionFormats);
215 //we have the list sorted after prios - now we try one after the other with the next part of the route
216 std::vector<am_ConnectionFormat_e>::iterator connectionFormatIterator = listPriorityConnectionFormats.begin();
218 //here we need to check if we are at the end and stop
219 if (nextIterator == listRoute.end())
221 if (!listPriorityConnectionFormats.empty())
223 routeIterator->connectionFormat = listPriorityConnectionFormats.front();
227 return E_NOT_POSSIBLE;
230 for (; connectionFormatIterator != listPriorityConnectionFormats.end(); ++connectionFormatIterator)
232 routeIterator->connectionFormat = *connectionFormatIterator;
233 if ((returnError = findBestWay(sinkID, sourceID, listRoute, nextIterator, gatewayIterator)) == E_OK)
239 return (returnError);
242 void CAmRouter::listRestrictedOutputFormatsGateways(const am_gatewayID_t gatewayID, const am_ConnectionFormat_e sinkConnectionFormat, std::vector<am_ConnectionFormat_e> & listFormats) const
245 am_Gateway_s gatewayData;
246 mDatabaseHandler->getGatewayInfoDB(gatewayID, gatewayData);
247 std::vector<am_ConnectionFormat_e>::const_iterator rowSinkIterator = gatewayData.listSinkFormats.begin();
248 std::vector<bool>::const_iterator matrixIterator = gatewayData.convertionMatrix.begin();
250 //find the row number of the sink
251 rowSinkIterator = find(gatewayData.listSinkFormats.begin(), gatewayData.listSinkFormats.end(), sinkConnectionFormat);
252 int rowNumberSink = rowSinkIterator - gatewayData.listSinkFormats.begin();
254 //go through the convertionMatrix and find out if the conversion is possible, if yes, add connectionFormat ...
255 std::advance(matrixIterator, rowNumberSink);
257 //iterate line-wise through the matrix and add more formats
262 listFormats.push_back(gatewayData.listSourceFormats.at((matrixIterator - gatewayData.convertionMatrix.begin()) / gatewayData.listSinkFormats.size()));
264 std::advance(matrixIterator, gatewayData.listSinkFormats.size());
265 } while (gatewayData.convertionMatrix.end() - matrixIterator > 0);
268 CAmRouter::~CAmRouter()
272 CAmRoutingTreeItem::CAmRoutingTreeItem(const am_domainID_t domainID, const am_gatewayID_t gatewayID, CAmRoutingTreeItem *parent) :
273 mDomainID(domainID), //
274 mGatewayID(gatewayID), //
277 assert(mDomainID!=0);
280 void CAmRoutingTreeItem::appendChild(CAmRoutingTreeItem *newChild)
283 mListChildItems.push_back(newChild);
286 void CAmRoutingTreeItem::returnChildItems(std::vector<CAmRoutingTreeItem*> listChildItems)
288 listChildItems = mListChildItems;
291 am_domainID_t CAmRoutingTreeItem::returnDomainID() const
296 am_gatewayID_t CAmRoutingTreeItem::returnGatewayID() const
301 CAmRoutingTreeItem* CAmRoutingTreeItem::returnParent() const
303 return (mParentItem);
306 CAmRoutingTreeItem::~CAmRoutingTreeItem()
310 CAmRoutingTree::CAmRoutingTree(const am_domainID_t rootDomainID) :
311 mRootItem(CAmRoutingTreeItem(rootDomainID))
313 assert(rootDomainID!=0);
316 CAmRoutingTreeItem *CAmRoutingTree::insertItem(const am_domainID_t domainID, const am_gatewayID_t gatewayID, CAmRoutingTreeItem *parent)
318 CAmRoutingTreeItem *newTree = new CAmRoutingTreeItem(domainID, gatewayID, parent);
319 parent->appendChild(newTree);
320 mListChild.push_back(newTree);
324 void CAmRoutingTree::getRoute(CAmRoutingTreeItem *targetItem, std::vector<am_gatewayID_t>& listGateways)
326 listGateways.clear();
327 CAmRoutingTreeItem *parentItem = targetItem;
328 while (parentItem != &mRootItem)
330 listGateways.push_back(parentItem->returnGatewayID());
331 parentItem = parentItem->returnParent();
333 std::reverse(listGateways.begin(), listGateways.end());
336 am_domainID_t CAmRoutingTree::returnRootDomainID() const
338 return (mRootItem.returnDomainID());
341 CAmRoutingTreeItem *CAmRoutingTree::returnRootItem()
346 CAmRoutingTree::~CAmRoutingTree()
348 std::vector<CAmRoutingTreeItem*>::iterator it = mListChild.begin();
349 for (; it != mListChild.end(); ++it)