diff options
42 files changed, 1102 insertions, 5384 deletions
diff --git a/package/libtapi/Makefile b/package/libtapi/Makefile deleted file mode 100644 index 5a2db1441b..0000000000 --- a/package/libtapi/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=libtapi -PKG_RELEASE:=1 - -include $(INCLUDE_DIR)/package.mk -include $(INCLUDE_DIR)/kernel.mk - -define Package/libtapi - SECTION:=libs - CATEGORY:=Libraries - TITLE:=libtapi - DEPENDS:=@TARGET_lantiq_xway -endef - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) - $(CP) ./src/* $(PKG_BUILD_DIR)/ -endef - -define Build/Compile - CFLAGS="$(TARGT_CPPFLAGS) $(TARGET_CFLAGS)" \ - $(MAKE) -C $(PKG_BUILD_DIR) \ - $(TARGET_CONFIGURE_OPTS) -endef - -define Build/InstallDev - $(INSTALL_DIR) $(1)/usr/{include,lib} - $(INSTALL_DATA) $(PKG_BUILD_DIR)/*.h $(1)/usr/include/ - $(INSTALL_DATA) $(PKG_BUILD_DIR)/*.so $(1)/usr/lib/ -endef - -define Package/libtapi/install - $(INSTALL_DIR) $(1)/usr/lib - $(INSTALL_BIN) $(PKG_BUILD_DIR)/libtapi.so* $(1)/usr/lib/ -endef - -$(eval $(call BuildPackage,libtapi)) diff --git a/package/libtapi/src/Makefile b/package/libtapi/src/Makefile deleted file mode 100644 index 70b46eb577..0000000000 --- a/package/libtapi/src/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -ifndef CFLAGS -CFLAGS = -O2 -g -I ../src -endif - -FPIC=-fPIC - -all: libtapi.so - -%.o: %.c - $(CC) $(CFLAGS) -c -o $@ $^ $(FPIC) - -TAPI_OBJS = \ - timer_fd.o \ - events.o \ - tapi-port.o \ - tapi-device.o \ - tapi-session.o \ - tapi-stream.o - -tapidemo: tapidemo.o libtapi.so - $(CC) $(LDFLAGS) -o $@ $^ - -libtapi.so: $(TAPI_OBJS) - $(CC) $(LDFLAGS) -shared -o $@ $^ $(FPIC) - -clean: - rm -rf *.o *.so diff --git a/package/libtapi/src/dialdetector.c b/package/libtapi/src/dialdetector.c deleted file mode 100644 index ff91b37aa2..0000000000 --- a/package/libtapi/src/dialdetector.c +++ /dev/null @@ -1,109 +0,0 @@ -#include <linux/input.h> -#include <sys/epoll.h> -#include <stdint.h> -#include <stdbool.h> - - -#include <stdlib.h> -#include <stdio.h> - -#include "events.h" -#include "timerfd.h" - -#include "tapi-port.h" -#include "dialdetector.h" - -static const struct itimerspec dialdetector_timeout = { - .it_value.tv_sec = 3, -}; - -static void dialdetector_note_digit(struct dialdetector *d, unsigned char digit) -{ - printf("note digit: %d\n", d->num_digits); - d->digits[d->num_digits] = digit; - ++d->num_digits; -} - -static void dialdetector_reset(struct dialdetector *d) -{ - event_unregister(d->timer_fd); - d->num_digits = 0; - d->state = DIALDETECTOR_IDLE; -} - -static bool dialdetector_timeout_event(int events, void *data) -{ - char num[20]; - struct dialdetector *dialdetector = data; - int i; - - for (i = 0; i < dialdetector->num_digits; ++i) { - num[i] = '0' + dialdetector->digits[i]; - } - num[i] = '\0'; - - printf("Dialing: %s\n", num); - dialdetector->dial_callback(dialdetector->port, dialdetector->num_digits, - dialdetector->digits); - - dialdetector_reset(dialdetector); - - return false; -} - -static void dialdetector_port_event(struct tapi_port *port, - struct tapi_event *event, void *data) -{ - struct dialdetector *d = data; - - printf("port event: %d %d\n", d->state, event->hook.on); - - switch (d->state) { - case DIALDETECTOR_IDLE: - if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) { - d->state = DIALDETECTOR_WAIT_FOR_NUMBER; - event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); - timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); - } - break; - case DIALDETECTOR_WAIT_FOR_NUMBER: - case DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT: - switch (event->type) { - case TAPI_EVENT_TYPE_HOOK: - if (event->hook.on == true) - dialdetector_reset(d); - break; - case TAPI_EVENT_TYPE_DTMF: - if (d->state == DIALDETECTOR_WAIT_FOR_NUMBER) - event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); - timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); - d->state = DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT; - dialdetector_note_digit(d, event->dtmf.code); - break; - default: - break; - } - } -} - -struct dialdetector *dialdetector_alloc(struct tapi_port *port) -{ - struct dialdetector *dialdetector; - dialdetector = malloc(sizeof(*dialdetector)); - - dialdetector->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); - dialdetector->port = port; - dialdetector->num_digits = 0; - dialdetector->state = DIALDETECTOR_IDLE; - - dialdetector->timeout_cb.callback = dialdetector_timeout_event; - dialdetector->timeout_cb.data = dialdetector; - - dialdetector->port_listener.callback = dialdetector_port_event; - dialdetector->port_listener.data = dialdetector; - - tapi_port_register_event(port, &dialdetector->port_listener); - - - return dialdetector; -} diff --git a/package/libtapi/src/dialdetector.h b/package/libtapi/src/dialdetector.h deleted file mode 100644 index ff91b37aa2..0000000000 --- a/package/libtapi/src/dialdetector.h +++ /dev/null @@ -1,109 +0,0 @@ -#include <linux/input.h> -#include <sys/epoll.h> -#include <stdint.h> -#include <stdbool.h> - - -#include <stdlib.h> -#include <stdio.h> - -#include "events.h" -#include "timerfd.h" - -#include "tapi-port.h" -#include "dialdetector.h" - -static const struct itimerspec dialdetector_timeout = { - .it_value.tv_sec = 3, -}; - -static void dialdetector_note_digit(struct dialdetector *d, unsigned char digit) -{ - printf("note digit: %d\n", d->num_digits); - d->digits[d->num_digits] = digit; - ++d->num_digits; -} - -static void dialdetector_reset(struct dialdetector *d) -{ - event_unregister(d->timer_fd); - d->num_digits = 0; - d->state = DIALDETECTOR_IDLE; -} - -static bool dialdetector_timeout_event(int events, void *data) -{ - char num[20]; - struct dialdetector *dialdetector = data; - int i; - - for (i = 0; i < dialdetector->num_digits; ++i) { - num[i] = '0' + dialdetector->digits[i]; - } - num[i] = '\0'; - - printf("Dialing: %s\n", num); - dialdetector->dial_callback(dialdetector->port, dialdetector->num_digits, - dialdetector->digits); - - dialdetector_reset(dialdetector); - - return false; -} - -static void dialdetector_port_event(struct tapi_port *port, - struct tapi_event *event, void *data) -{ - struct dialdetector *d = data; - - printf("port event: %d %d\n", d->state, event->hook.on); - - switch (d->state) { - case DIALDETECTOR_IDLE: - if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) { - d->state = DIALDETECTOR_WAIT_FOR_NUMBER; - event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); - timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); - } - break; - case DIALDETECTOR_WAIT_FOR_NUMBER: - case DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT: - switch (event->type) { - case TAPI_EVENT_TYPE_HOOK: - if (event->hook.on == true) - dialdetector_reset(d); - break; - case TAPI_EVENT_TYPE_DTMF: - if (d->state == DIALDETECTOR_WAIT_FOR_NUMBER) - event_register(d->timer_fd, EPOLLIN, &d->timeout_cb); - timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); - d->state = DIALDETECTOR_WAIT_FOR_NUMBER_TIMEOUT; - dialdetector_note_digit(d, event->dtmf.code); - break; - default: - break; - } - } -} - -struct dialdetector *dialdetector_alloc(struct tapi_port *port) -{ - struct dialdetector *dialdetector; - dialdetector = malloc(sizeof(*dialdetector)); - - dialdetector->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); - dialdetector->port = port; - dialdetector->num_digits = 0; - dialdetector->state = DIALDETECTOR_IDLE; - - dialdetector->timeout_cb.callback = dialdetector_timeout_event; - dialdetector->timeout_cb.data = dialdetector; - - dialdetector->port_listener.callback = dialdetector_port_event; - dialdetector->port_listener.data = dialdetector; - - tapi_port_register_event(port, &dialdetector->port_listener); - - - return dialdetector; -} diff --git a/package/libtapi/src/events.c b/package/libtapi/src/events.c deleted file mode 100644 index 36e9b62a01..0000000000 --- a/package/libtapi/src/events.c +++ /dev/null @@ -1,58 +0,0 @@ -#include <stdbool.h> -#include <sys/epoll.h> -#include <stdlib.h> -#include <errno.h> - -#include <stdio.h> - -#include "events.h" - -struct event_callback *event_callbacks; - -static int event_epoll_fd = -1; - -int event_register(int fd, int events, struct event_callback *cb) -{ - struct epoll_event ev; - - if (event_epoll_fd == -1) - event_epoll_fd = epoll_create(1); - - ev.events = events; - ev.data.ptr = cb; - - cb->fd = fd; - - return epoll_ctl(event_epoll_fd, EPOLL_CTL_ADD, fd, &ev); -} - -int event_unregister(int fd) -{ - return epoll_ctl(event_epoll_fd, EPOLL_CTL_DEL, fd, NULL); -} - -int tapi_mainloop(void) -{ - struct epoll_event ev[10]; - struct event_callback *cb; - int ret; - bool keep; - int i; - - if (event_epoll_fd == -1) - event_epoll_fd = epoll_create(1); - - while(true) { - ret = epoll_wait(event_epoll_fd, ev, 10, -1); - for(i = 0; i < ret; ++i) { - cb = ev[i].data.ptr; - keep = cb->callback(ev[i].events, cb->data); - if (!keep) - event_unregister(cb->fd); - } - if (ret < 0) - printf("epoll: %d\n", errno); - } - - return 0; -} diff --git a/package/libtapi/src/events.h b/package/libtapi/src/events.h deleted file mode 100644 index 9912fac3a4..0000000000 --- a/package/libtapi/src/events.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __EVENTS_H__ -#define __EVENTS_H__ - -struct event_callback { - bool (*callback)(int events, void *data); - void *data; - int fd; -}; - -int event_register(int fd, int events, - struct event_callback *callback); - -int event_unregister(int fd); - - -int tapi_mainloop(void); - -#endif diff --git a/package/libtapi/src/list.h b/package/libtapi/src/list.h deleted file mode 100644 index 2959a061d3..0000000000 --- a/package/libtapi/src/list.h +++ /dev/null @@ -1,601 +0,0 @@ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#include <stddef.h> -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#ifndef container_of -#define container_of(ptr, type, member) ( \ - (type *)( (char *)ptr - offsetof(type,member) )) -#endif - - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = NULL; - entry->prev = NULL; -} - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = NULL; - n->pprev = NULL; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos; pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos; pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; pos && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; pos && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/package/libtapi/src/tapi-device.c b/package/libtapi/src/tapi-device.c deleted file mode 100644 index 66e4260a0b..0000000000 --- a/package/libtapi/src/tapi-device.c +++ /dev/null @@ -1,46 +0,0 @@ -#include <stdio.h> - -#include "tapi-device.h" -#include "tapi-ioctl.h" - -int tapi_device_open(unsigned int id, struct tapi_device *dev) -{ - char path[100]; - - snprintf(path, sizeof(path), "/dev/tapi%dC", id); - dev->control_fd = open(path, 0); - if (dev->control_fd < 0) - return -1; - - snprintf(dev->stream_path, 100, "/dev/tapi%dS", id); - - dev->id = id; - dev->num_ports = 2; - - return 0; -} - -int tapi_link_alloc(struct tapi_device *dev, unsigned int ep1, unsigned int ep2) -{ - return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_ALLOC, (ep1 << 16) | ep2); -} - -int tapi_link_free(struct tapi_device *dev, unsigned int link) -{ - return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_FREE, link); -} - -int tapi_link_enable(struct tapi_device *dev, unsigned int link) -{ - return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_ENABLE, link); -} - -int tapi_link_disable(struct tapi_device *dev, unsigned int link) -{ - return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_LINK_DISABLE, link); -} - -int tapi_sync(struct tapi_device *dev) -{ - return ioctl(dev->control_fd, TAPI_CONTROL_IOCTL_SYNC, 0); -} diff --git a/package/libtapi/src/tapi-device.h b/package/libtapi/src/tapi-device.h deleted file mode 100644 index 27658b9d83..0000000000 --- a/package/libtapi/src/tapi-device.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __TAPI_DEVICE_H__ -#define __TAPI_DEVICE_H__ - -struct tapi_device { - int control_fd; - int stream_fd; - struct tapi_port *ports; - char stream_path[100]; - - unsigned int id; - - unsigned int num_ports; -}; - -struct tapi_endpoint; - -int tapi_device_open(unsigned int id, struct tapi_device *dev); - -int tapi_link_alloc(struct tapi_device *dev, unsigned int ep1, unsigned int ep2); -int tapi_link_free(struct tapi_device *dev, unsigned int link); -int tapi_link_enable(struct tapi_device *dev, unsigned int link); -int tapi_link_disable(struct tapi_device *dev, unsigned int link); -int tapi_sync(struct tapi_device *dev); - -#endif diff --git a/package/libtapi/src/tapi-ioctl.h b/package/libtapi/src/tapi-ioctl.h deleted file mode 100644 index c43fac1e73..0000000000 --- a/package/libtapi/src/tapi-ioctl.h +++ /dev/null @@ -1,20 +0,0 @@ - -#include <linux/ioctl.h> - -#define TAPI_MAGIC 't' -#define TAPI_IOCTL(x) _IO(TAPI_MAGIC, (x)) - -#define TAPI_CONTROL_IOCTL_LINK_ALLOC TAPI_IOCTL(0) -#define TAPI_CONTROL_IOCTL_LINK_FREE TAPI_IOCTL(1) -#define TAPI_CONTROL_IOCTL_LINK_ENABLE TAPI_IOCTL(2) -#define TAPI_CONTROL_IOCTL_LINK_DISABLE TAPI_IOCTL(3) - -#define TAPI_CONTROL_IOCTL_SYNC TAPI_IOCTL(4) - -#define TAPI_PORT_IOCTL_GET_ENDPOINT TAPI_IOCTL(5) -#define TAPI_PORT_IOCTL_SET_RING TAPI_IOCTL(6) - -#define TAPI_STREAM_IOCTL_GET_ENDPOINT TAPI_IOCTL(7) -#define TAPI_STREAM_IOCTL_CONFIGURE TAPI_IOCTL(8) -#define TAPI_STREAM_IOCTL_START TAPI_IOCTL(9) -#define TAPI_STREAM_IOCTL_STOP TAPI_IOCTL(10) diff --git a/package/libtapi/src/tapi-port.c b/package/libtapi/src/tapi-port.c deleted file mode 100644 index d06d946e12..0000000000 --- a/package/libtapi/src/tapi-port.c +++ /dev/null @@ -1,126 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/epoll.h> -#include <unistd.h> - -#include <linux/input.h> - -#include "tapi-ioctl.h" -#include "tapi-device.h" -#include "tapi-port.h" - -#include "events.h" -#include "list.h" - -static void tapi_port_event_dispatch(struct tapi_port *port, - struct tapi_event *event) -{ - struct tapi_port_event_listener *l; - - list_for_each_entry(l, &port->event_listeners, head) { - l->callback(port, event, l->data); - } -} - -static bool tapi_port_input_event(int events, void *data) -{ - struct tapi_port *port = data; - struct input_event event; - struct tapi_event tapi_event; - int ret; - - ret = read(port->input_fd, &event, sizeof(event)); - if (ret < 0) { - fprintf(stderr, "Port %d failed to read from input device: %d\n", - port->id, errno); - return true; - } - - if (!event.value) - return true; - - switch (event.code) { - case KEY_NUMERIC_0 ... KEY_NUMERIC_9: - tapi_event.type = TAPI_EVENT_TYPE_DTMF; - tapi_event.dtmf.code = event.code - KEY_NUMERIC_0; - break; - case KEY_NUMERIC_POUND: - tapi_event.type = TAPI_EVENT_TYPE_DTMF; - tapi_event.dtmf.code = 10; - break; - case KEY_NUMERIC_STAR: - tapi_event.type = TAPI_EVENT_TYPE_DTMF; - tapi_event.dtmf.code = 11; - break; - case KEY_ESC: - tapi_event.type = TAPI_EVENT_TYPE_HOOK; - tapi_event.hook.on = true; - break; - case KEY_ENTER: - tapi_event.type = TAPI_EVENT_TYPE_HOOK; - tapi_event.hook.on = false; - break; - default: - return true; - } - - if (tapi_event.type == TAPI_EVENT_TYPE_DTMF) - tapi_event.dtmf.time = event.time; - - tapi_port_event_dispatch(port, &tapi_event); - - return true; -} - -int tapi_port_open(struct tapi_device *dev, unsigned int id, struct tapi_port *port) -{ - int ret; - char path[100]; - - port->id = id; - - snprintf(path, 100, "/dev/tapi%uP%u", dev->id, id); - port->fd = open(path, 0); - if (port->fd < 0) { - printf("Failed to open %s: %d\n", path, errno); - return errno; - } - - snprintf(path, 100, "/dev/event%u", id); - port->input_fd = open(path, O_RDONLY); - if (port->input_fd < 0) { - printf("Failed to open %s: %d\n", path, errno); - return errno; - } - - port->ep = ioctl(port->fd, TAPI_PORT_IOCTL_GET_ENDPOINT, 0); - - INIT_LIST_HEAD(&port->event_listeners); - - port->input_cb.callback = tapi_port_input_event; - port->input_cb.data = port; - - return event_register(port->input_fd, EPOLLIN, - &port->input_cb); -} - -int tapi_port_set_ring(struct tapi_port *port, bool ring) -{ - return ioctl(port->fd, TAPI_PORT_IOCTL_SET_RING, ring); -} - -int tapi_port_register_event(struct tapi_port *port, - struct tapi_port_event_listener *cb) -{ - list_add_tail(&cb->head, &port->event_listeners); - return 0; -} - -void tapi_port_unregister_event(struct tapi_port *port, - struct tapi_port_event_listener *cb) -{ - list_del(&cb->head); -} diff --git a/package/libtapi/src/tapi-port.h b/package/libtapi/src/tapi-port.h deleted file mode 100644 index a290a4002d..0000000000 --- a/package/libtapi/src/tapi-port.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __TAPI_PORT_H__ -#define __TAPI_PORT_H__ - -#include <sys/time.h> - -#include "list.h" -#include "events.h" - -struct tapi_port; -struct tapi_device; - -struct tapi_dtmf_event { - struct timeval time; - unsigned char code; -}; - -struct tapi_hook_event { - bool on; -}; - -enum tapi_event_type { - TAPI_EVENT_TYPE_DTMF, - TAPI_EVENT_TYPE_HOOK, -}; - -struct tapi_event { - enum tapi_event_type type; - union { - struct tapi_dtmf_event dtmf; - struct tapi_hook_event hook; - }; -}; - -struct tapi_port_event_listener { - void (*callback)(struct tapi_port *, struct tapi_event *event, void *data); - void *data; - - struct list_head head; -}; - -struct tapi_port { - int id; - int fd; - int input_fd; - unsigned int ep; - - struct event_callback input_cb; - - struct list_head event_listeners; -}; - -int tapi_port_open(struct tapi_device *dev, unsigned int id, struct tapi_port -*port); -int tapi_port_set_ring(struct tapi_port *port, bool ring); -int tapi_port_register_event(struct tapi_port *port, - struct tapi_port_event_listener *cb); - -void tapi_port_unregister_event(struct tapi_port *port, - struct tapi_port_event_listener *cb); - -static inline int tapi_port_get_endpoint(struct tapi_port *port) -{ - return port->ep; -} - -#endif diff --git a/package/libtapi/src/tapi-session.c b/package/libtapi/src/tapi-session.c deleted file mode 100644 index 8b17053115..0000000000 --- a/package/libtapi/src/tapi-session.c +++ /dev/null @@ -1,122 +0,0 @@ -#include <stdlib.h> -#include <stdbool.h> -#include <stdint.h> - -#include "tapi-device.h" -#include "tapi-port.h" -#include "tapi-session.h" - -enum tapi_session_port_state { - TAPI_SESSION_PORT_STATE_IDLE, - TAPI_SESSION_PORT_STATE_RINGING, - TAPI_SESSION_PORT_STATE_ACTIVE, -}; - -struct tapi_session_port { - struct tapi_port *port; - struct tapi_port_event_listener event_listener; - - enum tapi_session_port_state state; -}; - -struct tapi_session { - struct tapi_device *dev; - struct tapi_session_port caller; - struct tapi_session_port callee; - - bool active; - unsigned int link; - - void (*release)(struct tapi_session *session, void *data); -}; - -static void tapi_session_terminate(struct tapi_session *session) -{ - if (session->active) { - tapi_link_enable(session->dev, session->link); - tapi_sync(session->dev); - tapi_link_free(session->dev, session->link); - } - - switch (session->callee.state) { - case TAPI_SESSION_PORT_STATE_RINGING: - tapi_port_set_ring(session->callee.port, false); - break; - default: - break; - } - - session->active = false; -} - -static void tapi_session_caller_event(struct tapi_port *port, - struct tapi_event *event, void *data) -{ - struct tapi_session *session = data; - - if (event->type != TAPI_EVENT_TYPE_HOOK) - return; - - if (event->hook.on) { - tapi_session_terminate(session); - } -} - -static void tapi_session_callee_event(struct tapi_port *port, - struct tapi_event *event, void *data) -{ - struct tapi_session *session = data; - - if (event->type != TAPI_EVENT_TYPE_HOOK) - return; - - if (event->hook.on) { - if (session->callee.state == TAPI_SESSION_PORT_STATE_ACTIVE) { - tapi_session_terminate(session); - } - } else { - if (session->callee.state == TAPI_SESSION_PORT_STATE_RINGING) { - tapi_port_set_ring(session->callee.port, false); - session->link = tapi_link_alloc(session->dev, - session->caller.port->ep, session->callee.port->ep); - session->callee.state = TAPI_SESSION_PORT_STATE_ACTIVE; - tapi_link_enable(session->dev, session->link); - tapi_sync(session->dev); - session->active = true; - } - } -} - -struct tapi_session *tapi_session_alloc(struct tapi_device *dev, - struct tapi_port *caller, struct tapi_port *callee, - void (*release)(struct tapi_session *session, void *data), void *release_data) -{ - struct tapi_session *session; - struct tapi_session_port *session_port; - - session = malloc(sizeof(*session)); - - session->dev = dev; - - session->callee.port = callee; - session->callee.state = TAPI_SESSION_PORT_STATE_RINGING; - session->callee.event_listener.callback = tapi_session_callee_event; - session->callee.event_listener.data = session; - tapi_port_register_event(callee, &session->callee.event_listener); - - session->caller.port = caller; - session->caller.state = TAPI_SESSION_PORT_STATE_ACTIVE; - session->caller.event_listener.callback = tapi_session_caller_event; - session->caller.event_listener.data = session; - tapi_port_register_event(caller, &session->caller.event_listener); - - tapi_port_set_ring(callee, true); -} - -void tapi_session_free(struct tapi_session *session) -{ - tapi_session_terminate(session); - tapi_port_register_event(session->callee.port, &session->callee.event_listener); - tapi_port_register_event(session->caller.port, &session->caller.event_listener); - free(session); -} diff --git a/package/libtapi/src/tapi-session.h b/package/libtapi/src/tapi-session.h deleted file mode 100644 index 15d94735eb..0000000000 --- a/package/libtapi/src/tapi-session.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __TAPI_SESSION_H__ -#define __TAPI_SESSION_H__ - -struct tapi_device; -struct tapi_port; -struct tapi_session; - -struct tapi_session *tapi_session_alloc(struct tapi_device *dev, - struct tapi_port *caller, struct tapi_port *callee, - void (*release)(struct tapi_session *session, void *data), void *release_data); - -void tapi_session_free(struct tapi_session *session); - -#endif diff --git a/package/libtapi/src/tapi-stream.c b/package/libtapi/src/tapi-stream.c deleted file mode 100644 index 5ae44a1631..0000000000 --- a/package/libtapi/src/tapi-stream.c +++ /dev/null @@ -1,42 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "tapi-device.h" -#include "tapi-stream.h" -#include "tapi-ioctl.h" - -struct tapi_stream *tapi_stream_alloc(struct tapi_device *dev) -{ - struct tapi_stream *stream; - - stream = malloc(sizeof(*stream)); - if (!stream) - return NULL; - - stream->fd = open(dev->stream_path, O_RDWR); - - if (stream->fd < 0) { - free(stream); - return NULL; - } - - stream->ep = ioctl(stream->fd, TAPI_STREAM_IOCTL_GET_ENDPOINT, 0); - - if (stream->ep < 0) { - close(stream->fd); - free(stream); - return NULL; - } - - return stream; -} - -void tapi_stream_free(struct tapi_stream *stream) -{ - close(stream->fd); - free(stream); -} diff --git a/package/libtapi/src/tapi-stream.h b/package/libtapi/src/tapi-stream.h deleted file mode 100644 index 0e3e04af24..0000000000 --- a/package/libtapi/src/tapi-stream.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __TAPI_STREAM_H__ -#define __TAPI_STREAM_H__ - -struct tapi_device; - -struct tapi_stream { - int fd; - int ep; -}; - -struct tapi_stream *tapi_stream_alloc(struct tapi_device *); -void tapi_stream_free(struct tapi_stream *); - -static inline int tapi_stream_get_endpoint(struct tapi_stream *stream) -{ - return stream->ep; -} - -#endif diff --git a/package/libtapi/src/tapidemo.c b/package/libtapi/src/tapidemo.c deleted file mode 100644 index 63098b89cf..0000000000 --- a/package/libtapi/src/tapidemo.c +++ /dev/null @@ -1,56 +0,0 @@ - -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/ioctl.h> -#include <fcntl.h> -#include <errno.h> -#include <poll.h> - -#include <linux/input.h> -/*#include <sys/timerfd.h>*/ -#include "timerfd.h" -#include "dialdetector.h" - -#include "tapi-ioctl.h" - -#include "tapi-device.h" -#include "tapi-port.h" - -static struct tapi_device dev; -static struct tapi_port ports[2]; - -void dial_callback(struct tapi_port *port, size_t num_digits, const unsigned char *digits) -{ - unsigned int link; - - if (num_digits != 1) - return; - if (port->id == digits[0] || digits[0] > 1) - return; - - tapi_port_set_ring(&ports[digits[0]], true); - - tapi_session_alloc(&dev, port, &ports[digits[0]]); -} - -int main(int argc, char *argv[]) -{ - struct dialdetector *dd, *dd2; - unsigned int link; - unsigned char buf[1024]; - int ret; - - tapi_device_open(0, &dev); - tapi_port_open(0, 0, &ports[0]); - tapi_port_open(0, 1, &ports[1]); - - dd = dialdetector_alloc(&ports[0]); - dd->dial_callback = dial_callback; - dd2 = dialdetector_alloc(&ports[1]); - dd2->dial_callback = dial_callback; - - tapi_mainloop(); - - return 0; -} diff --git a/package/libtapi/src/timer_fd.c b/package/libtapi/src/timer_fd.c deleted file mode 100644 index fbc951a9fc..0000000000 --- a/package/libtapi/src/timer_fd.c +++ /dev/null @@ -1,33 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * timerfd_create() / timerfd_settime() / timerfd_gettime() for uClibc - * - * Copyright (C) 2009 Stephan Raue <stephan@openelec.tv> - * - * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. - */ - -#include <sys/syscall.h> -/*#include <sys/timerfd.h>*/ -#include "timerfd.h" - -/* - * timerfd_create() - */ -#ifdef __NR_timerfd_create -int timerfd_create(int clockid, int flags) -{ - return syscall(__NR_timerfd_create, clockid, flags); -} -#endif - -/* - * timerfd_settime() - */ -#ifdef __NR_timerfd_settime -int timerfd_settime(int ufd, int flags, const struct itimerspec *umtr, struct itimerspec *otmr) -{ - return syscall(__NR_timerfd_settime, ufd, flags, umtr, otmr); -} -#endif - diff --git a/package/libtapi/src/timerfd.h b/package/libtapi/src/timerfd.h deleted file mode 100644 index f17bc798a6..0000000000 --- a/package/libtapi/src/timerfd.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2008 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _SYS_TIMERFD_H -#define _SYS_TIMERFD_H 1 - -#include <time.h> - - -/* Bits to be set in the FLAGS parameter of `timerfd_create'. */ -enum - { - TFD_CLOEXEC = 02000000, -#define TFD_CLOEXEC TFD_CLOEXEC - TFD_NONBLOCK = 04000 -#define TFD_NONBLOCK TFD_NONBLOCK - }; - - -/* Bits to be set in the FLAGS parameter of `timerfd_settime'. */ -enum - { - TFD_TIMER_ABSTIME = 1 << 0 -#define TFD_TIMER_ABSTIME TFD_TIMER_ABSTIME - }; - - -__BEGIN_DECLS - -/* Return file descriptor for new interval timer source. */ -extern int timerfd_create (clockid_t __clock_id, int __flags) __THROW; - -/* Set next expiration time of interval timer source UFD to UTMR. If - FLAGS has the TFD_TIMER_ABSTIME flag set the timeout value is - absolute. Optionally return the old expiration time in OTMR. */ -extern int timerfd_settime (int __ufd, int __flags, - __const struct itimerspec *__utmr, - struct itimerspec *__otmr) __THROW; - -/* Return the next expiration time of UFD. */ -extern int timerfd_gettime (int __ufd, struct itimerspec *__otmr) __THROW; - -__END_DECLS - -#endif /* sys/timerfd.h */ - diff --git a/package/pjsip/Makefile b/package/pjsip/Makefile index e9acaeb813..f1317fffd1 100644 --- a/package/pjsip/Makefile +++ b/package/pjsip/Makefile @@ -16,57 +16,65 @@ PKG_SOURCE_URL:=http://www.pjsip.org/release/$(PKG_VERSION)/ PKG_MD5SUM:=f9aa9e58b4d697245eb4bfa7d81a54a3 PKG_INSTALL:=1 -PKG_BUILD_DIR:=$(BUILD_DIR)/pjproject-$(PKG_VERSION) +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/pjproject-$(PKG_VERSION) include $(INCLUDE_DIR)/package.mk -define Package/pjsip +define Package/pjsip-template SECTION:=lib CATEGORY:=Libraries - TITLE:=Voip lib URL:=http://www.pjsip.org/ - DEPENDS:=+libuuid MAINTAINER:=John Crispin <blogic@openwrt.org> + TITLE:=pjsip-$(1) + VARIANT:=$(1) + DEPENDS:=+libuuid $(2) endef -define Package/pjsip/config - source "$(SOURCE)/Config.in" -endef +CONFIGURE_PREFIX=/usr/pjsip-$(BUILD_VARIANT) +ifeq ($(BUILD_VARIANT),oss) CONFIGURE_ARGS += \ --enable-g711-codec \ --disable-l16-codec \ --disable-g722-codec \ --disable-g7221-codec \ + --disable-gsm-codec \ --disable-ilbc-coder \ --disable-libsamplerate \ --disable-ipp \ --disable-ssl \ - $(call autoconf_bool,CONFIG_PJSIP_GSM,gsm-codec) \ - $(call autoconf_bool,CONFIG_PJSIP_SPEEX,speex-aec) \ - $(call autoconf_bool,CONFIG_PJSIP_OSS,oss) \ - $(call autoconf_bool,CONFIG_PJSIP_SOUND,sound) \ - $(call autoconf_bool,CONFIG_PJSIP_DEV_TAPI,ltq-tapi) + --enable-oss \ + --enable-sound +endif -ifeq ($(CONFIG_PJSIP_DEV_TAPI),y) +ifeq ($(BUILD_VARIANT),ltq-tapi) +CONFIGURE_ARGS += \ + --enable-g711-codec \ + --disable-l16-codec \ + --disable-g722-codec \ + --disable-g7221-codec \ + --disable-ilbc-coder \ + --disable-gsm-codec \ + --disable-libsamplerate \ + --disable-ipp \ + --disable-ssl \ + --enable-sound \ + --enable-ltq-tapi EXTRA_CFLAGS:=-I$(STAGING_DIR)/usr/include/drv_tapi -I$(STAGING_DIR)/usr/include/drv_vmmc endif -define Build/Configure - (cd $(PKG_BUILD_DIR); autoconf aconfigure.ac > aconfigure) - $(call Build/Configure/Default) -endef +Package/pjsip-oss=$(call Package/pjsip-template,oss,) +Package/pjsip-ltq-tapi=$(call Package/pjsip-template,ltq-tapi,@TARGET_lantiq) -define Build/InstallDev - $(INSTALL_DIR) $(1)/usr/{include,lib} - $(CP) $(PKG_INSTALL_DIR)/usr/include/* \ - $(1)/usr/include/ - $(CP) $(PKG_INSTALL_DIR)/usr/lib/* \ - $(1)/usr/lib/ +define Build/Prepare + $(PKG_UNPACK) + $(Build/Patch) + $(CP) ./src/* $(PKG_BUILD_DIR) endef -define Package/pjsip/install - $(INSTALL_DIR) $(1)/usr/sbin +define Build/Configure + (cd $(PKG_BUILD_DIR); autoconf aconfigure.ac > aconfigure) + $(call Build/Configure/Default) endef define Build/Compile @@ -75,4 +83,15 @@ define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR)/$(MAKE_PATH) endef -$(eval $(call BuildPackage,pjsip)) +define Build/InstallDev + $(INSTALL_DIR) $(1)/usr/ + $(CP) $(PKG_INSTALL_DIR)/usr/pjsip-$(BUILD_VARIANT) \ + $(1)/usr/ +endef + +define Package/pjsip-$(BUILD_VARIANT)/install + echo "foo" +endef + +$(eval $(call BuildPackage,pjsip-oss)) +$(eval $(call BuildPackage,pjsip-ltq-tapi)) diff --git a/package/pjsip/patches/200-pjmedia_tapi_audiodev.patch b/package/pjsip/patches/200-pjmedia_tapi_audiodev.patch deleted file mode 100644 index dc5ff2d5d3..0000000000 --- a/package/pjsip/patches/200-pjmedia_tapi_audiodev.patch +++ /dev/null @@ -1,1027 +0,0 @@ ---- /dev/null -+++ b/pjmedia/src/pjmedia-audiodev/tapi_dev.c -@@ -0,0 +1,1024 @@ -+/****************************************************************************** -+ -+ Copyright (c) 2010 -+ Lantiq Deutschland GmbH -+ Am Campeon 3; 85579 Neubiberg, Germany -+ -+ For licensing information, see the file 'LICENSE' in the root folder of -+ this software module. -+ -+******************************************************************************/ -+#include <pjmedia-audiodev/audiodev_imp.h> -+#include <pjmedia/errno.h> -+#include <pj/assert.h> -+#include <pj/pool.h> -+#include <pj/log.h> -+#include <pj/os.h> -+ -+/* Linux includes*/ -+#include <stdio.h> -+#include <string.h> -+#include <stdlib.h> -+#include <ctype.h> -+#include <sys/stat.h> -+#include <fcntl.h> -+#include <sys/types.h> -+#include <sys/ioctl.h> -+#include <sys/select.h> -+#include <sys/time.h> -+#include <unistd.h> -+ -+#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE -+ -+/* TAPI includes*/ -+#include "drv_tapi_io.h" -+#include "vmmc_io.h" -+ -+/* Maximum 2 devices*/ -+#define TAPI_AUDIO_DEV_NUM (1) -+#define TAPI_AUDIO_MAX_DEV_NUM (2) -+#define TAPI_BASE_NAME "TAPI" -+#define TAPI_LL_DEV_BASE_PATH "/dev/vmmc" -+#define TAPI_LL_DEV_FIRMWARE_NAME "/lib/firmware/danube_firmware.bin" -+ -+#define TAPI_LL_DEV_SELECT_TIMEOUT_MS (2000) -+#define TAPI_LL_DEV_MAX_PACKET_SIZE (800) -+#define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE (12) -+#define TAPI_LL_DEV_ENC_FRAME_LEN_MS (20) -+#define TAPI_LL_DEV_ENC_SMPL_PER_SEC (8000) -+#define TAPI_LL_DEV_ENC_BITS_PER_SMPLS (16) -+#define TAPI_LL_DEV_ENC_SMPL_PER_FRAME (160) -+#define TAPI_LL_DEV_ENC_BYTES_PER_FRAME (TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8)) -+ -+ -+#define FD_WIDTH_SET(fd, maxfd) (maxfd) < (fd) ? (fd) : maxfd -+ -+#define THIS_FILE "tapi_dev.c" -+ -+#if 1 -+# define TRACE_(x) PJ_LOG(1,x) -+#else -+# define TRACE_(x) -+#endif -+ -+typedef struct -+{ -+ pj_int32_t dev_fd; -+ pj_int32_t ch_fd[TAPI_AUDIO_DEV_NUM]; -+ pj_int8_t data2phone_map[TAPI_AUDIO_DEV_NUM]; -+ -+} tapi_ctx; -+ -+ -+/* TAPI factory */ -+struct tapi_aud_factory -+{ -+ pjmedia_aud_dev_factory base; -+ pj_pool_t *pool; -+ pj_pool_factory *pf; -+ -+ pj_uint32_t dev_count; -+ pjmedia_aud_dev_info *dev_info; -+ -+ tapi_ctx dev_ctx; -+}; -+ -+typedef struct tapi_aud_factory tapi_aud_factory_t; -+ -+/* -+ Sound stream descriptor. -+**/ -+struct tapi_aud_stream -+{ -+ /* Base*/ -+ pjmedia_aud_stream base; /**< Base class. */ -+ /* Pool*/ -+ pj_pool_t *pool; /**< Memory pool. */ -+ /* Common settings.*/ -+ pjmedia_aud_param param; /**< Stream param. */ -+ pjmedia_aud_rec_cb rec_cb; /**< Record callback. */ -+ pjmedia_aud_play_cb play_cb; /**< Playback callback. */ -+ void *user_data; /**< Application data. */ -+ -+ pj_thread_desc thread_desc; -+ pj_thread_t *thread; -+ tapi_ctx *dev_ctx; -+ pj_uint8_t run_flag; -+ pj_timestamp timestamp; -+}; -+ -+typedef struct tapi_aud_stream tapi_aud_stream_t; -+ -+/* Factory prototypes */ -+static pj_status_t factory_init(pjmedia_aud_dev_factory *f); -+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); -+static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f); -+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, -+ unsigned index, -+ pjmedia_aud_dev_info *info); -+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f, -+ unsigned index, -+ pjmedia_aud_param *param); -+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f, -+ const pjmedia_aud_param *param, -+ pjmedia_aud_rec_cb rec_cb, -+ pjmedia_aud_play_cb play_cb, -+ void *user_data, -+ pjmedia_aud_stream **p_aud_strm); -+ -+/* Stream prototypes */ -+static pj_status_t stream_get_param(pjmedia_aud_stream *strm, -+ pjmedia_aud_param *param); -+static pj_status_t stream_get_cap(pjmedia_aud_stream *strm, -+ pjmedia_aud_dev_cap cap, -+ void *value); -+static pj_status_t stream_set_cap(pjmedia_aud_stream *strm, -+ pjmedia_aud_dev_cap cap, -+ const void *value); -+static pj_status_t stream_start(pjmedia_aud_stream *strm); -+static pj_status_t stream_stop(pjmedia_aud_stream *strm); -+static pj_status_t stream_destroy(pjmedia_aud_stream *strm); -+ -+static pjmedia_aud_dev_factory_op tapi_fact_op = -+ { -+ &factory_init, -+ &factory_destroy, -+ &factory_get_dev_count, -+ &factory_get_dev_info, -+ &factory_default_param, -+ &factory_create_stream -+ }; -+ -+static pjmedia_aud_stream_op tapi_strm_op = -+{ -+ &stream_get_param, -+ &stream_get_cap, -+ &stream_set_cap, -+ &stream_start, -+ &stream_stop, -+ &stream_destroy -+}; -+ -+static pj_int32_t tapi_dev_open(char* dev_path, const pj_int32_t ch_num) -+{ -+ char devname[128] = {0}; -+ -+ pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num); -+ -+ return open((const char*)devname, O_RDWR, 0644); -+} -+ -+static pj_status_t tapi_dev_binary_buffer_create( -+ const char *pPath, -+ pj_uint8_t **ppBuf, -+ pj_uint32_t *pBufSz) -+{ -+ pj_status_t status = PJ_SUCCESS; -+ FILE *fd; -+ struct stat file_stat; -+ -+ /* Open binary file for reading*/ -+ fd = fopen(pPath, "rb"); -+ if (fd == NULL) { -+ TRACE_((THIS_FILE, "ERROR - binary file %s open failed!\n", pPath)); -+ return PJ_EUNKNOWN; -+ } -+ -+ /* Get file statistics*/ -+ if (stat(pPath, &file_stat) != 0) { -+ TRACE_((THIS_FILE, "ERROR - file %s statistics get failed!\n", pPath)); -+ return PJ_EUNKNOWN; -+ } -+ -+ *ppBuf = malloc(file_stat.st_size); -+ if (*ppBuf == NULL) { -+ TRACE_((THIS_FILE, "ERROR - binary file %s memory allocation failed!\n", pPath)); -+ status = PJ_EUNKNOWN; -+ -+ goto on_exit; -+ } -+ -+ if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) { -+ TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath)); -+ status = PJ_EUNKNOWN; -+ -+ goto on_exit; -+ } -+ -+ *pBufSz = file_stat.st_size; -+ -+on_exit: -+ if (fd != NULL) { -+ fclose(fd); -+ } -+ -+ if (*ppBuf != NULL && status != PJ_SUCCESS) { -+ free(*ppBuf); -+ } -+ -+ return status; -+} -+ -+static void tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf) -+{ -+ if (pBuf != NULL) -+ free(pBuf); -+} -+ -+static pj_status_t tapi_dev_firmware_download( -+ pj_int32_t fd, -+ const char *pPath) -+{ -+ pj_status_t status = PJ_SUCCESS; -+ pj_uint8_t *pFirmware = NULL; -+ pj_uint32_t binSz = 0; -+ VMMC_IO_INIT vmmc_io_init; -+ -+ /* Create binary buffer*/ -+ status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz); -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ /* Download Voice Firmware*/ -+ memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT)); -+ vmmc_io_init.pPRAMfw = pFirmware; -+ vmmc_io_init.pram_size = binSz; -+ -+ status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init); -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - FIO_FW_DOWNLOAD ioctl failed!")); -+ } -+ -+ /* Delete binary buffer*/ -+ tapi_dev_binary_buffer_delete(pFirmware); -+ -+ return status; -+} -+ -+ -+static pj_status_t tapi_dev_start(tapi_aud_factory_t *f) -+{ -+ pj_status_t status = PJ_SUCCESS; -+ pj_uint8_t c; -+ IFX_TAPI_DEV_START_CFG_t tapistart; -+ IFX_TAPI_MAP_DATA_t datamap; -+ IFX_TAPI_ENC_CFG_t enc_cfg; -+ IFX_TAPI_LINE_VOLUME_t vol; -+ -+ /* Open device*/ -+ f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0); -+ -+ if (f->dev_ctx.dev_fd < 0) { -+ TRACE_((THIS_FILE, "ERROR - TAPI device open failed!")); -+ return PJ_EUNKNOWN; -+ } -+ -+ for (c = 0; c < TAPI_AUDIO_DEV_NUM; c++) { -+ f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_MAX_DEV_NUM - c); -+ -+ if (f->dev_ctx.dev_fd < 0) { -+ TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c)); -+ return PJ_EUNKNOWN; -+ } -+ -+ f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1; -+ } -+ -+ status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME); -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!")); -+ return PJ_EUNKNOWN; -+ } -+ -+ memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t)); -+ tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER; -+ -+ /* Start TAPI*/ -+ status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart); -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed")); -+ return PJ_EUNKNOWN; -+ } -+ -+ -+ for (c = 0; c < TAPI_AUDIO_DEV_NUM; c++) { -+ /* Perform mapping*/ -+ memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t)); -+ datamap.nDstCh = f->dev_ctx.data2phone_map[c]; -+ datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE; -+ -+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap); -+ -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed")); -+ return PJ_EUNKNOWN; -+ } -+ -+ /* Set Line feed*/ -+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY); -+ -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed")); -+ return PJ_EUNKNOWN; -+ } -+ -+ /* Config encoder for linear stream*/ -+ memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t)); -+ -+ enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20; -+ enc_cfg.nEncType = IFX_TAPI_COD_TYPE_LIN16_8; -+ -+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg); -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed")); -+ return PJ_EUNKNOWN; -+ } -+ -+ -+ /* Suppress TAPI volume, otherwise PJSIP starts autogeneration!!!*/ -+ vol.nGainRx = -8; -+ vol.nGainTx = -8; -+ -+ status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &vol); -+ if (status != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed")); -+ return PJ_EUNKNOWN; -+ } -+ } -+ -+ -+ return status; -+} -+ -+static pj_status_t tapi_dev_stop(tapi_aud_factory_t *f) -+{ -+ pj_status_t status = PJ_SUCCESS; -+ pj_uint8_t c; -+ -+ /* Stop TAPI device*/ -+ if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed")); -+ status = PJ_EUNKNOWN; -+ } -+ -+ /* Close device FD*/ -+ close(f->dev_ctx.dev_fd); -+ -+ /* Close channel FD*/ -+ for (c = TAPI_AUDIO_DEV_NUM; c > 0; c--) { -+ close(f->dev_ctx.ch_fd[TAPI_AUDIO_DEV_NUM-c]); -+ } -+ -+ -+ return status; -+} -+ -+static pj_status_t tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start) -+{ -+ if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!", -+ start ? "START" : "STOP")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!", -+ start ? "START" : "STOP")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ return PJ_SUCCESS; -+} -+ -+static pj_status_t tapi_dev_event_ONHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx) -+{ -+ PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK")); -+ -+ if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET, -+ IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ /* enc/dec stop*/ -+ if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - codec start failed!")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ return PJ_SUCCESS; -+} -+ -+static pj_status_t tapi_dev_event_OFFHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx) -+{ -+ PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK")); -+ -+ if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET, -+ IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ /* enc/dec stop*/ -+ if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - codec start failed!")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ return PJ_SUCCESS; -+} -+ -+static pj_status_t tapi_dev_event_handler( -+ tapi_aud_stream_t *stream) -+{ -+ tapi_ctx *dev_ctx = stream->dev_ctx; -+ pj_uint32_t dev_idx = stream->param.rec_id; -+ pj_status_t status = PJ_SUCCESS; -+ IFX_TAPI_EVENT_t tapiEvent; -+ -+ memset (&tapiEvent, 0, sizeof(tapiEvent)); -+ -+ tapiEvent.ch = dev_ctx->data2phone_map[dev_idx]; -+ -+ /* Get event*/ -+ status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent); -+ -+ if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) { -+ switch(tapiEvent.id) { -+ case IFX_TAPI_EVENT_FXS_ONHOOK: -+ status = tapi_dev_event_ONHOOK(dev_ctx, dev_idx); -+ break; -+ case IFX_TAPI_EVENT_FXS_OFFHOOK: -+ status = tapi_dev_event_OFFHOOK(dev_ctx, dev_idx); -+ break; -+ default: -+ break; -+ } -+ } -+ -+ return status; -+} -+ -+static pj_status_t tapi_dev_data_handler( -+ tapi_aud_stream_t *stream) -+{ -+ pj_status_t status = PJ_SUCCESS; -+ tapi_ctx *dev_ctx = stream->dev_ctx; -+ pj_uint32_t dev_idx = stream->param.rec_id; -+ pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0}; -+ pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0}; -+ pjmedia_frame frame_rec, frame_play; -+ pj_int32_t ret; -+ -+ /* Get data from driver*/ -+ ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec)); -+ if (ret < 0) { -+ TRACE_((THIS_FILE, "ERROR - no data available from device!")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ if (ret > 0) { -+ frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO; -+ frame_rec.buf = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE; -+ frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE; -+ frame_rec.timestamp.u64 = stream->timestamp.u64; -+ -+ status = stream->rec_cb(stream->user_data, &frame_rec); -+ if (status != PJ_SUCCESS) -+ { -+ PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status)); -+ } -+ -+ frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO; -+ frame_play.buf = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE; -+ frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME; -+ frame_play.timestamp.u64 = stream->timestamp.u64; -+ -+ status = (*stream->play_cb)(stream->user_data, &frame_play); -+ if (status != PJ_SUCCESS) -+ { -+ PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status)); -+ } -+ else -+ { -+ memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE); -+ -+ ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play)); -+ -+ if (ret < 0) { -+ PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!")); -+ return PJ_EUNKNOWN; -+ } -+ -+ if (ret == 0) { -+ PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!")); -+ return PJ_EUNKNOWN; -+ } -+ } -+ -+ stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME; -+ } -+ -+ return PJ_SUCCESS; -+} -+ -+/* TAPI capture and playback thread. */ -+static int PJ_THREAD_FUNC tapi_dev_thread(void *arg) -+{ -+ tapi_aud_stream_t *strm = (struct tapi_aud_stream*)arg; -+ tapi_ctx *dev_ctx = strm->dev_ctx; -+ fd_set rfds, trfds; -+ pj_uint32_t width = 0; -+ struct timeval tv; -+ pj_uint32_t sretval; -+ pj_uint32_t dev_idx; -+ -+ PJ_LOG(1,(THIS_FILE, "TAPI: thread starting...")); -+ -+ if (strm->param.rec_id != strm->param.play_id) { -+ PJ_LOG(1,(THIS_FILE, "TAPI: thread exit - incorrect play/rec IDs")); -+ return 0; -+ } -+ -+ dev_idx = strm->param.rec_id; -+ -+ FD_ZERO(&rfds); -+ -+ FD_SET(dev_ctx->dev_fd, &rfds); -+ width = FD_WIDTH_SET(dev_ctx->dev_fd, width); -+ -+ FD_SET(dev_ctx->ch_fd[dev_idx], &rfds); -+ width = FD_WIDTH_SET(dev_ctx->ch_fd[dev_idx], width); -+ -+ tv.tv_sec = TAPI_LL_DEV_SELECT_TIMEOUT_MS / 1000; -+ tv.tv_usec = (TAPI_LL_DEV_SELECT_TIMEOUT_MS % 1000) * 1000; -+ -+ strm->run_flag = 1; -+ -+ while(1) -+ { -+ /* Update the local file descriptor by the copy in the task parameter */ -+ memcpy((void *) &trfds, (void*) &rfds, sizeof(fd_set)); -+ -+ sretval = select(width + 1, &trfds, NULL, NULL, &tv); -+ -+ if (!strm->run_flag) { -+ break; -+ } -+ -+ /* error or timeout on select */ -+ if (sretval <= 0) { -+ continue; -+ } -+ -+ /* Check device control channel*/ -+ if (FD_ISSET(dev_ctx->dev_fd, &trfds)) { -+ if (tapi_dev_event_handler(strm) != PJ_SUCCESS) { -+ PJ_LOG(1,(THIS_FILE, "TAPI: event hanldler failed!")); -+ break; -+ } -+ } -+ -+ /* Check device data channel*/ -+ if (FD_ISSET(dev_ctx->ch_fd[dev_idx], &trfds)) { -+ if (tapi_dev_data_handler(strm) != PJ_SUCCESS) { -+ PJ_LOG(1,(THIS_FILE, "TAPI: data hanldler failed!")); -+ break; -+ } -+ } -+ } -+ -+ PJ_LOG(1,(THIS_FILE, "TAPI: thread stopping...")); -+ -+ return 0; -+} -+ -+/**************************************************************************** -+ Factory operations -+ ****************************************************************************/ -+ -+/* Init tapi audio driver. */ -+pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf) -+{ -+ struct tapi_aud_factory *f; -+ pj_pool_t *pool; -+ -+ TRACE_((THIS_FILE, "pjmedia_tapi_factory()")); -+ -+ pool = pj_pool_create(pf, "tapi", 512, 512, NULL); -+ f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory); -+ f->pf = pf; -+ f->pool = pool; -+ f->base.op = &tapi_fact_op; -+ -+ return &f->base; -+} -+ -+/* API: init factory */ -+static pj_status_t factory_init(pjmedia_aud_dev_factory *f) -+{ -+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; -+ pj_uint8_t c; -+ -+ TRACE_((THIS_FILE, "factory_init()")); -+ -+ /* Enumerate sound devices */ -+ af->dev_count = TAPI_AUDIO_DEV_NUM; -+ -+ af->dev_info = (pjmedia_aud_dev_info*) -+ pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info)); -+ -+ for (c = 0; c < af->dev_count; c++) { -+ pj_ansi_sprintf(af->dev_info[c].name,"%s_%02d", TAPI_BASE_NAME, c); -+ -+ af->dev_info[c].input_count = af->dev_info[c].output_count = 1; -+ af->dev_info[c].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC; -+ pj_ansi_strcpy(af->dev_info[c].driver, "/dev/vmmc"); -+ -+ af->dev_info[c].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING | -+ PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY | -+ PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY; -+ -+ af->dev_info[c].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ; -+ } -+ -+ /* Initialize TAPI device(s)*/ -+ if (tapi_dev_start(af) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - TAPI device init failed!")); -+ return PJ_EUNKNOWN; -+ } -+ -+ return PJ_SUCCESS; -+} -+ -+/* API: destroy factory */ -+static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f) -+{ -+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; -+ pj_pool_t *pool; -+ pj_status_t status = PJ_SUCCESS; -+ -+ TRACE_((THIS_FILE, "factory_destroy()")); -+ -+ /* Stop TAPI device*/ -+ if (tapi_dev_stop(f) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!")); -+ status = PJ_EUNKNOWN; -+ } -+ -+ pool = af->pool; -+ af->pool = NULL; -+ pj_pool_release(pool); -+ -+ return status; -+} -+ -+/* API: get number of devices */ -+static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f) -+{ -+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; -+ TRACE_((THIS_FILE, "factory_get_dev_count()")); -+ -+ return af->dev_count; -+} -+ -+/* API: get device info */ -+static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, -+ unsigned index, -+ pjmedia_aud_dev_info *info) -+{ -+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; -+ -+ TRACE_((THIS_FILE, "factory_get_dev_info()")); -+ PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV); -+ -+ pj_memcpy(info, &af->dev_info[index], sizeof(*info)); -+ -+ return PJ_SUCCESS; -+} -+ -+/* API: create default device parameter */ -+static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f, -+ unsigned index, -+ pjmedia_aud_param *param) -+{ -+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; -+ struct pjmedia_aud_dev_info *di = &af->dev_info[index]; -+ -+ TRACE_((THIS_FILE, "factory_default_param.")); -+ PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV); -+ -+ pj_bzero(param, sizeof(*param)); -+ if (di->input_count && di->output_count) { -+ param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; -+ param->rec_id = index; -+ param->play_id = index; -+ } else if (di->input_count) { -+ param->dir = PJMEDIA_DIR_CAPTURE; -+ param->rec_id = index; -+ param->play_id = PJMEDIA_AUD_INVALID_DEV; -+ } else if (di->output_count) { -+ param->dir = PJMEDIA_DIR_PLAYBACK; -+ param->play_id = index; -+ param->rec_id = PJMEDIA_AUD_INVALID_DEV; -+ } else { -+ return PJMEDIA_EAUD_INVDEV; -+ } -+ -+ param->clock_rate = di->default_samples_per_sec; -+ param->channel_count = 1; -+ param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME; -+ param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS; -+ param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps; -+ param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT; -+ -+ return PJ_SUCCESS; -+} -+ -+/* API: create stream */ -+static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f, -+ const pjmedia_aud_param *param, -+ pjmedia_aud_rec_cb rec_cb, -+ pjmedia_aud_play_cb play_cb, -+ void *user_data, -+ pjmedia_aud_stream **p_aud_strm) -+{ -+ struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; -+ pj_pool_t *pool; -+ struct tapi_aud_stream *strm; -+ pj_status_t status; -+ -+ TRACE_((THIS_FILE, "factory_create_stream()")); -+ -+ /* Can only support 16bits per sample */ -+ PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL); -+ -+ PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL); -+ -+ PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL); -+ -+ /* Can only support bidirectional stream */ -+ PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL); -+ -+ /* Initialize our stream data */ -+ pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL); -+ PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); -+ -+ strm = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_stream); -+ strm->pool = pool; -+ strm->rec_cb = rec_cb; -+ strm->play_cb = play_cb; -+ strm->user_data = user_data; -+ pj_memcpy(&strm->param, param, sizeof(*param)); -+ -+ if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) { -+ strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16; -+ } -+ -+ strm->timestamp.u64 = 0; -+ strm->dev_ctx = &(af->dev_ctx); -+ -+ /* Create and start the thread */ -+ status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, -+ &strm->thread); -+ if (status != PJ_SUCCESS) { -+ stream_destroy(&strm->base); -+ return status; -+ } -+ -+ /* Done */ -+ strm->base.op = &tapi_strm_op; -+ *p_aud_strm = &strm->base; -+ -+ return PJ_SUCCESS; -+} -+ -+/**************************************************************************** -+ * Stream operations -+ */ -+/* API: Get stream info. */ -+static pj_status_t stream_get_param(pjmedia_aud_stream *s, -+ pjmedia_aud_param *pi) -+{ -+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; -+ -+ PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL); -+ -+ pj_memcpy(pi, &strm->param, sizeof(*pi)); -+ /* Update the volume setting */ -+ if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, -+ &pi->output_vol) == PJ_SUCCESS) -+ { -+ pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING; -+ } -+ -+ if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY, -+ &pi->output_latency_ms) == PJ_SUCCESS) -+ { -+ pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY; -+ } -+ -+ if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY, -+ &pi->input_latency_ms) == PJ_SUCCESS) -+ { -+ pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY; -+ } -+ -+ return PJ_SUCCESS; -+} -+ -+/* API: get capability */ -+static pj_status_t stream_get_cap(pjmedia_aud_stream *s, -+ pjmedia_aud_dev_cap cap, -+ void *pval) -+{ -+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; -+#ifdef OLD_IMPL -+ OSStatus status = 0; -+ PJ_ASSERT_RETURN(strm && pval, PJ_EINVAL); -+ -+ if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING && strm->play_strm->queue) -+ { -+ Float32 vol; -+ status = AudioQueueGetParameter(strm->play_strm->queue, -+ kAudioQueueParam_Volume, &vol); -+ if (!status) -+ { -+ *(unsigned*)pval = (vol * 100); -+ return PJ_SUCCESS; -+ } -+ } -+ else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY && strm->play_strm->queue) -+ { -+ Float32 lat; -+ UInt32 size = sizeof(lat); -+ status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, -+ &size, &lat); -+ if (!status) -+ { -+ *(unsigned*)pval = lat * 1000; -+ return PJ_SUCCESS; -+ } -+ } -+ else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE && strm->play_strm->queue) -+ { -+ *(pjmedia_aud_dev_route*)pval = strm->param.output_route; -+ return PJ_SUCCESS; -+ } -+ else if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY && strm->rec_strm->queue) -+ { -+ Float32 lat; -+ UInt32 size = sizeof(lat); -+ status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency, -+ &size, &lat); -+ if (!status) -+ { -+ *(unsigned*)pval = lat * 1000; -+ return PJ_SUCCESS; -+ } -+ } -+ -+ if (status) -+ PJ_LOG(1, (THIS_FILE, "AudioQueueGetParameter/AudioSessionGetProperty err %d", status)); -+ return PJMEDIA_EAUD_INVCAP; -+#else -+ return PJ_SUCCESS; -+#endif -+} -+ -+/* API: set capability */ -+static pj_status_t stream_set_cap(pjmedia_aud_stream *s, -+ pjmedia_aud_dev_cap cap, -+ const void *pval) -+{ -+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; -+#ifdef OLD_IMPL -+ OSStatus status = 0; -+ PJ_ASSERT_RETURN(strm && pval, PJ_EINVAL); -+ -+ if (strm->play_strm->queue) -+ switch (cap) -+ { -+ case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING: -+ { -+ /* Output volume setting */ -+ unsigned vol = *(unsigned*)pval; -+ Float32 volume; -+ -+ if (vol > 100) -+ vol = 100; -+ volume = vol / 100.; -+ status = AudioQueueSetParameter(strm->play_strm->queue, kAudioQueueParam_Volume, -+ volume); -+ if (!status) -+ { -+ PJ_LOG(1, (THIS_FILE, "AudioQueueSetParameter err %d", status)); -+ return PJMEDIA_EAUD_SYSERR; -+ } -+ strm->param.output_vol = *(unsigned*)pval; -+ return PJ_SUCCESS; -+ } -+ case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE: -+ { -+ pjmedia_aud_dev_route r = *(const pjmedia_aud_dev_route*)pval; -+ UInt32 route = (r == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER ? -+ kAudioSessionOverrideAudioRoute_Speaker : -+ kAudioSessionOverrideAudioRoute_None); -+ -+ status = AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, -+ sizeof(route), &route); -+ if (status) -+ { -+ PJ_LOG(1, (THIS_FILE, "AudioSessionSetProperty err %d", status)); -+ return PJMEDIA_EAUD_SYSERR; -+ } -+ strm->param.output_route = r; -+ return PJ_SUCCESS; -+ } -+ default: -+ return PJMEDIA_EAUD_INVCAP; -+ } -+ -+ -+ return PJMEDIA_EAUD_INVCAP; -+#else -+ return PJ_SUCCESS; -+#endif -+} -+ -+/* API: Start stream. */ -+static pj_status_t stream_start(pjmedia_aud_stream *s) -+{ -+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; -+ tapi_ctx *dev_ctx = strm->dev_ctx; -+ pj_uint32_t dev_idx; -+ -+ TRACE_((THIS_FILE, "stream_start()")); -+ -+ dev_idx = strm->param.rec_id; -+ -+ return PJ_SUCCESS; -+} -+ -+/* API: Stop stream. */ -+static pj_status_t stream_stop(pjmedia_aud_stream *s) -+{ -+ struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; -+ tapi_ctx *dev_ctx = strm->dev_ctx; -+ pj_uint32_t dev_idx; -+ -+ TRACE_((THIS_FILE, "stream_stop()")); -+ -+ dev_idx = strm->param.rec_id; -+ -+ /* enc/dec stop*/ -+ if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) { -+ TRACE_((THIS_FILE, "ERROR - codec start failed!")); -+ -+ return PJ_EUNKNOWN; -+ } -+ -+ return PJ_SUCCESS; -+} -+ -+/* API: Destroy stream. */ -+static pj_status_t stream_destroy(pjmedia_aud_stream *s) -+{ -+ pj_status_t state = PJ_SUCCESS; -+ struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s; -+ pj_pool_t *pool; -+ -+ PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); -+ -+ TRACE_((THIS_FILE, "stream_destroy()")); -+ -+ stream_stop(stream); -+ -+ stream->run_flag = 0; -+ -+ /* Stop the stream thread */ -+ if (stream->thread) -+ { -+ pj_thread_join(stream->thread); -+ pj_thread_destroy(stream->thread); -+ stream->thread = NULL; -+ } -+ -+ pool = stream->pool; -+ pj_bzero(stream, sizeof(stream)); -+ pj_pool_release(pool); -+ -+ return state; -+} -+ -+#endif /* PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE */ diff --git a/package/pjsip/src/pjmedia/src/pjmedia-audiodev/tapi_dev.c b/package/pjsip/src/pjmedia/src/pjmedia-audiodev/tapi_dev.c new file mode 100644 index 0000000000..a367df30fd --- /dev/null +++ b/package/pjsip/src/pjmedia/src/pjmedia-audiodev/tapi_dev.c @@ -0,0 +1,1057 @@ +/****************************************************************************** + + Copyright (c) 2010 + Lantiq Deutschland GmbH + Am Campeon 3; 85579 Neubiberg, Germany + + For licensing information, see the file 'LICENSE' in the root folder of + this software module. + +******************************************************************************/ +#include <pjmedia-audiodev/audiodev_imp.h> +#include <pjmedia/errno.h> +#include <pj/assert.h> +#include <pj/pool.h> +#include <pj/log.h> +#include <pj/os.h> + +/* Linux includes*/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/select.h> +#include <sys/time.h> +#include <unistd.h> + +#if PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE + +/* TAPI includes*/ +#include "drv_tapi_io.h" +#include "vmmc_io.h" + +/* Maximum 2 devices*/ +#define TAPI_AUDIO_DEV_NUM (1) +#define TAPI_AUDIO_MAX_DEV_NUM (2) +#define TAPI_BASE_NAME "TAPI" +#define TAPI_LL_DEV_BASE_PATH "/dev/vmmc" +#define TAPI_LL_DEV_FIRMWARE_NAME "/lib/firmware/danube_firmware.bin" + +#define TAPI_LL_DEV_SELECT_TIMEOUT_MS (2000) +#define TAPI_LL_DEV_MAX_PACKET_SIZE (800) +#define TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE (12) +#define TAPI_LL_DEV_ENC_FRAME_LEN_MS (20) +#define TAPI_LL_DEV_ENC_SMPL_PER_SEC (8000) +#define TAPI_LL_DEV_ENC_BITS_PER_SMPLS (16) +#define TAPI_LL_DEV_ENC_SMPL_PER_FRAME (160) +#define TAPI_LL_DEV_ENC_BYTES_PER_FRAME (TAPI_LL_DEV_ENC_SMPL_PER_FRAME * (TAPI_LL_DEV_ENC_BITS_PER_SMPLS / 8)) + + +#define FD_WIDTH_SET(fd, maxfd) (maxfd) < (fd) ? (fd) : maxfd + +#define THIS_FILE "tapi_dev.c" + +#if 1 +# define TRACE_(x) PJ_LOG(1,x) +#else +# define TRACE_(x) +#endif + +typedef struct +{ + pj_int32_t dev_fd; + pj_int32_t ch_fd[TAPI_AUDIO_DEV_NUM]; + pj_int8_t data2phone_map[TAPI_AUDIO_DEV_NUM]; + +} tapi_ctx; + + +/* TAPI factory */ +struct tapi_aud_factory +{ + pjmedia_aud_dev_factory base; + pj_pool_t *pool; + pj_pool_factory *pf; + + pj_uint32_t dev_count; + pjmedia_aud_dev_info *dev_info; + + tapi_ctx dev_ctx; +}; + +typedef struct tapi_aud_factory tapi_aud_factory_t; + +/* + Sound stream descriptor. +**/ +struct tapi_aud_stream +{ + /* Base*/ + pjmedia_aud_stream base; /**< Base class. */ + /* Pool*/ + pj_pool_t *pool; /**< Memory pool. */ + /* Common settings.*/ + pjmedia_aud_param param; /**< Stream param. */ + pjmedia_aud_rec_cb rec_cb; /**< Record callback. */ + pjmedia_aud_play_cb play_cb; /**< Playback callback. */ + void *user_data; /**< Application data. */ + + pj_thread_desc thread_desc; + pj_thread_t *thread; + tapi_ctx *dev_ctx; + pj_uint8_t run_flag; + pj_timestamp timestamp; +}; + +typedef struct tapi_aud_stream tapi_aud_stream_t; + +/* Factory prototypes */ +static pj_status_t factory_init(pjmedia_aud_dev_factory *f); +static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f); +static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f); +static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, + unsigned index, + pjmedia_aud_dev_info *info); +static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f, + unsigned index, + pjmedia_aud_param *param); +static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f, + const pjmedia_aud_param *param, + pjmedia_aud_rec_cb rec_cb, + pjmedia_aud_play_cb play_cb, + void *user_data, + pjmedia_aud_stream **p_aud_strm); + +/* Stream prototypes */ +static pj_status_t stream_get_param(pjmedia_aud_stream *strm, + pjmedia_aud_param *param); +static pj_status_t stream_get_cap(pjmedia_aud_stream *strm, + pjmedia_aud_dev_cap cap, + void *value); +static pj_status_t stream_set_cap(pjmedia_aud_stream *strm, + pjmedia_aud_dev_cap cap, + const void *value); +static pj_status_t stream_start(pjmedia_aud_stream *strm); +static pj_status_t stream_stop(pjmedia_aud_stream *strm); +static pj_status_t stream_destroy(pjmedia_aud_stream *strm); + +static pjmedia_aud_dev_factory_op tapi_fact_op = + { + &factory_init, + &factory_destroy, + &factory_get_dev_count, + &factory_get_dev_info, + &factory_default_param, + &factory_create_stream + }; + +static pjmedia_aud_stream_op tapi_strm_op = +{ + &stream_get_param, + &stream_get_cap, + &stream_set_cap, + &stream_start, + &stream_stop, + &stream_destroy +}; + +void (*tapi_digit_callback)(unsigned char digit) = NULL; +void (*tapi_hook_callback)(unsigned char event) = NULL; + +static pj_int32_t tapi_dev_open(char* dev_path, const pj_int32_t ch_num) +{ + char devname[128] = {0}; + + pj_ansi_sprintf(devname,"%s%u%u", dev_path, 1, ch_num); + + return open((const char*)devname, O_RDWR, 0644); +} + +static pj_status_t tapi_dev_binary_buffer_create( + const char *pPath, + pj_uint8_t **ppBuf, + pj_uint32_t *pBufSz) +{ + pj_status_t status = PJ_SUCCESS; + FILE *fd; + struct stat file_stat; + + /* Open binary file for reading*/ + fd = fopen(pPath, "rb"); + if (fd == NULL) { + TRACE_((THIS_FILE, "ERROR - binary file %s open failed!\n", pPath)); + return PJ_EUNKNOWN; + } + + /* Get file statistics*/ + if (stat(pPath, &file_stat) != 0) { + TRACE_((THIS_FILE, "ERROR - file %s statistics get failed!\n", pPath)); + return PJ_EUNKNOWN; + } + + *ppBuf = malloc(file_stat.st_size); + if (*ppBuf == NULL) { + TRACE_((THIS_FILE, "ERROR - binary file %s memory allocation failed!\n", pPath)); + status = PJ_EUNKNOWN; + + goto on_exit; + } + + if (fread (*ppBuf, sizeof(pj_uint8_t), file_stat.st_size, fd) <= 0) { + TRACE_((THIS_FILE, "ERROR - file %s read failed!\n", pPath)); + status = PJ_EUNKNOWN; + + goto on_exit; + } + + *pBufSz = file_stat.st_size; + +on_exit: + if (fd != NULL) { + fclose(fd); + } + + if (*ppBuf != NULL && status != PJ_SUCCESS) { + free(*ppBuf); + } + + return status; +} + +static void tapi_dev_binary_buffer_delete(pj_uint8_t *pBuf) +{ + if (pBuf != NULL) + free(pBuf); +} + +static pj_status_t tapi_dev_firmware_download( + pj_int32_t fd, + const char *pPath) +{ + pj_status_t status = PJ_SUCCESS; + pj_uint8_t *pFirmware = NULL; + pj_uint32_t binSz = 0; + VMMC_IO_INIT vmmc_io_init; + + /* Create binary buffer*/ + status = tapi_dev_binary_buffer_create(pPath, &pFirmware, &binSz); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - binary buffer create failed!\n")); + + return PJ_EUNKNOWN; + } + + /* Download Voice Firmware*/ + memset(&vmmc_io_init, 0, sizeof(VMMC_IO_INIT)); + vmmc_io_init.pPRAMfw = pFirmware; + vmmc_io_init.pram_size = binSz; + + status = ioctl(fd, FIO_FW_DOWNLOAD, &vmmc_io_init); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - FIO_FW_DOWNLOAD ioctl failed!")); + } + + /* Delete binary buffer*/ + tapi_dev_binary_buffer_delete(pFirmware); + + return status; +} + + +static pj_status_t tapi_dev_start(tapi_aud_factory_t *f) +{ + pj_status_t status = PJ_SUCCESS; + pj_uint8_t c; + IFX_TAPI_DEV_START_CFG_t tapistart; + IFX_TAPI_MAP_DATA_t datamap; + IFX_TAPI_ENC_CFG_t enc_cfg; + IFX_TAPI_LINE_VOLUME_t vol; + + /* Open device*/ + f->dev_ctx.dev_fd = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, 0); + + if (f->dev_ctx.dev_fd < 0) { + TRACE_((THIS_FILE, "ERROR - TAPI device open failed!")); + return PJ_EUNKNOWN; + } + + for (c = 0; c < TAPI_AUDIO_DEV_NUM; c++) { + f->dev_ctx.ch_fd[c] = tapi_dev_open(TAPI_LL_DEV_BASE_PATH, TAPI_AUDIO_MAX_DEV_NUM - c); + + if (f->dev_ctx.dev_fd < 0) { + TRACE_((THIS_FILE, "ERROR - TAPI channel%d open failed!", c)); + return PJ_EUNKNOWN; + } + + f->dev_ctx.data2phone_map[c] = c & 0x1 ? 0 : 1; + } + + status = tapi_dev_firmware_download(f->dev_ctx.dev_fd, TAPI_LL_DEV_FIRMWARE_NAME); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - Voice Firmware Download failed!")); + return PJ_EUNKNOWN; + } + + memset(&tapistart, 0x0, sizeof(IFX_TAPI_DEV_START_CFG_t)); + tapistart.nMode = IFX_TAPI_INIT_MODE_VOICE_CODER; + + /* Start TAPI*/ + status = ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_START, &tapistart); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_START ioctl failed")); + return PJ_EUNKNOWN; + } + + + for (c = 0; c < TAPI_AUDIO_DEV_NUM; c++) { + /* Perform mapping*/ + memset(&datamap, 0x0, sizeof(IFX_TAPI_MAP_DATA_t)); + datamap.nDstCh = f->dev_ctx.data2phone_map[c]; + datamap.nChType = IFX_TAPI_MAP_TYPE_PHONE; + + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_MAP_DATA_ADD, &datamap); + + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_MAP_DATA_ADD ioctl failed")); + return PJ_EUNKNOWN; + } + + /* Set Line feed*/ + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_LINE_FEED_SET, IFX_TAPI_LINE_FEED_STANDBY); + + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed")); + return PJ_EUNKNOWN; + } + + /* Config encoder for linear stream*/ + memset(&enc_cfg, 0x0, sizeof(IFX_TAPI_ENC_CFG_t)); + + enc_cfg.nFrameLen = IFX_TAPI_COD_LENGTH_20; + enc_cfg.nEncType = IFX_TAPI_COD_TYPE_LIN16_8; + + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_ENC_CFG_SET, &enc_cfg); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_CFG_SET ioctl failed")); + return PJ_EUNKNOWN; + } + + + /* Suppress TAPI volume, otherwise PJSIP starts autogeneration!!!*/ + vol.nGainRx = -8; + vol.nGainTx = -8; + + status = ioctl(f->dev_ctx.ch_fd[c], IFX_TAPI_PHONE_VOLUME_SET, &vol); + if (status != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_PHONE_VOLUME_SET ioctl failed")); + return PJ_EUNKNOWN; + } + } + + + return status; +} + +static pj_status_t tapi_dev_stop(tapi_aud_factory_t *f) +{ + pj_status_t status = PJ_SUCCESS; + pj_uint8_t c; + + /* Stop TAPI device*/ + if (ioctl(f->dev_ctx.dev_fd, IFX_TAPI_DEV_STOP, 0) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEV_STOP ioctl failed")); + status = PJ_EUNKNOWN; + } + + /* Close device FD*/ + close(f->dev_ctx.dev_fd); + + /* Close channel FD*/ + for (c = TAPI_AUDIO_DEV_NUM; c > 0; c--) { + close(f->dev_ctx.ch_fd[TAPI_AUDIO_DEV_NUM-c]); + } + + + return status; +} + +static pj_status_t tapi_dev_codec_control(pj_int32_t fd, pj_uint8_t start) +{ + if (ioctl(fd, start ? IFX_TAPI_ENC_START : IFX_TAPI_ENC_STOP, 0) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_ENC_%s ioctl failed!", + start ? "START" : "STOP")); + + return PJ_EUNKNOWN; + } + + if (ioctl(fd, start ? IFX_TAPI_DEC_START : IFX_TAPI_DEC_STOP, 0) != IFX_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_DEC_%s ioctl failed!", + start ? "START" : "STOP")); + + return PJ_EUNKNOWN; + } + + return PJ_SUCCESS; +} + +static pj_status_t tapi_dev_event_ONHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx) +{ + PJ_LOG(1,(THIS_FILE, "TAPI: ONHOOK")); + + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET, + IFX_TAPI_LINE_FEED_STANDBY) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!")); + + return PJ_EUNKNOWN; + } + + /* enc/dec stop*/ + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - codec start failed!")); + + return PJ_EUNKNOWN; + } + + return PJ_SUCCESS; +} + +static pj_status_t tapi_dev_event_OFFHOOK(tapi_ctx *dev_ctx, pj_uint32_t dev_idx) +{ + PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK")); + + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET, + IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!")); + + return PJ_EUNKNOWN; + } + + /* enc/dec stop*/ + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - codec start failed!")); + + return PJ_EUNKNOWN; + } + + return PJ_SUCCESS; +} + +static pj_status_t tapi_dev_event_digit(tapi_ctx *dev_ctx, pj_uint32_t dev_idx) +{ + PJ_LOG(1,(THIS_FILE, "TAPI: OFFHOOK")); + + if (ioctl(dev_ctx->ch_fd[dev_idx], IFX_TAPI_LINE_FEED_SET, + IFX_TAPI_LINE_FEED_ACTIVE) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - IFX_TAPI_LINE_FEED_SET ioctl failed!")); + + return PJ_EUNKNOWN; + } + + /* enc/dec stop*/ + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 1) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - codec start failed!")); + + return PJ_EUNKNOWN; + } + + return PJ_SUCCESS; +} + +static pj_status_t tapi_dev_event_handler( + tapi_aud_stream_t *stream) +{ + tapi_ctx *dev_ctx = stream->dev_ctx; + pj_uint32_t dev_idx = stream->param.rec_id; + pj_status_t status = PJ_SUCCESS; + IFX_TAPI_EVENT_t tapiEvent; + + memset (&tapiEvent, 0, sizeof(tapiEvent)); + + tapiEvent.ch = dev_ctx->data2phone_map[dev_idx]; + + /* Get event*/ + status = ioctl(dev_ctx->dev_fd, IFX_TAPI_EVENT_GET, &tapiEvent); + + if ((status == PJ_SUCCESS) && (tapiEvent.id != IFX_TAPI_EVENT_NONE)) { + switch(tapiEvent.id) { + case IFX_TAPI_EVENT_FXS_ONHOOK: + status = tapi_dev_event_ONHOOK(dev_ctx, dev_idx); + if(tapi_hook_callback) + tapi_hook_callback(0); + break; + case IFX_TAPI_EVENT_FXS_OFFHOOK: + status = tapi_dev_event_OFFHOOK(dev_ctx, dev_idx); + if(tapi_hook_callback) + tapi_hook_callback(1); + break; + case IFX_TAPI_EVENT_DTMF_DIGIT: + if(tapi_digit_callback) + tapi_digit_callback(tapiEvent.data.dtmf.ascii); + break; + default: + printf("%s:%s[%d]%04X\n", __FILE__, __func__, __LINE__, tapiEvent.id); + break; + } + } + + return status; +} + +static pj_status_t tapi_dev_data_handler( + tapi_aud_stream_t *stream) +{ + pj_status_t status = PJ_SUCCESS; + tapi_ctx *dev_ctx = stream->dev_ctx; + pj_uint32_t dev_idx = stream->param.rec_id; + pj_uint8_t buf_rec[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0}; + pj_uint8_t buf_play[TAPI_LL_DEV_ENC_BYTES_PER_FRAME + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE]={0}; + pjmedia_frame frame_rec, frame_play; + pj_int32_t ret; + + /* Get data from driver*/ + ret = read(dev_ctx->ch_fd[dev_idx], buf_rec, sizeof(buf_rec)); + if (ret < 0) { + TRACE_((THIS_FILE, "ERROR - no data available from device!")); + + return PJ_EUNKNOWN; + } + + if (ret > 0) { + frame_rec.type = PJMEDIA_FRAME_TYPE_AUDIO; + frame_rec.buf = buf_rec + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE; + frame_rec.size = ret - TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE; + frame_rec.timestamp.u64 = stream->timestamp.u64; + + status = stream->rec_cb(stream->user_data, &frame_rec); + if (status != PJ_SUCCESS) + { + PJ_LOG(1, (THIS_FILE, "rec_cb() failed %d", status)); + } + + frame_play.type = PJMEDIA_FRAME_TYPE_AUDIO; + frame_play.buf = buf_play + TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE; + frame_play.size = TAPI_LL_DEV_ENC_BYTES_PER_FRAME; + frame_play.timestamp.u64 = stream->timestamp.u64; + + status = (*stream->play_cb)(stream->user_data, &frame_play); + if (status != PJ_SUCCESS) + { + PJ_LOG(1, (THIS_FILE, "play_cb() failed %d", status)); + } + else + { + memcpy(buf_play, buf_rec, TAPI_LL_DEV_RTP_HEADER_SIZE_BYTE); + + ret = write(dev_ctx->ch_fd[dev_idx], buf_play, sizeof(buf_play)); + + if (ret < 0) { + PJ_LOG(1, (THIS_FILE, "ERROR - device data writing failed!")); + return PJ_EUNKNOWN; + } + + if (ret == 0) { + PJ_LOG(1, (THIS_FILE, "ERROR - no data written to device!")); + return PJ_EUNKNOWN; + } + } + + stream->timestamp.u64 += TAPI_LL_DEV_ENC_SMPL_PER_FRAME; + } + + return PJ_SUCCESS; +} + +/* TAPI capture and playback thread. */ +static int PJ_THREAD_FUNC tapi_dev_thread(void *arg) +{ + tapi_aud_stream_t *strm = (struct tapi_aud_stream*)arg; + tapi_ctx *dev_ctx = strm->dev_ctx; + fd_set rfds, trfds; + pj_uint32_t width = 0; + struct timeval tv; + pj_uint32_t sretval; + pj_uint32_t dev_idx; + + PJ_LOG(1,(THIS_FILE, "TAPI: thread starting...")); + + if (strm->param.rec_id != strm->param.play_id) { + PJ_LOG(1,(THIS_FILE, "TAPI: thread exit - incorrect play/rec IDs")); + return 0; + } + + dev_idx = strm->param.rec_id; + + FD_ZERO(&rfds); + + FD_SET(dev_ctx->dev_fd, &rfds); + width = FD_WIDTH_SET(dev_ctx->dev_fd, width); + + FD_SET(dev_ctx->ch_fd[dev_idx], &rfds); + width = FD_WIDTH_SET(dev_ctx->ch_fd[dev_idx], width); + + tv.tv_sec = TAPI_LL_DEV_SELECT_TIMEOUT_MS / 1000; + tv.tv_usec = (TAPI_LL_DEV_SELECT_TIMEOUT_MS % 1000) * 1000; + + strm->run_flag = 1; + + while(1) + { + /* Update the local file descriptor by the copy in the task parameter */ + memcpy((void *) &trfds, (void*) &rfds, sizeof(fd_set)); + + sretval = select(width + 1, &trfds, NULL, NULL, &tv); + + if (!strm->run_flag) { + break; + } + + /* error or timeout on select */ + if (sretval <= 0) { + continue; + } + + /* Check device control channel*/ + if (FD_ISSET(dev_ctx->dev_fd, &trfds)) { + if (tapi_dev_event_handler(strm) != PJ_SUCCESS) { + PJ_LOG(1,(THIS_FILE, "TAPI: event hanldler failed!")); + break; + } + } + + /* Check device data channel*/ + if (FD_ISSET(dev_ctx->ch_fd[dev_idx], &trfds)) { + if (tapi_dev_data_handler(strm) != PJ_SUCCESS) { + PJ_LOG(1,(THIS_FILE, "TAPI: data hanldler failed!")); + break; + } + } + } + + PJ_LOG(1,(THIS_FILE, "TAPI: thread stopping...")); + + return 0; +} + +/**************************************************************************** + Factory operations + ****************************************************************************/ + +/* Init tapi audio driver. */ +pjmedia_aud_dev_factory* pjmedia_tapi_factory(pj_pool_factory *pf) +{ + struct tapi_aud_factory *f; + pj_pool_t *pool; + + TRACE_((THIS_FILE, "pjmedia_tapi_factory()")); + + pool = pj_pool_create(pf, "tapi", 512, 512, NULL); + f = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_factory); + f->pf = pf; + f->pool = pool; + f->base.op = &tapi_fact_op; + + return &f->base; +} + +/* API: init factory */ +static pj_status_t factory_init(pjmedia_aud_dev_factory *f) +{ + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; + pj_uint8_t c; + + TRACE_((THIS_FILE, "factory_init()")); + + /* Enumerate sound devices */ + af->dev_count = TAPI_AUDIO_DEV_NUM; + + af->dev_info = (pjmedia_aud_dev_info*) + pj_pool_calloc(af->pool, af->dev_count, sizeof(pjmedia_aud_dev_info)); + + for (c = 0; c < af->dev_count; c++) { + pj_ansi_sprintf(af->dev_info[c].name,"%s_%02d", TAPI_BASE_NAME, c); + + af->dev_info[c].input_count = af->dev_info[c].output_count = 1; + af->dev_info[c].default_samples_per_sec = TAPI_LL_DEV_ENC_SMPL_PER_SEC; + pj_ansi_strcpy(af->dev_info[c].driver, "/dev/vmmc"); + + af->dev_info[c].caps = PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING | + PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY | + PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY; + + af->dev_info[c].routes = PJMEDIA_AUD_DEV_ROUTE_DEFAULT ; + } + + /* Initialize TAPI device(s)*/ + if (tapi_dev_start(af) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - TAPI device init failed!")); + return PJ_EUNKNOWN; + } + + return PJ_SUCCESS; +} + +/* API: destroy factory */ +static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f) +{ + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; + pj_pool_t *pool; + pj_status_t status = PJ_SUCCESS; + + TRACE_((THIS_FILE, "factory_destroy()")); + + /* Stop TAPI device*/ + if (tapi_dev_stop(f) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - TAPI device stop failed!")); + status = PJ_EUNKNOWN; + } + + pool = af->pool; + af->pool = NULL; + pj_pool_release(pool); + + return status; +} + +/* API: get number of devices */ +static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f) +{ + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; + TRACE_((THIS_FILE, "factory_get_dev_count()")); + + return af->dev_count; +} + +/* API: get device info */ +static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f, + unsigned index, + pjmedia_aud_dev_info *info) +{ + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; + + TRACE_((THIS_FILE, "factory_get_dev_info()")); + PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV); + + pj_memcpy(info, &af->dev_info[index], sizeof(*info)); + + return PJ_SUCCESS; +} + +/* API: create default device parameter */ +static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f, + unsigned index, + pjmedia_aud_param *param) +{ + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; + struct pjmedia_aud_dev_info *di = &af->dev_info[index]; + + TRACE_((THIS_FILE, "factory_default_param.")); + PJ_ASSERT_RETURN(index < af->dev_count, PJMEDIA_EAUD_INVDEV); + + pj_bzero(param, sizeof(*param)); + if (di->input_count && di->output_count) { + param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK; + param->rec_id = index; + param->play_id = index; + } else if (di->input_count) { + param->dir = PJMEDIA_DIR_CAPTURE; + param->rec_id = index; + param->play_id = PJMEDIA_AUD_INVALID_DEV; + } else if (di->output_count) { + param->dir = PJMEDIA_DIR_PLAYBACK; + param->play_id = index; + param->rec_id = PJMEDIA_AUD_INVALID_DEV; + } else { + return PJMEDIA_EAUD_INVDEV; + } + + param->clock_rate = TAPI_LL_DEV_ENC_SMPL_PER_SEC; //di->default_samples_per_sec; + param->channel_count = 1; + param->samples_per_frame = TAPI_LL_DEV_ENC_SMPL_PER_FRAME; + param->bits_per_sample = TAPI_LL_DEV_ENC_BITS_PER_SMPLS; + param->flags = PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE | di->caps; + param->output_route = PJMEDIA_AUD_DEV_ROUTE_DEFAULT; + + return PJ_SUCCESS; +} + +/* API: create stream */ +static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f, + const pjmedia_aud_param *param, + pjmedia_aud_rec_cb rec_cb, + pjmedia_aud_play_cb play_cb, + void *user_data, + pjmedia_aud_stream **p_aud_strm) +{ + struct tapi_aud_factory *af = (struct tapi_aud_factory*)f; + pj_pool_t *pool; + struct tapi_aud_stream *strm; + pj_status_t status; + + TRACE_((THIS_FILE, "factory_create_stream()")); + + /* Can only support 16bits per sample */ + PJ_ASSERT_RETURN(param->bits_per_sample == TAPI_LL_DEV_ENC_BITS_PER_SMPLS, PJ_EINVAL); + printf("param->clock_rate = %d, samples_per_frame = %d\n", param->clock_rate, param->samples_per_frame); + PJ_ASSERT_RETURN(param->clock_rate == TAPI_LL_DEV_ENC_SMPL_PER_SEC, PJ_EINVAL); + + PJ_ASSERT_RETURN(param->samples_per_frame == TAPI_LL_DEV_ENC_SMPL_PER_FRAME, PJ_EINVAL); + + /* Can only support bidirectional stream */ + PJ_ASSERT_RETURN(param->dir & PJMEDIA_DIR_CAPTURE_PLAYBACK, PJ_EINVAL); + + /* Initialize our stream data */ + pool = pj_pool_create(af->pf, "tapi-dev", 1000, 1000, NULL); + PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM); + + strm = PJ_POOL_ZALLOC_T(pool, struct tapi_aud_stream); + strm->pool = pool; + strm->rec_cb = rec_cb; + strm->play_cb = play_cb; + strm->user_data = user_data; + pj_memcpy(&strm->param, param, sizeof(*param)); + + if ((strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) == 0) { + strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16; + } + + strm->timestamp.u64 = 0; + strm->dev_ctx = &(af->dev_ctx); + + /* Create and start the thread */ + status = pj_thread_create(pool, "tapi", &tapi_dev_thread, strm, 0, 0, + &strm->thread); + if (status != PJ_SUCCESS) { + stream_destroy(&strm->base); + return status; + } + + /* Done */ + strm->base.op = &tapi_strm_op; + *p_aud_strm = &strm->base; + + return PJ_SUCCESS; +} + +/**************************************************************************** + * Stream operations + */ +/* API: Get stream info. */ +static pj_status_t stream_get_param(pjmedia_aud_stream *s, + pjmedia_aud_param *pi) +{ + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; + + PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL); + + pj_memcpy(pi, &strm->param, sizeof(*pi)); + /* Update the volume setting */ + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING, + &pi->output_vol) == PJ_SUCCESS) + { + pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING; + } + + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY, + &pi->output_latency_ms) == PJ_SUCCESS) + { + pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY; + } + + if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY, + &pi->input_latency_ms) == PJ_SUCCESS) + { + pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY; + } + + return PJ_SUCCESS; +} + +/* API: get capability */ +static pj_status_t stream_get_cap(pjmedia_aud_stream *s, + pjmedia_aud_dev_cap cap, + void *pval) +{ + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; +#ifdef OLD_IMPL + OSStatus status = 0; + PJ_ASSERT_RETURN(strm && pval, PJ_EINVAL); + + if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING && strm->play_strm->queue) + { + Float32 vol; + status = AudioQueueGetParameter(strm->play_strm->queue, + kAudioQueueParam_Volume, &vol); + if (!status) + { + *(unsigned*)pval = (vol * 100); + return PJ_SUCCESS; + } + } + else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY && strm->play_strm->queue) + { + Float32 lat; + UInt32 size = sizeof(lat); + status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputLatency, + &size, &lat); + if (!status) + { + *(unsigned*)pval = lat * 1000; + return PJ_SUCCESS; + } + } + else if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE && strm->play_strm->queue) + { + *(pjmedia_aud_dev_route*)pval = strm->param.output_route; + return PJ_SUCCESS; + } + else if (cap==PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY && strm->rec_strm->queue) + { + Float32 lat; + UInt32 size = sizeof(lat); + status = AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputLatency, + &size, &lat); + if (!status) + { + *(unsigned*)pval = lat * 1000; + return PJ_SUCCESS; + } + } + + if (status) + PJ_LOG(1, (THIS_FILE, "AudioQueueGetParameter/AudioSessionGetProperty err %d", status)); + return PJMEDIA_EAUD_INVCAP; +#else + return PJ_SUCCESS; +#endif +} + +/* API: set capability */ +static pj_status_t stream_set_cap(pjmedia_aud_stream *s, + pjmedia_aud_dev_cap cap, + const void *pval) +{ + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; +#ifdef OLD_IMPL + OSStatus status = 0; + PJ_ASSERT_RETURN(strm && pval, PJ_EINVAL); + + if (strm->play_strm->queue) + switch (cap) + { + case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING: + { + /* Output volume setting */ + unsigned vol = *(unsigned*)pval; + Float32 volume; + + if (vol > 100) + vol = 100; + volume = vol / 100.; + status = AudioQueueSetParameter(strm->play_strm->queue, kAudioQueueParam_Volume, + volume); + if (!status) + { + PJ_LOG(1, (THIS_FILE, "AudioQueueSetParameter err %d", status)); + return PJMEDIA_EAUD_SYSERR; + } + strm->param.output_vol = *(unsigned*)pval; + return PJ_SUCCESS; + } + case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE: + { + pjmedia_aud_dev_route r = *(const pjmedia_aud_dev_route*)pval; + UInt32 route = (r == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER ? + kAudioSessionOverrideAudioRoute_Speaker : + kAudioSessionOverrideAudioRoute_None); + + status = AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute, + sizeof(route), &route); + if (status) + { + PJ_LOG(1, (THIS_FILE, "AudioSessionSetProperty err %d", status)); + return PJMEDIA_EAUD_SYSERR; + } + strm->param.output_route = r; + return PJ_SUCCESS; + } + default: + return PJMEDIA_EAUD_INVCAP; + } + + + return PJMEDIA_EAUD_INVCAP; +#else + return PJ_SUCCESS; +#endif +} + +/* API: Start stream. */ +static pj_status_t stream_start(pjmedia_aud_stream *s) +{ + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; + tapi_ctx *dev_ctx = strm->dev_ctx; + pj_uint32_t dev_idx; + + TRACE_((THIS_FILE, "stream_start()")); + + dev_idx = strm->param.rec_id; + + return PJ_SUCCESS; +} + +/* API: Stop stream. */ +static pj_status_t stream_stop(pjmedia_aud_stream *s) +{ + struct tapi_aud_stream *strm = (struct tapi_aud_stream*)s; + tapi_ctx *dev_ctx = strm->dev_ctx; + pj_uint32_t dev_idx; + + TRACE_((THIS_FILE, "stream_stop()")); + + dev_idx = strm->param.rec_id; + + /* enc/dec stop*/ + if (tapi_dev_codec_control(dev_ctx->ch_fd[dev_idx], 0) != PJ_SUCCESS) { + TRACE_((THIS_FILE, "ERROR - codec start failed!")); + + return PJ_EUNKNOWN; + } + + return PJ_SUCCESS; +} + +/* API: Destroy stream. */ +static pj_status_t stream_destroy(pjmedia_aud_stream *s) +{ + pj_status_t state = PJ_SUCCESS; + struct tapi_aud_stream *stream = (struct tapi_aud_stream*)s; + pj_pool_t *pool; + + PJ_ASSERT_RETURN(stream != NULL, PJ_EINVAL); + + TRACE_((THIS_FILE, "stream_destroy()")); + + stream_stop(stream); + + stream->run_flag = 0; + + /* Stop the stream thread */ + if (stream->thread) + { + pj_thread_join(stream->thread); + pj_thread_destroy(stream->thread); + stream->thread = NULL; + } + + pool = stream->pool; + pj_bzero(stream, sizeof(stream)); + pj_pool_release(pool); + + return state; +} + +#endif /* PJMEDIA_AUDIO_DEV_HAS_TAPI_DEVICE */ diff --git a/package/tapi_sip/Makefile b/package/tapi_sip/Makefile deleted file mode 100644 index 7a3d6766ac..0000000000 --- a/package/tapi_sip/Makefile +++ /dev/null @@ -1,41 +0,0 @@ -# -# This is free software, licensed under the GNU General Public License v2. -# See /LICENSE for more information. -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=tapi_sip -PKG_RELEASE:=1 - -include $(INCLUDE_DIR)/package.mk - -define Package/tapi_sip - SECTION:=utils - CATEGORY:=Utilities - TITLE:=tapi_sip - DEPENDS:=+libuci +libtapi +pjsip +kmod-lqtapi -endef - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) - $(CP) ./src/* $(PKG_BUILD_DIR)/ -endef - -define Build/Compile - CFLAGS="$(TARGET_CPPFLAGS) $(TARGET_CFLAGS)" \ - LDFLAGS="$(TARGET_LDFLAGS)" \ - $(MAKE) -C $(PKG_BUILD_DIR) \ - $(TARGET_CONFIGURE_OPTS) -endef - -define Package/tapi_sip/install - $(INSTALL_DIR) $(1)/usr/bin - $(INSTALL_BIN) $(PKG_BUILD_DIR)/tapi-sip $(1)/usr/bin/ - - $(INSTALL_DIR) $(1)/etc/config $(1)/etc/init.d - $(INSTALL_DATA) ./files/telephony.conf $(1)/etc/config/telephony - $(INSTALL_BIN) ./files/telephony.init $(1)/etc/init.d/telephony -endef - -$(eval $(call BuildPackage,tapi_sip)) diff --git a/package/tapi_sip/files/telephony.conf b/package/tapi_sip/files/telephony.conf deleted file mode 100644 index 6d87f45a88..0000000000 --- a/package/tapi_sip/files/telephony.conf +++ /dev/null @@ -1,28 +0,0 @@ -config 'config' 'config' -# option 'fw_url' 'http://192.168.1.100/danube_firmware.bin' - option 'fw_file' 'danube_firmware.bin' - option 'netdev' 'pppoe-wan' - option 'disable' '1' - -config 'account' 'account' - option 'realm' 'example.com' - option 'username' 'user' - option 'password' 'password' - option 'stun_host' 'stun.example.com' - option 'stun_port' '3478' - option 'sip_port' '5600' - -config 'contact' - option 'name' 'sip example' - option 'identifier' 'sip:user@example.net' - option 'number' '123' - -config 'contact' - option 'name' 'local1' - option 'identifier' 'tel:1' - option 'number' '01' - -config 'contact' - option 'name' 'local2' - option 'identifier' 'tel:2' - option 'number' '02' diff --git a/package/tapi_sip/files/telephony.init b/package/tapi_sip/files/telephony.init deleted file mode 100755 index 082024c236..0000000000 --- a/package/tapi_sip/files/telephony.init +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/sh /etc/rc.common -START=80 - -download_fw() -{ - config_load telephony - config_get fw_url config fw_url - config_get fw_file config fw_file - wget $fw_url -O /tmp/$fw_file || { - echo "failed to load $fw_url" - exit 1 - } -} - -load_module() -{ - M=`lsmod | grep vmmc` - [ -z "$M" ] || return - config_load telephony - config_get fw_file config fw_file - [ -z "fw_file" ] && exit 1 - F=/lib/firmware/$fw_file - [ ! -f "$F" -a ! -L "$F" ] && { - echo "missing firmware file" - exit 1 - } - [ -L "$F" -a -f /tmp/$fw_file ] && F=/tmp/$fw_file - insmod vmmc - sleep 3 -} - -stop() -{ - killall tapi-sip 2>/dev/null -} - -start() -{ - stop - config_load telephony - config_get fw_url config fw_url - config_get fw_file config fw_file - config_get netdev config netdev - config_get disable config disable - [ "$disable" != "1" ] && { - [ ! -z "$fw_url" -a ! -f "/tmp/$fw_file" ] && download_fw - load_module - /usr/bin/tapi-sip $netdev & - } -} diff --git a/package/tapi_sip/src/Makefile b/package/tapi_sip/src/Makefile deleted file mode 100644 index 56013700fe..0000000000 --- a/package/tapi_sip/src/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -ifndef CFLAGS -CFLAGS = -O2 -g -I ../src -endif - -CFLAGS += -Werror -Wall -std=gnu99 - -PJ_CFLAGS ?= `pkg-config libpjproject --cflags` -PJ_LDFLAGS ?= `pkg-config libpjproject --libs` - -CFLAGS += $(PJ_CFLAGS) -LDFLAGS += $(PJ_LDFLAGS) - -FPIC=-fPIC - -all: tapi-sip - -%.o: %.c - $(CC) -c -o $@ $^ $(CFLAGS) - -tapi-sip: contact.o session.o tapi_agent.o tapi_sip.o sip_client.o stun.o dialdetector.o - $(CC) -o $@ $^ -ltapi -luci $(LDFLAGS) diff --git a/package/tapi_sip/src/agent.h b/package/tapi_sip/src/agent.h deleted file mode 100644 index 795994178e..0000000000 --- a/package/tapi_sip/src/agent.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __AGENT_H__ -#define __AGENT_H__ - -#include "agent.h" - -struct session; -struct agent; - -struct agent_ops { - int (*invite)(struct agent *, struct session *); - int (*accept)(struct agent *, struct session *); - int (*hangup)(struct agent *, struct session *); - - int (*get_endpoint)(struct agent *, struct session *); -}; - -struct agent { - const struct agent_ops *ops; -}; - -static inline int agent_invite(struct agent *agent, struct session *session) -{ - return agent->ops->invite(agent, session); -} - -static inline int agent_accept(struct agent *agent, struct session *session) -{ - return agent->ops->accept(agent, session); -} - -static inline int agent_hangup(struct agent *agent, struct session *session) -{ - return agent->ops->hangup(agent, session); -} - -static inline int agent_get_endpoint(struct agent *agent, struct session *session) -{ - return agent->ops->get_endpoint(agent, session); -} - -#endif diff --git a/package/tapi_sip/src/contact.c b/package/tapi_sip/src/contact.c deleted file mode 100644 index eeb38b4181..0000000000 --- a/package/tapi_sip/src/contact.c +++ /dev/null @@ -1,162 +0,0 @@ -#include <malloc.h> -#include <string.h> - -#include <uci.h> -#include <ucimap.h> - -#include "list.h" -#include "contact.h" - -static struct uci_context *ctx; -static struct uci_package *pkg; -static struct list_head contact_list; -static struct list_head account_list; - -static int contact_init(struct uci_map *map, void *section, - struct uci_section *s) -{ - struct contact *p = section; - p->name = strdup(s->e.name); - return 0; -} - -static int contact_add(struct uci_map *map, void *section) -{ - struct contact *c = section; - printf("add contact: %s\n", c->name); - list_add_tail(&c->head, &contact_list); - return 0; -} - -static struct uci_optmap contact_uci_map[] = { - { - UCIMAP_OPTION(struct contact, identifier), - .type = UCIMAP_STRING, - .name = "identifier", - }, - { - UCIMAP_OPTION(struct contact, number), - .type = UCIMAP_STRING, - .name = "number", - }, -}; - -static struct uci_sectionmap contact_sectionmap = { - UCIMAP_SECTION(struct contact, map), - .type = "contact", - .init = contact_init, - .add = contact_add, - .options = contact_uci_map, - .n_options = ARRAY_SIZE(contact_uci_map), - .options_size = sizeof(struct uci_optmap), -}; - -static int account_init(struct uci_map *map, void *section, - struct uci_section *s) -{ - struct account *a = section; - a->name = strdup(s->e.name); - return 0; -} - -static int account_add(struct uci_map *map, void *section) -{ - struct account *a = section; - list_add_tail(&a->head, &account_list); - return 0; -} - -static struct uci_optmap account_uci_map[] = { - { - UCIMAP_OPTION(struct account, realm), - .type = UCIMAP_STRING, - .name = "realm", - }, - { - UCIMAP_OPTION(struct account, username), - .type = UCIMAP_STRING, - .name = "username", - }, - { - UCIMAP_OPTION(struct account, sip_port), - .type = UCIMAP_INT, - .name = "sip_port", - }, - { - UCIMAP_OPTION(struct account, password), - .type = UCIMAP_STRING, - .name = "password", - }, - { - UCIMAP_OPTION(struct account, stun_host), - .type = UCIMAP_STRING, - .name = "stun_host", - }, - { - UCIMAP_OPTION(struct account, stun_port), - .type = UCIMAP_INT, - .name = "stun_port", - }, -}; - -static struct uci_sectionmap account_sectionmap = { - UCIMAP_SECTION(struct account, map), - .type = "account", - .init = account_init, - .add = account_add, - .options = account_uci_map, - .n_options = ARRAY_SIZE(account_uci_map), - .options_size = sizeof(struct uci_optmap), -}; - -static struct uci_sectionmap *network_smap[] = { - &contact_sectionmap, - &account_sectionmap, -}; - -static struct uci_map contact_map = { - .sections = network_smap, - .n_sections = ARRAY_SIZE(network_smap), -}; - -int contacts_init(void) -{ - int ret; - - INIT_LIST_HEAD(&contact_list); - INIT_LIST_HEAD(&account_list); - ctx = uci_alloc_context(); - - ucimap_init(&contact_map); - ret = uci_load(ctx, "telephony", &pkg); - if (ret) - return ret; - - ucimap_parse(&contact_map, pkg); - - return 0; -} - -void contacts_free(void) -{ -} - -struct contact *contact_get(const char *number) -{ - struct contact *contact; - list_for_each_entry(contact, &contact_list, head) - { - if (strcmp(contact->number, number) == 0) - return contact; - } - - return NULL; -} - -struct account *get_account(void) -{ - if (list_empty(&account_list)) - return NULL; - - return list_first_entry(&account_list, struct account, head); -} diff --git a/package/tapi_sip/src/contact.h b/package/tapi_sip/src/contact.h deleted file mode 100644 index 1fb0037bf6..0000000000 --- a/package/tapi_sip/src/contact.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __CONTACT_H__ -#define __CONTACT_H__ - -#include <ucimap.h> - -struct account { - struct ucimap_section_data map; - const char *name; - char *realm; - char *username; - char *password; - int sip_port; - char *stun_host; - int stun_port; - struct list_head head; -}; - -struct contact { - struct ucimap_section_data map; - const char *name; - const char *identifier; - const char *number; - - struct list_head head; -}; - -int contacts_init(void); -void contacts_free(void); -struct contact *contact_get(const char *number); - -struct account *get_account(void); - -#endif diff --git a/package/tapi_sip/src/dialdetector.c b/package/tapi_sip/src/dialdetector.c deleted file mode 100644 index 277b0296c6..0000000000 --- a/package/tapi_sip/src/dialdetector.c +++ /dev/null @@ -1,148 +0,0 @@ -#include <linux/input.h> -#include <sys/epoll.h> -#include <stdint.h> -#include <stdbool.h> - - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#include <events.h> -#include "timerfd.h" - -#include "tapi-port.h" -#include "dialdetector.h" - -static const struct itimerspec dialdetector_timeout = { - .it_value.tv_sec = 3, -}; - -static const struct itimerspec dialdetector_impulse_timeout = { - .it_value.tv_nsec = 200000000, -}; - -static void dialdetector_note_digit(struct dialdetector *d, unsigned char digit) -{ - printf("note digit: %d\n", d->num_digits); - - d->digits[d->num_digits] = digit; - ++d->num_digits; - - timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); - d->dial_state = DIALDETECTOR_DIAL_WAIT_TIMEOUT; -} - -static void dialdetector_reset(struct dialdetector *d) -{ - d->num_digits = 0; - d->impulses = 0; - d->dial_state = DIALDETECTOR_DIAL_WAIT; - d->port_state = DIALDETECTOR_PORT_INACTIVE; -} - -static bool dialdetector_timeout_event(int events, void *data) -{ - char num[20]; - struct dialdetector *dialdetector = data; - int i; - uint64_t tmp; - - read(dialdetector->timer_fd, &tmp, sizeof(tmp)); - - for (i = 0; i < dialdetector->num_digits; ++i) { - num[i] = '0' + dialdetector->digits[i]; - } - num[i] = '\0'; - - dialdetector->dial_callback(dialdetector->port, dialdetector->num_digits, - dialdetector->digits); - - dialdetector_reset(dialdetector); - - return true; -} - -static bool dialdetector_impulse_timeout_cb(int events, void *data) -{ - struct dialdetector *d = data; - uint64_t tmp; - - read(d->impulse_timer_fd, &tmp, sizeof(tmp)); - - if (d->port_state == DIALDETECTOR_PORT_ACTIVE_DOWN) { - d->port_state = DIALDETECTOR_PORT_INACTIVE; - } else { - printf("impulse: %d\n", d->impulses); - if (d->impulses > 0) - dialdetector_note_digit(d, d->impulses < 10 ? d->impulses : 0); - d->impulses = 0; - } - - return true; -} - -static void dialdetector_port_event(struct tapi_port *port, - struct tapi_event *event, void *data) -{ - struct dialdetector *d = data; - - printf("port event: %d %d\n", d->port_state, event->hook.on); - - switch (d->port_state) { - case DIALDETECTOR_PORT_INACTIVE: - if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) - d->port_state = DIALDETECTOR_PORT_ACTIVE; - break; - case DIALDETECTOR_PORT_ACTIVE: - switch (event->type) { - case TAPI_EVENT_TYPE_HOOK: - if (event->hook.on == true) { - d->port_state = DIALDETECTOR_PORT_ACTIVE_DOWN; - timerfd_settime(d->impulse_timer_fd, 0, &dialdetector_impulse_timeout, NULL); - } - break; - case TAPI_EVENT_TYPE_DTMF: - dialdetector_note_digit(d, event->dtmf.code); - break; - } - break; - case DIALDETECTOR_PORT_ACTIVE_DOWN: - if (event->type == TAPI_EVENT_TYPE_HOOK && event->hook.on == false) { - timerfd_settime(d->timer_fd, 0, &dialdetector_timeout, NULL); - ++d->impulses; - d->port_state = DIALDETECTOR_PORT_ACTIVE; - } - break; - } -} - -struct dialdetector *dialdetector_alloc(struct tapi_port *port) -{ - struct dialdetector *dialdetector; - dialdetector = malloc(sizeof(*dialdetector)); - - dialdetector->timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); - dialdetector->impulse_timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); - dialdetector->port = port; - dialdetector->num_digits = 0; - dialdetector->impulses = 0; - dialdetector->dial_state = DIALDETECTOR_DIAL_WAIT; - dialdetector->port_state = DIALDETECTOR_PORT_INACTIVE; - - dialdetector->timeout_cb.callback = dialdetector_timeout_event; - dialdetector->timeout_cb.data = dialdetector; - dialdetector->impulse_cb.callback = dialdetector_impulse_timeout_cb; - dialdetector->impulse_cb.data = dialdetector; - - dialdetector->port_listener.callback = dialdetector_port_event; - dialdetector->port_listener.data = dialdetector; - - tapi_port_register_event(port, &dialdetector->port_listener); - - event_register(dialdetector->impulse_timer_fd, EPOLLIN, - &dialdetector->impulse_cb); - event_register(dialdetector->timer_fd, EPOLLIN, &dialdetector->timeout_cb); - - return dialdetector; -} diff --git a/package/tapi_sip/src/dialdetector.h b/package/tapi_sip/src/dialdetector.h deleted file mode 100644 index c3737c36e9..0000000000 --- a/package/tapi_sip/src/dialdetector.h +++ /dev/null @@ -1,49 +0,0 @@ -#include <linux/input.h> -#include <sys/epoll.h> -#include <stdint.h> -#include <stdbool.h> - - -#include <stdlib.h> -#include <stdio.h> - -#include "events.h" -#include "timerfd.h" - -#include "tapi-port.h" - -enum dialdetector_dial_state { - DIALDETECTOR_DIAL_WAIT = 1, - DIALDETECTOR_DIAL_WAIT_TIMEOUT = 2, -}; - -enum dialdetector_port_state { - DIALDETECTOR_PORT_INACTIVE = 0, - DIALDETECTOR_PORT_ACTIVE = 1, - DIALDETECTOR_PORT_ACTIVE_DOWN = 2, -}; - -struct dialdetector { - enum dialdetector_dial_state dial_state; - enum dialdetector_port_state port_state; - - struct tapi_port *port; - int timer_fd; - int impulse_timer_fd; - - struct event_callback timeout_cb; - struct event_callback impulse_cb; - struct tapi_port_event_listener port_listener; - - size_t num_digits; - unsigned char digits[20]; - - unsigned int impulses; - - void (*dial_callback)(struct tapi_port *port, size_t num_digits, const unsigned char *digits); -}; - - -struct tapi_port; - -struct dialdetector *dialdetector_alloc(struct tapi_port *port); diff --git a/package/tapi_sip/src/list.h b/package/tapi_sip/src/list.h deleted file mode 100644 index 2959a061d3..0000000000 --- a/package/tapi_sip/src/list.h +++ /dev/null @@ -1,601 +0,0 @@ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#include <stddef.h> -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#ifndef container_of -#define container_of(ptr, type, member) ( \ - (type *)( (char *)ptr - offsetof(type,member) )) -#endif - - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - prev->next = next; -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = NULL; - entry->prev = NULL; -} - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del(list->prev, list->next); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -static inline void __list_splice(struct list_head *list, - struct list_head *head) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - struct list_head *at = head->next; - - first->prev = head; - head->next = first; - - last->next = at; - at->prev = last; -} - -/** - * list_splice - join two lists - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(struct list_head *list, struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_struct within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); \ - pos = pos->next) - -/** - * __list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - * - * This variant differs from list_for_each() in that it's the - * simplest possible list iteration code, no prefetching is done. - * Use this for code that knows the list to be very short (empty - * or 1 entry) most of the time. - */ -#define __list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); \ - pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_struct within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.prev, typeof(*pos), member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_continue - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_entry(pos->member.next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_from - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_for_each_entry_safe_reverse - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_entry((head)->prev, typeof(*pos), member), \ - n = list_entry(pos->member.prev, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.prev, typeof(*n), member)) - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - *pprev = next; - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = NULL; - n->pprev = NULL; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - h->first = n; - n->pprev = &h->first; -} - - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - *(n->pprev) = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *next) -{ - next->next = n->next; - n->next = next; - next->pprev = &n->next; - - if(next->next) - next->next->pprev = &next->next; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos; pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos; pos = n) - -/** - * hlist_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; pos && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(tpos, pos, member) \ - for (pos = (pos)->next; pos && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(tpos, pos, member) \ - for (; pos && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/package/tapi_sip/src/session.c b/package/tapi_sip/src/session.c deleted file mode 100644 index 97f6f06fe1..0000000000 --- a/package/tapi_sip/src/session.c +++ /dev/null @@ -1,84 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> - -#include "agent.h" -#include "session.h" - -#include <tapi-device.h> - - -struct session -{ - struct agent *agents[2]; - - struct tapi_device *tdev; - - void (*release)(struct session *); - - int link; -}; - -struct session *session_alloc(struct tapi_device *dev, struct agent *caller, - struct agent *callee, void (*release)(struct session *)) -{ - struct session *session; - int ret; - - session = malloc(sizeof(*session)); - - session->tdev = dev; - - session->agents[0] = caller; - session->agents[1] = callee; - - ret = agent_invite(callee, session); - if (ret < 0) { - session_hangup(session, callee); - free(session); - return NULL; - } - - session->release = release; - - return session; -} - -void session_accept(struct session *session, struct agent *agent) -{ - int ep[2]; - - printf("session_accept: %p %p\n", session, agent); - printf("session agents: %p %p\n", session->agents[0], session->agents[1]); - printf("session tdev: %p\n", session->tdev); - - agent_accept(session->agents[0], session); - - ep[0] = agent_get_endpoint(session->agents[0], session); - ep[1] = agent_get_endpoint(session->agents[1], session); - session->link = tapi_link_alloc(session->tdev, ep[0], ep[1]); - - printf("eps: %d %d\n", ep[0], ep[1]); - - tapi_link_enable(session->tdev, session->link); - - tapi_sync(session->tdev); -} - -void session_hangup(struct session *session, struct agent *agent) -{ - struct agent *other_agent; - - if (session->agents[0] == agent) - other_agent = session->agents[1]; - else - other_agent = session->agents[0]; - - agent_hangup(other_agent, session); - - tapi_link_disable(session->tdev, session->link); - tapi_link_free(session->tdev, session->link); - tapi_sync(session->tdev); - - if (session->release) - session->release(session); -} diff --git a/package/tapi_sip/src/session.h b/package/tapi_sip/src/session.h deleted file mode 100644 index 7403785f5f..0000000000 --- a/package/tapi_sip/src/session.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __SESSION_H__ -#define __SESSION_H__ - -struct agent; -struct session; -struct tapi_device; - -struct session *session_alloc(struct tapi_device *, struct agent *caller, - struct agent *callee, void (*release)(struct session *)); -void session_hangup(struct session *, struct agent *); -void session_accept(struct session *, struct agent *); -void session_free(struct session *); - -#endif diff --git a/package/tapi_sip/src/sip_agent.h b/package/tapi_sip/src/sip_agent.h deleted file mode 100644 index 7f711da437..0000000000 --- a/package/tapi_sip/src/sip_agent.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __SIP_AGENT_H__ -#define __SIP_AGENT_H__ - -#include "agent.h" -#include <events.h> - -struct sip_agent { - struct sip_client *client; - const char *identifier; - - struct tapi_stream *stream; - struct session *session; - - struct pjsip_inv_session *inv; - - int rtp_sockfd; - - struct sockaddr_storage remote_addr; - struct sockaddr_storage local_addr; - - struct agent agent; - - struct event_callback rtp_recv_callback; - struct event_callback stream_recv_callback; -}; - -#endif diff --git a/package/tapi_sip/src/sip_client.c b/package/tapi_sip/src/sip_client.c deleted file mode 100644 index 0b1e2ddd8f..0000000000 --- a/package/tapi_sip/src/sip_client.c +++ /dev/null @@ -1,800 +0,0 @@ -#include "sip_client.h" - -#include <stdint.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <netdb.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <errno.h> -#include <sys/epoll.h> -#include <stdbool.h> -#include <unistd.h> -#include <fcntl.h> -#include <net/if.h> -#include <sys/ioctl.h> - -#include "stun.h" -#include "sip_agent.h" -#include "session.h" -#include "list.h" - -static inline struct sip_agent *agent_to_sip_agent(struct agent *agent) -{ - return container_of(agent, struct sip_agent, agent); -} - -static int iface_get_addr(const char *iface, struct sockaddr_storage *addr) -{ - int fd; - int ret; - struct ifreq ifr; - - fd = socket(AF_INET, SOCK_DGRAM, 0); - - ifr.ifr_addr.sa_family = AF_INET; - strncpy(ifr.ifr_name, iface, IFNAMSIZ-1); - ret = ioctl(fd, SIOCGIFADDR, &ifr); - if (ret < 0) - perror("Failed to get interface address"); - - close(fd); - - if (ret == 0) - memcpy(addr, &ifr.ifr_addr, sizeof(ifr.ifr_addr)); - - return ret; -} - -#if 0 -static bool sockaddr_is_local(struct sockaddr_storage *addr) -{ - unsigned long s_addr; - bool is_local = false; - - switch (addr->ss_family) { - case AF_INET: - s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - if ((s_addr & 0xff000000) == 0x10000000) - is_local = true; - else if ((s_addr & 0xfff00000) == 0xac100000) - is_local = true; - else if ((s_addr & 0xffff0000) == 0xc0a80000) - is_local = true; - break; - default: - break; - } - - return is_local; -} -#endif - -static uint16_t sockaddr_get_port(struct sockaddr_storage *addr) -{ - uint16_t port; - - switch (addr->ss_family) { - case AF_INET: - port = ((struct sockaddr_in *)addr)->sin_port; - break; - case AF_INET6: - port = ((struct sockaddr_in6 *)addr)->sin6_port; - break; - default: - port = 0; - break; - } - - return port; -} - -static void sockaddr_set_port(struct sockaddr_storage *addr, uint16_t port) -{ - switch (addr->ss_family) { - case AF_INET: - ((struct sockaddr_in *)addr)->sin_port = port; - break; - case AF_INET6: - ((struct sockaddr_in6 *)addr)->sin6_port = port; - break; - default: - break; - } -} - -static void *sockaddr_get_addr(struct sockaddr_storage *addr) -{ - void *a; - switch (addr->ss_family) { - case AF_INET: - a = &((struct sockaddr_in *)addr)->sin_addr.s_addr; - break; - case AF_INET6: - a = ((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr; - break; - default: - a = NULL; - break; - } - - return a; -} - -static int sockaddr_to_string(struct sockaddr_storage *addr, char *s, size_t n) -{ - return inet_ntop(addr->ss_family, sockaddr_get_addr(addr), s, n) == NULL ? -1 : 0; -} - -static pjsip_module mod_siprtp; -static struct sip_client *global_client; - -/* Creates a datagram socket and binds it to a port in the range of - * start_port-end_port */ -static int sip_client_create_socket(struct sip_client *client, - struct sockaddr_storage *sockaddr, uint16_t start_port, - uint16_t end_port) -{ - int sockfd; - int ret; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); - if (sockfd < 0) - return sockfd; - - memcpy(sockaddr, &client->local_addr, sizeof(client->local_addr)); - do { - sockaddr_set_port(sockaddr, start_port); - ret = bind(sockfd, (struct sockaddr *)sockaddr, sizeof(*sockaddr)); - ++start_port; - } while (ret == -1 && start_port < end_port); - - if (ret == -1) - return -1; - - return sockfd; -} - -static int sip_worker_thread(void *arg) -{ - struct sip_client *client = arg; - - while (1) { - pj_time_val timeout = {0, 10}; - pjsip_endpt_handle_events(client->sip_endpt, &timeout); - } - - return 0; -} - -static bool sip_agent_stream_recv_callback(int events, void *data) -{ - struct sip_agent *agent = data; - char buf[512]; - int len; - int ret; - - len = read(agent->stream->fd, buf, 512); - if (len < 0) - return true; - - ret = sendto(agent->rtp_sockfd, buf, len, 0, - (struct sockaddr *)&agent->remote_addr, sizeof(agent->remote_addr)); - - if (ret < 0) - printf("failed to send rtp data: %d\n", errno); - - return true; -} - - -static bool sip_agent_rtp_recv_callback(int events, void *data) -{ - struct sip_agent *agent = data; - char buf[512]; - int len; - - len = recvfrom(agent->rtp_sockfd, buf, 512, 0, NULL, NULL); - if (agent->stream) - write(agent->stream->fd, buf, len); - - return true; -} - -static pj_status_t sip_client_create_sdp(struct sip_client *client, pj_pool_t *pool, - struct sip_agent *agent, - pjmedia_sdp_session **p_sdp) -{ - pj_time_val tv; - pjmedia_sdp_session *sdp; - pjmedia_sdp_media *m; - pjmedia_sdp_attr *attr; - struct sockaddr_storage rtp_addr; - char addr[INET6_ADDRSTRLEN]; - - PJ_ASSERT_RETURN(pool && p_sdp, PJ_EINVAL); - - agent->rtp_sockfd = sip_client_create_socket(client, &rtp_addr, 4000, 5000); - if (client->stun) - stun_client_resolve(client->stun, agent->rtp_sockfd, - (struct sockaddr *)&rtp_addr); - - agent->rtp_recv_callback.callback = sip_agent_rtp_recv_callback; - agent->rtp_recv_callback.data = agent; - event_register(agent->rtp_sockfd, EPOLLIN, &agent->rtp_recv_callback); - - /* Create and initialize basic SDP session */ - sdp = pj_pool_zalloc (pool, sizeof(pjmedia_sdp_session)); - - pj_gettimeofday(&tv); - sdp->origin.user = pj_str("pjsip-siprtp"); - sdp->origin.version = sdp->origin.id = tv.sec + 2208988800UL; - sdp->origin.net_type = pj_str("IN"); - sdp->origin.addr_type = pj_str("IP4"); - sdp->origin.addr = *pj_gethostname(); - sdp->name = pj_str("pjsip"); - - /* Since we only support one media stream at present, put the - * SDP connection line in the session level. - */ - sdp->conn = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_conn)); - sdp->conn->net_type = pj_str("IN"); - sdp->conn->addr_type = pj_str("IP4"); - sockaddr_to_string(&rtp_addr, addr, sizeof(addr)); - pj_strdup2_with_null(pool, &sdp->conn->addr, addr); - - /* SDP time and attributes. */ - sdp->time.start = sdp->time.stop = 0; - sdp->attr_count = 0; - - /* Create media stream 0: */ - - sdp->media_count = 1; - m = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_media)); - sdp->media[0] = m; - - /* Standard media info: */ - m->desc.media = pj_str("audio"); - m->desc.port = sockaddr_get_port(&rtp_addr); - m->desc.port_count = 1; - m->desc.transport = pj_str("RTP/AVP"); - - /* Add format and rtpmap for each codec. */ - m->desc.fmt_count = 1; - m->attr_count = 0; - - { - pjmedia_sdp_rtpmap rtpmap; - char ptstr[10]; - - sprintf(ptstr, "%d", 0); - pj_strdup2_with_null(pool, &m->desc.fmt[0], ptstr); - rtpmap.pt = m->desc.fmt[0]; - rtpmap.clock_rate = 64000; - rtpmap.enc_name = pj_str("PCMU"); - rtpmap.param.slen = 0; - - } - - /* Add sendrecv attribute. */ - attr = pj_pool_zalloc(pool, sizeof(pjmedia_sdp_attr)); - attr->name = pj_str("sendrecv"); - m->attr[m->attr_count++] = attr; - - /* Done */ - *p_sdp = sdp; - - return PJ_SUCCESS; -} - -static int sip_agent_invite(struct agent *agent, struct session *session) -{ - struct sip_agent *sip_agent = agent_to_sip_agent(agent); - struct sip_client *client = sip_agent->client; - pjsip_dialog *dlg; - pjmedia_sdp_session *sdp; - pjsip_tx_data *tdata; - pj_status_t status; - pj_str_t dst_uri; - - sip_agent->session = session; - - dst_uri = pj_str((char *)sip_agent->identifier); - - /* Create UAC dialog */ - status = pjsip_dlg_create_uac(pjsip_ua_instance(), - &client->local_contact, /* local URI */ - &client->local_contact, /* local Contact */ - &dst_uri, /* remote URI */ - &dst_uri, /* remote target */ - &dlg); /* dialog */ - if (status != PJ_SUCCESS) { - fprintf(stderr, "Failed to create uac dialog\n"); - return -1; - } - - pjsip_auth_clt_set_credentials(&dlg->auth_sess, 1, &client->cred); - - /* Create SDP */ - sip_client_create_sdp(client, dlg->pool, sip_agent, &sdp); - - /* Create the INVITE session. */ - status = pjsip_inv_create_uac(dlg, sdp, 0, &sip_agent->inv); - if (status != PJ_SUCCESS) { - fprintf(stderr, "Failed to create invite session\n"); - pjsip_dlg_terminate(dlg); - return -1; - } - - - /* Attach call data to invite session */ - sip_agent->inv->mod_data[mod_siprtp.id] = sip_agent; - - /* Create initial INVITE request. - * This INVITE request will contain a perfectly good request and - * an SDP body as well. - */ - status = pjsip_inv_invite(sip_agent->inv, &tdata); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, -1); /*TODO*/ - - /* Send initial INVITE request. - * From now on, the invite session's state will be reported to us - * via the invite session callbacks. - */ - status = pjsip_inv_send_msg(sip_agent->inv, tdata); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, -1); /*TODO*/ - - return 0; -} - -static int sip_agent_hangup(struct agent *agent, struct session *session) -{ - struct sip_agent *sip_agent = agent_to_sip_agent(agent); - pjsip_tx_data *tdata; - pj_status_t status; - - printf("hangup %p\n", sip_agent->inv); - - status = pjsip_inv_end_session(sip_agent->inv, 603, NULL, &tdata); - if (status == PJ_SUCCESS && tdata != NULL) - pjsip_inv_send_msg(sip_agent->inv, tdata); - - if (sip_agent->rtp_sockfd) { - event_unregister(sip_agent->rtp_sockfd); - close(sip_agent->rtp_sockfd); - } - if (sip_agent->stream) { - event_unregister(sip_agent->stream->fd); - tapi_stream_free(sip_agent->stream); - } - - sip_agent->inv->mod_data[mod_siprtp.id] = NULL; - free(sip_agent); - - return 0; -} - -static int sip_agent_alloc_stream(struct sip_agent *agent) -{ - int flags; - - if (agent->stream) - printf("BUG!!!! %s:%s[%d]\n", __FILE__, __func__, __LINE__); - - agent->stream = tapi_stream_alloc(agent->client->tdev); - agent->stream_recv_callback.callback = sip_agent_stream_recv_callback; - agent->stream_recv_callback.data = agent; - - flags = fcntl(agent->stream->fd, F_GETFL, 0); - fcntl(agent->stream->fd, F_SETFL, flags | O_NONBLOCK); - - event_register(agent->stream->fd, EPOLLIN, &agent->stream_recv_callback); - - return 0; -} - -static void sip_agent_free_stream(struct sip_agent *agent) -{ - if (!agent->stream) - return; - - event_unregister(agent->stream->fd); - tapi_stream_free(agent->stream); - agent->stream = NULL; -} - -static int sip_agent_accept(struct agent *agent, struct session *session) -{ - struct sip_agent *sip_agent = agent_to_sip_agent(agent); - pj_status_t status; - pjsip_tx_data *tdata; - - /* Create 200 response .*/ - status = pjsip_inv_answer(sip_agent->inv, 200, - NULL, NULL, &tdata); - if (status != PJ_SUCCESS) { - status = pjsip_inv_answer(sip_agent->inv, - PJSIP_SC_NOT_ACCEPTABLE, - NULL, NULL, &tdata); - if (status == PJ_SUCCESS) - pjsip_inv_send_msg(sip_agent->inv, tdata); - else - pjsip_inv_terminate(sip_agent->inv, 500, PJ_FALSE); - return -1; - } - - /* Send the 200 response. */ - status = pjsip_inv_send_msg(sip_agent->inv, tdata); - PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return -1); - - sip_agent_alloc_stream(sip_agent); - - return 0; -} - -static int sip_agent_get_endpoint(struct agent *agent, struct session *session) -{ - struct sip_agent *sip_agent = agent_to_sip_agent(agent); - return tapi_stream_get_endpoint(sip_agent->stream); -} - -static const struct agent_ops sip_agent_ops = { - .invite = sip_agent_invite, - .accept = sip_agent_accept, - .hangup = sip_agent_hangup, - .get_endpoint = sip_agent_get_endpoint, -}; - -struct sip_agent *sip_client_alloc_agent(struct sip_client *client, - const char *identifier) -{ - struct sip_agent *agent; - - agent = malloc(sizeof(*agent)); - memset(agent, 0, sizeof(*agent)); - - agent->agent.ops = &sip_agent_ops; - agent->identifier = identifier; - agent->client = client; - - return agent; -} - -/* - * Receive incoming call - */ -static void process_incoming_call(struct sip_client *client, pjsip_rx_data *rdata) -{ - unsigned options; - struct sip_agent *agent; - pjsip_tx_data *tdata; - pj_status_t status; - pjsip_dialog *dlg; - pjmedia_sdp_session *sdp; - - agent = sip_client_alloc_agent(client, "extern"); - - /* Verify that we can handle the request. */ - options = 0; - status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, - client->sip_endpt, &tdata); - if (status != PJ_SUCCESS) { - /* - * No we can't handle the incoming INVITE request. - */ - if (tdata) { - pjsip_response_addr res_addr; - pjsip_get_response_addr(tdata->pool, rdata, &res_addr); - pjsip_endpt_send_response(client->sip_endpt, &res_addr, tdata, - NULL, NULL); - } else { - /* Respond with 500 (Internal Server Error) */ - pjsip_endpt_respond_stateless(client->sip_endpt, rdata, 500, NULL, - NULL, NULL); - } - - return; - } - - /* Create UAS dialog */ - status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, - &client->local_contact, &dlg); - if (status != PJ_SUCCESS) { - const pj_str_t reason = pj_str("Unable to create dialog"); - pjsip_endpt_respond_stateless(client->sip_endpt, rdata, - 500, &reason, - NULL, NULL); - return; - } - - /* Create SDP */ - sip_client_create_sdp(client, dlg->pool, agent, &sdp); - - /* Create UAS invite session */ - status = pjsip_inv_create_uas(dlg, rdata, sdp, 0, &agent->inv); - if (status != PJ_SUCCESS) { - pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata); - pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); - return; - } - - /* Attach call data to invite session */ - agent->inv->mod_data[mod_siprtp.id] = agent; - - /* Create 180 response .*/ - status = pjsip_inv_initial_answer(agent->inv, rdata, 180, - NULL, NULL, &tdata); - if (status != PJ_SUCCESS) { - status = pjsip_inv_initial_answer(agent->inv, rdata, - PJSIP_SC_NOT_ACCEPTABLE, - NULL, NULL, &tdata); - if (status == PJ_SUCCESS) - pjsip_inv_send_msg(agent->inv, tdata); - else - pjsip_inv_terminate(agent->inv, 500, PJ_FALSE); - return; - } - - /* Send the 180 response. */ - status = pjsip_inv_send_msg(agent->inv, tdata); - PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return); - - if (client->incoming_call_cb) - client->incoming_call_cb(client, agent); -} - -/* Callback to be called to handle incoming requests outside dialogs: */ -static pj_bool_t on_rx_request(pjsip_rx_data *rdata) -{ - struct sip_client *client = global_client; - - /* Ignore strandled ACKs (must not send respone */ - if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) - return PJ_FALSE; - - /* Respond (statelessly) any non-INVITE requests with 500 */ - if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { - pj_str_t reason = pj_str("Unsupported Operation"); - pjsip_endpt_respond_stateless(client->sip_endpt, rdata, - 500, &reason, - NULL, NULL); - return PJ_TRUE; - } - - /* Handle incoming INVITE */ - process_incoming_call(client, rdata); - - /* Done */ - return PJ_TRUE; -} - -static pjsip_module sip_client_mod = { - NULL, NULL, /* prev, next. */ - { "mod-tapisip", 13 }, /* Name. */ - -1, /* Id */ - PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */ - NULL, /* load() */ - NULL, /* start() */ - NULL, /* stop() */ - NULL, /* unload() */ - &on_rx_request, /* on_rx_request() */ - NULL, /* on_rx_response() */ - NULL, /* on_tx_request. */ - NULL, /* on_tx_response() */ - NULL, /* on_tsx_state() */ -}; - -/* Callback to be called when dialog has forked: */ -static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e) -{ - PJ_UNUSED_ARG(inv); - PJ_UNUSED_ARG(e); -} - -/* Callback to be called when invite session's state has changed: */ -static void call_on_state_changed(pjsip_inv_session *inv, pjsip_event *e) -{ - struct sip_agent *agent = inv->mod_data[mod_siprtp.id]; - - printf("state changed: %d\n", inv->state); - - if (!agent) - return; - - switch (inv->state) { - case PJSIP_INV_STATE_DISCONNECTED: - printf("Disconnected\n"); - if (agent->session) - session_hangup(agent->session, &agent->agent); - if (agent->rtp_sockfd) { - event_unregister(agent->rtp_sockfd); - close(agent->rtp_sockfd); - } - sip_agent_free_stream(agent); - free(agent); - inv->mod_data[mod_siprtp.id] = NULL; - break; - case PJSIP_INV_STATE_CONFIRMED: - printf("Connected: %p\n", agent->stream); - if (agent->stream) - break; - sip_agent_alloc_stream(agent); - session_accept(agent->session, &agent->agent); - break; - default: - break; - } -} - -static void call_on_media_update(pjsip_inv_session *inv, pj_status_t status) -{ - struct sip_agent *agent; - pj_pool_t *pool; - const pjmedia_sdp_session *local_sdp, *remote_sdp; - char local[100]; - char remote[100]; - int i; - - printf("media updte\n"); - - agent = inv->mod_data[mod_siprtp.id]; - pool = inv->dlg->pool; - - /* Do nothing if media negotiation has failed */ - if (status != PJ_SUCCESS) - return; - /* Capture stream definition from the SDP */ - pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp); - pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp); - - strlcpy(local, local_sdp->conn->addr.ptr, local_sdp->conn->addr.slen + 1); - printf("local media count: %d\n", local_sdp->media_count); - printf("local: %s %d\n", local, - ntohs(local_sdp->media[0]->desc.port)); - strlcpy(remote, remote_sdp->conn->addr.ptr, remote_sdp->conn->addr.slen + 1); - printf("remote media count: %d\n", remote_sdp->media_count); - printf("remote: %s %d\n", remote, - ntohs(remote_sdp->media[0]->desc.port)); - - agent->remote_addr.ss_family = AF_INET; - inet_pton(AF_INET, remote, - sockaddr_get_addr(&agent->remote_addr)); - sockaddr_set_port(&agent->remote_addr, remote_sdp->media[0]->desc.port); - - printf("attributes: %d\n", remote_sdp->attr_count); - for (i = 0; i < remote_sdp->attr_count; ++i) - printf("%s: %s\n", remote_sdp->attr[i]->name.ptr, - remote_sdp->attr[i]->value.ptr); - -} - -static int sip_client_init_sip_endpoint(struct sip_client *client) -{ - pj_status_t status; - pjsip_host_port addrname; - pjsip_inv_callback inv_cb; - pjsip_transport *tp; - char public_addr[INET6_ADDRSTRLEN]; - - global_client = client; - - pj_caching_pool_init(&client->cp, &pj_pool_factory_default_policy, 0); - client->pool = pj_pool_create(&client->cp.factory, "tapi sip", 1000, 1000, NULL); - - status = pjsip_endpt_create(&client->cp.factory, NULL, - &client->sip_endpt); - - client->sockfd = sip_client_create_socket(client, &client->public_addr, 5060, 5100); - if (client->stun) - stun_client_resolve(client->stun, client->sockfd, (struct sockaddr *)&client->public_addr); - - sockaddr_to_string(&client->public_addr, public_addr, sizeof(public_addr)); - - addrname.host = pj_str(public_addr); - addrname.port = sockaddr_get_port(&client->public_addr); - - pjsip_udp_transport_attach(client->sip_endpt, client->sockfd, &addrname, 1, &tp); - - status = pjsip_tsx_layer_init_module(client->sip_endpt); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); - - status = pjsip_ua_init_module(client->sip_endpt, NULL); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); - - status = pjsip_100rel_init_module(client->sip_endpt); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); - - pj_bzero(&inv_cb, sizeof(inv_cb)); - inv_cb.on_state_changed = &call_on_state_changed; - inv_cb.on_new_session = &call_on_forked; - inv_cb.on_media_update = &call_on_media_update; - - status = pjsip_inv_usage_init(client->sip_endpt, &inv_cb); - PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); - - status = pjsip_endpt_register_module(client->sip_endpt, &sip_client_mod); - - pj_thread_create(client->pool, "sip client", &sip_worker_thread, client, - 0, 0, &client->sip_thread); - - return status; -} - -static void sip_client_register_callback(struct pjsip_regc_cbparam *param) -{ - if (param->status != PJ_SUCCESS || param->code / 100 != 2) - printf("Failed to register: %d %d", param->status, param->code); -} - -void sip_client_free(struct sip_client *client) -{ - pjsip_regc_destroy(client->regc); - pjsip_endpt_destroy(client->sip_endpt); -} - -void sip_client_register(struct sip_client *client) -{ - pjsip_tx_data *tdata; - - pjsip_regc_register(client->regc, true, &tdata); - pjsip_regc_send(client->regc, tdata); -} - -void sip_client_set_cred(struct sip_client *client) -{ - char local_contact[100]; - char server_uri[100]; - char s[INET6_ADDRSTRLEN]; - char contact_addr[INET6_ADDRSTRLEN + 10]; - pj_str_t pj_contact_addr; - - sockaddr_to_string(&client->public_addr, s, sizeof(s)); - - snprintf(contact_addr, sizeof(contact_addr), "sip:%s:%d", s, - sockaddr_get_port(&client->public_addr)); - pj_contact_addr = pj_str(contact_addr); - - client->cred.realm = pj_str((char *)client->config->host); - client->cred.scheme = pj_str("digest"); - client->cred.username = pj_str((char *)client->config->username); - client->cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; - client->cred.data = pj_str((char *)client->config->password); - - snprintf(local_contact, sizeof(local_contact), "sip:%s@%s", - client->config->username, client->config->host); - pj_strdup2_with_null(client->pool, &client->local_contact, local_contact); - - snprintf(server_uri, sizeof(server_uri), "sip:%s\n", client->config->host); - pj_strdup2_with_null(client->pool, &client->server_uri, server_uri); - - pjsip_regc_init(client->regc, &client->server_uri, &client->local_contact, - &client->local_contact, 1, &pj_contact_addr, 3600); - pjsip_regc_set_credentials(client->regc, 1, &client->cred); - - sip_client_register(client); -} - -void sip_client_init(struct sip_client *client, struct tapi_device *tdev, - const struct sip_client_config *config) -{ - global_client = client; - client->config = config; - - client->tdev = tdev; - - iface_get_addr(config->iface, &client->local_addr); - - if (config->stun_host && config->stun_port) - client->stun = stun_client_alloc(config->stun_host, config->stun_port); - else - client->stun = NULL; - - sip_client_init_sip_endpoint(client); - - pjsip_regc_create(client->sip_endpt, client, sip_client_register_callback, - &client->regc); - - sip_client_set_cred(client); -} - - diff --git a/package/tapi_sip/src/sip_client.h b/package/tapi_sip/src/sip_client.h deleted file mode 100644 index 1c494b6dc3..0000000000 --- a/package/tapi_sip/src/sip_client.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __SIP_CLIENT_H__ -#define __SIP_CLIENT_H__ - -#include <tapi-stream.h> -#include <tapi-device.h> - -#include <pjsip.h> -#include <pjsip_ua.h> -#include <pjsip_simple.h> -#include <pjlib-util.h> -#include <pjlib.h> - -#include <stdlib.h> -#include <sys/socket.h> -#include <stdint.h> - -struct stun_client; -struct sip_agent; - -struct sip_client_config { - const char *iface; - - const char *host; - uint16_t port; - const char *username; - const char *password; - - const char *stun_host; - uint16_t stun_port; -}; - -struct sip_client { - const struct sip_client_config *config; - - struct tapi_device *tdev; - struct stun_client *stun; - - struct sockaddr_storage public_addr; - struct sockaddr_storage local_addr; - - int sockfd; - - pj_thread_t *sip_thread; - pj_caching_pool cp; - pj_pool_t *pool; - pjsip_endpoint *sip_endpt; - pjsip_cred_info cred; - pj_str_t local_contact; - pj_str_t server_uri; - - pjsip_regc *regc; - - int (*incoming_call_cb)(struct sip_client *client, struct sip_agent *agent); -}; - -void sip_client_init(struct sip_client *client, struct tapi_device *dev, - const struct sip_client_config *config); - -struct sip_agent *sip_client_alloc_agent(struct sip_client *client, const char *dst_uri); - -#endif diff --git a/package/tapi_sip/src/stun.c b/package/tapi_sip/src/stun.c deleted file mode 100644 index 5c6b240679..0000000000 --- a/package/tapi_sip/src/stun.c +++ /dev/null @@ -1,243 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> - -#include <poll.h> - - -struct stun_client { - struct addrinfo *serverinfo; -}; - -struct stun_response { - struct sockaddr addr; -}; - -struct stun_header { - uint16_t type; - uint16_t length; - uint32_t cookie; - uint32_t id[3]; -} __attribute((packed)); - -struct stun_packet { - struct stun_header header; - uint8_t data[0]; -} __attribute((packed)); - -#define STUN_CLASS(c0, c1) (((c0) << 4) | ((c1) << 8)) - -#define STUN_CLASS_REQUEST STUN_CLASS(0, 0) -#define STUN_CLASS_INDICATION STUN_CLASS(0, 1) -#define STUN_CLASS_SUCCESS STUN_CLASS(1, 0) -#define STUN_CLASS_ERROR STUN_CLASS(1, 1) - -#define STUN_CLASS_MASK STUN_CLASS(1, 1) - -#define STUN_MESSAGE(msg) (((msg & 0xf10) << 2) | ((msg & 0x70) << 1) | (msg & 0xf)) -#define STUN_MESSAGE_BIND STUN_MESSAGE(1) - -#define STUN_COOKIE 0x2112a442 - -enum { - STUN_ATTR_TYPE_MAPPED_ADDRESS = 0x1, - STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS = 0x20, - STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS2 = 0x8020, -}; - -static inline uint16_t get_unaligned_be16(const uint8_t *buf) -{ - return (buf[0] << 8) | buf[1]; -} - -static inline uint16_t get_unaligned_be32(const uint8_t *buf) -{ - return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; -} - -static int stun_parse_xor_mapped_address(struct stun_response *response, - const uint8_t *buf, int length) -{ - uint8_t fam = buf[1]; - uint16_t port = get_unaligned_be16(&buf[2]); - struct sockaddr_in *sin = (struct sockaddr_in *)&response->addr; - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&response->addr; - - - switch (fam) { - case 0x1: - sin->sin_family = AF_INET; - sin->sin_port = htons((port ^ (uint16_t)((STUN_COOKIE & 0xffff0000) >> 16))); - memcpy(&sin->sin_addr.s_addr, buf + 4, 4); - sin->sin_addr.s_addr ^= htonl(STUN_COOKIE); - printf("xor port: %d\n", sin->sin_port); - break; - case 0x2: - sin6->sin6_family = AF_INET6; - sin->sin_port = htons((port ^ (uint16_t)((STUN_COOKIE & 0xffff0000) >> 16))); - memcpy(sin6->sin6_addr.s6_addr, buf + 4, 16); - break; - } - - return 0; -} - -static int stun_parse_mapped_address(struct stun_response *response, - const uint8_t *buf, int length) -{ - uint8_t fam = buf[1]; - uint16_t port = get_unaligned_be16(&buf[2]); - struct sockaddr_in *sin = (struct sockaddr_in *)&response->addr; - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&response->addr; - - printf("port: %d\n", port); - - switch (fam) { - case 0x1: - sin->sin_family = AF_INET; - sin->sin_port = htons(port); - memcpy(&sin->sin_addr.s_addr, buf + 4, 4); - break; - case 0x2: - sin6->sin6_family = AF_INET6; - sin6->sin6_port = htons(port); - memcpy(sin6->sin6_addr.s6_addr, buf + 4, 16); - break; - } - - return 0; -} - -static int stun_parse_response(struct stun_response *response, - const struct stun_packet *packet) -{ - uint16_t attr_type, attr_length; - const uint8_t *buf; - int length = ntohs(packet->header.length); - int ret; - int i = 0; - - if (packet->header.cookie != htonl(STUN_COOKIE)) - return -1; - - if (packet->header.length < 4) - return 0; - - buf = packet->data; - - do { - attr_type = get_unaligned_be16(&buf[i]); - attr_length = get_unaligned_be16(&buf[i + 2]); - i += 4; - - if (i + attr_length > length) - break; - - switch (attr_type) { - case STUN_ATTR_TYPE_MAPPED_ADDRESS: - ret = stun_parse_mapped_address(response, &buf[i], attr_length); - break; - case STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS: - case STUN_ATTR_TYPE_XOR_MAPPED_ADDRESS2: - ret = stun_parse_xor_mapped_address(response, &buf[i], attr_length); - break; - } - - i += attr_length; - - } while (i < length && ret == 0); - - return 0; -} - -static struct stun_packet *stun_packet_alloc(size_t data_size) -{ - return malloc(sizeof(struct stun_packet) + data_size); -} - -int stun_client_resolve(struct stun_client *stun, int sockfd, struct sockaddr *addr) -{ - struct stun_packet *packet = stun_packet_alloc(200); - struct stun_response response; - int ret; - int retries = 4; - int timeout = 500; - struct pollfd pollfd; - - pollfd.events = POLLIN; - pollfd.fd = sockfd; - - packet->header.type = htons(STUN_CLASS_REQUEST | STUN_MESSAGE_BIND); - packet->header.cookie = htonl(STUN_COOKIE); - packet->header.id[0] = 0x12345678; - packet->header.id[1] = 0x12345678; - packet->header.id[2] = 0x12345678; - packet->header.length = 0; - - while (retries--) { - ret = sendto(sockfd, packet, sizeof(struct stun_header) + packet->header.length, - 0, stun->serverinfo->ai_addr, stun->serverinfo->ai_addrlen); - - ret = poll(&pollfd, 1, timeout); - switch (ret) { - case 0: - timeout <<= 1; - case -EINTR: - printf("retry\n"); - continue; - default: - retries = 0; - } - ret = recvfrom(sockfd, packet, 200, 0, NULL, NULL); - } - - if (ret <= 0) - return ret ? ret : -ETIMEDOUT; - - memset(&response, 0, sizeof(response)); - ret = stun_parse_response(&response, packet); - - *addr = response.addr; - - return ret; -} - -struct stun_client *stun_client_alloc(const char *hostname, uint16_t port) -{ - struct addrinfo hints; - struct stun_client *stun; - int ret; - char p[6]; - - - stun = malloc(sizeof(*stun)); - if (!stun) - return NULL; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICSERV; - - snprintf(p, sizeof(p), "%d", port); - if ((ret = getaddrinfo(hostname, p, &hints, &stun->serverinfo)) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret)); - return NULL; - } - - - return stun; -} - -void stun_client_free(struct stun_client *stun) -{ - freeaddrinfo(stun->serverinfo); - free(stun); -} diff --git a/package/tapi_sip/src/stun.h b/package/tapi_sip/src/stun.h deleted file mode 100644 index 2cd61c9f16..0000000000 --- a/package/tapi_sip/src/stun.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __STUN_H__ -#define __STUN_H__ - -#include <stdint.h> - -struct stun_client; - -struct stun_client *stun_client_alloc(const char *hostname, uint16_t port); -void stun_client_free(struct stun_client *); -int stun_client_resolve(struct stun_client *stun, int sockfd, struct sockaddr *addr); - -#endif diff --git a/package/tapi_sip/src/tapi_agent.c b/package/tapi_sip/src/tapi_agent.c deleted file mode 100644 index 93c73c24d8..0000000000 --- a/package/tapi_sip/src/tapi_agent.c +++ /dev/null @@ -1,105 +0,0 @@ - -#include <stdbool.h> -#include <stdio.h> -#include <tapi-port.h> - -#include "session.h" -#include "agent.h" -#include "tapi_agent.h" - -static int tapi_agent_invite(struct agent *agent, struct session *session) -{ - struct tapi_agent *tagent = agent_to_tapi_agent(agent); - - if (tagent->session) - return -1; - - tagent->state = TAPI_AGENT_STATE_RINGING; - tapi_port_set_ring(&tagent->port, true); - - tagent->session = session; - - return 0; -} - -static int tapi_agent_accept(struct agent *agent, struct session *session) -{ - return 0; -} - -static int tapi_agent_hangup(struct agent *agent, struct session *session) -{ - struct tapi_agent *tagent = agent_to_tapi_agent(agent); - - switch (tagent->state) { - case TAPI_AGENT_STATE_RINGING: - tapi_port_set_ring(&tagent->port, false); - break; - default: - break; - } - - tagent->state = TAPI_AGENT_STATE_IDLE; - tagent->session = NULL; - - return 0; -} - -static int tapi_agent_get_endpoint(struct agent *agent, struct session *session) -{ - struct tapi_agent *tagent = agent_to_tapi_agent(agent); - return tapi_port_get_endpoint(&tagent->port); -} - -static const struct agent_ops tapi_agent_ops = { - .invite = tapi_agent_invite, - .accept = tapi_agent_accept, - .hangup = tapi_agent_hangup, - .get_endpoint = tapi_agent_get_endpoint, -}; - -static void tapi_agent_event(struct tapi_port *port, struct tapi_event *event, - void *data) -{ - struct tapi_agent *tagent = data; - - if (event->type != TAPI_EVENT_TYPE_HOOK) - return; - - if (!tagent->session) - return; - - if (event->hook.on) { - session_hangup(tagent->session, &tagent->agent); - tagent->state = TAPI_AGENT_STATE_IDLE; - tagent->session = NULL; - } else { - session_accept(tagent->session, &tagent->agent); - tagent->state = TAPI_AGENT_STATE_ACTIVE; - } -} - -void tapi_agent_init(struct tapi_device *tdev, int port, struct tapi_agent *tagent) -{ - int ret; - - tagent->agent.ops = &tapi_agent_ops; - tagent->state = TAPI_AGENT_STATE_IDLE; - tagent->session = NULL; - - ret = tapi_port_open(tdev, port, &tagent->port); - if (ret) { - printf("Failed to open tapi port %d: %d\n", port, ret); - return; - } - - tagent->event_listener.callback = tapi_agent_event; - tagent->event_listener.data = tagent; - - tapi_port_register_event(&tagent->port, &tagent->event_listener); -} - -void tapi_agent_free(struct tapi_agent *tagent) -{ - tapi_port_unregister_event(&tagent->port, &tagent->event_listener); -} diff --git a/package/tapi_sip/src/tapi_agent.h b/package/tapi_sip/src/tapi_agent.h deleted file mode 100644 index 12e8701215..0000000000 --- a/package/tapi_sip/src/tapi_agent.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __TAPI_AGENT_H__ -#define __TAPI_AGENT_H__ - -#include "agent.h" -#include <tapi-port.h> - -struct session; - -enum tapi_agent_state { - TAPI_AGENT_STATE_IDLE, - TAPI_AGENT_STATE_RINGING, - TAPI_AGENT_STATE_ACTIVE, -}; - -struct tapi_agent { - struct agent agent; - struct tapi_port port; - struct tapi_port_event_listener event_listener; - - enum tapi_agent_state state; - - struct session *session; -}; - -static inline struct tapi_agent *agent_to_tapi_agent(struct agent *agent) -{ - return container_of(agent, struct tapi_agent, agent); -} - -static inline struct tapi_agent *port_to_tapi_agent(struct tapi_port *port) -{ - return container_of(port, struct tapi_agent, port); -} - -void tapi_agent_init(struct tapi_device *tdev, int port, struct tapi_agent *tagent); - -#endif diff --git a/package/tapi_sip/src/tapi_sip.c b/package/tapi_sip/src/tapi_sip.c deleted file mode 100644 index 518c63c3dd..0000000000 --- a/package/tapi_sip/src/tapi_sip.c +++ /dev/null @@ -1,179 +0,0 @@ - -#include <stdbool.h> -#include <stdlib.h> -#include <stdio.h> -#include <sys/ioctl.h> -#include <fcntl.h> -#include <errno.h> -#include <poll.h> -#include <string.h> - -#include <linux/input.h> -#include "dialdetector.h" - -#include <tapi-ioctl.h> - -#include <tapi-device.h> -#include <tapi-port.h> - -#include "contact.h" -#include "session.h" -#include "sip_client.h" -#include "sip_agent.h" -#include "tapi_agent.h" - -static struct tapi_device dev; -static struct tapi_agent *ports; - -static struct sip_client sip_client; - -static void release_session(struct session *session) -{ - free(session); -} - -static void dial(struct tapi_agent *caller, struct agent *callee) -{ - struct session *session; - - session = session_alloc(&dev, &caller->agent, callee, release_session); - - if (!session) - return; - - caller->session = session; -} - -static void tel_dial(struct tapi_agent *caller, const char *number) -{ - int callee; - - callee = atoi(number) - 1; - - if (callee < 0 || callee > 1) - return; - dial(caller, &ports[callee].agent); -} - -static void sip_dial(struct tapi_agent *caller, const char *identifier) -{ - struct sip_agent *callee; - - callee = sip_client_alloc_agent(&sip_client, identifier); - if (!callee) - return; - - dial(caller, &callee->agent); -} - -static void dial_callback(struct tapi_port *port, size_t num_digits, const unsigned char *digits) -{ - struct tapi_agent *tagent = port_to_tapi_agent(port); - char number[100]; - struct contact *contact; - size_t i; - - if (tagent->state != TAPI_AGENT_STATE_IDLE) - return; - - for (i = 0; i < num_digits; ++i) { - if (digits[0] > 9) - break; - number[i] = digits[i] + '0'; - } - number[i] = '\0'; - - printf("dial callback: %s\n", number); - - contact = contact_get(number); - - if (!contact) - return; - - if (strncmp("tel:", contact->identifier, 4) == 0) { - tel_dial(tagent, contact->identifier + 4); - } else if (strncmp("sip:", contact->identifier, 4) == 0) { - sip_dial(tagent, contact->identifier); - } - tagent->state = TAPI_AGENT_STATE_ACTIVE; -} - -static int incoming_sip_call(struct sip_client *client, - struct sip_agent *caller) -{ - struct tapi_agent *callee = NULL;; - struct session *session; - int i; - - for (i = 0; i < 2; ++i) { - if (ports[i].state == TAPI_AGENT_STATE_IDLE) { - callee = &ports[i]; - break; - } - } - - if (callee == NULL) - return -1; - - session = session_alloc(&dev, &caller->agent, &callee->agent, - release_session); - caller->session = session; - - return 0; -} - -int main(int argc, char *argv[]) -{ - struct dialdetector *dd, *dd2; - struct account *account; - struct sip_client_config config; - const char *interface = "eth0"; - int ret; - int i; - - if (argc > 1) - interface = argv[1]; - - pj_init(); - pjlib_util_init(); - - contacts_init(); - - account = get_account(); - if (!account) { - printf("No account\n"); - return 1; - } - - ret = tapi_device_open(0, &dev); - if (ret) { - printf("Failed to open tapi device: %d\n", ret); - return 1; - } - - ports = calloc(dev.num_ports, sizeof(*ports)); - for (i = 0; i < dev.num_ports; ++i) - tapi_agent_init(&dev, i, &ports[i]); - - dd = dialdetector_alloc(&ports[0].port); - dd->dial_callback = dial_callback; - dd2 = dialdetector_alloc(&ports[1].port); - dd2->dial_callback = dial_callback; - - config.iface = interface; - config.host = account->realm; - config.port = account->sip_port; - config.username = account->username; - config.password = account->password; - - config.stun_host = account->stun_host; - config.stun_port = account->stun_port; - - sip_client_init(&sip_client, &dev, &config); - - sip_client.incoming_call_cb = incoming_sip_call; - - tapi_mainloop(); - - return 0; -} |