SOURCES: asterisk-chan_bluetooth.patch (NEW) - added, NFY

aredridel aredridel at pld-linux.org
Mon Nov 6 20:50:47 CET 2006


Author: aredridel                    Date: Mon Nov  6 19:50:47 2006 GMT
Module: SOURCES                       Tag: HEAD
---- Log message:
- added, NFY

---- Files affected:
SOURCES:
   asterisk-chan_bluetooth.patch (NONE -> 1.1)  (NEW)

---- Diffs:

================================================================
Index: SOURCES/asterisk-chan_bluetooth.patch
diff -u /dev/null SOURCES/asterisk-chan_bluetooth.patch:1.1
--- /dev/null	Mon Nov  6 20:50:47 2006
+++ SOURCES/asterisk-chan_bluetooth.patch	Mon Nov  6 20:50:42 2006
@@ -0,0 +1,3225 @@
+diff -urN asterisk-1.4.0-beta3-o-o/build_tools/menuselect-deps.in asterisk-1.4.0-beta3/build_tools/menuselect-deps.in
+--- asterisk-1.4.0-beta3-o-o/build_tools/menuselect-deps.in	2006-09-19 11:07:22.000000000 -0600
++++ asterisk-1.4.0-beta3/build_tools/menuselect-deps.in	2006-11-06 12:45:04.000000000 -0700
+@@ -1,4 +1,5 @@
+ ASOUND=@PBX_ALSA@
++BLUETOOTH=@PBX_BLUETOOTH@
+ CURL=@PBX_CURL@
+ FREETDS=@PBX_FREETDS@
+ GSM=@PBX_GSM@
+diff -urN asterisk-1.4.0-beta3-o-o/channels/chan_bluetooth.c asterisk-1.4.0-beta3/channels/chan_bluetooth.c
+--- asterisk-1.4.0-beta3-o-o/channels/chan_bluetooth.c	1969-12-31 17:00:00.000000000 -0700
++++ asterisk-1.4.0-beta3/channels/chan_bluetooth.c	2006-11-06 12:44:39.000000000 -0700
+@@ -0,0 +1,3145 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Asterisk Bluetooth Channel
++ *
++ * Author: Theo Zourzouvillys <theo at adaptive-it.co.uk>
++ *
++ * Adaptive Linux Solutions <http://www.adaptive-it.co.uk>
++ *
++ * Copyright (C) 2004 Adaptive Linux Solutions
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ *
++ * ******************* NOTE NOTE NOTE NOTE NOTE *********************
++ *
++ * This code is not at all tested, and only been developed with a
++ * HBH-200 headset and a Nokia 6310i right now.
++ *
++ * Expect it to crash, dial random numbers, and steal all your money.
++ *
++ * PLEASE try any headsets and phones, and let me know the results,
++ * working or not, along with all debug output!
++ *
++ * ------------------------------------------------------------------
++ *
++ * Asterisk Bluetooth Support
++ *
++ * Well, here we go - Attempt to provide Handsfree profile support in
++ * both AG and HF modes, AG (AudioGateway) mode support for using
++ * headsets, and HF (Handsfree) mode for utilising mobile/cell phones
++ *
++ * It would be nice to also provide Headset support at some time in
++ * the future, however, a working Handsfree profile is nice for now,
++ * and as far as I can see, almost all new HS devices also support HF
++ *
++ * ------------------------------------------------------------------
++ * INSTRUCTIONS
++ *
++ * You need to have bluez's bluetooth stack, along with user space
++ * tools (>=v2.10), and running hcid and sdsp.
++ *
++ * See bluetooth.conf for configuration details.
++ *
++ * - Ensure bluetooth subsystem is up and running.  'hciconfig'
++ *   should show interface as UP.
++ *
++ * - If you're trying to use a headset/HS, start up asterisk, and try
++ *   to pair it as you normally would.
++ *
++ * - If you're trying to use a Phone/AG, just make sure bluetooth is
++ *   enabled on your phone, and start up asterisk.
++ *
++ * - 'bluetooth show peers' will show all bluetooth devices states.
++ *
++ * - Send a call out by using Dial(BLT/DevName/0123456).  Call a HS 
++ *   with Dial(BLT/DevName)
++ *
++ * ------------------------------------------------------------------
++ * BUGS
++ *
++ * - What should happen when an AG is paired with asterisk and
++ *   someone uses the AG dalling a number manually?  My test phone
++ *   seems to try to open an SCO link.  Perhaps an extension to 
++ *   route the call to, or maybe drop the RFCOM link all together?
++ *
++ * ------------------------------------------------------------------
++ * COMPATIBILITY
++ *
++ * PLEASE email <theo at adaptive-it.co.uk> with the results of ANY
++ * device not listed in here (working or not), or if the device is
++ * listed and it doesn't work!  Please also email full debug output
++ * for any device not working correctly or generating errors in log.
++ * 
++ * HandsFree Profile:
++ *
++ *  HS (HeadSet):
++ *   - Ericsson HBH-200
++ *
++ *  AG (AudioGateway):
++ *   - Nokia 6310i
++ *
++ * ------------------------------------------------------------------
++ *
++ * Questions, bugs, or (preferably) patches to:
++ *
++ *  <theo at adaptive-it.co.uk>
++ *
++ * ------------------------------------------------------------------
++ */
++
++/*! \file
++ *
++ * \brief Channel driver for Bluetooth phones and headsets
++ *
++ * \author Theo Zourzouvillys <theo at adaptive-it.co.uk>
++ *
++ * \par See also
++ * \arg \ref Config_bluetooth
++ *
++ * \ingroup channel_drivers
++ */
++
++
++/*** MODULEINFO
++	 <depend>bluetooth</depend>
++ ***/
++
++
++/* ---------------------------------- */
++
++#include <stdio.h>
++#include <string.h>
++#include <asterisk/lock.h>
++#include <asterisk/utils.h>
++#include <asterisk/channel.h>
++#include <asterisk/channel_pvt.h>
++#include <asterisk/config.h>
++#include <asterisk/logger.h>
++#include <asterisk/module.h>
++#include <asterisk/pbx.h>
++#include <asterisk/sched.h>
++#include <asterisk/options.h>
++#include <asterisk/cli.h>
++#include <asterisk/callerid.h>
++#include <sys/socket.h>
++#include <sys/signal.h>
++#include <sys/time.h>
++#include <errno.h>
++#include <unistd.h>
++#include <stdlib.h>
++#include <arpa/inet.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <ctype.h>
++
++#include <bluetooth/bluetooth.h>
++#include <bluetooth/hci.h>
++#include <bluetooth/hci_lib.h>
++#include <bluetooth/sco.h>
++#include <bluetooth/rfcomm.h>
++#include <bluetooth/sdp.h>
++#include <bluetooth/sdp_lib.h>
++
++/* --- Data types and definitions --- */
++
++#ifndef HANDSFREE_AUDIO_GW_SVCLASS_ID
++# define HANDSFREE_AUDIO_GW_SVCLASS_ID 0x111f
++#endif
++
++#define BLUETOOTH_FORMAT    AST_FORMAT_SLINEAR
++#define BLT_CHAN_NAME       "BLT"
++#define BLT_CONFIG_FILE     "bluetooth.conf"
++#define BLT_RDBUFF_MAX      1024
++#define BLT_DEFAULT_HCI_DEV 0
++#define BLT_SVN_REVISION    "$Rev: 38 $"
++
++/* ---------------------------------- */
++
++typedef enum {
++  BLT_ROLE_NONE = 0, // Unknown Device
++  BLT_ROLE_HS = 1,   // Device is a Headset
++  BLT_ROLE_AG = 2    // Device is an Audio Gateway
++} blt_role_t;
++
++/* State when we're in HS mode */
++
++typedef enum {
++  BLT_STATE_WANT_R   = 0,
++  BLT_STATE_WANT_N   = 1,
++  BLT_STATE_WANT_CMD = 2,
++  BLT_STATE_WANT_N2  = 3,
++} blt_state_t;
++
++typedef enum {
++  BLT_STATUS_DOWN,
++  BLT_STATUS_CONNECTING,
++  BLT_STATUS_NEGOTIATING,
++  BLT_STATUS_READY,
++  BLT_STATUS_RINGING,
++  BLT_STATUS_IN_CALL,
++} blt_status_t;
++
++/* ---------------------------------- */
++
++/* Default config settings */
++
++#define BLT_DEFAULT_CHANNEL_AG   5
++#define BLT_DEFAULT_CHANNEL_HS   6
++#define BLT_DEFAULT_ROLE         BLT_ROLE_HS
++#define BLT_OBUF_LEN             (48 * 25)
++
++#define BUFLEN 4800
++
++/* ---------------------------------- */
++
++typedef struct blt_dev blt_dev_t;
++
++// XXX:T: Tidy this lot up.
++struct blt_dev {
++
++  blt_status_t status;              /* Device Status */
++
++  struct ast_channel * owner;       /* Channel we belong to, possibly NULL */
++  blt_dev_t * dev;                  /* The bluetooth device channel is for */
++  struct ast_frame fr;              /* Recieved frame */
++
++  /* SCO Handler */
++  int sco_pipe[2];                   /* SCO alert pipe */
++  int sco;                           /* SCO fd */
++  int sco_handle;                    /* SCO Handle */
++  int sco_mtu;                       /* SCO MTU */
++  int sco_running;                   /* 1 when sCO thread should be running */
++  pthread_t sco_thread;              /* SCO thread */
++  ast_mutex_t sco_lock;              /* SCO lock */
++  int sco_pos_in;                    /* Reader in position */
++  int sco_pos_out;                   /* Reader out position */
++  int sco_sending;                   /* Sending SCO packets */
++  char buf[1024];                    /* Incoming data buffer */
++  char sco_buf_out[BUFLEN+1];          /* 24 chunks of 48 */
++  char sco_buf_in[BUFLEN+1];           /* 24 chunks of 48 */
++
++  char dnid[1024];                    /* Outgoi gncall dialed number */
++  unsigned char * obuf[BLT_OBUF_LEN]; /* Outgoing data buffer */
++  int obuf_len;                       /* Output Buffer Position */
++  int obuf_wpos;                      /* Buffer Reader */
++
++  // device
++  int autoconnect;                  /* 1 for autoconnect */
++  int outgoing_id;                  /* Outgoing connection scheduler id */
++  char * name;                      /* Devices friendly name */
++  blt_role_t role;                  /* Device role (HS or AG) */
++  bdaddr_t bdaddr;                  /* remote address */
++  int channel;                      /* remote channel */
++  int rd;                           /* RFCOMM fd */
++  int tmp_rd;                       /* RFCOMM fd */
++  int call_cnt;                     /* Number of attempted calls */
++  ast_mutex_t lock;                 /* RFCOMM socket lock */
++  char rd_buff[BLT_RDBUFF_MAX];     /* RFCOMM input buffer */
++  int rd_buff_pos;                  /* RFCOMM input buffer position */
++  int ready;                        /* 1 When ready */
++
++  /* AG mode */
++  char last_ok_cmd[BLT_RDBUFF_MAX];        /* Runtime[AG]: Last AT command that was OK */
++  int cind;                                /* Runtime[AG]: Recieved +CIND */  
++  int call_pos, service_pos, callsetup_pos;  /* Runtime[AG]: Positions in CIND/CMER */
++  int call, service, callsetup;              /* Runtime[AG]: Values */
++
++  /* HS mode */
++  blt_state_t state;                       /* Runtime: Device state (AG mode only) */
++  int ring_timer;                          /* Runtime:Ring Timer */
++  char last_err_cmd[BLT_RDBUFF_MAX];       /* Runtime: Last AT command that was OK */
++  void (*cb)(blt_dev_t * dev, char * str); /* Runtime: Callback when in HS mode */
++
++  int brsf;                                /* Runtime: Bluetooth Retrieve Supported Features */
++  int bvra;                                /* Runtime: Bluetooth Voice Recognised Activation */
++  int gain_speaker;                        /* Runtime: Gain Of Speaker */
++  int clip;                                /* Runtime: Supports CLID */
++  int colp;                                /* Runtime: Connected Line ID */
++  int elip;                                /* Runtime: (Ericsson) Supports CLID */
++  int eolp;                                /* Runtime: (Ericsson) Connected Line ID */
++  int ringing;                             /* Runtime: Device is ringing */
++
++  blt_dev_t * next;                        /* Next in linked list */
++
++};
++
++typedef struct blt_atcb {
++
++  /* The command */
++  char * str;
++
++  /* DTE callbacks: */
++  int (*set)(blt_dev_t * dev, const char * arg, int len);
++  int (*read)(blt_dev_t * dev);
++  int (*execute)(blt_dev_t * dev, const char * data);
++  int (*test)(blt_dev_t * dev);
++
++  /* DCE callbacks: */
++  int (*unsolicited)(blt_dev_t * dev, const char * value);
++
++} blt_atcb_t;
++
++/* ---------------------------------- */
++
++static void rd_close(blt_dev_t * dev, int reconnect, int err);
++static int send_atcmd(blt_dev_t * device, const char * fmt, ...);
++static int sco_connect(blt_dev_t * dev);
++
++/* ---------------------------------- */
++
++/* RFCOMM channel we listen on*/
++static int rfcomm_channel_ag = BLT_DEFAULT_CHANNEL_AG;
++static int rfcomm_channel_hs = BLT_DEFAULT_CHANNEL_HS;
++
++/* Address of local bluetooth interface */
++static int hcidev_id;
++static bdaddr_t local_bdaddr;
++
++/* All the current sockets */
++AST_MUTEX_DEFINE_STATIC(iface_lock);
++static blt_dev_t * iface_head;
++static int ifcount = 0;
++
++static int sdp_record_hs = -1;
++static int sdp_record_ag = -1;
++
++/* RFCOMM listen socket */
++static int rfcomm_sock_ag = -1;
++static int rfcomm_sock_hs = -1;
++static int sco_socket = -1;
++
++static int monitor_pid = -1;
++
++/* The socket monitoring thread */
++static pthread_t monitor_thread = AST_PTHREADT_NULL;
++AST_MUTEX_DEFINE_STATIC(monitor_lock);
++
++/* Cound how many times this module is currently in use */
++static int usecnt = 0;
++AST_MUTEX_DEFINE_STATIC(usecnt_lock);
++
++static struct sched_context * sched = NULL;
++
++/* ---------------------------------- */
++
++static const char *
++role2str(blt_role_t role)
++{
++  switch (role) {
++    case BLT_ROLE_HS:
++      return "HS";
++    case BLT_ROLE_AG:
++      return "AG";
++    case BLT_ROLE_NONE:
++      return "??";
++  }
++}
++
++static const char *
++status2str(blt_status_t status)
++{
++  switch (status) {
++    case BLT_STATUS_DOWN:
++      return "Down";
++    case BLT_STATUS_CONNECTING:
++      return "Connecting";
++    case BLT_STATUS_NEGOTIATING:
++      return "Negotiating";
++    case BLT_STATUS_READY:
++      return "Ready";
++    case BLT_STATUS_RINGING:
++      return "Ringing";
++    case BLT_STATUS_IN_CALL:
++      return "InCall";
++  };
++  return "Unknown";
++}
++
++int sock_err(int fd)
++{
++  int ret;
++  int len = sizeof(ret);
++  getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len);
++  return ret;
++}
++
++/* ---------------------------------- */
++
++static const char *
++parse_cind(const char * str, char * name, int name_len)
++{
++  int c = 0;
++
++  memset(name, 0, name_len);
++
++  while (*str) {
++    if (*str == '(') {
++      if (++c == 1 && *(str+1) == '"') {
++        const char * start = str + 2;
++        int len = 0;
++        str += 2;
++        while (*str && *str != '"') {
++          len++;
++          str++;
++        }
++        if (len == 0)
++          return NULL;
++        strncpy(name, start, (len > name_len) ? name_len : len);
++      }
++    } else if (*str == ')')
++      c--;
++    else if (c == 0 && *str == ',')
++      return str + 1;
++    str++;
++  }
++  return NULL;
++}
++
++static void
++set_cind(blt_dev_t * dev, int indicator, int val)
++{
++
++  ast_log(LOG_DEBUG, "CIND %d set to %d\n", indicator, val);
++
++  if (indicator == dev->callsetup_pos) {
++
++    // call progress
++
++    dev->callsetup = val;
++
++    switch (val) {
++      case 3:
++        // Outgoign ringing
++        if (dev->owner && dev->role == BLT_ROLE_AG)
++          ast_queue_control(dev->owner, AST_CONTROL_RINGING);
++        break;
++      case 2:
++        break;
++      case 1:
++        break;
++      case 0:
++        if (dev->owner && dev->role == BLT_ROLE_AG && dev->call == 0)
++          ast_queue_control(dev->owner, AST_CONTROL_CONGESTION);
++        break;
++    }
++
++  } else if (indicator == dev->service_pos) {
++
++    // Signal
++
++    if (val == 0)
++      ast_log(LOG_NOTICE, "Audio Gateway %s lost signal\n", dev->name);
++    else if (dev->service == 0 && val > 0)
++      ast_log(LOG_NOTICE, "Audio Gateway %s got signal\n", dev->name);
++
++    dev->service = val;
++
++  } else if (indicator == dev->call_pos) {
++
++    // Call
++
++    dev->call = val;
++
++    if (dev->owner) {
++      if (val == 1) {
++        ast_queue_control(dev->owner, AST_CONTROL_ANSWER);
++      } else if (val == 0)
++        ast_queue_control(dev->owner, AST_CONTROL_HANGUP);
++    }
++
++  }
++
++
++}
++
++/* ---------------------------------- */
++
++int
++set_buffer(char * ring, char * data, int circular_len, int * pos, int data_len)
++{
++  int start_pos = *(pos);
++  int done = 0;
++  int copy;
++
++  while (data_len) {
++    // Set can_do to the most we can do in this copy.
++
++    copy = MIN(circular_len - start_pos, data_len);
++    memcpy(ring + start_pos, data + done, copy);
++
++    done += copy;
++    start_pos += copy;
++    data_len -= copy;
++
++    if (start_pos == circular_len)
++      start_pos = 0;
++  }
++  *(pos) = start_pos;
++  return 0;
++}
++
++int
++get_buffer(char * dst, char * ring, int ring_size, int * head, int to_copy)
++{
++  int copy;
++
++  // |1|2|3|4|5|6|7|8|9|
++  //      |-----|
++
++  while (to_copy) {
++
++    // Set can_do to the most we can do in this copy.
++    copy = MIN(ring_size - *head, to_copy);
++
++    // ast_log(LOG_DEBUG, "Getting: %d bytes, From pos %d\n", copy, *head);
++    memcpy(dst, ring + *head, copy);
++
++    dst += copy;
++    *head += copy;
++    to_copy -= copy;
++
++    if (*head == ring_size )
++      *head = 0;
++
++  }
++
++  return 0;
++}
++
++/* Handle SCO audio sync.
++ *
++ * If we are the MASTER, then we control the timing,
++ * in 48 byte chunks.  If we're the SLAVE, we send
++ * as and when we recieve a packet.
++ *
++ * Because of packet/timing nessecity, we 
++ * start up a thread when we're passing audio, so
++ * that things are timed exactly right.
++ *
++ * sco_thread() is the function that handles it.
++ *
++ */
++
++static void *
++sco_thread(void * data)
++{
++  blt_dev_t * dev = (blt_dev_t*)data;
++  int res;
++  struct pollfd pfd[2];
++  int in_pos = 0;
++  int out_pos = 0;
++  char c = 1;
++  int sending;
++  char buf[1024];
++  int len;
++
++  // Avoid deadlock in odd circumstances
++
++  ast_log(LOG_DEBUG, "SCO thread started on fd %d, pid %d\n", dev->sco, getpid());
++
++  // dev->status = BLT_STATUS_IN_CALL;
++  // ast_queue_control(dev->owner, AST_CONTROL_ANSWER);
++  // Set buffer to silence, just incase.
++
++  ast_mutex_lock(&(dev->sco_lock));
++
++  memset(dev->sco_buf_in,  0x7f, BUFLEN);
++  memset(dev->sco_buf_out, 0x7f, BUFLEN);
++
++  dev->sco_pos_in  = 0;
++  dev->sco_pos_out = 0;
++
++  ast_mutex_unlock(&(dev->sco_lock));
++
++  while (1) {
++
++    ast_mutex_lock(&(dev->sco_lock));
++
++    if (dev->sco_running != 1) {
++      ast_log(LOG_DEBUG, "SCO stopped.\n");
++      break;
++    }
++
++    pfd[0].fd = dev->sco;
++    pfd[0].events = POLLIN;
++
++    pfd[1].fd = dev->sco_pipe[1];
++    pfd[1].events = POLLIN;
++
++    ast_mutex_unlock(&(dev->sco_lock));
++
++    res = poll(pfd, 2, 50);
++
++    if (res == -1 && errno != EINTR) {
++      ast_log(LOG_DEBUG, "SCO poll() error\n");
++      break;
++    }
<<Diff was trimmed, longer than 597 lines>>


More information about the pld-cvs-commit mailing list