1 /*
2 * Copyright (c) 2007-2014, Anthony Minessale II
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of the original author; nor the names of any contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34
35 #include "freetdm.h"
36 #include "ftdm_pika.h"
37
38
39 #define MAX_NUMBER_OF_TRUNKS 64
40 #define PIKA_BLOCK_SIZE 160
41 #define PIKA_BLOCK_LEN 20
42 #define PIKA_NUM_BUFFERS 8
43 #define TRY_OR_DIE(__code, __status, __label) if ((status = __code ) != __status) goto __label
44 #define pk_atof(__a) (PK_FLOAT) atof(__a)
45
46 PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event);
47
48 FTDM_ENUM_NAMES(PIKA_SPAN_NAMES, PIKA_SPAN_STRINGS)
49 PIKA_STR2ENUM(pika_str2span, pika_span2str, PIKA_TSpanFraming, PIKA_SPAN_NAMES, PIKA_SPAN_INVALID)
50
51 FTDM_ENUM_NAMES(PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_STRINGS)
52 PIKA_STR2ENUM(pika_str2span_encoding, pika_span_encoding2str, PIKA_TSpanEncoding, PIKA_SPAN_ENCODING_NAMES, PIKA_SPAN_ENCODING_INVALID)
53
54 FTDM_ENUM_NAMES(PIKA_LL_NAMES, PIKA_LL_STRINGS)
55 PIKA_STR2ENUM(pika_str2loop_length, pika_loop_length2str, PIKA_TSpanLoopLength, PIKA_LL_NAMES, PIKA_SPAN_LOOP_INVALID)
56
57 FTDM_ENUM_NAMES(PIKA_LBO_NAMES, PIKA_LBO_STRINGS)
58 PIKA_STR2ENUM(pika_str2lbo, pika_lbo2str, PIKA_TSpanBuildOut, PIKA_LBO_NAMES, PIKA_SPAN_LBO_INVALID)
59
60 FTDM_ENUM_NAMES(PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_STRINGS)
61 PIKA_STR2ENUM(pika_str2compand_mode, pika_compand_mode2str, PIKA_TSpanCompandMode, PIKA_SPAN_COMPAND_MODE_NAMES, PIKA_SPAN_COMPAND_MODE_INVALID)
62
63
64 typedef enum {
65 PK_FLAG_READY = (1 << 0),
66 PK_FLAG_LOCKED = (1 << 1)
67 } pk_flag_t;
68
69 struct general_config {
70 uint32_t region;
71 };
72 typedef struct general_config general_config_t;
73
74 struct pika_channel_profile {
75 char name[80];
76 PKH_TRecordConfig record_config;
77 PKH_TPlayConfig play_config;
78 int ec_enabled;
79 PKH_TECConfig ec_config;
80 PKH_TSpanConfig span_config;
81 general_config_t general_config;
82 int cust_span;
83 };
84 typedef struct pika_channel_profile pika_channel_profile_t;
85
86 static struct {
87 PKH_TSystemDeviceList board_list;
88 TPikaHandle open_boards[MAX_NUMBER_OF_TRUNKS];
89 TPikaHandle system_handle;
90 PKH_TSystemConfig system_config;
91 PKH_TRecordConfig record_config;
92 PKH_TPlayConfig play_config;
93 PKH_TECConfig ec_config;
94 PKH_TSpanConfig t1_span_config;
95 PKH_TSpanConfig e1_span_config;
96 ftdm_hash_t *profile_hash;
97 general_config_t general_config;
98 } globals;
99
100
101 struct pika_span_data {
102 TPikaHandle event_queue;
103 PKH_TPikaEvent last_oob_event;
104 uint32_t boardno;
105 PKH_TSpanConfig span_config;
106 TPikaHandle handle;
107 uint32_t flags;
108 };
109 typedef struct pika_span_data pika_span_data_t;
110
111 struct pika_chan_data {
112 TPikaHandle handle;
113 TPikaHandle media_in;
114 TPikaHandle media_out;
115 TPikaHandle media_in_queue;
116 TPikaHandle media_out_queue;
117 PKH_TPikaEvent last_media_event;
118 PKH_TPikaEvent last_oob_event;
119 PKH_TRecordConfig record_config;
120 PKH_TPlayConfig play_config;
121 int ec_enabled;
122 PKH_TECConfig ec_config;
123 PKH_THDLCConfig hdlc_config;
124 ftdm_buffer_t *digit_buffer;
125 ftdm_mutex_t *digit_mutex;
126 ftdm_size_t dtmf_len;
127 uint32_t flags;
128 uint32_t hdlc_bytes;
129 };
130 typedef struct pika_chan_data pika_chan_data_t;
131
pika_board_type_string(PK_UINT type)132 static const char *pika_board_type_string(PK_UINT type)
133 {
134 if (type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
135 return "digital_gateway";
136 }
137
138 if (type == PKH_BOARD_TYPE_ANALOG_GATEWAY) {
139 return "analog_gateway";
140 }
141
142 return "unknown";
143 }
144
145 /**
146 * \brief Process configuration variable for a pika profile
147 * \param category Pika profile name
148 * \param var Variable name
149 * \param val Variable value
150 * \param lineno Line number from configuration file (unused)
151 * \return Success
152 */
FIO_CONFIGURE_FUNCTION(pika_configure)153 static FIO_CONFIGURE_FUNCTION(pika_configure)
154 {
155 pika_channel_profile_t *profile = NULL;
156 int ok = 1;
157
158 if (!(profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
159 profile = ftdm_malloc(sizeof(*profile));
160 memset(profile, 0, sizeof(*profile));
161 ftdm_set_string(profile->name, category);
162 profile->ec_config = globals.ec_config;
163 profile->record_config = globals.record_config;
164 profile->play_config = globals.play_config;
165 hashtable_insert(globals.profile_hash, (void *)profile->name, profile, HASHTABLE_FLAG_NONE);
166 ftdm_log(FTDM_LOG_INFO, "creating profile [%s]\n", category);
167 }
168
169 if (!strcasecmp(var, "rx-gain")) {
170 profile->record_config.gain = pk_atof(val);
171 } else if (!strcasecmp(var, "rx-agc-enabled")) {
172 profile->record_config.AGC.enabled = ftdm_true(val);
173 } else if (!strcasecmp(var, "rx-agc-targetPower")) {
174 profile->record_config.AGC.targetPower = pk_atof(val);
175 } else if (!strcasecmp(var, "rx-agc-minGain")) {
176 profile->record_config.AGC.minGain = pk_atof(val);
177 } else if (!strcasecmp(var, "rx-agc-maxGain")) {
178 profile->record_config.AGC.maxGain = pk_atof(val);
179 } else if (!strcasecmp(var, "rx-agc-attackRate")) {
180 profile->record_config.AGC.attackRate = atoi(val);
181 } else if (!strcasecmp(var, "rx-agc-decayRate")) {
182 profile->record_config.AGC.decayRate = atoi(val);
183 } else if (!strcasecmp(var, "rx-agc-speechThreshold")) {
184 profile->record_config.AGC.speechThreshold = pk_atof(val);
185 } else if (!strcasecmp(var, "rx-vad-enabled")) {
186 profile->record_config.VAD.enabled = ftdm_true(val);
187 } else if (!strcasecmp(var, "rx-vad-activationThreshold")) {
188 profile->record_config.VAD.activationThreshold = pk_atof(val);
189 } else if (!strcasecmp(var, "rx-vad-activationDebounceTime")) {
190 profile->record_config.VAD.activationDebounceTime = atoi(val);
191 } else if (!strcasecmp(var, "rx-vad-deactivationThreshold")) {
192 profile->record_config.VAD.deactivationThreshold = pk_atof(val);
193 } else if (!strcasecmp(var, "rx-vad-deactivationDebounceTime")) {
194 profile->record_config.VAD.deactivationDebounceTime = atoi(val);
195 } else if (!strcasecmp(var, "rx-vad-preSpeechBufferSize")) {
196 profile->record_config.VAD.preSpeechBufferSize = atoi(val);
197 } else if (!strcasecmp(var, "tx-gain")) {
198 profile->play_config.gain = pk_atof(val);
199 } else if (!strcasecmp(var, "tx-agc-enabled")) {
200 profile->play_config.AGC.enabled = ftdm_true(val);
201 } else if (!strcasecmp(var, "tx-agc-targetPower")) {
202 profile->play_config.AGC.targetPower = pk_atof(val);
203 } else if (!strcasecmp(var, "tx-agc-minGain")) {
204 profile->play_config.AGC.minGain = pk_atof(val);
205 } else if (!strcasecmp(var, "tx-agc-maxGain")) {
206 profile->play_config.AGC.maxGain = pk_atof(val);
207 } else if (!strcasecmp(var, "tx-agc-attackRate")) {
208 profile->play_config.AGC.attackRate = atoi(val);
209 } else if (!strcasecmp(var, "tx-agc-decayRate")) {
210 profile->play_config.AGC.decayRate = atoi(val);
211 } else if (!strcasecmp(var, "tx-agc-speechThreshold")) {
212 profile->play_config.AGC.speechThreshold = pk_atof(val);
213 } else if (!strcasecmp(var, "ec-enabled")) {
214 profile->ec_enabled = ftdm_true(val);
215 } else if (!strcasecmp(var, "ec-doubleTalkerThreshold")) {
216 profile->ec_config.doubleTalkerThreshold = pk_atof(val);
217 } else if (!strcasecmp(var, "ec-speechPresentThreshold")) {
218 profile->ec_config.speechPresentThreshold = pk_atof(val);
219 } else if (!strcasecmp(var, "ec-echoSuppressionThreshold")) {
220 profile->ec_config.echoSuppressionThreshold = pk_atof(val);
221 } else if (!strcasecmp(var, "ec-echoSuppressionEnabled")) {
222 profile->ec_config.echoSuppressionEnabled = ftdm_true(val);
223 } else if (!strcasecmp(var, "ec-comfortNoiseEnabled")) {
224 profile->ec_config.comfortNoiseEnabled = ftdm_true(val);
225 } else if (!strcasecmp(var, "ec-adaptationModeEnabled")) {
226 profile->ec_config.adaptationModeEnabled = ftdm_true(val);
227 } else if (!strcasecmp(var, "framing")) {
228 profile->span_config.framing = pika_str2span(val);
229 profile->cust_span++;
230 } else if (!strcasecmp(var, "encoding")) {
231 profile->span_config.encoding = pika_str2span_encoding(val);
232 profile->cust_span++;
233 } else if (!strcasecmp(var, "loopLength")) {
234 profile->span_config.loopLength = pika_str2loop_length(val);
235 profile->cust_span++;
236 } else if (!strcasecmp(var, "buildOut")) {
237 profile->span_config.buildOut = pika_str2lbo(val);
238 profile->cust_span++;
239 } else if (!strcasecmp(var, "compandMode")) {
240 profile->span_config.compandMode = pika_str2compand_mode(val);
241 profile->cust_span++;
242 } else if (!strcasecmp(var, "region")) {
243 if (!strcasecmp(val, "eu")) {
244 profile->general_config.region = PKH_TRUNK_EU;
245 } else {
246 profile->general_config.region = PKH_TRUNK_NA;
247 }
248 } else {
249 ok = 0;
250 }
251
252 if (ok) {
253 ftdm_log(FTDM_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
254 } else {
255 ftdm_log(FTDM_LOG_ERROR, "unknown param [%s]\n", var);
256 }
257
258 return FTDM_SUCCESS;
259 }
260
261 /**
262 * \brief Pika event handler
263 * \param event Pika event
264 */
media_out_callback(PKH_TPikaEvent * event)265 PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event)
266 {
267 PK_STATUS pk_status;
268 ftdm_channel_t *ftdmchan = event->userData;
269 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
270
271 //PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
272 //PKH_EVENT_GetText(event->id, event_text, sizeof(event_text));
273 //ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
274
275 switch (event->id) {
276 case PKH_EVENT_PLAY_IDLE:
277 {
278 while (ftdm_buffer_inuse(chan_data->digit_buffer)) {
279 char dtmf[128] = "";
280 ftdm_mutex_lock(chan_data->digit_mutex);
281 chan_data->dtmf_len = ftdm_buffer_read(chan_data->digit_buffer, dtmf, sizeof(dtmf));
282 pk_status = PKH_TG_PlayDTMF(chan_data->media_out, dtmf);
283 ftdm_mutex_unlock(chan_data->digit_mutex);
284 }
285 }
286 break;
287 case PKH_EVENT_TG_TONE_PLAYED:
288 {
289
290 if (!event->p1) {
291 ftdm_mutex_lock(chan_data->digit_mutex);
292 PKH_PLAY_Start(chan_data->media_out);
293 chan_data->dtmf_len = 0;
294 ftdm_mutex_unlock(chan_data->digit_mutex);
295 }
296
297
298 }
299 break;
300 default:
301 break;
302 }
303
304 }
305
306 /**
307 * \brief Initialises a range of pika channels
308 * \param span FreeTDM span
309 * \param boardno Pika board number
310 * \param spanno Pika span number
311 * \param start Initial pika channel number
312 * \param end Final pika channel number
313 * \param type FreeTDM channel type
314 * \param name FreeTDM span name
315 * \param number FreeTDM span number
316 * \param profile Pika channel profile
317 * \return number of spans configured
318 */
pika_open_range(ftdm_span_t * span,unsigned boardno,unsigned spanno,unsigned start,unsigned end,ftdm_chan_type_t type,char * name,char * number,pika_channel_profile_t * profile)319 static unsigned pika_open_range(ftdm_span_t *span, unsigned boardno, unsigned spanno, unsigned start, unsigned end,
320 ftdm_chan_type_t type, char *name, char *number, pika_channel_profile_t *profile)
321 {
322 unsigned configured = 0, x;
323 PK_STATUS status;
324 PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
325 pika_span_data_t *span_data;
326
327 if (boardno >= globals.board_list.numberOfBoards) {
328 ftdm_log(FTDM_LOG_ERROR, "Board %u is not present!\n", boardno);
329 return 0;
330 }
331
332 if (!globals.open_boards[boardno]) {
333 status = PKH_BOARD_Open(globals.board_list.board[boardno].id,
334 NULL,
335 &globals.open_boards[boardno]);
336 if(status != PK_SUCCESS) {
337 ftdm_log(FTDM_LOG_ERROR, "Error: PKH_BOARD_Open %d failed(%s)!\n", boardno,
338 PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
339 return 0;
340 }
341
342 ftdm_log(FTDM_LOG_DEBUG, "Open board %u\n", boardno);
343
344 //PKH_BOARD_SetDebugTrace(globals.open_boards[boardno], 1, 0);
345
346 }
347
348 if (span->io_data) {
349 span_data = span->io_data;
350 } else {
351 span_data = ftdm_malloc(sizeof(*span_data));
352 assert(span_data != NULL);
353 memset(span_data, 0, sizeof(*span_data));
354 span_data->boardno = boardno;
355
356 status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &span_data->event_queue);
357
358 if (status != PK_SUCCESS) {
359 ftdm_log(FTDM_LOG_ERROR, "Error: PKH_QUEUE_Create failed(%s)!\n",
360 PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
361 ftdm_safe_free(span_data);
362 return 0;
363 }
364
365 //PKH_QUEUE_Attach(span_data->event_queue, globals.open_boards[boardno], NULL);
366
367 span->io_data = span_data;
368 }
369
370 if (type == FTDM_CHAN_TYPE_FXS || type == FTDM_CHAN_TYPE_FXO) {
371 start--;
372 end--;
373 }
374
375 for(x = start; x < end; x++) {
376 ftdm_channel_t *chan;
377 pika_chan_data_t *chan_data = NULL;
378
379 chan_data = ftdm_malloc(sizeof *chan_data);
380 assert(chan_data);
381 memset(chan_data, 0, sizeof(*chan_data));
382 ftdm_span_add_channel(span, 0, type, &chan);
383 chan->io_data = chan_data;
384
385 if ((type == FTDM_CHAN_TYPE_B || type == FTDM_CHAN_TYPE_DQ921) && !span_data->handle) {
386 PKH_TBoardConfig boardConfig;
387
388 TRY_OR_DIE(PKH_BOARD_GetConfig(globals.open_boards[boardno], &boardConfig), PK_SUCCESS, error);
389 if ((profile && profile->general_config.region == PKH_TRUNK_EU) || ftdm_test_flag(span_data, PK_FLAG_LOCKED)) {
390 if (span->trunk_type == FTDM_TRUNK_T1) {
391 ftdm_log(FTDM_LOG_WARNING, "Changing trunk type to E1 based on previous config.\n");
392 }
393 span->trunk_type = FTDM_TRUNK_E1;
394 }
395
396 if (span->trunk_type == FTDM_TRUNK_T1) {
397 if (ftdm_test_flag(span_data, PK_FLAG_LOCKED)) {
398 ftdm_log(FTDM_LOG_WARNING, "Already locked into E1 mode!\n");
399 }
400 } else if (span->trunk_type == FTDM_TRUNK_E1) {
401 boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
402 if ((status = PKH_BOARD_SetConfig(globals.open_boards[boardno], &boardConfig)) != PK_SUCCESS) {
403 ftdm_log(FTDM_LOG_ERROR, "Error: [%s]\n",
404 PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
405 }
406 ftdm_set_flag(span_data, PK_FLAG_LOCKED);
407 }
408
409 TRY_OR_DIE(PKH_SPAN_Open(globals.open_boards[boardno], spanno, NULL, &span_data->handle), PK_SUCCESS, error);
410 TRY_OR_DIE(PKH_SPAN_GetConfig(span_data->handle, &span_data->span_config), PK_SUCCESS, error);
411 TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, span_data->handle, (PK_VOID*) span), PK_SUCCESS, error);
412 }
413
414 if (type == FTDM_CHAN_TYPE_FXO) {
415 PKH_TTrunkConfig trunkConfig;
416
417 TRY_OR_DIE(PKH_TRUNK_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
418 TRY_OR_DIE(PKH_TRUNK_Seize(chan_data->handle), PK_SUCCESS, error);
419
420 if (profile && profile->general_config.region == PKH_TRUNK_EU) {
421 TRY_OR_DIE(PKH_TRUNK_GetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
422 trunkConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
423 trunkConfig.audioFormat = PKH_AUDIO_ALAW;
424 trunkConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
425 chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
426 TRY_OR_DIE(PKH_TRUNK_SetConfig(chan_data->handle, &trunkConfig), PK_SUCCESS, error);
427 } else {
428 chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
429 }
430
431
432 TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
433 TRY_OR_DIE(PKH_TRUNK_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
434 TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
435 TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
436 TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
437 TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
438 TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
439 TRY_OR_DIE(PKH_TRUNK_Start(chan_data->handle), PK_SUCCESS, error);
440 } else if (type == FTDM_CHAN_TYPE_FXS) {
441 PKH_TPhoneConfig phoneConfig;
442
443 if (profile && profile->general_config.region == PKH_TRUNK_EU) {
444 TRY_OR_DIE(PKH_PHONE_GetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
445 phoneConfig.internationalControl = PKH_PHONE_INTERNATIONAL_CONTROL_EU;
446 phoneConfig.compandMode = PKH_PHONE_AUDIO_ALAW;
447 chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
448 TRY_OR_DIE(PKH_PHONE_SetConfig(chan_data->handle, &phoneConfig), PK_SUCCESS, error);
449 } else {
450 chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
451 }
452
453 TRY_OR_DIE(PKH_PHONE_Open(globals.open_boards[boardno], x, &chan_data->handle), PK_SUCCESS, error);
454 TRY_OR_DIE(PKH_PHONE_Seize(chan_data->handle), PK_SUCCESS, error);
455 TRY_OR_DIE(PKH_PHONE_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
456 TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
457 TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
458 TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
459 TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
460 TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
461 TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
462 TRY_OR_DIE(PKH_PHONE_Start(chan_data->handle), PK_SUCCESS, error);
463 } else if (type == FTDM_CHAN_TYPE_B) {
464 TRY_OR_DIE(PKH_SPAN_SeizeChannel(span_data->handle, x), PK_SUCCESS, error);
465 TRY_OR_DIE(PKH_SPAN_GetMediaStreams(span_data->handle, x, &chan_data->media_in, &chan_data->media_out), PK_SUCCESS, error);
466 TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
467 TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan), PK_SUCCESS, error);
468 TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue), PK_SUCCESS, error);
469 TRY_OR_DIE(PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback), PK_SUCCESS, error);
470 TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan), PK_SUCCESS, error);
471 } else if (type == FTDM_CHAN_TYPE_DQ921) {
472 TRY_OR_DIE(PKH_SPAN_HDLC_Open(span_data->handle, PKH_SPAN_HDLC_MODE_NORMAL, &chan_data->handle), PK_SUCCESS, error);
473 TRY_OR_DIE(PKH_SPAN_HDLC_GetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
474 chan_data->hdlc_config.channelId = x;
475 TRY_OR_DIE(PKH_SPAN_HDLC_SetConfig(chan_data->handle, &chan_data->hdlc_config), PK_SUCCESS, error);
476 TRY_OR_DIE(PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue), PK_SUCCESS, error);
477 TRY_OR_DIE(PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
478 TRY_OR_DIE(PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan), PK_SUCCESS, error);
479
480 if (profile) {
481 if (profile->cust_span) {
482 span_data->span_config.framing = profile->span_config.framing;
483 span_data->span_config.encoding = profile->span_config.encoding;
484 span_data->span_config.loopLength = profile->span_config.loopLength;
485 span_data->span_config.buildOut = profile->span_config.buildOut;
486 span_data->span_config.compandMode = profile->span_config.compandMode;
487 } else {
488 if (profile->general_config.region == PKH_TRUNK_EU) {
489 span_data->span_config = globals.e1_span_config;
490 } else {
491 span_data->span_config = globals.t1_span_config;
492 }
493 }
494 } else {
495 if (span->trunk_type == FTDM_TRUNK_E1) {
496 span_data->span_config = globals.e1_span_config;
497 } else {
498 span_data->span_config = globals.t1_span_config;
499 }
500 }
501
502 PKH_SPAN_SetConfig(span_data->handle, &span_data->span_config);
503 TRY_OR_DIE(PKH_SPAN_Start(span_data->handle), PK_SUCCESS, error);
504 }
505
506 goto ok;
507
508 error:
509 PKH_ERROR_GetText(status, error_text, sizeof(error_text));
510 ftdm_log(FTDM_LOG_ERROR, "failure configuring device b%ds%dc%d [%s]\n", boardno, spanno, x, error_text);
511 continue;
512 ok:
513 ftdm_set_flag(chan_data, PK_FLAG_READY);
514 status = PKH_RECORD_GetConfig(chan_data->media_in, &chan_data->record_config);
515 chan_data->record_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
516 chan_data->record_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
517 chan_data->record_config.bufferSize = PIKA_BLOCK_SIZE;
518 chan_data->record_config.numberOfBuffers = PIKA_NUM_BUFFERS;
519 chan_data->record_config.VAD.enabled = PK_FALSE;
520 //chan_data->record_config.speechSegmentEventsEnabled = PK_FALSE;
521 //chan_data->record_config.gain = rxgain;
522
523 status = PKH_PLAY_GetConfig(chan_data->media_out, &chan_data->play_config);
524 chan_data->play_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
525 chan_data->play_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
526 chan_data->play_config.AGC.enabled = PK_FALSE;
527 ftdm_log(FTDM_LOG_INFO, "configuring device b%ds%dc%d as FreeTDM device %d:%d\n", boardno, spanno, x, chan->span_id, chan->chan_id);
528
529 if (profile) {
530 ftdm_log(FTDM_LOG_INFO, "applying config profile %s to device %d:%d\n", profile->name, chan->span_id, chan->chan_id);
531 chan_data->record_config.gain = profile->record_config.gain;
532 chan_data->record_config.AGC = profile->record_config.AGC;
533 chan_data->record_config.VAD = profile->record_config.VAD;
534 chan_data->play_config.gain = profile->play_config.gain;
535 chan_data->play_config.AGC = profile->play_config.AGC;
536 chan_data->ec_enabled = profile->ec_enabled;
537 chan_data->ec_config = profile->ec_config;
538 }
539
540 if (type == FTDM_CHAN_TYPE_B) {
541 if (span_data->span_config.compandMode == PKH_SPAN_COMPAND_MODE_A_LAW) {
542 chan->native_codec = chan->effective_codec = FTDM_CODEC_ALAW;
543 } else {
544 chan->native_codec = chan->effective_codec = FTDM_CODEC_ULAW;
545 }
546 }
547
548 status = PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
549 status = PKH_PLAY_SetConfig(chan_data->media_out, &chan_data->play_config);
550
551 chan->physical_span_id = spanno;
552 chan->physical_chan_id = x;
553
554 chan->rate = 8000;
555 chan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
556 chan->effective_interval = chan->native_interval = chan->packet_len / 8;
557
558 PKH_RECORD_Start(chan_data->media_in);
559 PKH_PLAY_Start(chan_data->media_out);
560 if (chan_data->ec_enabled) {
561 PKH_EC_SetConfig(chan_data->media_in, &chan_data->ec_config);
562 PKH_EC_Start(chan_data->media_in, chan_data->media_in, chan_data->media_out);
563 }
564
565 if (!ftdm_strlen_zero(name)) {
566 ftdm_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
567 }
568
569 if (!ftdm_strlen_zero(number)) {
570 ftdm_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
571 }
572
573 ftdm_channel_set_feature(chan, FTDM_CHANNEL_FEATURE_DTMF_GENERATE);
574 ftdm_buffer_create(&chan_data->digit_buffer, 128, 128, 0);
575 ftdm_mutex_create(&chan_data->digit_mutex);
576
577 configured++;
578 }
579
580
581 return configured;
582 }
583
584 /**
585 * \brief Initialises an freetdm pika span from a configuration string
586 * \param span FreeTDM span
587 * \param str Configuration string
588 * \param type FreeTDM span type
589 * \param name FreeTDM span name
590 * \param number FreeTDM span number
591 * \return Success or failure
592 */
FIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)593 static FIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
594 {
595 int items, i;
596 char *mydata, *item_list[10];
597 char *bd, *sp, *ch = NULL, *mx;
598 int boardno;
599 int channo;
600 int spanno;
601 int top = 0;
602 unsigned configured = 0;
603 char *profile_name = NULL;
604 pika_channel_profile_t *profile = NULL;
605
606 assert(str != NULL);
607
608 mydata = ftdm_strdup(str);
609 assert(mydata != NULL);
610
611 if ((profile_name = strchr(mydata, '@'))) {
612 *profile_name++ = '\0';
613 if (!ftdm_strlen_zero(profile_name)) {
614 profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)profile_name);
615 }
616 }
617
618 items = ftdm_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
619
620 for(i = 0; i < items; i++) {
621 bd = item_list[i];
622 if ((sp = strchr(bd, ':'))) {
623 *sp++ = '\0';
624 if ((ch = strchr(sp, ':'))) {
625 *ch++ = '\0';
626 }
627 }
628
629 if (!(bd && sp && ch)) {
630 ftdm_log(FTDM_LOG_ERROR, "Invalid input\n");
631 continue;
632 }
633
634 boardno = atoi(bd);
635 channo = atoi(ch);
636 spanno = atoi(sp);
637
638
639 if (boardno < 0) {
640 ftdm_log(FTDM_LOG_ERROR, "Invalid board number %d\n", boardno);
641 continue;
642 }
643
644 if (channo < 0) {
645 ftdm_log(FTDM_LOG_ERROR, "Invalid channel number %d\n", channo);
646 continue;
647 }
648
649 if (spanno < 0) {
650 ftdm_log(FTDM_LOG_ERROR, "Invalid span number %d\n", channo);
651 continue;
652 }
653
654 if ((mx = strchr(ch, '-'))) {
655 mx++;
656 top = atoi(mx) + 1;
657 } else {
658 top = channo + 1;
659 }
660
661
662 if (top < 0) {
663 ftdm_log(FTDM_LOG_ERROR, "Invalid range number %d\n", top);
664 continue;
665 }
666
667 configured += pika_open_range(span, boardno, spanno, channo, top, type, name, number, profile);
668
669 }
670
671 ftdm_safe_free(mydata);
672
673 return configured;
674 }
675
676 /**
677 * \brief Opens Pika channel
678 * \param ftdmchan Channel to open
679 * \return Success or failure
680 */
FIO_OPEN_FUNCTION(pika_open)681 static FIO_OPEN_FUNCTION(pika_open)
682 {
683 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
684
685 if (!chan_data && !ftdm_test_flag(chan_data, PK_FLAG_READY)) {
686 return FTDM_FAIL;
687 }
688
689 if (chan_data->media_in_queue) {
690 PKH_QUEUE_Flush(chan_data->media_in_queue);
691 }
692
693 if (ftdmchan->type == FTDM_CHAN_TYPE_FXS || ftdmchan->type == FTDM_CHAN_TYPE_FXO || ftdmchan->type == FTDM_CHAN_TYPE_B) {
694 PKH_PLAY_Start(chan_data->media_out);
695 }
696 return FTDM_SUCCESS;
697 }
698
699 /**
700 * \brief Closes Pika channel
701 * \param ftdmchan Channel to close
702 * \return Success
703 */
FIO_CLOSE_FUNCTION(pika_close)704 static FIO_CLOSE_FUNCTION(pika_close)
705 {
706 return FTDM_SUCCESS;
707 }
708
709 /**
710 * \brief Waits for an event on a Pika channel
711 * \param ftdmchan Channel to open
712 * \param flags Type of event to wait for
713 * \param to Time to wait (in ms)
714 * \return Success, failure or timeout
715 */
FIO_WAIT_FUNCTION(pika_wait)716 static FIO_WAIT_FUNCTION(pika_wait)
717 {
718 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
719 PK_STATUS status;
720 ftdm_wait_flag_t myflags = *flags;
721 PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
722
723 *flags = FTDM_NO_FLAGS;
724
725 if (myflags & FTDM_READ) {
726 if (chan_data->hdlc_bytes) {
727 *flags |= FTDM_READ;
728 return FTDM_SUCCESS;
729 }
730 status = PKH_QUEUE_WaitOnEvent(chan_data->media_in_queue, to, &chan_data->last_media_event);
731
732 if (status == PK_SUCCESS) {
733 if (chan_data->last_media_event.id == PKH_EVENT_QUEUE_TIMEOUT || chan_data->last_media_event.id == PKH_EVENT_RECORD_BUFFER_OVERFLOW) {
734 return FTDM_TIMEOUT;
735 }
736
737 *flags |= FTDM_READ;
738 return FTDM_SUCCESS;
739 }
740
741 PKH_EVENT_GetText(chan_data->last_media_event.id, event_text, sizeof(event_text));
742 ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
743 }
744
745 return FTDM_SUCCESS;
746 }
747
748 /**
749 * \brief Reads data from a Pika channel
750 * \param ftdmchan Channel to read from
751 * \param data Data buffer
752 * \param datalen Size of data buffer
753 * \return Success or failure
754 */
FIO_READ_FUNCTION(pika_read)755 static FIO_READ_FUNCTION(pika_read)
756 {
757 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
758 PK_STATUS status;
759 PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
760 uint32_t len;
761
762 if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
763 if ((status = PKH_SPAN_HDLC_GetMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
764 *datalen = chan_data->hdlc_bytes;
765 chan_data->hdlc_bytes = 0;
766 return FTDM_SUCCESS;
767 }
768 return FTDM_FAIL;
769 }
770
771 if (!(len = chan_data->last_media_event.p0)) {
772 len = ftdmchan->packet_len;
773 }
774
775 if (len < *datalen) {
776 *datalen = len;
777 }
778
779 if ((status = PKH_RECORD_GetData(chan_data->media_in, data, *datalen)) == PK_SUCCESS) {
780 return FTDM_SUCCESS;
781 }
782
783
784 PKH_ERROR_GetText(status, event_text, sizeof(event_text));
785 ftdm_log(FTDM_LOG_DEBUG, "ERR: %s\n", event_text);
786 return FTDM_FAIL;
787 }
788
789 /**
790 * \brief Writes data to a Pika channel
791 * \param ftdmchan Channel to write to
792 * \param data Data buffer
793 * \param datalen Size of data buffer
794 * \return Success or failure
795 */
FIO_WRITE_FUNCTION(pika_write)796 static FIO_WRITE_FUNCTION(pika_write)
797 {
798 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
799 PK_STATUS status;
800
801 if (ftdmchan->type == FTDM_CHAN_TYPE_DQ921) {
802 if ((status = PKH_SPAN_HDLC_SendMessage(chan_data->handle, data, *datalen)) == PK_SUCCESS) {
803 return FTDM_SUCCESS;
804 }
805 return FTDM_FAIL;
806 }
807
808 if (PKH_PLAY_AddData(chan_data->media_out, 0, data, *datalen) == PK_SUCCESS) {
809 return FTDM_SUCCESS;
810 }
811
812 return FTDM_FAIL;
813 }
814
815 /**
816 * \brief Executes an FreeTDM command on a Pika channel
817 * \param ftdmchan Channel to execute command on
818 * \param command FreeTDM command to execute
819 * \param obj Object (unused)
820 * \return Success or failure
821 */
FIO_COMMAND_FUNCTION(pika_command)822 static FIO_COMMAND_FUNCTION(pika_command)
823 {
824 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
825 //pika_span_data_t *span_data = (pika_span_data_t *) ftdmchan->span->io_data;
826 PK_STATUS pk_status;
827 ftdm_status_t status = FTDM_SUCCESS;
828
829 switch(command) {
830 case FTDM_COMMAND_OFFHOOK:
831 {
832 if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_OFFHOOK)) != PK_SUCCESS) {
833 PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
834 GOTO_STATUS(done, FTDM_FAIL);
835 } else {
836 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
837 }
838 }
839 break;
840 case FTDM_COMMAND_ONHOOK:
841 {
842 if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_ONHOOK)) != PK_SUCCESS) {
843 PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
844 GOTO_STATUS(done, FTDM_FAIL);
845 } else {
846 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_OFFHOOK);
847 }
848 }
849 break;
850 case FTDM_COMMAND_GENERATE_RING_ON:
851 {
852 if ((pk_status = PKH_PHONE_RingStart(chan_data->handle, 0, 0)) != PK_SUCCESS) {
853 PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
854 GOTO_STATUS(done, FTDM_FAIL);
855 } else {
856 ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
857 }
858 }
859 break;
860 case FTDM_COMMAND_GENERATE_RING_OFF:
861 {
862 if ((pk_status = PKH_PHONE_RingStop(chan_data->handle)) != PK_SUCCESS) {
863 PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
864 GOTO_STATUS(done, FTDM_FAIL);
865 } else {
866 ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_RINGING);
867 }
868 }
869 break;
870 case FTDM_COMMAND_GET_INTERVAL:
871 {
872
873 FTDM_COMMAND_OBJ_INT = ftdmchan->native_interval;
874
875 }
876 break;
877 case FTDM_COMMAND_SET_INTERVAL:
878 {
879 int interval = FTDM_COMMAND_OBJ_INT;
880 int len = interval * 8;
881 chan_data->record_config.bufferSize = len;
882 chan_data->record_config.numberOfBuffers = (PK_UINT)chan_data->record_config.bufferSize;
883 ftdmchan->packet_len = (uint32_t)chan_data->record_config.bufferSize;
884 ftdmchan->effective_interval = ftdmchan->native_interval = ftdmchan->packet_len / 8;
885 PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
886 GOTO_STATUS(done, FTDM_SUCCESS);
887 }
888 break;
889 case FTDM_COMMAND_GET_DTMF_ON_PERIOD:
890 {
891
892 FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
893 GOTO_STATUS(done, FTDM_SUCCESS);
894
895 }
896 break;
897 case FTDM_COMMAND_GET_DTMF_OFF_PERIOD:
898 {
899 FTDM_COMMAND_OBJ_INT = ftdmchan->dtmf_on;
900 GOTO_STATUS(done, FTDM_SUCCESS);
901 }
902 break;
903 case FTDM_COMMAND_SET_DTMF_ON_PERIOD:
904 {
905 int val = FTDM_COMMAND_OBJ_INT;
906 if (val > 10 && val < 1000) {
907 ftdmchan->dtmf_on = val;
908 GOTO_STATUS(done, FTDM_SUCCESS);
909 } else {
910 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
911 GOTO_STATUS(done, FTDM_FAIL);
912 }
913 }
914 break;
915 case FTDM_COMMAND_SET_DTMF_OFF_PERIOD:
916 {
917 int val = FTDM_COMMAND_OBJ_INT;
918 if (val > 10 && val < 1000) {
919 ftdmchan->dtmf_off = val;
920 GOTO_STATUS(done, FTDM_SUCCESS);
921 } else {
922 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "invalid value %d range 10-1000", val);
923 GOTO_STATUS(done, FTDM_FAIL);
924 }
925 }
926 break;
927 case FTDM_COMMAND_SEND_DTMF:
928 {
929 char *digits = FTDM_COMMAND_OBJ_CHAR_P;
930 ftdm_log(FTDM_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
931 ftdm_mutex_lock(chan_data->digit_mutex);
932 ftdm_buffer_write(chan_data->digit_buffer, digits, strlen(digits));
933 ftdm_mutex_unlock(chan_data->digit_mutex);
934 pk_status = PKH_PLAY_Stop(chan_data->media_out);
935
936 if (pk_status != PK_SUCCESS) {
937 PKH_ERROR_GetText(pk_status, ftdmchan->last_error, sizeof(ftdmchan->last_error));
938 GOTO_STATUS(done, FTDM_FAIL);
939 }
940 GOTO_STATUS(done, FTDM_SUCCESS);
941 }
942 break;
943 default:
944 break;
945 };
946
947 done:
948 return status;
949 }
950
951 /**
952 * \brief Checks for events on a Pika span
953 * \param span Span to check for events
954 * \param ms Time to wait for event
955 * \return Success if event is waiting or failure if not
956 */
FIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)957 static FIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
958 {
959 pika_span_data_t *span_data = (pika_span_data_t *) span->io_data;
960 PK_STATUS status;
961 PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
962
963 status = PKH_QUEUE_WaitOnEvent(span_data->event_queue, ms, &span_data->last_oob_event);
964
965 if (status == PK_SUCCESS) {
966 ftdm_channel_t *ftdmchan = NULL;
967 uint32_t *data = (uint32_t *) span_data->last_oob_event.userData;
968 ftdm_data_type_t data_type = FTDM_TYPE_NONE;
969
970 if (span_data->last_oob_event.id == PKH_EVENT_QUEUE_TIMEOUT) {
971 return FTDM_TIMEOUT;
972 }
973
974 if (data) {
975 data_type = *data;
976 }
977
978 if (data_type == FTDM_TYPE_CHANNEL) {
979 ftdmchan = span_data->last_oob_event.userData;
980 } else if (data_type == FTDM_TYPE_SPAN) {
981 ftdm_time_t last_event_time = ftdm_current_time_in_ms();
982 uint32_t event_id = 0;
983
984 switch (span_data->last_oob_event.id) {
985 case PKH_EVENT_SPAN_ALARM_T1_RED:
986 case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
987 case PKH_EVENT_SPAN_ALARM_T1_AIS:
988 case PKH_EVENT_SPAN_ALARM_E1_RED:
989 case PKH_EVENT_SPAN_ALARM_E1_RAI:
990 case PKH_EVENT_SPAN_ALARM_E1_AIS:
991 case PKH_EVENT_SPAN_ALARM_E1_RMAI:
992 case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
993 case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
994 case PKH_EVENT_SPAN_OUT_OF_SYNC:
995 case PKH_EVENT_SPAN_FRAMING_ERROR:
996 case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
997 case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
998 case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
999 event_id = FTDM_OOB_ALARM_TRAP;
1000 break;
1001 case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
1002 case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
1003 case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
1004 case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
1005 case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
1006 case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
1007 case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
1008 case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
1009 case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
1010 case PKH_EVENT_SPAN_IN_SYNC:
1011 case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
1012 case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
1013 case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
1014 event_id = FTDM_OOB_ALARM_CLEAR;
1015 break;
1016 case PKH_EVENT_SPAN_MESSAGE:
1017 case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
1018 break;
1019 }
1020
1021 if (event_id) {
1022 uint32_t x = 0;
1023 ftdm_channel_t *ftdmchan;
1024 pika_chan_data_t *chan_data;
1025 for(x = 1; x <= span->chan_count; x++) {
1026 ftdmchan = span->channels[x];
1027 assert(ftdmchan != NULL);
1028 chan_data = (pika_chan_data_t *) ftdmchan->io_data;
1029 assert(chan_data != NULL);
1030
1031
1032 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
1033 ftdmchan->last_event_time = last_event_time;
1034 chan_data->last_oob_event = span_data->last_oob_event;
1035 }
1036
1037 }
1038
1039 }
1040
1041 PKH_EVENT_GetText(span_data->last_oob_event.id, event_text, sizeof(event_text));
1042 //ftdm_log(FTDM_LOG_DEBUG, "Event: %s\n", event_text);
1043
1044 if (ftdmchan) {
1045 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
1046
1047 assert(chan_data != NULL);
1048 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_EVENT);
1049 ftdmchan->last_event_time = ftdm_current_time_in_ms();
1050 chan_data->last_oob_event = span_data->last_oob_event;
1051 }
1052
1053 return FTDM_SUCCESS;
1054 }
1055
1056 return FTDM_FAIL;
1057 }
1058
1059 /**
1060 * \brief Retrieves an event from a Pika span
1061 * \param span Span to retrieve event from
1062 * \param event FreeTDM event to return
1063 * \return Success or failure
1064 */
FIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)1065 static FIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
1066 {
1067 uint32_t i, event_id = 0;
1068
1069 for(i = 1; i <= span->chan_count; i++) {
1070 if (ftdm_test_flag(span->channels[i], FTDM_CHANNEL_EVENT)) {
1071 pika_chan_data_t *chan_data = (pika_chan_data_t *) span->channels[i]->io_data;
1072 PK_CHAR event_text[PKH_EVENT_MAX_NAME_LENGTH];
1073
1074 ftdm_clear_flag(span->channels[i], FTDM_CHANNEL_EVENT);
1075
1076 PKH_EVENT_GetText(chan_data->last_oob_event.id, event_text, sizeof(event_text));
1077
1078 switch(chan_data->last_oob_event.id) {
1079 case PKH_EVENT_HDLC_MESSAGE:
1080 chan_data->hdlc_bytes = chan_data->last_oob_event.p2;
1081 continue;
1082 case PKH_EVENT_TRUNK_HOOKFLASH:
1083 event_id = FTDM_OOB_FLASH;
1084 break;
1085 case PKH_EVENT_TRUNK_RING_OFF:
1086 event_id = FTDM_OOB_RING_STOP;
1087 break;
1088 case PKH_EVENT_TRUNK_RING_ON:
1089 event_id = FTDM_OOB_RING_START;
1090 break;
1091
1092 case PKH_EVENT_PHONE_OFFHOOK:
1093 ftdm_set_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1094 event_id = FTDM_OOB_OFFHOOK;
1095 break;
1096
1097 case PKH_EVENT_TRUNK_BELOW_THRESHOLD:
1098 case PKH_EVENT_TRUNK_ABOVE_THRESHOLD:
1099 case PKH_EVENT_PHONE_ONHOOK:
1100 ftdm_clear_flag_locked(span->channels[i], FTDM_CHANNEL_OFFHOOK);
1101 event_id = FTDM_OOB_ONHOOK;
1102 break;
1103
1104
1105
1106 case PKH_EVENT_SPAN_ALARM_T1_RED:
1107 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
1108 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
1109 event_id = FTDM_OOB_ALARM_TRAP;
1110 break;
1111 case PKH_EVENT_SPAN_ALARM_T1_YELLOW:
1112 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_YELLOW);
1113 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "YELLOW ALARM");
1114 event_id = FTDM_OOB_ALARM_TRAP;
1115 break;
1116 case PKH_EVENT_SPAN_ALARM_T1_AIS:
1117 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
1118 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
1119 event_id = FTDM_OOB_ALARM_TRAP;
1120 break;
1121 case PKH_EVENT_SPAN_ALARM_E1_RED:
1122 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
1123 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RED ALARM");
1124 event_id = FTDM_OOB_ALARM_TRAP;
1125 break;
1126 case PKH_EVENT_SPAN_ALARM_E1_RAI:
1127 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RAI);
1128 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "RAI ALARM");
1129 event_id = FTDM_OOB_ALARM_TRAP;
1130 break;
1131 case PKH_EVENT_SPAN_ALARM_E1_AIS:
1132 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
1133 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "AIS ALARM");
1134 event_id = FTDM_OOB_ALARM_TRAP;
1135 break;
1136 case PKH_EVENT_SPAN_ALARM_E1_RMAI:
1137 case PKH_EVENT_SPAN_ALARM_E1_TS16AIS:
1138 case PKH_EVENT_SPAN_ALARM_E1_TS16LOS:
1139 case PKH_EVENT_SPAN_OUT_OF_SYNC:
1140 case PKH_EVENT_SPAN_FRAMING_ERROR:
1141 case PKH_EVENT_SPAN_LOSS_OF_SIGNAL:
1142 case PKH_EVENT_SPAN_OUT_OF_CRC_MF_SYNC:
1143 case PKH_EVENT_SPAN_OUT_OF_CAS_MF_SYNC:
1144 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_GENERAL);
1145 snprintf(span->channels[i]->last_error, sizeof(span->channels[i]->last_error), "GENERAL ALARM");
1146 event_id = FTDM_OOB_ALARM_TRAP;
1147 break;
1148 case PKH_EVENT_SPAN_ALARM_T1_RED_CLEAR:
1149 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
1150 case PKH_EVENT_SPAN_ALARM_T1_YELLOW_CLEAR:
1151 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_YELLOW);
1152 case PKH_EVENT_SPAN_ALARM_T1_AIS_CLEAR:
1153 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
1154 case PKH_EVENT_SPAN_ALARM_E1_RED_CLEAR:
1155 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RED);
1156 case PKH_EVENT_SPAN_ALARM_E1_RAI_CLEAR:
1157 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_RAI);
1158 case PKH_EVENT_SPAN_ALARM_E1_AIS_CLEAR:
1159 ftdm_set_alarm_flag(span->channels[i], FTDM_ALARM_AIS);
1160 case PKH_EVENT_SPAN_ALARM_E1_RMAI_CLEAR:
1161 case PKH_EVENT_SPAN_ALARM_E1_TS16AIS_CLEAR:
1162 case PKH_EVENT_SPAN_ALARM_E1_TS16LOS_CLEAR:
1163 case PKH_EVENT_SPAN_IN_SYNC:
1164 case PKH_EVENT_SPAN_LOSS_OF_SIGNAL_CLEAR:
1165 case PKH_EVENT_SPAN_IN_CRC_MF_SYNC:
1166 case PKH_EVENT_SPAN_IN_CAS_MF_SYNC:
1167 ftdm_clear_alarm_flag(span->channels[i], FTDM_ALARM_GENERAL);
1168 event_id = FTDM_OOB_ALARM_CLEAR;
1169 break;
1170 case PKH_EVENT_SPAN_MESSAGE:
1171 case PKH_EVENT_SPAN_ABCD_SIGNAL_CHANGE:
1172 break;
1173
1174
1175
1176
1177 case PKH_EVENT_TRUNK_ONHOOK:
1178 case PKH_EVENT_TRUNK_OFFHOOK:
1179 case PKH_EVENT_TRUNK_DIALED :
1180 case PKH_EVENT_TRUNK_REVERSAL:
1181 case PKH_EVENT_TRUNK_LCSO:
1182 case PKH_EVENT_TRUNK_DROPOUT:
1183 case PKH_EVENT_TRUNK_LOF:
1184 case PKH_EVENT_TRUNK_RX_OVERLOAD:
1185 default:
1186 ftdm_log(FTDM_LOG_DEBUG, "Unhandled event %d on channel %d [%s]\n", chan_data->last_oob_event.id, i, event_text);
1187 event_id = FTDM_OOB_INVALID;
1188 break;
1189 }
1190
1191 span->channels[i]->last_event_time = 0;
1192 span->event_header.e_type = FTDM_EVENT_OOB;
1193 span->event_header.enum_id = event_id;
1194 span->event_header.channel = span->channels[i];
1195 *event = &span->event_header;
1196 return FTDM_SUCCESS;
1197 }
1198 }
1199
1200 return FTDM_FAIL;
1201 }
1202
1203 /**
1204 * \brief Destroys a Pika Span
1205 * \param span Span to destroy
1206 * \return Success
1207 */
FIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)1208 static FIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)
1209 {
1210 pika_span_data_t *span_data = (pika_span_data_t *) span->io_data;
1211
1212 if (span_data) {
1213 PKH_QUEUE_Destroy(span_data->event_queue);
1214 ftdm_safe_free(span_data);
1215 }
1216
1217 return FTDM_SUCCESS;
1218 }
1219
1220 /**
1221 * \brief Destroys a Pika Channel
1222 * \param ftdmchan Channel to destroy
1223 * \return Success or failure
1224 */
FIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)1225 static FIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)
1226 {
1227 pika_chan_data_t *chan_data = (pika_chan_data_t *) ftdmchan->io_data;
1228 pika_span_data_t *span_data = (pika_span_data_t *) ftdmchan->span->io_data;
1229
1230 if (!chan_data) {
1231 return FTDM_FAIL;
1232 }
1233
1234 if (!ftdm_test_flag(chan_data, PK_FLAG_READY)) {
1235 goto end;
1236 }
1237
1238 PKH_RECORD_Stop(chan_data->media_in);
1239 PKH_PLAY_Stop(chan_data->media_out);
1240 PKH_QUEUE_Destroy(chan_data->media_in_queue);
1241 PKH_QUEUE_Destroy(chan_data->media_out_queue);
1242
1243 switch(ftdmchan->type) {
1244 case FTDM_CHAN_TYPE_FXS:
1245 PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
1246 PKH_PHONE_Close(chan_data->handle);
1247 break;
1248 case FTDM_CHAN_TYPE_FXO:
1249 PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
1250 PKH_TRUNK_Close(chan_data->handle);
1251 break;
1252 case FTDM_CHAN_TYPE_DQ921:
1253 PKH_SPAN_Stop(span_data->handle);
1254 break;
1255 default:
1256 break;
1257 }
1258
1259
1260 ftdm_mutex_destroy(&chan_data->digit_mutex);
1261 ftdm_buffer_destroy(&chan_data->digit_buffer);
1262
1263 end:
1264 ftdm_safe_free(chan_data);
1265
1266 return FTDM_SUCCESS;
1267 }
1268
1269 /**
1270 * \brief Gets alarms from a Pika Channel (does nothing)
1271 * \param ftdmchan Channel to get alarms from
1272 * \return Failure
1273 */
FIO_GET_ALARMS_FUNCTION(pika_get_alarms)1274 static FIO_GET_ALARMS_FUNCTION(pika_get_alarms)
1275 {
1276 return FTDM_FAIL;
1277 }
1278
1279 static ftdm_io_interface_t pika_interface;
1280
1281 /**
1282 * \brief Loads Pika IO module
1283 * \param fio FreeTDM IO interface
1284 * \return Success or failure
1285 */
FIO_IO_LOAD_FUNCTION(pika_init)1286 static FIO_IO_LOAD_FUNCTION(pika_init)
1287 {
1288
1289 PK_STATUS status;
1290 PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
1291 uint32_t i;
1292 int ok = 0;
1293 PKH_TLogMasks m;
1294 TPikaHandle tmpHandle;
1295
1296 assert(fio != NULL);
1297 memset(&pika_interface, 0, sizeof(pika_interface));
1298 memset(&globals, 0, sizeof(globals));
1299 globals.general_config.region = PKH_TRUNK_NA;
1300
1301 globals.profile_hash = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
1302
1303 // Open the system object, to enumerate boards configured for this system
1304 if ((status = PKH_SYSTEM_Open(&globals.system_handle)) != PK_SUCCESS) {
1305 ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Open failed(%s)!\n",
1306 PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
1307 return FTDM_FAIL;
1308 }
1309
1310 // Retrieves a list of all boards in this system, existing,
1311 // or listed in pika.cfg
1312 if ((status = PKH_SYSTEM_Detect(globals.system_handle, &globals.board_list)) != PK_SUCCESS) {
1313 ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Detect failed(%s)!\n",
1314 PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
1315 return FTDM_FAIL;
1316 }
1317
1318 PKH_SYSTEM_GetConfig(globals.system_handle, &globals.system_config);
1319 globals.system_config.maxAudioProcessBlockSize = PIKA_BLOCK_LEN;
1320 globals.system_config.playBufferSize = PIKA_BLOCK_SIZE;
1321 globals.system_config.recordBufferSize = PIKA_BLOCK_SIZE;
1322 globals.system_config.recordNumberOfBuffers = PIKA_NUM_BUFFERS;
1323 PKH_SYSTEM_SetConfig(globals.system_handle, &globals.system_config);
1324
1325 status = PKH_MEDIA_STREAM_Create(&tmpHandle);
1326 status = PKH_RECORD_GetConfig(tmpHandle, &globals.record_config);
1327 status = PKH_PLAY_GetConfig(tmpHandle, &globals.play_config);
1328 status = PKH_EC_GetConfig(tmpHandle, &globals.ec_config);
1329 status = PKH_MEDIA_STREAM_Destroy(tmpHandle);
1330
1331
1332
1333 ftdm_log(FTDM_LOG_DEBUG, "Found %u board%s\n", globals.board_list.numberOfBoards, globals.board_list.numberOfBoards == 1 ? "" : "s");
1334 for(i = 0; i < globals.board_list.numberOfBoards; ++i) {
1335 ftdm_log(FTDM_LOG_INFO, "Found PIKA board type:[%s] id:[%u] serno:[%u]\n",
1336 pika_board_type_string(globals.board_list.board[i].type), globals.board_list.board[i].id, (uint32_t)
1337 globals.board_list.board[i].serialNumber);
1338
1339 if (globals.board_list.board[i].type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
1340 TPikaHandle board_handle, span_handle;
1341 PKH_TBoardConfig boardConfig;
1342 PKH_BOARD_GetConfig(board_handle, &boardConfig);
1343 PKH_BOARD_Open(globals.board_list.board[i].id, NULL, &board_handle);
1344 PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
1345 PKH_SPAN_GetConfig(span_handle, &globals.t1_span_config);
1346 PKH_SPAN_Close(span_handle);
1347 boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_E1;
1348 PKH_BOARD_SetConfig(board_handle, &boardConfig);
1349 PKH_SPAN_Open(board_handle, 0, NULL, &span_handle);
1350 PKH_SPAN_GetConfig(span_handle, &globals.e1_span_config);
1351 PKH_SPAN_Close(span_handle);
1352 boardConfig.specific.DigitalGateway.interfaceType = PKH_BOARD_INTERFACE_TYPE_T1;
1353 PKH_BOARD_SetConfig(board_handle, &boardConfig);
1354 PKH_BOARD_Close(board_handle);
1355 }
1356 ok++;
1357
1358 }
1359
1360 if (!ok) {
1361 return FTDM_FAIL;
1362 }
1363
1364 pika_interface.name = "pika";
1365 pika_interface.configure = pika_configure;
1366 pika_interface.configure_span = pika_configure_span;
1367 pika_interface.open = pika_open;
1368 pika_interface.close = pika_close;
1369 pika_interface.wait = pika_wait;
1370 pika_interface.read = pika_read;
1371 pika_interface.write = pika_write;
1372 pika_interface.command = pika_command;
1373 pika_interface.poll_event = pika_poll_event;
1374 pika_interface.next_event = pika_next_event;
1375 pika_interface.channel_destroy = pika_channel_destroy;
1376 pika_interface.span_destroy = pika_span_destroy;
1377 pika_interface.get_alarms = pika_get_alarms;
1378 *fio = &pika_interface;
1379
1380
1381 ftdm_log(FTDM_LOG_INFO, "Dumping Default configs:\n");
1382 ftdm_log(FTDM_LOG_INFO, "rx-gain => %0.2f\n", (float)globals.record_config.gain);
1383 ftdm_log(FTDM_LOG_INFO, "rx-agc-enabled => %s\n", globals.record_config.AGC.enabled ? "true" : "false");
1384 ftdm_log(FTDM_LOG_INFO, "rx-agc-targetPower => %0.2f\n", (float)globals.record_config.AGC.targetPower);
1385 ftdm_log(FTDM_LOG_INFO, "rx-agc-minGain => %0.2f\n", (float)globals.record_config.AGC.minGain);
1386 ftdm_log(FTDM_LOG_INFO, "rx-agc-maxGain => %0.2f\n", (float)globals.record_config.AGC.maxGain);
1387 ftdm_log(FTDM_LOG_INFO, "rx-agc-attackRate => %d\n", (int)globals.record_config.AGC.attackRate);
1388 ftdm_log(FTDM_LOG_INFO, "rx-agc-decayRate => %d\n", (int)globals.record_config.AGC.decayRate);
1389 ftdm_log(FTDM_LOG_INFO, "rx-agc-speechThreshold => %0.2f\n", (float)globals.record_config.AGC.speechThreshold);
1390 ftdm_log(FTDM_LOG_INFO, "rx-vad-enabled => %s\n", globals.record_config.VAD.enabled ? "true" : "false");
1391 ftdm_log(FTDM_LOG_INFO, "rx-vad-activationThreshold => %0.2f\n", (float)globals.record_config.VAD.activationThreshold);
1392 ftdm_log(FTDM_LOG_INFO, "rx-vad-activationDebounceTime => %d\n", (int)globals.record_config.VAD.activationDebounceTime);
1393 ftdm_log(FTDM_LOG_INFO, "rx-vad-deactivationThreshold => %0.2f\n", (float)globals.record_config.VAD.deactivationThreshold);
1394 ftdm_log(FTDM_LOG_INFO, "rx-vad-deactivationDebounceTime => %d\n", (int)globals.record_config.VAD.deactivationDebounceTime);
1395 ftdm_log(FTDM_LOG_INFO, "rx-vad-preSpeechBufferSize => %d\n", (int)globals.record_config.VAD.preSpeechBufferSize);
1396 ftdm_log(FTDM_LOG_INFO, "tx-gain => %0.2f\n", (float)globals.play_config.gain);
1397 ftdm_log(FTDM_LOG_INFO, "tx-agc-enabled => %s\n", globals.play_config.AGC.enabled ? "true" : "false");
1398 ftdm_log(FTDM_LOG_INFO, "tx-agc-targetPower => %0.2f\n", (float)globals.play_config.AGC.targetPower);
1399 ftdm_log(FTDM_LOG_INFO, "tx-agc-minGain => %0.2f\n", (float)globals.play_config.AGC.minGain);
1400 ftdm_log(FTDM_LOG_INFO, "tx-agc-maxGain => %0.2f\n", (float)globals.play_config.AGC.maxGain);
1401 ftdm_log(FTDM_LOG_INFO, "tx-agc-attackRate => %d\n", (int)globals.play_config.AGC.attackRate);
1402 ftdm_log(FTDM_LOG_INFO, "tx-agc-decayRate => %d\n", (int)globals.play_config.AGC.decayRate);
1403 ftdm_log(FTDM_LOG_INFO, "tx-agc-speechThreshold => %0.2f\n", (float)globals.play_config.AGC.speechThreshold);
1404 ftdm_log(FTDM_LOG_INFO, "ec-doubleTalkerThreshold => %0.2f\n", (float)globals.ec_config.doubleTalkerThreshold);
1405 ftdm_log(FTDM_LOG_INFO, "ec-speechPresentThreshold => %0.2f\n", (float)globals.ec_config.speechPresentThreshold);
1406 ftdm_log(FTDM_LOG_INFO, "ec-echoSuppressionThreshold => %0.2f\n", (float)globals.ec_config.echoSuppressionThreshold);
1407 ftdm_log(FTDM_LOG_INFO, "ec-echoSuppressionEnabled => %s\n", globals.ec_config.echoSuppressionEnabled ? "true" : "false");
1408 ftdm_log(FTDM_LOG_INFO, "ec-comfortNoiseEnabled => %s\n", globals.ec_config.comfortNoiseEnabled ? "true" : "false");
1409 ftdm_log(FTDM_LOG_INFO, "ec-adaptationModeEnabled => %s\n", globals.ec_config.adaptationModeEnabled ? "true" : "false");
1410
1411
1412
1413 memset(&m, 0, sizeof(m));
1414 //m.apiMask = 0xffffffff;
1415 //PKH_LOG_SetMasks(&m);
1416
1417 return FTDM_SUCCESS;
1418 }
1419
1420 /**
1421 * \brief Unloads Pika IO module
1422 * \return Success
1423 */
FIO_IO_UNLOAD_FUNCTION(pika_destroy)1424 static FIO_IO_UNLOAD_FUNCTION(pika_destroy)
1425 {
1426 uint32_t x;
1427 PK_STATUS status;
1428 PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
1429
1430 for (x = 0; x < MAX_NUMBER_OF_TRUNKS; x++) {
1431 if (globals.open_boards[x]) {
1432 ftdm_log(FTDM_LOG_INFO, "Closing board %u\n", x);
1433 PKH_BOARD_Close(globals.open_boards[x]);
1434 }
1435 }
1436
1437 // The system can now be closed.
1438 if ((status = PKH_SYSTEM_Close(globals.system_handle)) != PK_SUCCESS) {
1439 ftdm_log(FTDM_LOG_ERROR, "Error: PKH_SYSTEM_Close failed(%s)!\n",
1440 PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
1441 } else {
1442 ftdm_log(FTDM_LOG_INFO, "Closing system handle\n");
1443 }
1444
1445 hashtable_destroy(globals.profile_hash);
1446
1447 return FTDM_SUCCESS;
1448 }
1449
1450 /**
1451 * \brief Pika IO module definition
1452 */
1453 EX_DECLARE_DATA ftdm_module_t ftdm_module = {
1454 "pika",
1455 pika_init,
1456 pika_destroy,
1457 };
1458
1459 /* For Emacs:
1460 * Local Variables:
1461 * mode:c
1462 * indent-tabs-mode:t
1463 * tab-width:4
1464 * c-basic-offset:4
1465 * End:
1466 * For VIM:
1467 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
1468 */
1469
1470