1 /*
2     KHOMP generic endpoint/channel library.
3     Copyright (C) 2007-2009 Khomp Ind. & Com.
4 
5   The contents of this file are subject to the Mozilla Public License Version 1.1
6   (the "License"); you may not use this file except in compliance with the
7   License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
8 
9   Software distributed under the License is distributed on an "AS IS" basis,
10   WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
11   the specific language governing rights and limitations under the License.
12 
13   Alternatively, the contents of this file may be used under the terms of the
14   "GNU Lesser General Public License 2.1" license (the “LGPL" License), in which
15   case the provisions of "LGPL License" are applicable instead of those above.
16 
17   If you wish to allow use of your version of this file only under the terms of
18   the LGPL License and not to allow others to use your version of this file under
19   the MPL, indicate your decision by deleting the provisions above and replace them
20   with the notice and other provisions required by the LGPL License. If you do not
21   delete the provisions above, a recipient may use your version of this file under
22   either the MPL or the LGPL License.
23 
24   The LGPL header follows below:
25 
26     This library is free software; you can redistribute it and/or
27     modify it under the terms of the GNU Lesser General Public
28     License as published by the Free Software Foundation; either
29     version 2.1 of the License, or (at your option) any later version.
30 
31     This library is distributed in the hope that it will be useful,
32     but WITHOUT ANY WARRANTY; without even the implied warranty of
33     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
34     Lesser General Public License for more details.
35 
36     You should have received a copy of the GNU Lesser General Public License
37     along with this library; if not, write to the Free Software Foundation, Inc.,
38     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
39 
40 */
41 
42 #include <string>
43 #include <stdexcept>
44 
45 #include <format.hpp>
46 
47 #include <k3l.h>
48 
49 /* if using full k3l.h (for softpbx), version already defined. */
50 #ifndef k3lApiMajorVersion
51 # include <k3lVersion.h>
52 #endif
53 
54 #ifdef __GNUC_PREREQ
55 #if __GNUC_PREREQ(4,3)
56 #include <cstring>
57 #endif
58 #endif
59 
60 #include <types.hpp>
61 
62 #ifndef _K3LAPI_HPP_
63 #define _K3LAPI_HPP_
64 
65 struct K3LAPITraits
66 {
67     struct invalid_device;
68     struct invalid_channel;
69     struct invalid_link;
70 
71     struct invalid_target: public std::runtime_error
72     {
73         friend class invalid_device;
74         friend class invalid_channel;
75         friend class invalid_link;
76 
77         const int32 device, object;
78 
79       protected:
invalid_targetK3LAPITraits::invalid_target80         invalid_target(int32 _device, int32 _object, const std::string & msg)
81         : std::runtime_error(msg), device(_device), object(_object) {};
82     };
83 
84     struct invalid_device: public invalid_target
85     {
invalid_deviceK3LAPITraits::invalid_device86         invalid_device(int32 _device)
87         : invalid_target(_device, -1, STG(FMT("invalid device number '%d'") % _device)) {};
88     };
89 
90     struct invalid_channel: public invalid_target
91     {
invalid_channelK3LAPITraits::invalid_channel92         invalid_channel(int32 _device, int32 _channel)
93         : invalid_target(_device, _channel, STG(FMT("invalid channel number '%d' on device '%d'") % _channel % _device)) {};
94     };
95 
96     struct invalid_link: public invalid_target
97     {
invalid_linkK3LAPITraits::invalid_link98         invalid_link(int32 _device, int32 _link)
99         : invalid_target(_device, _link, STG(FMT("invalid link number '%d' on device '%d'") % _link % _device)) {};
100     };
101 };
102 
103 struct K3LAPIBase
104 {
105     /* High level checked object identifier. */
106 
107     struct GenericTarget
108     {
109         typedef enum { DEVICE, CHANNEL, MIXER, LINK } Type;
110 
GenericTargetK3LAPIBase::GenericTarget111         GenericTarget(const K3LAPIBase & k3lapi, Type _type, int32 _device, int32 _object)
112         : type(_type), device((unsigned int)_device), object((unsigned int)_object)
113         {
114             switch (_type)
115             {
116                 case DEVICE:
117                     if (!k3lapi.valid_device(_device))
118                         throw K3LAPITraits::invalid_device(_device);
119                     break;
120 
121                 case CHANNEL:
122                 case MIXER:
123                     if (!k3lapi.valid_channel(_device, _object))
124                         throw K3LAPITraits::invalid_channel(_device, _object);
125                     break;
126 
127                 case LINK:
128                     if (!k3lapi.valid_link(_device, _object))
129                         throw K3LAPITraits::invalid_link(_device, _object);
130                     break;
131             }
132         };
133 
134         const Type type;
135 
136         const unsigned int device;
137         const unsigned int object;
138     };
139 
140 /*
141     struct LinkTarget    : public GenericTarget
142     {
143         LinkTarget(const K3LAPIBase & k3lapi, int32 _device, int32 _object)
144         : GenericTarget(k3lapi, GenericTarget::LINK, _device, _object) {};
145     };
146 
147     struct ChannelTarget : public GenericTarget
148     {
149         ChannelTarget(const K3LAPIBase & k3lapi, int32 _device, int32 _object)
150         : GenericTarget(k3lapi, GenericTarget::CHANNEL, _device, _object) {};
151     };
152 
153 */
154     template < GenericTarget::Type T >
155     struct Target: public GenericTarget
156     {
TargetK3LAPIBase::Target157         Target(const K3LAPIBase & k3lapi, int32 _device, int32 _object)
158         : GenericTarget(k3lapi, T, _device, _object) {};
159 
160 //        operator const GenericTarget&() const { return static_cast<const GenericTarget &>(*this); };
161     };
162 
163     /* exceptions */
164 
165     struct start_failed: public std::runtime_error
166     {
start_failedK3LAPIBase::start_failed167         start_failed(const char * msg)
168         : std::runtime_error(msg) {};
169     };
170 
171     struct failed_command
172     {
failed_commandK3LAPIBase::failed_command173         failed_command(int32 _code, unsigned short _dev, unsigned short _obj, int32 _rc)
174         : code(_code), dev(_dev), obj(_obj), rc(_rc) {};
175 
176         int32           code;
177         unsigned short  dev;
178         unsigned short  obj;
179         int32           rc;
180     };
181 
182     struct failed_raw_command
183     {
failed_raw_commandK3LAPIBase::failed_raw_command184         failed_raw_command(unsigned short _dev, unsigned short _dsp, int32 _rc)
185         : dev(_dev), dsp(_dsp), rc(_rc) {};
186 
187         unsigned short  dev;
188         unsigned short  dsp;
189         int32           rc;
190     };
191 
192     struct get_param_failed
193     {
get_param_failedK3LAPIBase::get_param_failed194         get_param_failed(std::string _name, int32 _rc)
195         : name(_name), rc((KLibraryStatus)_rc) {};
196 
197         std::string name;
198         KLibraryStatus rc;
199     };
200 
201     /* typedefs essenciais */
202 
203     typedef K3L_DEVICE_CONFIG          device_conf_type;
204     typedef K3L_CHANNEL_CONFIG        channel_conf_type;
205     typedef K3L_CHANNEL_CONFIG *  channel_ptr_conf_type;
206     typedef K3L_LINK_CONFIG              link_conf_type;
207     typedef K3L_LINK_CONFIG *        link_ptr_conf_type;
208 
209     /* constructors/destructors */
210 
211              K3LAPIBase();
~K3LAPIBaseK3LAPIBase212     virtual ~K3LAPIBase() {};
213 
214     /* (init|final)ialize the whole thing! */
215 
216     void start(void);
217     void stop(void);
218 
219     /* verificacao de intervalos */
220 
valid_deviceK3LAPIBase221     inline bool valid_device(int32 dev) const
222     {
223         return (dev >= 0 && dev < ((int32)_device_count));
224     }
225 
valid_channelK3LAPIBase226     inline bool valid_channel(int32 dev, int32 obj) const
227     {
228         return (valid_device(dev) && obj >= 0 && obj < ((int32)_channel_count[dev]));
229     }
230 
valid_linkK3LAPIBase231     inline bool valid_link(int32 dev, int32 obj) const
232     {
233         return (valid_device(dev) && obj >= 0 && obj < ((int32)_link_count[dev]));
234     }
235 
236     /* envio de comandos para placa (geral) */
237 
238     void raw_command(int32 dev, int32 dsp, std::string & str) const;
239     void raw_command(int32 dev, int32 dsp, const char * cmds, int32 size) const;
240 
241     /* obter dados 'cacheados' (geral) */
242 
device_countK3LAPIBase243     inline unsigned int device_count(void) const
244     {
245         return _device_count;
246     }
247 
248     /* envio de comandos para placa (sem identificadores) */
249 
250     void mixer(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const;
251     void mixerRecord(int32 dev, KDeviceType type, int32 obj, byte track, KMixerSource src, int32 index) const;
252     void mixerCTbus(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const;
253 
254     void command (int32 dev, int32 obj, int32 code, std::string & str) const;
255     void command (int32 dev, int32 obj, int32 code, const char * parms = NULL) const;
256 
257 
258     /* envio de comandos para placa (com identificadores) */
259 
mixerK3LAPIBase260     void mixer(const GenericTarget & tgt, byte track, KMixerSource src, int32 index) const
261     {
262         mixer(tgt.device, tgt.object, track, src, index);
263     }
264 
mixerRecordK3LAPIBase265     void mixerRecord(const GenericTarget & tgt, byte track, KMixerSource src, int32 index) const
266     {
267         mixerRecord((int32)tgt.device, _device_type[tgt.device], (int32)tgt.object, track, src, index);
268     }
269 
mixerCTbusK3LAPIBase270     void mixerCTbus(const GenericTarget & tgt, byte track, KMixerSource src, int32 index) const
271     {
272         mixerCTbus((int32)tgt.device, (int32)tgt.object, track, src, index);
273     }
274 
commandK3LAPIBase275     void command(const GenericTarget & tgt, int32 code, std::string & str) const
276     {
277         command((int32)tgt.device, (int32)tgt.object, code, str);
278     };
279 
commandK3LAPIBase280     void command(const GenericTarget & tgt, int32 code, const char * parms = NULL) const
281     {
282         command((int32)tgt.device, (int32)tgt.object, code, parms);
283     };
284 
285     /* obter dados 'cacheados' (com indentificadores) */
286 
channel_countK3LAPIBase287     inline unsigned int channel_count(const GenericTarget & tgt) const
288     {
289         return _channel_count[tgt.device];
290     }
291 
link_countK3LAPIBase292     inline unsigned int link_count(const GenericTarget & tgt) const
293     {
294         return _link_count[tgt.device];
295     }
296 
device_typeK3LAPIBase297     KDeviceType device_type(const GenericTarget & tgt) const
298     {
299         return _device_type[tgt.device];
300     }
301 
device_configK3LAPIBase302     const K3L_DEVICE_CONFIG & device_config(const GenericTarget & tgt) const
303     {
304         return _device_config[tgt.device];
305     }
306 
channel_configK3LAPIBase307     const K3L_CHANNEL_CONFIG & channel_config(const Target<GenericTarget::CHANNEL> & tgt) const
308     {
309         return _channel_config[tgt.device][tgt.object];
310     }
311 
link_configK3LAPIBase312     const K3L_LINK_CONFIG & link_config(const Target<GenericTarget::LINK> & tgt) const
313     {
314         return _link_config[tgt.device][tgt.object];
315     }
316 
317     /* pega valores em strings de eventos */
318 
319     KLibraryStatus get_param(K3L_EVENT *ev, const char *name, std::string &res) const;
320 
321     std::string get_param(K3L_EVENT *ev, const char *name) const;
322     std::string get_param_optional(K3L_EVENT *ev, const char *name) const;
323 
324     /* inicializa valores em cache */
325 
326     void init(void);
327     void fini(void);
328 
329     /* utilidades diversas e informacoes */
330 
331     enum DspType
332     {
333         DSP_AUDIO,
334         DSP_SIGNALING,
335     };
336 
337     int32 get_dsp(KDeviceType, DspType) const;
338 
339     int32 get_dsp(const GenericTarget &, DspType) const;
340 
341  protected:
342 
343     unsigned int           _device_count;
344     unsigned int *        _channel_count;
345     unsigned int *           _link_count;
346 
347          device_conf_type *   _device_config;
348     channel_ptr_conf_type *  _channel_config;
349        link_ptr_conf_type *     _link_config;
350               KDeviceType *     _device_type;
351 };
352 
353 /* exceptions */
354 template < bool E = false >
355 struct K3LAPIException
356 {
invalid_deviceK3LAPIException357     void invalid_device(const int32 device) const
358     {
359         /* NOTHING */
360     }
361 
invalid_channelK3LAPIException362     void invalid_channel(const int32 device, const int32 channel) const
363     {
364         /* NOTHING */
365     }
366 
invalid_linkK3LAPIException367     void invalid_link(const int32 device, const int32 link) const
368     {
369         /* NOTHING */
370     }
371 };
372 
373 template < >
374 struct K3LAPIException < true >
375 {
invalid_deviceK3LAPIException376     void invalid_device(const int32 device) const
377     {
378         throw K3LAPITraits::invalid_device(device);
379     }
380 
invalid_channelK3LAPIException381     void invalid_channel(const int32 device, const int32 channel) const
382     {
383         throw K3LAPITraits::invalid_channel(device, channel);
384     }
385 
invalid_linkK3LAPIException386     void invalid_link(const int32 device, const int32 link) const
387     {
388         throw K3LAPITraits::invalid_link(device, link);
389     }
390 };
391 
392 template < bool E = false >
393 struct K3LAPITemplate: public K3LAPIBase, protected K3LAPIException < E >
394 {
395     using K3LAPIBase::device_config;
396     using K3LAPIBase::channel_config;
397     using K3LAPIBase::link_config;
398 
399     using K3LAPIBase::device_type;
400     using K3LAPIBase::get_dsp;
401 
402     using K3LAPIBase::mixerRecord;
403 
404     /* obter dados 'cacheados' (sem identificadores) */
405 
channel_countK3LAPITemplate406     inline unsigned int channel_count(int32 dev) const
407     {
408         if (!valid_device(dev))
409         {
410             K3LAPIException< E >::invalid_device(dev);
411             return 0;
412         }
413 
414         return _channel_count[dev];
415     }
416 
link_countK3LAPITemplate417     inline unsigned int link_count(int32 dev) const
418     {
419         if (!valid_device(dev))
420         {
421             K3LAPIException< E >::invalid_device(dev);
422             return 0;
423         }
424 
425         return _link_count[dev];
426     }
427 
channel_statsK3LAPITemplate428     inline uint32 channel_stats(int32 dev, int32 obj, uint32 index) const
429     {
430         if (!valid_channel(dev, obj))
431         {
432             K3LAPIException< E >::invalid_channel(dev, obj);
433             return 0u;
434         }
435 
436         uint32 res_value = 0u;
437 
438 #if K3L_AT_LEAST(2,1,0)
439         if (k3lGetChannelStats(dev, obj, index, &res_value) != ksSuccess)
440             return 0u;
441 
442         return res_value;
443 #endif
444     }
445 
device_typeK3LAPITemplate446     KDeviceType device_type(int32 dev) const
447     {
448         if (!valid_device(dev))
449         {
450             K3LAPIException< E >::invalid_device(dev);
451             return kdtDevTypeCount;
452         }
453 
454         return _device_type[dev];
455     }
456 
device_configK3LAPITemplate457     const K3L_DEVICE_CONFIG & device_config(int32 dev) const
458     {
459         if (!valid_device(dev))
460             throw K3LAPITraits::invalid_device(dev);
461 
462         return _device_config[dev];
463     }
464 
channel_configK3LAPITemplate465     const K3L_CHANNEL_CONFIG & channel_config(int32 dev, int32 obj) const
466     {
467         if (!valid_channel(dev, obj))
468             throw K3LAPITraits::invalid_channel(dev, obj);
469 
470         return _channel_config[dev][obj];
471     }
472 
link_configK3LAPITemplate473     const K3L_LINK_CONFIG & link_config(int32 dev, int32 obj) const
474     {
475         if (!valid_link(dev, obj))
476             throw K3LAPITraits::invalid_link(dev, obj);
477 
478         return _link_config[dev][obj];
479     }
480 
get_dspK3LAPITemplate481     int32 get_dsp(int32 dev, DspType type) const
482     {
483         return get_dsp(device_type(dev), type);
484     }
485 
mixerRecordK3LAPITemplate486     void mixerRecord(int32 dev, int32 obj, byte track, KMixerSource src, int32 index) const
487     {
488         mixerRecord(dev, device_type(dev), obj, track, src, index);
489     }
490 };
491 
492 typedef K3LAPITemplate<> K3LAPI;
493 
494 #endif /* _K3LAPI_HPP_ */
495