* fix [GAM-28] problems in routingsender.cpp
[profile/ivi/audiomanager.git] / AudioManagerDaemon / src / CAmRouter.cpp
1 /**
2  * Copyright (C) 2011, BMW AG
3  *
4  * GeniviAudioMananger AudioManagerDaemon
5  *
6  * \file CAmRouter.cpp
7  *
8  * \date 20-Oct-2011 3:42:04 PM
9  * \author Christian Mueller (christian.ei.mueller@bmw.de)
10  *
11  * \section License
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
14  *
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.
22  *
23  */
24
25 #include "CAmRouter.h"
26 #include <cassert>
27 #include <algorithm>
28 #include <vector>
29 #include <iterator>
30 #include "CAmDatabaseHandler.h"
31 #include "CAmControlSender.h"
32
33 namespace am {
34
35 CAmRouter::CAmRouter(CAmDatabaseHandler* iDatabaseHandler, CAmControlSender* iSender) :
36         mDatabaseHandler(iDatabaseHandler), //
37         mControlSender(iSender)
38 {
39     assert(mDatabaseHandler);
40     assert(mControlSender);
41 }
42
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)
44 {
45     returnList.clear();
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);
53
54     if (sourceDomainID == sinkDomainID) //shortcut if the domains are the same...
55     {
56         //first get the list of possible connection formats
57         std::vector<am_ConnectionFormat_e> listFormats, listPriorityConnectionFormats;
58         listPossibleConnectionFormats(sourceID, sinkID, listFormats);
59
60         //dummy route
61         am_Route_s route;
62         route.sinkID = sinkID;
63         route.sourceID = sourceID;
64         route.route.clear();
65
66         //get the prio of the Controller:
67         mControlSender->getConnectionFormatChoice(sourceID, sinkID, route, listFormats, listPriorityConnectionFormats);
68
69         //no possible connection, so no route ! But we report OK since there is no fault ...
70         if (listPriorityConnectionFormats.empty())
71             return E_OK;
72
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;
79
80         //Now get a route:
81         am_Route_s actualRoute;
82         actualRoute.route.push_back(routingElement);
83         actualRoute.sourceID = sourceID;
84         actualRoute.sinkID = sinkID;
85
86         //push it to the return list - we are done here ...
87         returnList.push_back(actualRoute);
88         return E_OK;
89
90     }
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;
98
99     mDatabaseHandler->getRoutingTree(onlyfree, routingtree, flattree); //Build up the tree out of the database as
100
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)
104     {
105         if ((*iterator)->returnDomainID() == sinkDomainID)
106         {
107             matchtree.push_back(*iterator);
108         }
109     }
110
111     //No we need to trace back the routes for each entry in matchtree
112     iterator = matchtree.begin();
113     for (; iterator != matchtree.end(); ++iterator)
114     {
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
118
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)
122         {
123             am_Gateway_s gatewayData;
124             if (mDatabaseHandler->getGatewayInfoDB(*gatewayIterator, gatewayData) != E_OK)
125                 return (E_UNKNOWN);
126
127             //at the beginning of the route, we connect first the source to the first gateway
128             if (gatewayIterator == listGatewayID.begin())
129             {
130                 routingElement.sourceID = sourceID;
131                 routingElement.domainID = sourceDomainID;
132             }
133             else
134             {
135                 routingElement.sourceID = lastSource;
136                 routingElement.domainID = gatewayData.domainSinkID;
137             }
138             routingElement.sinkID = gatewayData.sinkID;
139             actualRoutingElement.push_back(routingElement);
140             lastSource = gatewayData.sourceID;
141         }
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);
147
148         //So now we got the route, what is missing are the connectionFormats...
149
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)
154         {
155             continue;
156         }
157
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);
163     }
164     return (E_OK);
165 }
166
167 void CAmRouter::listPossibleConnectionFormats(const am_sourceID_t sourceID, const am_sinkID_t sinkID, std::vector<am_ConnectionFormat_e>& listFormats) const
168 {
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);
177 }
178
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)
180 {
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);
188
189     //if we have not just started, we need to take care about the gateways...
190     if (routeIterator != listRoute.begin())
191     {
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);
196         tempIterator--;
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);
200         gatewayIterator++;
201     }
202     else
203     {
204         listMergeConnectionFormats = listConnectionFormats;
205     }
206
207     am_Route_s route;
208     route.sinkID = sinkID;
209     route.sourceID = sourceID;
210     route.route = listRoute;
211
212     //let the controller decide:
213     mControlSender->getConnectionFormatChoice(routeIterator->sourceID, routeIterator->sinkID, route, listMergeConnectionFormats, listPriorityConnectionFormats);
214
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();
217
218     //here we need to check if we are at the end and stop
219     if (nextIterator == listRoute.end())
220     {
221         if (!listPriorityConnectionFormats.empty())
222         {
223             routeIterator->connectionFormat = listPriorityConnectionFormats.front();
224             return E_OK;
225         }
226         else
227             return E_NOT_POSSIBLE;
228     }
229
230     for (; connectionFormatIterator != listPriorityConnectionFormats.end(); ++connectionFormatIterator)
231     {
232         routeIterator->connectionFormat = *connectionFormatIterator;
233         if ((returnError = findBestWay(sinkID, sourceID, listRoute, nextIterator, gatewayIterator)) == E_OK)
234         {
235             break;
236         }
237     }
238
239     return (returnError);
240 }
241
242 void CAmRouter::listRestrictedOutputFormatsGateways(const am_gatewayID_t gatewayID, const am_ConnectionFormat_e sinkConnectionFormat, std::vector<am_ConnectionFormat_e> & listFormats) const
243 {
244     listFormats.clear();
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();
249
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();
253
254     //go through the convertionMatrix and find out if the conversion is possible, if yes, add connectionFormat ...
255     std::advance(matrixIterator, rowNumberSink);
256
257     //iterate line-wise through the matrix and add more formats
258     do
259     {
260         if (*matrixIterator)
261         {
262             listFormats.push_back(gatewayData.listSourceFormats.at((matrixIterator - gatewayData.convertionMatrix.begin()) / gatewayData.listSinkFormats.size()));
263         }
264         std::advance(matrixIterator, gatewayData.listSinkFormats.size());
265     } while (gatewayData.convertionMatrix.end() - matrixIterator > 0);
266 }
267
268 CAmRouter::~CAmRouter()
269 {
270 }
271
272 CAmRoutingTreeItem::CAmRoutingTreeItem(const am_domainID_t domainID, const am_gatewayID_t gatewayID, CAmRoutingTreeItem *parent) :
273         mDomainID(domainID), //
274         mGatewayID(gatewayID), //
275         mParentItem(parent)
276 {
277     assert(mDomainID!=0);
278 }
279
280 void CAmRoutingTreeItem::appendChild(CAmRoutingTreeItem *newChild)
281 {
282     assert(newChild);
283     mListChildItems.push_back(newChild);
284 }
285
286 void CAmRoutingTreeItem::returnChildItems(std::vector<CAmRoutingTreeItem*> listChildItems)
287 {
288     listChildItems = mListChildItems;
289 }
290
291 am_domainID_t CAmRoutingTreeItem::returnDomainID() const
292 {
293     return (mDomainID);
294 }
295
296 am_gatewayID_t CAmRoutingTreeItem::returnGatewayID() const
297 {
298     return (mGatewayID);
299 }
300
301 CAmRoutingTreeItem* CAmRoutingTreeItem::returnParent() const
302 {
303     return (mParentItem);
304 }
305
306 CAmRoutingTreeItem::~CAmRoutingTreeItem()
307 {
308 }
309
310 CAmRoutingTree::CAmRoutingTree(const am_domainID_t rootDomainID) :
311         mRootItem(CAmRoutingTreeItem(rootDomainID))
312 {
313     assert(rootDomainID!=0);
314 }
315
316 CAmRoutingTreeItem *CAmRoutingTree::insertItem(const am_domainID_t domainID, const am_gatewayID_t gatewayID, CAmRoutingTreeItem *parent)
317 {
318     CAmRoutingTreeItem *newTree = new CAmRoutingTreeItem(domainID, gatewayID, parent);
319     parent->appendChild(newTree);
320     mListChild.push_back(newTree);
321     return newTree;
322 }
323
324 void CAmRoutingTree::getRoute(CAmRoutingTreeItem *targetItem, std::vector<am_gatewayID_t>& listGateways)
325 {
326     listGateways.clear();
327     CAmRoutingTreeItem *parentItem = targetItem;
328     while (parentItem != &mRootItem)
329     {
330         listGateways.push_back(parentItem->returnGatewayID());
331         parentItem = parentItem->returnParent();
332     }
333     std::reverse(listGateways.begin(), listGateways.end());
334 }
335
336 am_domainID_t CAmRoutingTree::returnRootDomainID() const
337 {
338     return (mRootItem.returnDomainID());
339 }
340
341 CAmRoutingTreeItem *CAmRoutingTree::returnRootItem()
342 {
343     return (&mRootItem);
344 }
345
346 CAmRoutingTree::~CAmRoutingTree()
347 {
348     std::vector<CAmRoutingTreeItem*>::iterator it = mListChild.begin();
349     for (; it != mListChild.end(); ++it)
350     {
351         delete *it;
352     }
353 }
354 }