Asterisk - The Open Source Telephony Project  GIT-master-b7027de
chan_nbs.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief Network broadcast sound support channel driver
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \ingroup channel_drivers
26  */
27 
28 /*** MODULEINFO
29  <depend>nbs</depend>
30  <support_level>deprecated</support_level>
31  ***/
32 
33 #include "asterisk.h"
34 
35 #include <sys/socket.h>
36 #include <sys/time.h>
37 #include <arpa/inet.h>
38 #include <fcntl.h>
39 #include <sys/ioctl.h>
40 #include <nbs.h>
41 
42 #include "asterisk/lock.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/config.h"
45 #include "asterisk/module.h"
46 #include "asterisk/pbx.h"
47 #include "asterisk/utils.h"
48 #include "asterisk/format_cache.h"
49 
50 static const char tdesc[] = "Network Broadcast Sound Driver";
51 
52 static char context[AST_MAX_EXTENSION] = "default";
53 static const char type[] = "NBS";
54 
55 /* NBS creates private structures on demand */
56 
57 struct nbs_pvt {
58  NBS *nbs;
59  struct ast_channel *owner; /* Channel we belong to, possibly NULL */
60  char app[16]; /* Our app */
61  char stream[80]; /* Our stream */
62  struct ast_module_user *u; /*! for holding a reference to this module */
63 };
64 
65 static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause);
66 static int nbs_call(struct ast_channel *ast, const char *dest, int timeout);
67 static int nbs_hangup(struct ast_channel *ast);
68 static struct ast_frame *nbs_xread(struct ast_channel *ast);
69 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame);
70 
71 static struct ast_channel_tech nbs_tech = {
72  .type = type,
73  .description = tdesc,
74  .requester = nbs_request,
75  .call = nbs_call,
76  .hangup = nbs_hangup,
77  .read = nbs_xread,
78  .write = nbs_xwrite,
79 };
80 
81 static int nbs_call(struct ast_channel *ast, const char *dest, int timeout)
82 {
83  struct nbs_pvt *p;
84 
85  p = ast_channel_tech_pvt(ast);
86 
88  ast_log(LOG_WARNING, "nbs_call called on %s, neither down nor reserved\n", ast_channel_name(ast));
89  return -1;
90  }
91  /* When we call, it just works, really, there's no destination... Just
92  ring the phone and wait for someone to answer */
93  ast_debug(1, "Calling %s on %s\n", dest, ast_channel_name(ast));
94 
95  /* If we can't connect, return congestion */
96  if (nbs_connect(p->nbs)) {
97  ast_log(LOG_WARNING, "NBS Connection failed on %s\n", ast_channel_name(ast));
99  } else {
102  }
103 
104  return 0;
105 }
106 
107 static void nbs_destroy(struct nbs_pvt *p)
108 {
109  if (p->nbs)
110  nbs_delstream(p->nbs);
112  ast_free(p);
113 }
114 
115 static struct nbs_pvt *nbs_alloc(const char *data)
116 {
117  struct nbs_pvt *p;
118  int flags = 0;
119  char stream[256];
120  char *opts;
121 
122  ast_copy_string(stream, data, sizeof(stream));
123  if ((opts = strchr(stream, ':'))) {
124  *opts = '\0';
125  opts++;
126  } else
127  opts = "";
128  p = ast_calloc(1, sizeof(*p));
129  if (p) {
130  if (!ast_strlen_zero(opts)) {
131  if (strchr(opts, 'm'))
132  flags |= NBS_FLAG_MUTE;
133  if (strchr(opts, 'o'))
134  flags |= NBS_FLAG_OVERSPEAK;
135  if (strchr(opts, 'e'))
136  flags |= NBS_FLAG_EMERGENCY;
137  if (strchr(opts, 'O'))
138  flags |= NBS_FLAG_OVERRIDE;
139  } else
140  flags = NBS_FLAG_OVERSPEAK;
141 
142  ast_copy_string(p->stream, stream, sizeof(p->stream));
143  p->nbs = nbs_newstream("asterisk", stream, flags);
144  if (!p->nbs) {
145  ast_log(LOG_WARNING, "Unable to allocate new NBS stream '%s' with flags %d\n", stream, flags);
146  ast_free(p);
147  p = NULL;
148  } else {
149  /* Set for 8000 hz mono, 640 samples */
150  nbs_setbitrate(p->nbs, 8000);
151  nbs_setchannels(p->nbs, 1);
152  nbs_setblocksize(p->nbs, 640);
153  nbs_setblocking(p->nbs, 0);
154  }
155  }
156  return p;
157 }
158 
159 static int nbs_hangup(struct ast_channel *ast)
160 {
161  struct nbs_pvt *p;
162  p = ast_channel_tech_pvt(ast);
163  ast_debug(1, "nbs_hangup(%s)\n", ast_channel_name(ast));
164  if (!ast_channel_tech_pvt(ast)) {
165  ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
166  return 0;
167  }
168  nbs_destroy(p);
171  return 0;
172 }
173 
174 static struct ast_frame *nbs_xread(struct ast_channel *ast)
175 {
176  ast_debug(1, "Returning null frame on %s\n", ast_channel_name(ast));
177 
178  return &ast_null_frame;
179 }
180 
181 static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
182 {
183  struct nbs_pvt *p = ast_channel_tech_pvt(ast);
184  if (ast_channel_state(ast) != AST_STATE_UP) {
185  /* Don't try tos end audio on-hook */
186  return 0;
187  }
188  if (nbs_write(p->nbs, frame->data.ptr, frame->datalen / 2) < 0)
189  return -1;
190  return 0;
191 }
192 
193 static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
194 {
195  struct ast_channel *tmp;
196  tmp = ast_channel_alloc(1, state, 0, 0, "", "s", context, assignedids, requestor, 0, "NBS/%s", i->stream);
197  if (tmp) {
198  ast_channel_tech_set(tmp, &nbs_tech);
199  ast_channel_set_fd(tmp, 0, nbs_fd(i->nbs));
200 
206  if (state == AST_STATE_RING)
207  ast_channel_rings_set(tmp, 1);
208  ast_channel_tech_pvt_set(tmp, i);
210  ast_channel_exten_set(tmp, "s");
211  ast_channel_language_set(tmp, "");
212  i->owner = tmp;
213  i->u = ast_module_user_add(tmp);
214  ast_channel_unlock(tmp);
215  if (state != AST_STATE_DOWN) {
216  if (ast_pbx_start(tmp)) {
217  ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
218  ast_hangup(tmp);
219  }
220  }
221  } else
222  ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
223  return tmp;
224 }
225 
226 
227 static struct ast_channel *nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
228 {
229  struct nbs_pvt *p;
230  struct ast_channel *tmp = NULL;
231 
234 
235  ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%s'\n",
236  ast_format_cap_get_names(cap, &cap_buf));
237  return NULL;
238  }
239  p = nbs_alloc(data);
240  if (p) {
241  tmp = nbs_new(p, AST_STATE_DOWN, assignedids, requestor);
242  if (!tmp)
243  nbs_destroy(p);
244  }
245  return tmp;
246 }
247 
248 static int unload_module(void)
249 {
250  /* First, take us out of the channel loop */
251  ast_channel_unregister(&nbs_tech);
252  ao2_ref(nbs_tech.capabilities, -1);
253  nbs_tech.capabilities = NULL;
254  return 0;
255 }
256 
257 static int load_module(void)
258 {
261  }
263  /* Make sure we can register our channel type */
264  if (ast_channel_register(&nbs_tech)) {
265  ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
266  ao2_ref(nbs_tech.capabilities, -1);
267  nbs_tech.capabilities = NULL;
269  }
271 }
272 
273 AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "Network Broadcast Sound Support");
Main Channel structure associated with a channel.
static int unload_module(void)
Definition: chan_nbs.c:248
const char *const type
Definition: channel.h:630
static struct ast_channel_tech nbs_tech
Definition: chan_nbs.c:71
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
static int nbs_hangup(struct ast_channel *ast)
Definition: chan_nbs.c:159
int ast_queue_control(struct ast_channel *chan, enum ast_control_frame_type control)
Queue a control frame without payload.
Definition: channel.c:1227
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
void ast_channel_unregister(const struct ast_channel_tech *tech)
Unregister a channel technology.
Definition: channel.c:566
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
#define LOG_WARNING
Definition: logger.h:274
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Create a new thread and start the PBX.
Definition: pbx.c:4712
#define AST_FORMAT_CAP_NAMES_LEN
Definition: format_cap.h:326
union ast_frame::@257 data
static int timeout
Definition: cdr_mysql.c:86
static int tmp()
Definition: bt_open.c:389
Structure to pass both assignedid values to channel drivers.
Definition: channel.h:605
ast_channel_state
ast_channel states
Definition: channelstate.h:35
NBS * nbs
Definition: chan_nbs.c:58
int ast_channel_register(const struct ast_channel_tech *tech)
Register a channel technology (a new channel driver) Called by a channel module to register the kind ...
Definition: channel.c:535
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define NULL
Definition: resample.c:96
const char * data
AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "Network Broadcast Sound Support")
#define ast_module_user_remove(user)
Definition: module.h:427
static struct ast_frame * nbs_xread(struct ast_channel *ast)
Definition: chan_nbs.c:174
Utility functions.
enum ast_format_cmp_res ast_format_cap_iscompatible_format(const struct ast_format_cap *cap, const struct ast_format *format)
Find if ast_format is within the capabilities of the ast_format_cap object.
Definition: format_cap.c:583
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
static struct nbs_pvt * nbs_alloc(const char *data)
Definition: chan_nbs.c:115
Configuration File Parser.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
General Asterisk PBX channel definitions.
void ast_channel_rings_set(struct ast_channel *chan, int value)
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
static struct ast_channel * nbs_new(struct nbs_pvt *i, int state, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor)
Definition: chan_nbs.c:193
#define AST_MAX_EXTENSION
Definition: channel.h:135
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define ast_format_cap_append(cap, format, framing)
Definition: format_cap.h:103
#define ast_format_cap_alloc(flags)
Definition: format_cap.h:52
#define ast_module_user_add(chan)
Definition: module.h:426
Structure to describe a channel "technology", ie a channel driver See for examples: ...
Definition: channel.h:629
Core PBX routines and definitions.
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
char app[16]
Definition: chan_nbs.c:60
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
static int nbs_xwrite(struct ast_channel *ast, struct ast_frame *frame)
Definition: chan_nbs.c:181
#define LOG_NOTICE
Definition: logger.h:263
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition: format_cap.c:736
struct ast_format_cap * capabilities
Definition: channel.h:633
#define ast_strlen_zero(a)
Definition: muted.c:73
#define ast_channel_unlock(chan)
Definition: channel.h:2903
static const char tdesc[]
Definition: chan_nbs.c:50
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2534
static int nbs_call(struct ast_channel *ast, const char *dest, int timeout)
Definition: chan_nbs.c:81
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
struct ast_module_user * u
Definition: chan_nbs.c:62
static const char type[]
Definition: chan_nbs.c:53
void ast_channel_set_fd(struct ast_channel *chan, int which, int fd)
Definition: channel.c:2417
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
struct ast_frame ast_null_frame
Definition: main/frame.c:79
static char context[AST_MAX_EXTENSION]
Definition: chan_nbs.c:52
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
int ast_setstate(struct ast_channel *chan, enum ast_channel_state)
Change the state of a channel.
Definition: channel.c:7393
static struct ast_channel * nbs_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
Definition: chan_nbs.c:227
Data structure associated with a single frame of data.
static int load_module(void)
Definition: chan_nbs.c:257
char stream[80]
Definition: chan_nbs.c:61
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition: channel.h:1259
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
Asterisk module definitions.
void ast_channel_tech_pvt_set(struct ast_channel *chan, void *value)
struct ast_channel * owner
Definition: chan_nbs.c:59
Media Format Cache API.
static void nbs_destroy(struct nbs_pvt *p)
Definition: chan_nbs.c:107