提交 6b88eec7 authored 作者: Anthony Minessale's avatar Anthony Minessale

pika-choo i choose you

git-svn-id: http://svn.openzap.org/svn/openzap/trunk@331 a93c3328-9c30-0410-af19-c9cd2b2d52af
上级 b25d204d
......@@ -135,6 +135,9 @@ testtones: $(SRC)/testtones.c $(MYLIB)
detect_tones: $(SRC)/detect_tones.c $(MYLIB)
$(CC) $(INCS) -L. $(SRC)/detect_tones.c -o detect_tones -lopenzap -lm
detect_dtmf: $(SRC)/detect_dtmf.c $(MYLIB)
$(CC) $(INCS) -L. $(SRC)/detect_dtmf.c -o detect_dtmf -lopenzap -lm
testisdn: $(SRC)/testisdn.c $(MYLIB)
$(CC) $(INCS) $(ZAP_CFLAGS) -L. $(SRC)/testisdn.c -o testisdn -lopenzap -lm -lpthread
......@@ -174,6 +177,6 @@ mod_openzap-clean:
@if [ -f mod_openzap/mod_openzap.so ] ; then cd mod_openzap && make clean ; fi
clean: mod_openzap-clean
rm -f $(SRC)/*.o $(SRC)/isdn/*.o $(MYLIB) *~ \#* testapp testcid testtones detect_tones priserver testisdn testanalog
rm -f $(SRC)/*.o $(SRC)/isdn/*.o $(MYLIB) *~ \#* testapp testcid testtones detect_tones detect_dtmf priserver testisdn testanalog
@if [ -f $(LIBPRI)/$(LIBPRIA) ] ; then cd $(LIBPRI) && make clean ; fi
; each category is a config profile
; to apply the profile append it to a channel def in
; openzap.conf with @<profile_name>
; e.g.
; [span pika]
; name => pika
; number => pika
; fxs-channel => 1:0:1-12@default
[default]
rx-gain => 0
rx-agc-enabled => 0
rx-agc-targetPower => 0
rx-agc-minGain => 0
rx-agc-maxGain => 0
rx-agc-attackRate => 0
rx-agc-decayRate => 0
rx-agc-speechThreshold => 0
rx-vad-enabled => 0
rx-vad-activationThreshold => 0
rx-vad-activationDebounceTime => 0
rx-vad-deactivationThreshold => 0
rx-vad-deactivationDebounceTime => 0
rx-vad-preSpeechBufferSize => 0
tx-gain => 0
tx-agc-enabled => 0
tx-agc-targetPower => 0
tx-agc-minGain => 0
tx-agc-maxGain => 0
tx-agc-attackRate => 0
tx-agc-decayRate => 0
tx-agc-speechThreshold => 0
......@@ -304,14 +304,14 @@ static switch_status_t channel_on_hangup(switch_core_session_t *session)
switch (tech_pvt->zchan->type) {
case ZAP_CHAN_TYPE_FXO:
{
if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
zap_set_state_locked(tech_pvt->zchan, ZAP_CHANNEL_STATE_HANGUP);
}
}
break;
case ZAP_CHAN_TYPE_FXS:
{
if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
if (tech_pvt->zchan->state != ZAP_CHANNEL_STATE_BUSY && tech_pvt->zchan->state != ZAP_CHANNEL_STATE_DOWN) {
if (tech_pvt->zchan->token_count) {
cycle_foreground(tech_pvt->zchan, 0);
} else {
......@@ -466,20 +466,21 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
}
if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
return SWITCH_STATUS_FALSE;
goto fail;
}
wflags = ZAP_READ;
status = zap_channel_wait(tech_pvt->zchan, &wflags, chunk);
if (status == ZAP_FAIL) {
return SWITCH_STATUS_GENERR;
goto fail;
}
if (status == ZAP_TIMEOUT) {
if (timeout > 0 && !switch_test_flag(tech_pvt, TFLAG_HOLD)) {
total_to -= chunk;
if (total_to <= 0) {
return SWITCH_STATUS_BREAK;
goto fail;
}
}
......@@ -487,12 +488,12 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
}
if (!(wflags & ZAP_READ)) {
return SWITCH_STATUS_GENERR;
goto fail;
}
len = tech_pvt->read_frame.buflen;
if (zap_channel_read(tech_pvt->zchan, tech_pvt->read_frame.data, &len) != ZAP_SUCCESS) {
return SWITCH_STATUS_GENERR;
goto fail;
}
*frame = &tech_pvt->read_frame;
......@@ -509,6 +510,12 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
return SWITCH_STATUS_SUCCESS;
fail:
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
return SWITCH_STATUS_GENERR;
}
static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id)
......@@ -530,13 +537,13 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
}
if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
return SWITCH_STATUS_FALSE;
goto fail;
}
len = frame->datalen;
if (zap_channel_write(tech_pvt->zchan, frame->data, frame->buflen, &len) != ZAP_SUCCESS) {
if (++tech_pvt->wr_error > 10) {
return SWITCH_STATUS_GENERR;
goto fail;
}
} else {
tech_pvt->wr_error = 0;
......@@ -544,6 +551,11 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
return SWITCH_STATUS_SUCCESS;
fail:
switch_clear_flag_locked(tech_pvt, TFLAG_IO);
return SWITCH_STATUS_GENERR;
}
static switch_status_t channel_receive_message_b(switch_core_session_t *session, switch_core_session_message_t *msg)
......@@ -875,9 +887,29 @@ static ZIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
switch_channel_t *channel = NULL;
zap_status_t status;
zap_log(ZAP_LOG_DEBUG, "got FXO sig [%s]\n", zap_signal_event2str(sigmsg->event_id));
zap_log(ZAP_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", sigmsg->channel->span_id, sigmsg->channel->chan_id, zap_signal_event2str(sigmsg->event_id));
switch(sigmsg->event_id) {
case ZAP_SIGEVENT_PROGRESS_MEDIA:
{
if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
channel = switch_core_session_get_channel(session);
switch_channel_mark_pre_answered(channel);
switch_core_session_rwunlock(session);
}
}
break;
case ZAP_SIGEVENT_STOP:
{
while((session = zap_channel_get_session(sigmsg->channel, 0))) {
zap_channel_clear_token(sigmsg->channel, 0);
channel = switch_core_session_get_channel(session);
switch_channel_hangup(channel, sigmsg->channel->caller_data.hangup_cause);
switch_core_session_rwunlock(session);
}
}
break;
case ZAP_SIGEVENT_UP:
{
if ((session = zap_channel_get_session(sigmsg->channel, 0))) {
......
//#include "openzap.h"
#include "libteletone_detect.h"
int main(int argc, char *argv[])
{
int fd, b;
short sln[512] = {0};
teletone_dtmf_detect_state_t dtmf_detect = {0};
char digit_str[128] = "";
if (argc < 2) {
fprintf(stderr, "Arg Error!\n");
exit(-1);
}
teletone_dtmf_detect_init (&dtmf_detect, 8000);
if ((fd = open(argv[1], O_RDONLY)) < 0) {
fprintf(stderr, "File Error!\n", strerror(errno));
exit(-1);
}
while((b = read(fd, sln, 320)) > 0) {
teletone_dtmf_detect(&dtmf_detect, sln, b / 2);
teletone_dtmf_get(&dtmf_detect, digit_str, sizeof(digit_str));
if (*digit_str) {
printf("digit: %s\n", digit_str);
}
}
close(fd);
}
......@@ -5,7 +5,7 @@ int main(int argc, char *argv[])
{
teletone_generation_session_t ts;
teletone_multi_tone_t mt = {0};
teletone_tone_map_t map = {350.0, 440.0, 0.0};
teletone_tone_map_t map = {0};
int fd, b;
short sln[512] = {0};
......@@ -15,6 +15,9 @@ int main(int argc, char *argv[])
exit(-1);
}
map.freqs[0] = atof("350");
map.freqs[1] = atof("440");
teletone_multi_tone_init(&mt, &map);
......
......@@ -211,12 +211,12 @@
#define zap_set_state_locked(obj, s) if ( obj->state == s ) { \
zap_log(ZAP_LOG_WARNING, "Why bother changing state from %s to %s\n", zap_channel_state2str(obj->state), zap_channel_state2str(s)); \
zap_log(ZAP_LOG_WARNING, "Why bother changing state on %d:%dfrom %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(obj->state), zap_channel_state2str(s)); \
} else if (zap_test_flag(obj, ZAP_CHANNEL_READY)) { \
int st = obj->state; \
zap_channel_set_state(obj, s); \
if (obj->state == s) zap_log(ZAP_LOG_DEBUG, "Changing state from %s to %s\n", zap_channel_state2str(st), zap_channel_state2str(s)); \
else zap_log(ZAP_LOG_WARNING, "VETO Changing state from %s to %s\n", zap_channel_state2str(st), zap_channel_state2str(s)); \
if (obj->state == s) zap_log(ZAP_LOG_DEBUG, "Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); \
else zap_log(ZAP_LOG_WARNING, "VETO Changing state on %d:%d from %s to %s\n", obj->span_id, obj->chan_id, zap_channel_state2str(st), zap_channel_state2str(s)); \
}
......@@ -344,7 +344,6 @@ struct zap_channel {
zap_event_t event_header;
char last_error[256];
zio_event_cb_t event_callback;
void *mod_data;
uint32_t skip_read_frames;
zap_buffer_t *dtmf_buffer;
zap_buffer_t *digit_buffer;
......@@ -365,6 +364,7 @@ struct zap_channel {
zap_fsk_data_state_t fsk;
uint8_t fsk_buf[80];
uint32_t ring_count;
void *mod_data;
struct zap_caller_data caller_data;
struct zap_span *span;
struct zap_io_interface *zio;
......@@ -416,7 +416,8 @@ struct zap_span {
teletone_multi_tone_t tone_finder[ZAP_TONEMAP_INVALID+1];
zap_channel_t channels[ZAP_MAX_CHANNELS_SPAN];
zio_channel_outgoing_call_t outgoing_call;
void *app_data;
void *mod_data;
char *type;
};
......@@ -429,6 +430,7 @@ struct zap_io_interface {
zio_open_t open;
zio_close_t close;
zio_channel_destroy_t channel_destroy;
zio_span_destroy_t span_destroy;
zio_get_alarms_t get_alarms;
zio_command_t command;
zio_wait_t wait;
......@@ -505,6 +507,8 @@ void zap_global_set_default_logger(int level);
uint32_t zap_separate_string(char *buf, char delim, char **array, int arraylen);
void print_bits(uint8_t *b, int bl, char *buf, int blen, int e, uint8_t ss);
void print_hex_bytes(uint8_t *data, zap_size_t dlen, char *buf, zap_size_t blen);
int zap_hash_equalkeys(void *k1, void *k2);
uint32_t zap_hash_hashfromstring(void *ky);
ZIO_CODEC_FUNCTION(zio_slin2ulaw);
ZIO_CODEC_FUNCTION(zio_ulaw2slin);
ZIO_CODEC_FUNCTION(zio_slin2alaw);
......
/*
* Copyright (c) 2007, Anthony Minessale II
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ZAP_PIKA_H
#define ZAP_PIKA_H
#include "openzap.h"
#include "pikahmpapi.h"
/* Openzap PIKA hardware interface functions */
zap_status_t pika_init(zap_io_interface_t **zint);
zap_status_t pika_destroy(void);
#endif
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/
......@@ -267,10 +267,11 @@ typedef enum {
} zap_chan_type_t;
typedef enum {
ZAP_CHANNEL_FEATURE_DTMF = (1 << 0),
ZAP_CHANNEL_FEATURE_CODECS = (1 << 1),
ZAP_CHANNEL_FEATURE_INTERVAL = (1 << 2),
ZAP_CHANNEL_FEATURE_CALLERID = (1 << 3)
ZAP_CHANNEL_FEATURE_DTMF_DETECT = (1 << 0),
ZAP_CHANNEL_FEATURE_DTMF_GENERATE = (1 << 1),
ZAP_CHANNEL_FEATURE_CODECS = (1 << 2),
ZAP_CHANNEL_FEATURE_INTERVAL = (1 << 3),
ZAP_CHANNEL_FEATURE_CALLERID = (1 << 4)
} zap_channel_feature_t;
typedef enum {
......@@ -339,6 +340,7 @@ typedef struct zap_span zap_span_t;
#define ZIO_OPEN_ARGS (zap_channel_t *zchan)
#define ZIO_CLOSE_ARGS (zap_channel_t *zchan)
#define ZIO_CHANNEL_DESTROY_ARGS (zap_channel_t *zchan)
#define ZIO_SPAN_DESTROY_ARGS (zap_span_t *span)
#define ZIO_COMMAND_ARGS (zap_channel_t *zchan, zap_command_t command, void *obj)
#define ZIO_WAIT_ARGS (zap_channel_t *zchan, zap_wait_flag_t *flags, int32_t to)
#define ZIO_GET_ALARMS_ARGS (zap_channel_t *zchan)
......@@ -356,6 +358,7 @@ typedef zap_status_t (*zio_configure_t) ZIO_CONFIGURE_ARGS ;
typedef zap_status_t (*zio_open_t) ZIO_OPEN_ARGS ;
typedef zap_status_t (*zio_close_t) ZIO_CLOSE_ARGS ;
typedef zap_status_t (*zio_channel_destroy_t) ZIO_CHANNEL_DESTROY_ARGS ;
typedef zap_status_t (*zio_span_destroy_t) ZIO_SPAN_DESTROY_ARGS ;
typedef zap_status_t (*zio_get_alarms_t) ZIO_GET_ALARMS_ARGS ;
typedef zap_status_t (*zio_command_t) ZIO_COMMAND_ARGS ;
typedef zap_status_t (*zio_wait_t) ZIO_WAIT_ARGS ;
......@@ -373,6 +376,7 @@ typedef zap_status_t (*zio_write_t) ZIO_WRITE_ARGS ;
#define ZIO_OPEN_FUNCTION(name) zap_status_t name ZIO_OPEN_ARGS
#define ZIO_CLOSE_FUNCTION(name) zap_status_t name ZIO_CLOSE_ARGS
#define ZIO_CHANNEL_DESTROY_FUNCTION(name) zap_status_t name ZIO_CHANNEL_DESTROY_ARGS
#define ZIO_SPAN_DESTROY_FUNCTION(name) zap_status_t name ZIO_SPAN_DESTROY_ARGS
#define ZIO_GET_ALARMS_FUNCTION(name) zap_status_t name ZIO_GET_ALARMS_ARGS
#define ZIO_COMMAND_FUNCTION(name) zap_status_t name ZIO_COMMAND_ARGS
#define ZIO_WAIT_FUNCTION(name) zap_status_t name ZIO_WAIT_ARGS
......@@ -410,6 +414,69 @@ typedef struct value zap_hash_val_t;
typedef struct zap_bitstream zap_bitstream_t;
typedef struct zap_fsk_modulator zap_fsk_modulator_t;
typedef enum {
ZAP_CAUSE_UNALLOCATED = 0,
ZAP_CAUSE_SUCCESS = 1,
ZAP_CAUSE_NO_ROUTE_TRANSIT_NET = 2,
ZAP_CAUSE_NO_ROUTE_DESTINATION = 3,
ZAP_CAUSE_CHANNEL_UNACCEPTABLE = 6,
ZAP_CAUSE_CALL_AWARDED_DELIVERED = 7,
ZAP_CAUSE_NORMAL_CLEARING = 16,
ZAP_CAUSE_USER_BUSY = 17,
ZAP_CAUSE_NO_USER_RESPONSE = 18,
ZAP_CAUSE_NO_ANSWER = 19,
ZAP_CAUSE_SUBSCRIBER_ABSENT = 20,
ZAP_CAUSE_CALL_REJECTED = 21,
ZAP_CAUSE_NUMBER_CHANGED = 22,
ZAP_CAUSE_REDIRECTION_TO_NEW_DESTINATION = 23,
ZAP_CAUSE_EXCHANGE_ROUTING_ERROR = 25,
ZAP_CAUSE_DESTINATION_OUT_OF_ORDER = 27,
ZAP_CAUSE_INVALID_NUMBER_FORMAT = 28,
ZAP_CAUSE_FACILITY_REJECTED = 29,
ZAP_CAUSE_RESPONSE_TO_STATUS_ENQUIRY = 30,
ZAP_CAUSE_NORMAL_UNSPECIFIED = 31,
ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION = 34,
ZAP_CAUSE_NETWORK_OUT_OF_ORDER = 38,
ZAP_CAUSE_NORMAL_TEMPORARY_FAILURE = 41,
ZAP_CAUSE_SWITCH_CONGESTION = 42,
ZAP_CAUSE_ACCESS_INFO_DISCARDED = 43,
ZAP_CAUSE_REQUESTED_CHAN_UNAVAIL = 44,
ZAP_CAUSE_PRE_EMPTED = 45,
ZAP_CAUSE_FACILITY_NOT_SUBSCRIBED = 50,
ZAP_CAUSE_OUTGOING_CALL_BARRED = 52,
ZAP_CAUSE_INCOMING_CALL_BARRED = 54,
ZAP_CAUSE_BEARERCAPABILITY_NOTAUTH = 57,
ZAP_CAUSE_BEARERCAPABILITY_NOTAVAIL = 58,
ZAP_CAUSE_SERVICE_UNAVAILABLE = 63,
ZAP_CAUSE_BEARERCAPABILITY_NOTIMPL = 65,
ZAP_CAUSE_CHAN_NOT_IMPLEMENTED = 66,
ZAP_CAUSE_FACILITY_NOT_IMPLEMENTED = 69,
ZAP_CAUSE_SERVICE_NOT_IMPLEMENTED = 79,
ZAP_CAUSE_INVALID_CALL_REFERENCE = 81,
ZAP_CAUSE_INCOMPATIBLE_DESTINATION = 88,
ZAP_CAUSE_INVALID_MSG_UNSPECIFIED = 95,
ZAP_CAUSE_MANDATORY_IE_MISSING = 96,
ZAP_CAUSE_MESSAGE_TYPE_NONEXIST = 97,
ZAP_CAUSE_WRONG_MESSAGE = 98,
ZAP_CAUSE_IE_NONEXIST = 99,
ZAP_CAUSE_INVALID_IE_CONTENTS = 100,
ZAP_CAUSE_WRONG_CALL_STATE = 101,
ZAP_CAUSE_RECOVERY_ON_TIMER_EXPIRE = 102,
ZAP_CAUSE_MANDATORY_IE_LENGTH_ERROR = 103,
ZAP_CAUSE_PROTOCOL_ERROR = 111,
ZAP_CAUSE_INTERWORKING = 127,
ZAP_CAUSE_ORIGINATOR_CANCEL = 487,
ZAP_CAUSE_CRASH = 500,
ZAP_CAUSE_SYSTEM_SHUTDOWN = 501,
ZAP_CAUSE_LOSE_RACE = 502,
ZAP_CAUSE_MANAGER_REQUEST = 503,
ZAP_CAUSE_BLIND_TRANSFER = 600,
ZAP_CAUSE_ATTENDED_TRANSFER = 601,
ZAP_CAUSE_ALLOTTED_TIMEOUT = 602,
ZAP_CAUSE_USER_CHALLENGE = 603,
ZAP_CAUSE_MEDIA_TIMEOUT = 604
} zap_call_cause_t;
#endif
/* For Emacs:
......
......@@ -14,6 +14,7 @@ static void *test_call(zap_thread_t *me, void *obj)
zap_log(ZAP_LOG_DEBUG, "answer call and start echo test\n");
zap_set_state_locked(chan, ZAP_CHANNEL_STATE_UP);
zap_channel_command(chan, ZAP_COMMAND_SEND_DTMF, "5551212");
while (chan->state == ZAP_CHANNEL_STATE_UP) {
zap_wait_flag_t flags = ZAP_READ;
......
......@@ -20,8 +20,8 @@ int main(int argc, char *argv[])
teletone_generation_session_t ts;
struct ttmp tmp;
if (argc < 2) {
fprintf(stderr, "Arg Error!\n");
if (argc < 3) {
fprintf(stderr, "Arg Error! <file> <tones>\n");
exit(-1);
}
......
......@@ -44,7 +44,8 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj);
static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_fxo_outgoing_call)
{
if (!zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_INTHREAD)) {
//zap_channel_command(zchan, ZAP_COMMAND_TRACE_INPUT, "/tmp/inbound.ul");
zap_channel_command(zchan, ZAP_COMMAND_TRACE_INPUT, "/tmp/inbound.ul");
zap_channel_command(zchan, ZAP_COMMAND_TRACE_OUTPUT, "/tmp/outbound.ul");
zap_channel_clear_needed_tones(zchan);
zap_channel_clear_detected_tones(zchan);
......@@ -281,13 +282,14 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
case ZAP_CHANNEL_STATE_HANGUP:
{
if (state_counter > 500) {
if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
}
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && zchan->last_state >= ZAP_CHANNEL_STATE_IDLE) {
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
} else {
if (zap_test_flag(zchan, ZAP_CHANNEL_RINGING)) {
zap_channel_command(zchan, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
}
zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CLEARING;
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
}
}
......@@ -346,7 +348,9 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
zap_clear_flag_locked(zchan->span, ZAP_SPAN_STATE_CHANGE);
indicate = 0;
state_counter = 0;
zap_log(ZAP_LOG_DEBUG, "Executing state handler for %s\n", zap_channel_state2str(zchan->state));
zap_log(ZAP_LOG_DEBUG, "Executing state handler on %d:%d for %s\n",
zchan->span_id, zchan->chan_id,
zap_channel_state2str(zchan->state));
switch(zchan->state) {
case ZAP_CHANNEL_STATE_UP:
{
......@@ -399,9 +403,9 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
break;
case ZAP_CHANNEL_STATE_DOWN:
{
zap_channel_done(zchan);
sig.event_id = ZAP_SIGEVENT_STOP;
analog_data->sig_cb(&sig);
zap_channel_done(zchan);
goto done;
}
break;
......@@ -453,18 +457,27 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
break;
case ZAP_CHANNEL_STATE_BUSY:
{
zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_CIRCUIT_CONGESTION;
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
zap_channel_done(zchan);
zap_buffer_zero(dt_buffer);
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_BUSY]);
indicate = 1;
} else {
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
}
}
break;
case ZAP_CHANNEL_STATE_ATTN:
{
if (zap_test_flag(zchan, ZAP_CHANNEL_OFFHOOK) && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
zap_channel_done(zchan);
zap_buffer_zero(dt_buffer);
teletone_run(&ts, zchan->span->tone_map[ZAP_TONEMAP_ATTN]);
indicate = 1;
} else {
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
}
}
break;
default:
......@@ -514,25 +527,42 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
if (zchan->detected_tones[i]) {
zap_log(ZAP_LOG_DEBUG, "Detected tone %s\n", zap_tonemap2str(zchan->detected_tones[i]));
zap_log(ZAP_LOG_DEBUG, "Detected tone %s on %d:%d\n", zap_tonemap2str(i), zchan->span_id, zchan->chan_id);
sig.raw_data = &i;
if (analog_data->sig_cb) {
analog_data->sig_cb(&sig);
}
}
}
if (zchan->detected_tones[ZAP_TONEMAP_DIAL]) {
zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani);
if (zchan->detected_tones[ZAP_TONEMAP_BUSY] ||
zchan->detected_tones[ZAP_TONEMAP_FAIL1] ||
zchan->detected_tones[ZAP_TONEMAP_FAIL2] ||
zchan->detected_tones[ZAP_TONEMAP_FAIL3] ||
zchan->detected_tones[ZAP_TONEMAP_ATTN]
) {
zap_log(ZAP_LOG_ERROR, "Failure indication detected!\n");
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
} else if (zchan->detected_tones[ZAP_TONEMAP_DIAL]) {
if (zap_strlen_zero(zchan->caller_data.ani)) {
zap_log(ZAP_LOG_ERROR, "No Digits to send!\n");
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
} else {
if (zap_channel_command(zchan, ZAP_COMMAND_SEND_DTMF, zchan->caller_data.ani) != ZAP_SUCCESS) {
zap_log(ZAP_LOG_ERROR, "Send Digits Failed [%s]\n", zchan->last_error);
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
} else {
state_counter = 0;
zchan->needed_tones[ZAP_TONEMAP_RING] = 1;
zchan->needed_tones[ZAP_TONEMAP_BUSY] = 1;
zchan->needed_tones[ZAP_TONEMAP_FAIL1] = 1;
zchan->needed_tones[ZAP_TONEMAP_FAIL2] = 1;
zchan->needed_tones[ZAP_TONEMAP_FAIL3] = 1;
dial_timeout = (zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani) + 50;
dial_timeout = ((zchan->dtmf_on + zchan->dtmf_off) * strlen(zchan->caller_data.ani)) + 3000;
}
}
} else if (zchan->detected_tones[ZAP_TONEMAP_RING]) {
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
} else if (zchan->detected_tones[ZAP_TONEMAP_BUSY]) {
zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_BUSY);
}
zap_channel_clear_detected_tones(zchan);
......@@ -580,6 +610,7 @@ static void *zap_analog_channel_run(zap_thread_t *me, void *obj)
}
done:
zap_channel_done(zchan);
......@@ -647,8 +678,11 @@ static __inline__ zap_status_t process_event(zap_span_t *span, zap_event_t *even
if (zap_test_flag(event->channel, ZAP_CHANNEL_RINGING)) {
zap_channel_command(event->channel, ZAP_COMMAND_GENERATE_RING_OFF, NULL);
}
if (event->channel->state != ZAP_CHANNEL_STATE_DOWN) {
zap_set_state_locked(event->channel, ZAP_CHANNEL_STATE_DOWN);
}
}
break;
case ZAP_OOB_FLASH:
{
......
......@@ -47,6 +47,9 @@
#ifdef ZAP_ZT_SUPPORT
#include "zap_zt.h"
#endif
#ifdef ZAP_PIKA_SUPPORT
#include "zap_pika.h"
#endif
static int time_is_init = 0;
......@@ -192,12 +195,12 @@ void zap_global_set_default_logger(int level)
zap_log_level = level;
}
static int equalkeys(void *k1, void *k2)
int zap_hash_equalkeys(void *k1, void *k2)
{
return strcmp((char *) k1, (char *) k2) ? 0 : 1;
}
static uint32_t hashfromstring(void *ky)
uint32_t zap_hash_hashfromstring(void *ky)
{
unsigned char *str = (unsigned char *) ky;
uint32_t hash = 0;
......@@ -211,6 +214,19 @@ static uint32_t hashfromstring(void *ky)
}
static zap_status_t zap_span_destroy(zap_span_t *span)
{
zap_status_t status = ZAP_FAIL;
if (zap_test_flag(span, ZAP_SPAN_CONFIGURED) && span->zio && span->zio->span_destroy) {
zap_log(ZAP_LOG_INFO, "Destroying span %u type (%s)\n", span->span_id, span->type);
status = span->zio->span_destroy(span);
zap_safe_free(span->type);
}
return status;
}
static zap_status_t zap_channel_destroy(zap_channel_t *zchan)
{
......@@ -227,7 +243,7 @@ static zap_status_t zap_channel_destroy(zap_channel_t *zchan)
if (zchan->span->zio->channel_destroy) {
zap_log(ZAP_LOG_INFO, "Closing channel %u:%u fd:%d\n", zchan->span_id, zchan->chan_id, zchan->sockfd);
zap_log(ZAP_LOG_INFO, "Closing channel %s:%u:%u fd:%d\n", zchan->span->type, zchan->span_id, zchan->chan_id, zchan->sockfd);
if (zchan->span->zio->channel_destroy(zchan) == ZAP_SUCCESS) {
zap_clear_flag_locked(zchan, ZAP_CHANNEL_CONFIGURED);
} else {
......@@ -315,14 +331,13 @@ zap_status_t zap_span_close_all(void)
uint32_t i, j;
zap_mutex_lock(globals.mutex);
for(i = 0; i < globals.span_index; i++) {
for(i = 1; i <= globals.span_index; i++) {
span = &globals.spans[i];
if (zap_test_flag(span, ZAP_SPAN_CONFIGURED)) {
for(j = 0; j < span->chan_count; j++) {
zap_channel_destroy(&span->channels[i]);
}
zap_safe_free(span->signal_data);
}
}
zap_mutex_unlock(globals.mutex);
......@@ -939,6 +954,7 @@ static zap_status_t zchan_activate_dtmf_buffer(zap_channel_t *zchan)
}
}
if (!zchan->tone_session.buffer) {
memset(&zchan->tone_session, 0, sizeof(zchan->tone_session));
teletone_init_session(&zchan->tone_session, 0, NULL, NULL);
......@@ -947,6 +963,8 @@ static zap_status_t zchan_activate_dtmf_buffer(zap_channel_t *zchan)
zchan->tone_session.rate = zchan->rate;
zchan->tone_session.duration = zchan->dtmf_on * (zchan->tone_session.rate / 1000);
zchan->tone_session.wait = zchan->dtmf_off * (zchan->tone_session.rate / 1000);
zchan->tone_session.volume = -7;
/*
zchan->tone_session.debug = 1;
zchan->tone_session.debug_stream = stdout;
......@@ -1083,6 +1101,8 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
case ZAP_COMMAND_ENABLE_PROGRESS_DETECT:
{
/* if they don't have thier own, use ours */
zap_channel_clear_detected_tones(zchan);
zap_channel_clear_needed_tones(zchan);
teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_DIAL], &zchan->span->tone_detect_map[ZAP_TONEMAP_DIAL]);
teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_RING], &zchan->span->tone_detect_map[ZAP_TONEMAP_RING]);
teletone_multi_tone_init(&zchan->span->tone_finder[ZAP_TONEMAP_BUSY], &zchan->span->tone_detect_map[ZAP_TONEMAP_BUSY]);
......@@ -1101,7 +1121,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
case ZAP_COMMAND_ENABLE_DTMF_DETECT:
{
/* if they don't have thier own, use ours */
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
if (tt == ZAP_TONE_DTMF) {
teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
......@@ -1117,7 +1137,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
break;
case ZAP_COMMAND_DISABLE_DTMF_DETECT:
{
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_DETECT)) {
zap_tone_type_t tt = ZAP_COMMAND_OBJ_INT;
if (tt == ZAP_TONE_DTMF) {
teletone_dtmf_detect_init (&zchan->dtmf_detect, zchan->rate);
......@@ -1132,7 +1152,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
}
case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
{
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
GOTO_STATUS(done, ZAP_SUCCESS);
}
......@@ -1140,7 +1160,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
break;
case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
{
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
GOTO_STATUS(done, ZAP_SUCCESS);
}
......@@ -1148,7 +1168,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
break;
case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
{
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
int val = ZAP_COMMAND_OBJ_INT;
if (val > 10 && val < 1000) {
zchan->dtmf_on = val;
......@@ -1162,7 +1182,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
break;
case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
{
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
int val = ZAP_COMMAND_OBJ_INT;
if (val > 10 && val < 1000) {
zchan->dtmf_off = val;
......@@ -1176,7 +1196,7 @@ zap_status_t zap_channel_command(zap_channel_t *zchan, zap_command_t command, vo
break;
case ZAP_COMMAND_SEND_DTMF:
{
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF)) {
if (!zap_channel_test_feature(zchan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE)) {
char *cur;
char *digits = ZAP_COMMAND_OBJ_CHAR_P;
int x = 0;
......@@ -1523,7 +1543,7 @@ zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *data
*(str+mlen) = '\0';
zap_copy_string(str, sp, ++mlen);
zap_clean_string(str);
zap_log(ZAP_LOG_ERROR, "FSK: TYPE %s LEN %d VAL [%s]\n", zap_mdmf_type2str(type), mlen-1, str);
zap_log(ZAP_LOG_DEBUG, "FSK: TYPE %s LEN %d VAL [%s]\n", zap_mdmf_type2str(type), mlen-1, str);
switch(type) {
case MDMF_DDN:
......@@ -1574,13 +1594,14 @@ zap_status_t zap_channel_read(zap_channel_t *zchan, void *data, zap_size_t *data
for (i = 1; i < ZAP_TONEMAP_INVALID; i++) {
if (zchan->span->tone_finder[i].tone_count) {
if (zchan->needed_tones[i] && teletone_multi_tone_detect(&zchan->span->tone_finder[i], sln, (int)slen)) {
zchan->detected_tones[i] = 1;
if (++zchan->detected_tones[i]) {
zchan->needed_tones[i] = 0;
zchan->detected_tones[0]++;
}
}
}
}
}
if (zap_test_flag(zchan, ZAP_CHANNEL_DTMF_DETECT)) {
......@@ -1713,6 +1734,7 @@ zap_status_t zap_channel_write(zap_channel_t *zchan, void *data, zap_size_t data
static struct {
zap_io_interface_t *wanpipe_interface;
zap_io_interface_t *zt_interface;
zap_io_interface_t *pika_interface;
} interfaces;
......@@ -1760,7 +1782,14 @@ static zap_status_t load_config(void)
continue;
}
if (!zio->configure_span) {
zap_log(ZAP_LOG_CRIT, "failure creating span, no configure_span method for '%s'\n", type);
span = NULL;
continue;
}
if (zap_span_create(zio, &span) == ZAP_SUCCESS) {
span->type = strdup(type);
zap_log(ZAP_LOG_DEBUG, "created span %d of type %s\n", span->span_id, type);
d = 0;
} else {
......@@ -1886,7 +1915,7 @@ zap_status_t zap_global_init(void)
zap_isdn_init();
memset(&interfaces, 0, sizeof(interfaces));
globals.interface_hash = create_hashtable(16, hashfromstring, equalkeys);
globals.interface_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
modcount = 0;
zap_mutex_create(&globals.mutex);
......@@ -1914,6 +1943,19 @@ zap_status_t zap_global_init(void)
}
#endif
#ifdef ZAP_PIKA_SUPPORT
if (pika_init(&interfaces.pika_interface) == ZAP_SUCCESS) {
zap_mutex_lock(globals.mutex);
hashtable_insert(globals.interface_hash, (void *)interfaces.pika_interface->name, interfaces.pika_interface);
process_module_config(interfaces.pika_interface);
zap_mutex_unlock(globals.mutex);
modcount++;
} else {
zap_log(ZAP_LOG_ERROR, "Error initilizing pika.\n");
}
#endif
if (!modcount) {
zap_log(ZAP_LOG_ERROR, "Error initilizing anything.\n");
return ZAP_FAIL;
......@@ -1953,6 +1995,10 @@ zap_status_t zap_global_destroy(void)
if (cur_span->mutex) {
zap_mutex_destroy(&cur_span->mutex);
}
zap_safe_free(cur_span->signal_data);
zap_span_destroy(cur_span);
}
}
......@@ -1962,6 +2008,13 @@ zap_status_t zap_global_destroy(void)
zt_destroy();
}
#endif
#ifdef ZAP_PIKA_SUPPORT
if (interfaces.pika_interface) {
pika_destroy();
}
#endif
#ifdef ZAP_WANPIPE_SUPPORT
if (interfaces.wanpipe_interface) {
wanpipe_destroy();
......
/*
* Copyright (c) 2007, Anthony Minessale II
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "openzap.h"
#include "zap_pika.h"
#define MAX_NUMBER_OF_TRUNKS 64
#define PIKA_BLOCK_SIZE 160
#define PIKA_BLOCK_LEN 20
struct pika_channel_profile {
char name[80];
PKH_TRecordConfig record_config;
PKH_TPlayConfig play_config;
};
typedef struct pika_channel_profile pika_channel_profile_t;
static struct {
PKH_TSystemDeviceList board_list;
TPikaHandle open_boards[MAX_NUMBER_OF_TRUNKS];
TPikaHandle system_handle;
PKH_TSystemConfig system_config;
zap_hash_t *profile_hash;
} globals;
struct pika_span_data {
TPikaHandle event_queue;
PKH_TPikaEvent last_oob_event;
uint32_t boardno;
};
typedef struct pika_span_data pika_span_data_t;
struct pika_chan_data {
TPikaHandle handle;
TPikaHandle media_in;
TPikaHandle media_out;
TPikaHandle media_in_queue;
TPikaHandle media_out_queue;
PKH_TPikaEvent last_media_event;
PKH_TPikaEvent last_oob_event;
PKH_TRecordConfig record_config;
PKH_TPlayConfig play_config;
zap_buffer_t *digit_buffer;
zap_mutex_t *digit_mutex;
int dtmf_len;
};
typedef struct pika_chan_data pika_chan_data_t;
static char *pika_board_type_string(PK_UINT type)
{
if (type == PKH_BOARD_TYPE_DIGITAL_GATEWAY) {
return "digital_gateway";
}
if (type == PKH_BOARD_TYPE_ANALOG_GATEWAY) {
return "analog_gateway";
}
return "unknown";
}
static ZIO_CONFIGURE_FUNCTION(pika_configure)
{
pika_channel_profile_t *profile = NULL;
int ok = 1;
if (!(profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)category))) {
profile = malloc(sizeof(*profile));
memset(profile, 0, sizeof(*profile));
zap_set_string(profile->name, category);
hashtable_insert(globals.profile_hash, (void *)profile->name, profile);
zap_log(ZAP_LOG_INFO, "creating profile [%s]\n", category);
}
if (!strcasecmp(var, "rx-gain")) {
profile->record_config.gain = atof(val);
} else if (!strcasecmp(var, "rx-agc-enabled")) {
profile->record_config.AGC.enabled = zap_true(val);
} else if (!strcasecmp(var, "rx-agc-targetPower")) {
profile->record_config.AGC.targetPower = atof(val);
} else if (!strcasecmp(var, "rx-agc-minGain")) {
profile->record_config.AGC.minGain = atof(val);
} else if (!strcasecmp(var, "rx-agc-maxGain")) {
profile->record_config.AGC.maxGain = atof(val);
} else if (!strcasecmp(var, "rx-agc-attackRate")) {
profile->record_config.AGC.attackRate = atoi(val);
} else if (!strcasecmp(var, "rx-agc-decayRate")) {
profile->record_config.AGC.decayRate = atoi(val);
} else if (!strcasecmp(var, "rx-agc-speechThreshold")) {
profile->record_config.AGC.speechThreshold = atof(val);
} else if (!strcasecmp(var, "rx-vad-enabled")) {
profile->record_config.VAD.enabled = zap_true(val);
} else if (!strcasecmp(var, "rx-vad-activationThreshold")) {
profile->record_config.VAD.activationThreshold = atof(val);
} else if (!strcasecmp(var, "rx-vad-activationDebounceTime")) {
profile->record_config.VAD.activationDebounceTime = atoi(val);
} else if (!strcasecmp(var, "rx-vad-deactivationThreshold")) {
profile->record_config.VAD.deactivationThreshold = atof(val);
} else if (!strcasecmp(var, "rx-vad-deactivationDebounceTime")) {
profile->record_config.VAD.deactivationDebounceTime = atoi(val);
} else if (!strcasecmp(var, "rx-vad-preSpeechBufferSize")) {
profile->record_config.VAD.preSpeechBufferSize = atoi(val);
} else if (!strcasecmp(var, "tx-gain")) {
profile->play_config.gain = atof(val);
} else if (!strcasecmp(var, "tx-agc-enabled")) {
profile->play_config.AGC.enabled = zap_true(val);
} else if (!strcasecmp(var, "tx-agc-targetPower")) {
profile->play_config.AGC.targetPower = atof(val);
} else if (!strcasecmp(var, "tx-agc-minGain")) {
profile->play_config.AGC.minGain = atof(val);
} else if (!strcasecmp(var, "tx-agc-maxGain")) {
profile->play_config.AGC.maxGain = atof(val);
} else if (!strcasecmp(var, "tx-agc-attackRate")) {
profile->play_config.AGC.attackRate = atoi(val);
} else if (!strcasecmp(var, "tx-agc-decayRate")) {
profile->play_config.AGC.decayRate = atoi(val);
} else if (!strcasecmp(var, "tx-agc-speechThreshold")) {
profile->play_config.AGC.speechThreshold = atof(val);
} else {
ok = 0;
}
if (ok) {
zap_log(ZAP_LOG_INFO, "setting param [%s]=[%s] for profile [%s]\n", var, val, category);
} else {
zap_log(ZAP_LOG_ERROR, "unknown param [%s]\n", var);
}
return ZAP_SUCCESS;
}
PK_VOID PK_CALLBACK media_out_callback(PKH_TPikaEvent *event)
{
PK_STATUS pk_status;
zap_channel_t *zchan = event->userData;
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
//PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
//PKH_EVENT_GetText(event->id, g_EventText, sizeof(g_EventText));
//zap_log(ZAP_LOG_DEBUG, "Event: %s\n", g_EventText);
switch (event->id) {
case PKH_EVENT_PLAY_IDLE:
{
while (zap_buffer_inuse(chan_data->digit_buffer)) {
char dtmf[128] = "";
zap_mutex_lock(chan_data->digit_mutex);
chan_data->dtmf_len = zap_buffer_read(chan_data->digit_buffer, dtmf, sizeof(dtmf));
pk_status = PKH_TG_PlayDTMF(chan_data->media_out, dtmf);
zap_mutex_unlock(chan_data->digit_mutex);
}
}
break;
case PKH_EVENT_TG_TONE_PLAYED:
{
if (!event->p1) {
zap_mutex_lock(chan_data->digit_mutex);
PKH_PLAY_Start(chan_data->media_out);
chan_data->dtmf_len = 0;
zap_mutex_unlock(chan_data->digit_mutex);
}
}
break;
default:
break;
}
}
static unsigned pika_open_range(zap_span_t *span, unsigned boardno, unsigned spanno, unsigned start, unsigned end,
zap_chan_type_t type, char *name, char *number, pika_channel_profile_t *profile)
{
unsigned configured = 0, x;
PK_STATUS status;
PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
pika_span_data_t *span_data;
if (boardno >= globals.board_list.numberOfBoards) {
zap_log(ZAP_LOG_ERROR, "Board %u is not present!\n", boardno);
return 0;
}
if (!globals.open_boards[boardno]) {
status = PKH_BOARD_Open(globals.board_list.board[boardno].id,
NULL,
&globals.open_boards[boardno]);
if(status != PK_SUCCESS) {
zap_log(ZAP_LOG_ERROR, "Error: PKH_BOARD_Open %d failed(%s)!\n", boardno,
PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
return 0;
}
zap_log(ZAP_LOG_DEBUG, "Open board %u\n", boardno);
//PKH_BOARD_SetDebugTrace(globals.open_boards[boardno], 1, 0);
}
if (!span->mod_data) {
span_data = malloc(sizeof(*span_data));
assert(span_data != NULL);
memset(span_data, 0, sizeof(*span_data));
span_data->boardno = boardno;
status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &span_data->event_queue);
if (status != PK_SUCCESS) {
zap_log(ZAP_LOG_ERROR, "Error: PKH_QUEUE_Create failed(%s)!\n",
PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
free(span_data);
return 0;
}
PKH_QUEUE_Attach(span_data->event_queue, globals.open_boards[boardno], NULL);
span->mod_data = span_data;
}
start--;
end--;
for(x = start; x < end; x++) {
zap_channel_t *chan;
pika_chan_data_t *chan_data = NULL;
chan_data = malloc(sizeof *chan_data);
assert(chan_data);
memset(chan_data, 0, sizeof(*chan_data));
if (type == ZAP_CHAN_TYPE_FXO) {
PKH_TTrunkConfig trunkConfig;
if((status = PKH_TRUNK_Open(globals.open_boards[boardno], x, &chan_data->handle)) != PK_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_TRUNK_Seize(chan_data->handle) != PK_SUCCESS)) {
goto fail_fxo;
}
if (zap_span_add_channel(span, 0, type, &chan) != ZAP_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_TRUNK_GetConfig(chan_data->handle, &trunkConfig) != PK_SUCCESS)) {
goto fail_fxo;
}
trunkConfig.internationalControl = PKH_TRUNK_NA;
trunkConfig.audioFormat = PKH_AUDIO_MULAW;
if ((status = PKH_TRUNK_SetConfig(chan_data->handle, &trunkConfig) != PK_SUCCESS)) {
goto fail_fxo;
}
if ((status = PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan)) != PK_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_TRUNK_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out)) != ZAP_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue)) != PK_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan)) != PK_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue)) != PK_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback)) != PK_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan)) != PK_SUCCESS) {
goto fail_fxo;
}
if ((status = PKH_TRUNK_Start(chan_data->handle)) != PK_SUCCESS) {
goto fail_fxo;
}
goto ok;
fail_fxo:
zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
zap_log(ZAP_LOG_ERROR, "Error: PKH_TRUNK_Open %u failed(%s)!\n", x,
PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
if (chan_data->handle) {
PKH_TRUNK_Close(chan_data->handle);
}
PKH_QUEUE_Destroy(chan_data->media_in_queue);
free(chan_data);
continue;
} else if (type == ZAP_CHAN_TYPE_FXS) {
if((status = PKH_PHONE_Open(globals.open_boards[boardno], x, &chan_data->handle)) != PK_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_PHONE_Seize(chan_data->handle) != PK_SUCCESS)) {
goto fail_fxs;
}
if (zap_span_add_channel(span, 0, type, &chan) != ZAP_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_PHONE_GetMediaStreams(chan_data->handle, &chan_data->media_in, &chan_data->media_out)) != ZAP_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_QUEUE_Attach(span_data->event_queue, chan_data->handle, (PK_VOID*) chan)) != PK_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_NORMAL, &chan_data->media_in_queue)) != PK_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_QUEUE_Attach(chan_data->media_in_queue, chan_data->media_in, (PK_VOID*) chan)) != PK_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_QUEUE_Create(PKH_QUEUE_TYPE_CALLBACK, &chan_data->media_out_queue)) != PK_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_QUEUE_SetEventHandler(chan_data->media_out_queue, media_out_callback)) != PK_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_QUEUE_Attach(chan_data->media_out_queue, chan_data->media_out, (PK_VOID*) chan)) != PK_SUCCESS) {
goto fail_fxs;
}
if ((status = PKH_PHONE_Start(chan_data->handle)) != PK_SUCCESS) {
goto fail_fxs;
}
goto ok;
fail_fxs:
zap_log(ZAP_LOG_ERROR, "failure configuring device s%dc%d\n", spanno, x);
zap_log(ZAP_LOG_ERROR, "Error: PKH_PHONE_Open %u failed(%s)!\n", x,
PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
if (chan_data->handle) {
PKH_PHONE_Close(chan_data->handle);
}
PKH_QUEUE_Destroy(chan_data->media_in_queue);
free(chan_data);
}
ok:
status = PKH_RECORD_GetConfig(chan_data->media_in, &chan_data->record_config);
chan_data->record_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
chan_data->record_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
chan_data->record_config.bufferSize = PIKA_BLOCK_SIZE;
chan_data->record_config.numberOfBuffers = chan_data->record_config.bufferSize;
chan_data->record_config.VAD.enabled = PK_FALSE;
//chan_data->record_config.speechSegmentEventsEnabled = PK_FALSE;
//chan_data->record_config.gain = rxgain;
status = PKH_PLAY_GetConfig(chan_data->media_out, &chan_data->play_config);
chan_data->play_config.encoding = PKH_RECORD_ENCODING_MU_LAW;
chan_data->play_config.samplingRate = PKH_RECORD_SAMPLING_RATE_8KHZ;
chan_data->play_config.AGC.enabled = PK_FALSE;
zap_log(ZAP_LOG_INFO, "configuring device b%ds%dc%d as OpenZAP device %d:%d\n", boardno, spanno, x, chan->span_id, chan->chan_id);
if (profile) {
zap_log(ZAP_LOG_INFO, "applying config profile %s to device %d:%d\n", profile->name, chan->span_id, chan->chan_id);
chan_data->record_config.gain = profile->record_config.gain;
chan_data->record_config.AGC.enabled = profile->record_config.AGC.enabled;
chan_data->record_config.AGC.targetPower = profile->record_config.AGC.targetPower;
chan_data->record_config.AGC.minGain = profile->record_config.AGC.minGain;
chan_data->record_config.AGC.maxGain = profile->record_config.AGC.maxGain;
chan_data->record_config.AGC.attackRate = profile->record_config.AGC.attackRate;
chan_data->record_config.AGC.decayRate = profile->record_config.AGC.decayRate;
chan_data->record_config.AGC.speechThreshold = profile->record_config.AGC.speechThreshold;
chan_data->record_config.VAD.enabled = profile->record_config.VAD.enabled;
chan_data->record_config.VAD.activationThreshold = profile->record_config.VAD.activationThreshold;
chan_data->record_config.VAD.activationDebounceTime = profile->record_config.VAD.activationDebounceTime;
chan_data->record_config.VAD.deactivationThreshold = profile->record_config.VAD.deactivationThreshold;
chan_data->record_config.VAD.deactivationDebounceTime = profile->record_config.VAD.deactivationDebounceTime;
chan_data->record_config.VAD.preSpeechBufferSize = profile->record_config.VAD.preSpeechBufferSize;
chan_data->play_config.gain = profile->play_config.gain;
chan_data->play_config.AGC.enabled = profile->play_config.AGC.enabled;
chan_data->play_config.AGC.targetPower = profile->play_config.AGC.targetPower;
chan_data->play_config.AGC.minGain = profile->play_config.AGC.minGain;
chan_data->play_config.AGC.maxGain = profile->play_config.AGC.maxGain;
chan_data->play_config.AGC.attackRate = profile->play_config.AGC.attackRate;
chan_data->play_config.AGC.decayRate = profile->play_config.AGC.decayRate;
chan_data->play_config.AGC.speechThreshold = profile->play_config.AGC.speechThreshold;
}
status = PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
status = PKH_PLAY_SetConfig(chan_data->media_out, &chan_data->play_config);
chan->mod_data = chan_data;
chan->physical_span_id = spanno;
chan->physical_chan_id = x;
chan->rate = 8000;
chan->packet_len = chan_data->record_config.bufferSize;
chan->effective_interval = chan->native_interval = chan->packet_len / 8;
PKH_RECORD_Start(chan_data->media_in);
PKH_PLAY_Start(chan_data->media_out);
PKH_EC_Start(chan_data->media_in, chan_data->media_in, chan_data->media_out);
if (!zap_strlen_zero(name)) {
zap_copy_string(chan->chan_name, name, sizeof(chan->chan_name));
}
if (!zap_strlen_zero(number)) {
zap_copy_string(chan->chan_number, number, sizeof(chan->chan_number));
}
zap_channel_set_feature(chan, ZAP_CHANNEL_FEATURE_DTMF_GENERATE);
zap_buffer_create(&chan_data->digit_buffer, 128, 128, 0);
zap_mutex_create(&chan_data->digit_mutex);
configured++;
}
return configured;
}
static ZIO_CONFIGURE_SPAN_FUNCTION(pika_configure_span)
{
int items, i;
char *mydata, *item_list[10];
char *bd, *sp, *ch, *mx;
int boardno;
int channo;
int spanno;
int top = 0;
unsigned configured = 0;
char *profile_name = NULL;
pika_channel_profile_t *profile = NULL;
assert(str != NULL);
mydata = strdup(str);
assert(mydata != NULL);
if ((profile_name = strchr(mydata, '@'))) {
*profile_name++ = '\0';
if (!zap_strlen_zero(profile_name)) {
profile = (pika_channel_profile_t *) hashtable_search(globals.profile_hash, (char *)profile_name);
}
}
items = zap_separate_string(mydata, ',', item_list, (sizeof(item_list) / sizeof(item_list[0])));
for(i = 0; i < items; i++) {
bd = item_list[i];
if ((sp = strchr(bd, ':'))) {
*sp++ = '\0';
}
if ((ch = strchr(sp, ':'))) {
*ch++ = '\0';
}
if (!(bd && sp && ch)) {
zap_log(ZAP_LOG_ERROR, "Invalid input\n");
continue;
}
boardno = atoi(bd);
channo = atoi(ch);
spanno = atoi(sp);
if (boardno < 0) {
zap_log(ZAP_LOG_ERROR, "Invalid board number %d\n", boardno);
continue;
}
if (channo < 0) {
zap_log(ZAP_LOG_ERROR, "Invalid channel number %d\n", channo);
continue;
}
if (spanno < 0) {
zap_log(ZAP_LOG_ERROR, "Invalid span number %d\n", channo);
continue;
}
if ((mx = strchr(ch, '-'))) {
mx++;
top = atoi(mx) + 1;
} else {
top = channo + 1;
}
if (top < 0) {
zap_log(ZAP_LOG_ERROR, "Invalid range number %d\n", top);
continue;
}
configured += pika_open_range(span, boardno, spanno, channo, top, type, name, number, profile);
}
free(mydata);
return configured;
}
static ZIO_OPEN_FUNCTION(pika_open)
{
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
PKH_QUEUE_Flush(chan_data->media_in_queue);
PKH_PLAY_Start(chan_data->media_out);
return ZAP_SUCCESS;
}
static ZIO_CLOSE_FUNCTION(pika_close)
{
return ZAP_SUCCESS;
}
static ZIO_WAIT_FUNCTION(pika_wait)
{
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
PK_STATUS status;
zap_wait_flag_t myflags = *flags;
PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
*flags = ZAP_NO_FLAGS;
if (myflags & ZAP_READ) {
status = PKH_QUEUE_WaitOnEvent(chan_data->media_in_queue, to, &chan_data->last_media_event);
if (status == PK_SUCCESS) {
if (chan_data->last_media_event.id == PKH_EVENT_QUEUE_TIMEOUT || chan_data->last_media_event.id == PKH_EVENT_RECORD_BUFFER_OVERFLOW) {
return ZAP_TIMEOUT;
}
*flags |= ZAP_READ;
return ZAP_SUCCESS;
}
PKH_EVENT_GetText(chan_data->last_media_event.id, g_EventText, sizeof(g_EventText));
zap_log(ZAP_LOG_DEBUG, "Event: %s\n", g_EventText);
}
return ZAP_SUCCESS;
}
static ZIO_READ_FUNCTION(pika_read)
{
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
PK_STATUS status;
PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
if (zchan->packet_len < *datalen) {
*datalen = zchan->packet_len;
}
if ((status = PKH_RECORD_GetData(chan_data->media_in, data, *datalen)) == PK_SUCCESS) {
return ZAP_SUCCESS;
}
PKH_ERROR_GetText(status, g_EventText, sizeof(g_EventText));
zap_log(ZAP_LOG_DEBUG, "ERR: %s\n", g_EventText);
return ZAP_FAIL;
}
static ZIO_WRITE_FUNCTION(pika_write)
{
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
if (PKH_PLAY_AddData(chan_data->media_out, 0, data, *datalen) == PK_SUCCESS) {
return ZAP_SUCCESS;
}
return ZAP_FAIL;
}
static ZIO_COMMAND_FUNCTION(pika_command)
{
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
//pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
PK_STATUS pk_status;
zap_status_t status = ZAP_SUCCESS;
switch(command) {
case ZAP_COMMAND_OFFHOOK:
{
if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_OFFHOOK)) != PK_SUCCESS) {
PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
GOTO_STATUS(done, ZAP_FAIL);
} else {
zap_set_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
}
}
break;
case ZAP_COMMAND_ONHOOK:
{
if ((pk_status = PKH_TRUNK_SetHookSwitch(chan_data->handle, PKH_TRUNK_ONHOOK)) != PK_SUCCESS) {
PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
GOTO_STATUS(done, ZAP_FAIL);
} else {
zap_clear_flag_locked(zchan, ZAP_CHANNEL_OFFHOOK);
}
}
break;
case ZAP_COMMAND_GENERATE_RING_ON:
{
if ((pk_status = PKH_PHONE_RingStart(chan_data->handle, 0, 0)) != PK_SUCCESS) {
PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
GOTO_STATUS(done, ZAP_FAIL);
} else {
zap_set_flag_locked(zchan, ZAP_CHANNEL_RINGING);
}
}
break;
case ZAP_COMMAND_GENERATE_RING_OFF:
{
if ((pk_status = PKH_PHONE_RingStop(chan_data->handle)) != PK_SUCCESS) {
PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
GOTO_STATUS(done, ZAP_FAIL);
} else {
zap_clear_flag_locked(zchan, ZAP_CHANNEL_RINGING);
}
}
break;
case ZAP_COMMAND_GET_INTERVAL:
{
ZAP_COMMAND_OBJ_INT = zchan->native_interval;
}
break;
case ZAP_COMMAND_SET_INTERVAL:
{
int interval = ZAP_COMMAND_OBJ_INT;
int len = interval * 8;
chan_data->record_config.bufferSize = len;
chan_data->record_config.numberOfBuffers = chan_data->record_config.bufferSize;
zchan->packet_len = chan_data->record_config.bufferSize;
zchan->effective_interval = zchan->native_interval = zchan->packet_len / 8;
PKH_RECORD_SetConfig(chan_data->media_in, &chan_data->record_config);
GOTO_STATUS(done, ZAP_SUCCESS);
}
break;
case ZAP_COMMAND_GET_DTMF_ON_PERIOD:
{
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
GOTO_STATUS(done, ZAP_SUCCESS);
}
break;
case ZAP_COMMAND_GET_DTMF_OFF_PERIOD:
{
ZAP_COMMAND_OBJ_INT = zchan->dtmf_on;
GOTO_STATUS(done, ZAP_SUCCESS);
}
break;
case ZAP_COMMAND_SET_DTMF_ON_PERIOD:
{
int val = ZAP_COMMAND_OBJ_INT;
if (val > 10 && val < 1000) {
zchan->dtmf_on = val;
GOTO_STATUS(done, ZAP_SUCCESS);
} else {
snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
GOTO_STATUS(done, ZAP_FAIL);
}
}
break;
case ZAP_COMMAND_SET_DTMF_OFF_PERIOD:
{
int val = ZAP_COMMAND_OBJ_INT;
if (val > 10 && val < 1000) {
zchan->dtmf_off = val;
GOTO_STATUS(done, ZAP_SUCCESS);
} else {
snprintf(zchan->last_error, sizeof(zchan->last_error), "invalid value %d range 10-1000", val);
GOTO_STATUS(done, ZAP_FAIL);
}
}
break;
case ZAP_COMMAND_SEND_DTMF:
{
char *digits = ZAP_COMMAND_OBJ_CHAR_P;
zap_log(ZAP_LOG_DEBUG, "Adding DTMF SEQ [%s]\n", digits);
zap_mutex_lock(chan_data->digit_mutex);
zap_buffer_write(chan_data->digit_buffer, digits, strlen(digits));
zap_mutex_unlock(chan_data->digit_mutex);
pk_status = PKH_PLAY_Stop(chan_data->media_out);
if (pk_status != PK_SUCCESS) {
PKH_ERROR_GetText(pk_status, zchan->last_error, sizeof(zchan->last_error));
GOTO_STATUS(done, ZAP_FAIL);
}
GOTO_STATUS(done, ZAP_SUCCESS);
}
break;
default:
break;
};
done:
return status;
}
static ZIO_SPAN_POLL_EVENT_FUNCTION(pika_poll_event)
{
pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
PK_STATUS status;
status = PKH_QUEUE_WaitOnEvent(span_data->event_queue, ms, &span_data->last_oob_event);
if (status == PK_SUCCESS) {
zap_channel_t *zchan = span_data->last_oob_event.userData;
//PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
if (span_data->last_oob_event.id == PKH_EVENT_QUEUE_TIMEOUT) {
return ZAP_TIMEOUT;
}
//PKH_EVENT_GetText(span_data->last_oob_event.id, g_EventText, sizeof(g_EventText));
//zap_log(ZAP_LOG_DEBUG, "Event: %s\n", g_EventText);
if (zchan) {
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
zap_set_flag(zchan, ZAP_CHANNEL_EVENT);
zchan->last_event_time = zap_current_time_in_ms();
chan_data->last_oob_event = span_data->last_oob_event;
}
return ZAP_SUCCESS;
}
return ZAP_FAIL;
}
static ZIO_SPAN_NEXT_EVENT_FUNCTION(pika_next_event)
{
uint32_t i, event_id;
for(i = 1; i <= span->chan_count; i++) {
if (zap_test_flag((&span->channels[i]), ZAP_CHANNEL_EVENT)) {
pika_chan_data_t *chan_data = (pika_chan_data_t *) span->channels[i].mod_data;
PK_CHAR g_EventText[PKH_EVENT_MAX_NAME_LENGTH];
zap_clear_flag((&span->channels[i]), ZAP_CHANNEL_EVENT);
PKH_EVENT_GetText(chan_data->last_oob_event.id, g_EventText, sizeof(g_EventText));
zap_log(ZAP_LOG_DEBUG, "Event %d on channel %d:%d [%s]\n",
chan_data->last_oob_event.id,
span->channels[i].span_id,
span->channels[i].chan_id,
g_EventText);
switch(chan_data->last_oob_event.id) {
case PKH_EVENT_TRUNK_HOOKFLASH:
event_id = ZAP_OOB_FLASH;
break;
case PKH_EVENT_TRUNK_RING_OFF:
event_id = ZAP_OOB_RING_STOP;
break;
case PKH_EVENT_TRUNK_RING_ON:
event_id = ZAP_OOB_RING_START;
break;
case PKH_EVENT_PHONE_OFFHOOK:
zap_set_flag_locked((&span->channels[i]), ZAP_CHANNEL_OFFHOOK);
event_id = ZAP_OOB_OFFHOOK;
break;
case PKH_EVENT_TRUNK_BELOW_THRESHOLD:
case PKH_EVENT_TRUNK_ABOVE_THRESHOLD:
case PKH_EVENT_PHONE_ONHOOK:
zap_clear_flag_locked((&span->channels[i]), ZAP_CHANNEL_OFFHOOK);
event_id = ZAP_OOB_ONHOOK;
break;
case PKH_EVENT_TRUNK_ONHOOK:
case PKH_EVENT_TRUNK_OFFHOOK:
case PKH_EVENT_TRUNK_DIALED :
case PKH_EVENT_TRUNK_REVERSAL:
case PKH_EVENT_TRUNK_LCSO:
case PKH_EVENT_TRUNK_DROPOUT:
case PKH_EVENT_TRUNK_LOF:
case PKH_EVENT_TRUNK_RX_OVERLOAD:
default:
zap_log(ZAP_LOG_DEBUG, "Unhandled event %d on channel %d [%s]\n", chan_data->last_oob_event.id, i, g_EventText);
event_id = ZAP_OOB_INVALID;
break;
}
span->channels[i].last_event_time = 0;
span->event_header.e_type = ZAP_EVENT_OOB;
span->event_header.enum_id = event_id;
span->event_header.channel = &span->channels[i];
*event = &span->event_header;
return ZAP_SUCCESS;
}
}
return ZAP_FAIL;
}
static ZIO_SPAN_DESTROY_FUNCTION(pika_span_destroy)
{
pika_span_data_t *span_data = (pika_span_data_t *) span->mod_data;
if (span_data) {
PKH_QUEUE_Destroy(span_data->event_queue);
free(span_data);
}
return ZAP_SUCCESS;
}
static ZIO_CHANNEL_DESTROY_FUNCTION(pika_channel_destroy)
{
pika_chan_data_t *chan_data = (pika_chan_data_t *) zchan->mod_data;
pika_span_data_t *span_data = (pika_span_data_t *) zchan->span->mod_data;
if (zchan->type == ZAP_CHAN_TYPE_FXS || zchan->type == ZAP_CHAN_TYPE_FXO) {
PKH_QUEUE_Detach(span_data->event_queue, chan_data->handle);
PKH_TRUNK_Close(chan_data->handle);
}
PKH_RECORD_Stop(chan_data->media_in);
PKH_PLAY_Stop(chan_data->media_out);
PKH_QUEUE_Destroy(chan_data->media_in_queue);
PKH_QUEUE_Destroy(chan_data->media_out_queue);
zap_mutex_destroy(&chan_data->digit_mutex);
zap_buffer_destroy(&chan_data->digit_buffer);
zap_safe_free(chan_data);
return ZAP_SUCCESS;
}
static ZIO_GET_ALARMS_FUNCTION(pika_get_alarms)
{
return ZAP_FAIL;
}
static zap_io_interface_t pika_interface;
zap_status_t pika_init(zap_io_interface_t **zint)
{
PK_STATUS status;
PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
uint32_t i;
int ok = 0;
PKH_TLogMasks m;
assert(zint != NULL);
memset(&pika_interface, 0, sizeof(pika_interface));
memset(&globals, 0, sizeof(globals));
globals.profile_hash = create_hashtable(16, zap_hash_hashfromstring, zap_hash_equalkeys);
// Open the system object, to enumerate boards configured for this system
if ((status = PKH_SYSTEM_Open(&globals.system_handle)) != PK_SUCCESS) {
zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Open failed(%s)!\n",
PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
return ZAP_FAIL;
}
// Retrieves a list of all boards in this system, existing,
// or listed in pika.cfg
if ((status = PKH_SYSTEM_Detect(globals.system_handle, &globals.board_list)) != PK_SUCCESS) {
zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Detect failed(%s)!\n",
PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
return ZAP_FAIL;
}
PKH_SYSTEM_GetConfig(globals.system_handle, &globals.system_config);
globals.system_config.maxAudioProcessBlockSize = PIKA_BLOCK_LEN;
globals.system_config.playBufferSize = PIKA_BLOCK_SIZE;
globals.system_config.recordBufferSize = PIKA_BLOCK_SIZE;
globals.system_config.recordNumberOfBuffers = 8;
PKH_SYSTEM_SetConfig(globals.system_handle, &globals.system_config);
zap_log(ZAP_LOG_DEBUG, "Found %u board%s\n", globals.board_list.numberOfBoards, globals.board_list.numberOfBoards == 1 ? "" : "s");
for(i = 0; i < globals.board_list.numberOfBoards; ++i) {
zap_log(ZAP_LOG_INFO, "Found PIKA board type:[%s] id:[%u] serno:[%u]\n",
pika_board_type_string(globals.board_list.board[i].type), globals.board_list.board[i].id, (uint32_t)
globals.board_list.board[i].serialNumber);
ok++;
}
if (!ok) {
return ZAP_FAIL;
}
pika_interface.name = "pika";
pika_interface.configure = pika_configure;
pika_interface.configure_span = pika_configure_span;
pika_interface.open = pika_open;
pika_interface.close = pika_close;
pika_interface.wait = pika_wait;
pika_interface.read = pika_read;
pika_interface.write = pika_write;
pika_interface.command = pika_command;
pika_interface.poll_event = pika_poll_event;
pika_interface.next_event = pika_next_event;
pika_interface.channel_destroy = pika_channel_destroy;
pika_interface.span_destroy = pika_span_destroy;
pika_interface.get_alarms = pika_get_alarms;
*zint = &pika_interface;
memset(&m, 0, sizeof(m));
//m.apiMask = 0xffffffff;
//PKH_LOG_SetMasks(&m);
return ZAP_SUCCESS;
}
zap_status_t pika_destroy(void)
{
uint32_t x;
PK_STATUS status;
PK_CHAR error_text[PKH_ERROR_MAX_NAME_LENGTH];
for (x = 0; x < MAX_NUMBER_OF_TRUNKS; x++) {
if (globals.open_boards[x]) {
zap_log(ZAP_LOG_INFO, "Closing board %u\n", x);
PKH_BOARD_Close(globals.open_boards[x]);
}
}
// The system can now be closed.
if ((status = PKH_SYSTEM_Close(globals.system_handle)) != PK_SUCCESS) {
zap_log(ZAP_LOG_ERROR, "Error: PKH_SYSTEM_Close failed(%s)!\n",
PKH_ERROR_GetText(status, error_text, sizeof(error_text)));
}
hashtable_destroy(globals.profile_hash, 0, 1);
return ZAP_SUCCESS;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/
......@@ -82,6 +82,11 @@ static ZIO_WRITE_FUNCTION(skel_write)
return ZAP_FAIL;
}
static ZIO_COMMAND_FUNCTION(skel_command)
{
return ZAP_FAIL;
}
static ZIO_SPAN_POLL_EVENT_FUNCTION(skel_poll_event)
{
return ZAP_FAIL;
......@@ -97,6 +102,11 @@ static ZIO_CHANNEL_DESTROY_FUNCTION(skel_channel_destroy)
return ZAP_FAIL;
}
static ZIO_CHANNEL_DESTROY_FUNCTION(skel_span_destroy)
{
return ZAP_FAIL;
}
static ZIO_GET_ALARMS_FUNCTION(skel_get_alarms)
{
return zap_fail;
......@@ -117,9 +127,11 @@ zap_status_t skel_init(zap_io_interface_t **zint)
skel_interface.wait = skel_wait;
skel_interface.read = skel_read;
skel_interface.write = skel_write;
skel_interface.command = skel_command;
skel_interface.poll_event = skel_poll_event;
skel_interface.next_event = skel_next_event;
skel_interface.channel_destroy = skel_channel_destroy;
skel_interface.span_destroy = skel_span_destroy;
skel_interface.get_alarms = skel_get_alarms;
*zint = &skel_interface;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论