* updated license headers
[profile/ivi/audiomanager.git] / AudioManagerDaemon / src / CAmRouter.cpp
1 /**
2  * Copyright (C) 2012, GENIVI Alliance, Inc.
3  * Copyright (C) 2012, BMW AG
4  *
5  * This file is part of GENIVI Project AudioManager.
6  *
7  * Contributions are licensed to the GENIVI Alliance under one or more
8  * Contribution License Agreements.
9  *
10  * \copyright
11  * This Source Code Form is subject to the terms of the
12  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
13  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  *
16  * \author Christian Mueller, christian.ei.mueller@bmw.de BMW 2011,2012
17  *
18  * \file CAmRouter.cpp
19  * For further information see http://www.genivi.org/.
20  *
21  */
22
23 #include "CAmRouter.h"
24 #include <cassert>
25 #include <algorithm>
26 #include <vector>
27 #include <iterator>
28 #include "CAmDatabaseHandler.h"
29 #include "CAmControlSender.h"
30
31 namespace am {
32
33 CAmRouter::CAmRouter(CAmDatabaseHandler* iDatabaseHandler, CAmControlSender* iSender) :
34         mpDatabaseHandler(iDatabaseHandler), //
35         mpControlSender(iSender)
36 {
37     assert(mpDatabaseHandler);
38     assert(mpControlSender);
39 }
40
41 /**
42  * returns the best route between a source and a sink
43  * @param onlyfree if true only free gateways are used
44  * @param sourceID
45  * @param sinkID
46  * @param returnList this list contains a set of routes
47  * @return E_OK in case of success
48  */
49 am_Error_e CAmRouter::getRoute(const bool onlyfree, const am_sourceID_t sourceID, const am_sinkID_t sinkID, std::vector<am_Route_s> & returnList)
50 {
51     returnList.clear();
52     //first find out in which domains the source and sink are
53     am_domainID_t sourceDomainID;
54     am_domainID_t sinkDomainID;
55     if (mpDatabaseHandler->getDomainOfSource(sourceID, sourceDomainID) != E_OK)
56         return (E_NON_EXISTENT);
57     if (mpDatabaseHandler->getDomainOfSink(sinkID, sinkDomainID) != E_OK)
58         return (E_NON_EXISTENT);
59
60     if (sourceDomainID == sinkDomainID) //shortcut if the domains are the same...
61     {
62         //first get the list of possible connection formats
63         std::vector<am_ConnectionFormat_e> listFormats, listPriorityConnectionFormats;
64         listPossibleConnectionFormats(sourceID, sinkID, listFormats);
65
66         //dummy route
67         am_Route_s route;
68         route.sinkID = sinkID;
69         route.sourceID = sourceID;
70         route.route.clear();
71
72         //get the prio of the Controller:
73         mpControlSender->getConnectionFormatChoice(sourceID, sinkID, route, listFormats, listPriorityConnectionFormats);
74
75         //no possible connection, so no route ! But we report OK since there is no fault ...
76         if (listPriorityConnectionFormats.empty())
77             return (E_OK);
78
79         //return the first item as route:
80         am_RoutingElement_s routingElement;
81         routingElement.sourceID = sourceID;
82         routingElement.sinkID = sinkID;
83         routingElement.connectionFormat = listPriorityConnectionFormats[0];
84         routingElement.domainID = sourceDomainID;
85
86         //Now get a route:
87         am_Route_s actualRoute;
88         actualRoute.route.push_back(routingElement);
89         actualRoute.sourceID = sourceID;
90         actualRoute.sinkID = sinkID;
91
92         //push it to the return list - we are done here ...
93         returnList.push_back(actualRoute);
94         return (E_OK);
95
96     }
97     CAmRoutingTree routingtree(sourceDomainID); //Build up a Tree from the Source_Domain to every other domain.
98     std::vector<CAmRoutingTreeItem*> flattree; //This list is the flat tree
99     std::vector<CAmRoutingTreeItem*> matchtree;
100     std::vector<am_gatewayID_t> listGatewayID; //holds all gateway ids of the route
101     am_RoutingElement_s routingElement;
102     am_Route_s actualRoute; //holds the actual Route
103     am_sourceID_t lastSource = 0;
104
105     mpDatabaseHandler->getRoutingTree(onlyfree, routingtree, flattree); //Build up the tree out of the database as
106
107     //we go through the returned flattree and look for our sink, after that flattree holds only treeItems that match
108     std::vector<CAmRoutingTreeItem*>::iterator iterator = flattree.begin();
109     for (; iterator != flattree.end(); ++iterator)
110     {
111         if ((*iterator)->returnDomainID() == sinkDomainID)
112         {
113             matchtree.push_back(*iterator);
114         }
115     }
116
117     //No we need to trace back the routes for each entry in matchtree
118     iterator = matchtree.begin();
119     for (; iterator != matchtree.end(); ++iterator)
120     {
121         std::vector<am_RoutingElement_s> actualRoutingElement; //intermediate list of current routing pairs
122         //getting the route for the actual item
123         routingtree.getRoute(*iterator, listGatewayID); //This gives only the Gateway IDs we need more
124
125         //go throught the gatewayids and get more information
126         std::vector<am_gatewayID_t>::iterator gatewayIterator = listGatewayID.begin();
127         for (; gatewayIterator != listGatewayID.end(); ++gatewayIterator)
128         {
129             am_Gateway_s gatewayData;
130             if (mpDatabaseHandler->getGatewayInfoDB(*gatewayIterator, gatewayData) != E_OK)
131                 return (E_UNKNOWN);
132
133             //at the beginning of the route, we connect first the source to the first gateway
134             if (gatewayIterator == listGatewayID.begin())
135             {
136                 routingElement.sourceID = sourceID;
137                 routingElement.domainID = sourceDomainID;
138             }
139             else
140             {
141                 routingElement.sourceID = lastSource;
142                 routingElement.domainID = gatewayData.domainSinkID;
143             }
144             routingElement.sinkID = gatewayData.sinkID;
145             actualRoutingElement.push_back(routingElement);
146             lastSource = gatewayData.sourceID;
147         }
148         //at the end of the route, connect to the sink !
149         routingElement.sourceID = lastSource;
150         routingElement.sinkID = sinkID;
151         routingElement.domainID = sinkDomainID;
152         actualRoutingElement.push_back(routingElement);
153
154         //So now we got the route, what is missing are the connectionFormats...
155
156         //Step through the routes and try to use always the best connectionFormat
157         std::vector<am_RoutingElement_s>::iterator routingInterator = actualRoutingElement.begin();
158         gatewayIterator = listGatewayID.begin();
159         if (findBestWay(sinkID, sourceID, actualRoutingElement, routingInterator, gatewayIterator) != E_OK)
160         {
161             continue;
162         }
163
164         //add the route to the list of routes...
165         actualRoute.sourceID = sourceID;
166         actualRoute.sinkID = sinkID;
167         actualRoute.route = actualRoutingElement;
168         returnList.push_back(actualRoute);
169     }
170     return (E_OK);
171 }
172
173 void CAmRouter::listPossibleConnectionFormats(const am_sourceID_t sourceID, const am_sinkID_t sinkID, std::vector<am_ConnectionFormat_e>& listFormats) const
174 {
175     std::vector<am_ConnectionFormat_e> listSourceFormats;
176     std::vector<am_ConnectionFormat_e> listSinkFormats;
177     mpDatabaseHandler->getListSinkConnectionFormats(sinkID, listSinkFormats);
178     mpDatabaseHandler->getListSourceConnectionFormats(sourceID, listSourceFormats);
179     std::sort(listSinkFormats.begin(), listSinkFormats.end()); //todo: this might be not needed if we use strictly sorted input
180     std::sort(listSourceFormats.begin(), listSourceFormats.end()); //todo: this might be not needed if we use strictly sorted input
181     std::insert_iterator<std::vector<am_ConnectionFormat_e> > inserter(listFormats, listFormats.begin());
182     set_intersection(listSourceFormats.begin(), listSourceFormats.end(), listSinkFormats.begin(), listSinkFormats.end(), inserter);
183 }
184
185 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)
186 {
187     am_Error_e returnError = E_NOT_POSSIBLE;
188     std::vector<am_ConnectionFormat_e> listConnectionFormats;
189     std::vector<am_ConnectionFormat_e> listMergeConnectionFormats;
190     std::vector<am_ConnectionFormat_e> listPriorityConnectionFormats;
191     std::vector<am_RoutingElement_s>::iterator nextIterator = routeIterator + 1;
192     //get best connection format
193     listPossibleConnectionFormats(routeIterator->sourceID, routeIterator->sinkID, listConnectionFormats);
194
195     //if we have not just started, we need to take care about the gateways...
196     if (routeIterator != listRoute.begin())
197     {
198         //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:
199         std::vector<am_ConnectionFormat_e> listRestrictedConnectionFormats;
200         std::insert_iterator<std::vector<am_ConnectionFormat_e> > inserter(listMergeConnectionFormats, listMergeConnectionFormats.begin());
201         std::vector<am_RoutingElement_s>::iterator tempIterator(routeIterator);
202         tempIterator--;
203         listRestrictedOutputFormatsGateways(*gatewayIterator, (tempIterator)->connectionFormat, listRestrictedConnectionFormats);
204         std::sort(listRestrictedConnectionFormats.begin(), listRestrictedConnectionFormats.end()); //todo: this might be not needed if we use strictly sorted input
205         set_intersection(listConnectionFormats.begin(), listConnectionFormats.end(), listRestrictedConnectionFormats.begin(), listRestrictedConnectionFormats.end(), inserter);
206         gatewayIterator++;
207     }
208     else
209     {
210         listMergeConnectionFormats = listConnectionFormats;
211     }
212
213     am_Route_s route;
214     route.sinkID = sinkID;
215     route.sourceID = sourceID;
216     route.route = listRoute;
217
218     //let the controller decide:
219     mpControlSender->getConnectionFormatChoice(routeIterator->sourceID, routeIterator->sinkID, route, listMergeConnectionFormats, listPriorityConnectionFormats);
220
221     //we have the list sorted after prios - now we try one after the other with the next part of the route
222     std::vector<am_ConnectionFormat_e>::iterator connectionFormatIterator = listPriorityConnectionFormats.begin();
223
224     //here we need to check if we are at the end and stop
225     if (nextIterator == listRoute.end())
226     {
227         if (!listPriorityConnectionFormats.empty())
228         {
229             routeIterator->connectionFormat = listPriorityConnectionFormats.front();
230             return (E_OK);
231         }
232         else
233             return (E_NOT_POSSIBLE);
234     }
235
236     for (; connectionFormatIterator != listPriorityConnectionFormats.end(); ++connectionFormatIterator)
237     {
238         routeIterator->connectionFormat = *connectionFormatIterator;
239         if ((returnError = findBestWay(sinkID, sourceID, listRoute, nextIterator, gatewayIterator)) == E_OK)
240         {
241             break;
242         }
243     }
244
245     return (returnError);
246 }
247
248 void CAmRouter::listRestrictedOutputFormatsGateways(const am_gatewayID_t gatewayID, const am_ConnectionFormat_e sinkConnectionFormat, std::vector<am_ConnectionFormat_e> & listFormats) const
249 {
250     listFormats.clear();
251     am_Gateway_s gatewayData;
252     mpDatabaseHandler->getGatewayInfoDB(gatewayID, gatewayData);
253     std::vector<am_ConnectionFormat_e>::const_iterator rowSinkIterator = gatewayData.listSinkFormats.begin();
254     std::vector<bool>::const_iterator matrixIterator = gatewayData.convertionMatrix.begin();
255
256     //find the row number of the sink
257     rowSinkIterator = find(gatewayData.listSinkFormats.begin(), gatewayData.listSinkFormats.end(), sinkConnectionFormat);
258     int rowNumberSink = rowSinkIterator - gatewayData.listSinkFormats.begin();
259
260     //go through the convertionMatrix and find out if the conversion is possible, if yes, add connectionFormat ...
261     std::advance(matrixIterator, rowNumberSink);
262
263     //iterate line-wise through the matrix and add more formats
264     do
265     {
266         if (*matrixIterator)
267         {
268             listFormats.push_back(gatewayData.listSourceFormats.at((matrixIterator - gatewayData.convertionMatrix.begin()) / gatewayData.listSinkFormats.size()));
269         }
270         std::advance(matrixIterator, gatewayData.listSinkFormats.size());
271     } while (gatewayData.convertionMatrix.end() - matrixIterator > 0);
272 }
273
274 CAmRouter::~CAmRouter()
275 {
276 }
277
278 CAmRoutingTreeItem::CAmRoutingTreeItem(const am_domainID_t domainID, const am_gatewayID_t gatewayID, CAmRoutingTreeItem *parent) :
279         mDomainID(domainID), //
280         mGatewayID(gatewayID), //
281         mpParentItem(parent)
282 {
283     assert(mDomainID!=0);
284 }
285
286 void CAmRoutingTreeItem::appendChild(CAmRoutingTreeItem *newChild)
287 {
288     assert(newChild);
289     mListChildItems.push_back(newChild);
290 }
291
292 void CAmRoutingTreeItem::returnChildItems(std::vector<CAmRoutingTreeItem*> listChildItems)
293 {
294     listChildItems = mListChildItems;
295 }
296
297 am_domainID_t CAmRoutingTreeItem::returnDomainID() const
298 {
299     return (mDomainID);
300 }
301
302 am_gatewayID_t CAmRoutingTreeItem::returnGatewayID() const
303 {
304     return (mGatewayID);
305 }
306
307 CAmRoutingTreeItem* CAmRoutingTreeItem::returnParent() const
308 {
309     return (mpParentItem);
310 }
311
312 CAmRoutingTreeItem::~CAmRoutingTreeItem()
313 {
314 }
315
316 CAmRoutingTree::CAmRoutingTree(const am_domainID_t rootDomainID) :
317         mRootItem(CAmRoutingTreeItem(rootDomainID))
318 {
319     assert(rootDomainID!=0);
320 }
321
322 CAmRoutingTreeItem *CAmRoutingTree::insertItem(const am_domainID_t domainID, const am_gatewayID_t gatewayID, CAmRoutingTreeItem *parent)
323 {
324     CAmRoutingTreeItem *newTree = new CAmRoutingTreeItem(domainID, gatewayID, parent);
325     parent->appendChild(newTree);
326     mListChild.push_back(newTree);
327     return (newTree);
328 }
329
330 void CAmRoutingTree::getRoute(CAmRoutingTreeItem *targetItem, std::vector<am_gatewayID_t>& listGateways)
331 {
332     listGateways.clear();
333     CAmRoutingTreeItem *parentItem = targetItem;
334     while (parentItem != &mRootItem)
335     {
336         listGateways.push_back(parentItem->returnGatewayID());
337         parentItem = parentItem->returnParent();
338     }
339     std::reverse(listGateways.begin(), listGateways.end());
340 }
341
342 am_domainID_t CAmRoutingTree::returnRootDomainID() const
343 {
344     return (mRootItem.returnDomainID());
345 }
346
347 CAmRoutingTreeItem *CAmRoutingTree::returnRootItem()
348 {
349     return (&mRootItem);
350 }
351
352 CAmRoutingTree::~CAmRoutingTree()
353 {
354     std::vector<CAmRoutingTreeItem*>::iterator it = mListChild.begin();
355     for (; it != mListChild.end(); ++it)
356     {
357         delete *it;
358     }
359 }
360 }