RDK Documentation (Open Sourced RDK Components)
AampcliVirtualChannelMap.cpp
Go to the documentation of this file.
1 /*
2  * If not stated otherwise in this file or this component's license file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2022 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 /**
21  * @file AampcliVirtualChannelMap.cpp
22  * @brief Aampcli VirtualChannelMap handler
23  */
24 
25 #include "AampcliVirtualChannelMap.h"
26 
27 VirtualChannelMap mVirtualChannelMap;
28 
29 void VirtualChannelMap::add(VirtualChannelInfo& channelInfo)
30 {
31  if( !channelInfo.name.empty() )
32  {
33  if( !channelInfo.uri.empty() )
34  {
35  if( !VIRTUAL_CHANNEL_VALID(channelInfo.channelNumber) )
36  { // No channel set, use an auto. This could conflict with a later add, we can't check for that here
37  channelInfo.channelNumber = mAutoChannelNumber+1;
38  }
39 
40  if (isPresent(channelInfo) == true)
41  {
42  return; // duplicate
43  }
44  mAutoChannelNumber = channelInfo.channelNumber;
45  }
46  }
47  mVirtualChannelMap.push_back(channelInfo);
48 }
49 
50 VirtualChannelInfo* VirtualChannelMap::find(const int channelNumber)
51 {
52  VirtualChannelInfo *found = NULL;
53  for (std::list<VirtualChannelInfo>::iterator it = mVirtualChannelMap.begin(); it != mVirtualChannelMap.end(); ++it)
54  {
55  VirtualChannelInfo &existingChannelInfo = *it;
56  if (channelNumber == existingChannelInfo.channelNumber)
57  {
58  found = &existingChannelInfo;
59  break;
60  }
61  }
62  return found;
63 }
64 bool VirtualChannelMap::isPresent(const VirtualChannelInfo& channelInfo)
65 {
66  for (std::list<VirtualChannelInfo>::iterator it = mVirtualChannelMap.begin(); it != mVirtualChannelMap.end(); ++it)
67  {
68  VirtualChannelInfo &existingChannelInfo = *it;
69  if(channelInfo.channelNumber == existingChannelInfo.channelNumber)
70  {
71  printf("[AAMPCLI] duplicate channel number: %d: '%s'\n", channelInfo.channelNumber, channelInfo.uri.c_str() );
72  return true;
73  }
74  if(channelInfo.uri == existingChannelInfo.uri )
75  {
76  printf("[AAMPCLI] duplicate URL: %d: '%s'\n", channelInfo.channelNumber, channelInfo.uri.c_str() );
77  return true;
78  }
79  }
80  return false;
81 }
82 
83 // NOTE: prev() and next() are IDENTICAL other than the direction of the iterator. They could be collapsed using a template,
84 // but will all target compilers support this, it wouldn't save much code space, and may make the code harder to understand.
85 // Can not simply use different runtime iterators, as the types of each in C++ are not compatible (really).
86 VirtualChannelInfo* VirtualChannelMap::prev()
87 {
88  VirtualChannelInfo *pPrevChannel = NULL;
89  VirtualChannelInfo *pLastChannel = NULL;
90  bool prevFound = false;
91 
92  // mCurrentlyTunedChannel is 0 for manually entered urls, not having used mVirtualChannelMap yet or empty
93  if (mCurrentlyTunedChannel == 0 && mVirtualChannelMap.size() > 0)
94  {
95  prevFound = true; // return the last valid channel
96  }
97 
98  for(std::list<VirtualChannelInfo>::reverse_iterator it = mVirtualChannelMap.rbegin(); it != mVirtualChannelMap.rend(); ++it)
99  {
100  VirtualChannelInfo &existingChannelInfo = *it;
101  if (VIRTUAL_CHANNEL_VALID(existingChannelInfo.channelNumber) ) // skip group headings
102  {
103  if ( pLastChannel == NULL )
104  { // remember this channel for wrap case
105  pLastChannel = &existingChannelInfo;
106  }
107  if ( prevFound )
108  {
109  pPrevChannel = &existingChannelInfo;
110  break;
111  }
112  else if ( existingChannelInfo.channelNumber == mCurrentlyTunedChannel )
113  {
114  prevFound = true;
115  }
116  }
117  }
118  if (prevFound && pPrevChannel == NULL)
119  {
120  pPrevChannel = pLastChannel; // if we end up here we are probably at the first channel -- wrap to back
121  }
122  return pPrevChannel;
123 }
124 
125 VirtualChannelInfo* VirtualChannelMap::next()
126 {
127  VirtualChannelInfo *pNextChannel = NULL;
128  VirtualChannelInfo *pFirstChannel = NULL;
129  bool nextFound = false;
130 
131  // mCurrentlyTunedChannel is 0 for manually entered urls, not using mVirtualChannelMap
132  if (mCurrentlyTunedChannel == 0 && mVirtualChannelMap.size() > 0)
133  {
134  nextFound = true; // return the first valid channel
135  }
136 
137  for (std::list<VirtualChannelInfo>::iterator it = mVirtualChannelMap.begin(); it != mVirtualChannelMap.end(); ++it)
138  {
139  VirtualChannelInfo &existingChannelInfo = *it;
140  if (VIRTUAL_CHANNEL_VALID(existingChannelInfo.channelNumber) ) // skip group headings
141  {
142  if ( pFirstChannel == NULL )
143  { // remember this channel for wrap case
144  pFirstChannel = &existingChannelInfo;
145  }
146  if ( nextFound )
147  {
148  pNextChannel = &existingChannelInfo;
149  break;
150  }
151  else if ( existingChannelInfo.channelNumber == mCurrentlyTunedChannel )
152  {
153  nextFound = true;
154  }
155  }
156  }
157  if (nextFound && pNextChannel == NULL)
158  {
159  pNextChannel = pFirstChannel; // if we end up here we are probably at the last channel -- wrap to front
160  }
161  return pNextChannel;
162 }
163 
164 void VirtualChannelMap::print()
165 {
166  if (mVirtualChannelMap.empty())
167  {
168  return;
169  }
170 
171  printf("[AAMPCLI] aampcli.cfg virtual channel map:\n");
172 
173  int numCols = 0;
174  for (std::list<VirtualChannelInfo>::iterator it = mVirtualChannelMap.begin(); it != mVirtualChannelMap.end(); ++it )
175  {
176  VirtualChannelInfo &pChannelInfo = *it;
177  std::string channelName = pChannelInfo.name.c_str();
178  size_t len = channelName.length();
179  int maxNameLen = 20;
180  if( len>maxNameLen )
181  {
182  len = maxNameLen;
183  channelName = channelName.substr(0,len);
184  }
185  if( pChannelInfo.uri.empty() )
186  {
187  if( numCols!=0 )
188  {
189  printf( "\n" );
190  }
191  printf( "%s\n", channelName.c_str() );
192  numCols = 0;
193  continue;
194  }
195  printf("%4d: %s", pChannelInfo.channelNumber, channelName.c_str() );
196  if( numCols>=4 )
197  { // four virtual channels per row
198  printf("\n");
199  numCols = 0;
200  }
201  else
202  {
203  while( len<maxNameLen )
204  { // pad each column to 20 characters, for clean layout
205  printf( " " );
206  len++;
207  }
208  numCols++;
209  }
210  }
211  printf("\n\n");
212 }
213 
214 void VirtualChannelMap::setCurrentlyTunedChannel(int value)
215 {
216  mCurrentlyTunedChannel = value;
217 }
218 
219 void VirtualChannelMap::showList(void)
220 {
221  printf("******************************************************************************************\n");
222  printf("* Virtual Channel Map\n");
223  printf("******************************************************************************************\n");
224  print();
225 }
226 
227 void VirtualChannelMap::tuneToChannel( VirtualChannelInfo &channel, PlayerInstanceAAMP *playerInstanceAamp)
228 {
229  setCurrentlyTunedChannel(channel.channelNumber);
230  const char *name = channel.name.c_str();
231  const char *locator = channel.uri.c_str();
232  printf( "TUNING to '%s' %s\n", name, locator );
233  playerInstanceAamp->Tune(locator);
234 }
235 
236 std::string VirtualChannelMap::getNextFieldFromCSV( const char **pptr )
237 {
238  const char *ptr = *pptr;
239  const char *delim = ptr;
240  const char *next = ptr;
241 
242  if (!isprint(*ptr) && *ptr != '\0')
243  { // Skip BOM UTF-8 start codes and not end of string
244  while (!isprint(*ptr) && *ptr != '\0')
245  {
246  ptr++;
247  }
248  delim = ptr;
249  }
250 
251  if( *ptr=='\"' )
252  { // Skip startquote
253  ptr++;
254  delim = strchr(ptr,'\"');
255  if( delim )
256  {
257  next = delim+1; // skip endquote
258  }
259  else
260  {
261  delim = ptr;
262  }
263  }
264  else
265  { // Include space and greater chars and not , and not end of string
266  while( *delim >= ' ' && *delim != ',' && *delim != '\0')
267  {
268  delim++;
269  }
270  next = delim;
271  }
272 
273  if( *next==',' ) next++;
274  *pptr = next;
275 
276  return std::string(ptr,delim-ptr);
277 }
278 
279 void VirtualChannelMap::loadVirtualChannelMapFromCSV( FILE *f )
280 {
281  char buf[MAX_BUFFER_LENGTH];
282  while (fgets(buf, sizeof(buf), f))
283  {
284  VirtualChannelInfo channelInfo;
285  const char *ptr = buf;
286  std::string channelNumber = getNextFieldFromCSV( &ptr );
287  // invalid input results in 0 -- !VIRTUAL_CHANNEL_VALID, will be auto assigned
288  channelInfo.channelNumber = atoi(channelNumber.c_str());
289  channelInfo.name = getNextFieldFromCSV(&ptr);
290  channelInfo.uri = getNextFieldFromCSV(&ptr);
291  if (!channelInfo.name.empty() && !channelInfo.uri.empty())
292  {
293  add( channelInfo );
294  }
295  else
296  { // no name, no uri, no service
297  //printf("[AAMPCLI] can not parse virtual channel '%s'\n", buf);
298  }
299  }
300 }
301 
302 /**
303  * @brief Parse config entries for aamp-cli, and update mVirtualChannelMap
304  * based on the config.
305  * @param f File pointer to config to process
306  */
308 {
309  char buf[MAX_BUFFER_LENGTH];
310  while (fgets(buf, sizeof(buf), f))
311  {
312  const char *ptr = buf;
313  ptr = skipwhitespace(ptr);
314  if( *ptr=='#' )
315  { // comment line
316  continue;
317  }
318 
319  if( *ptr=='*' )
320  { // skip "*" character, if present
321  ptr = skipwhitespace(ptr+1);
322  }
323  else
324  { // not a virtual channel
325  continue;
326  }
327 
328  VirtualChannelInfo channelInfo; // extract channel number
329  // invalid input results in 0 -- !VIRTUAL_CHANNEL_VALID, will be auto assigned
330  channelInfo.channelNumber = atoi(ptr);
331  while( *ptr>='0' && *ptr<='9' ) ptr++;
332  ptr = skipwhitespace(ptr);
333 
334  // extract name
335  const char *delim = ptr;
336  while( *delim>' ' )
337  {
338  delim++;
339  }
340  channelInfo.name = std::string(ptr,delim-ptr);
341 
342  // extract locator
343  ptr = skipwhitespace(delim);
344  delim = ptr;
345  while( *delim>' ' )
346  {
347  delim++;
348  }
349  channelInfo.uri = std::string(ptr,delim-ptr);
350 
351  add( channelInfo );
352  }
353 } // loadVirtualChannelMapLegacyFormat
354 
355 const char *VirtualChannelMap::skipwhitespace( const char *ptr )
356 {
357  while( *ptr==' ' ) ptr++;
358  return ptr;
359 }
360 
VirtualChannelInfo
Holds information of a virtual channel.
Definition: AampcliVirtualChannelMap.h:39
VirtualChannelMap::loadVirtualChannelMapLegacyFormat
void loadVirtualChannelMapLegacyFormat(FILE *f)
Parse config entries for aamp-cli, and update mVirtualChannelMap based on the config.
Definition: AampcliVirtualChannelMap.cpp:307
PlayerInstanceAAMP
Player interface class for the JS pluggin.
Definition: main_aamp.h:692
VirtualChannelMap
Holds all of the virtual channels.
Definition: AampcliVirtualChannelMap.h:54
PlayerInstanceAAMP::Tune
void Tune(const char *mainManifestUrl, const char *contentType, bool bFirstAttempt, bool bFinalAttempt, const char *traceUUID, bool audioDecoderStreamSync)
Tune to a URL. DEPRECATED! This is included for backwards compatibility with current Sky AS integrati...
Definition: main_aamp.cpp:312