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