00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 180369 $")
00031
00032 #include <fcntl.h>
00033 #include <sys/signal.h>
00034
00035 #include "asterisk/lock.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/config.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/pbx.h"
00040 #include "asterisk/sched.h"
00041 #include "asterisk/io.h"
00042 #include "asterisk/rtp.h"
00043 #include "asterisk/acl.h"
00044 #include "asterisk/callerid.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/cli.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/bridging.h"
00049
00050 static struct ast_channel *bridge_request(const char *type, int format, void *data, int *cause);
00051 static int bridge_call(struct ast_channel *ast, char *dest, int timeout);
00052 static int bridge_hangup(struct ast_channel *ast);
00053 static struct ast_frame *bridge_read(struct ast_channel *ast);
00054 static int bridge_write(struct ast_channel *ast, struct ast_frame *f);
00055 static struct ast_channel *bridge_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
00056
00057 static const struct ast_channel_tech bridge_tech = {
00058 .type = "Bridge",
00059 .description = "Bridge Interaction Channel",
00060 .capabilities = -1,
00061 .requester = bridge_request,
00062 .call = bridge_call,
00063 .hangup = bridge_hangup,
00064 .read = bridge_read,
00065 .write = bridge_write,
00066 .write_video = bridge_write,
00067 .exception = bridge_read,
00068 .bridged_channel = bridge_bridgedchannel,
00069 };
00070
00071 struct bridge_pvt {
00072 ast_mutex_t lock;
00073 struct ast_channel *input;
00074 struct ast_channel *output;
00075 };
00076
00077
00078 static struct ast_channel *bridge_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
00079 {
00080 struct bridge_pvt *p = chan->tech_pvt;
00081 return (chan == p->input) ? p->output : bridge;
00082 }
00083
00084
00085 static struct ast_frame *bridge_read(struct ast_channel *ast)
00086 {
00087 return &ast_null_frame;
00088 }
00089
00090
00091 static int bridge_write(struct ast_channel *ast, struct ast_frame *f)
00092 {
00093 struct bridge_pvt *p = ast->tech_pvt;
00094 struct ast_channel *other;
00095
00096 ast_mutex_lock(&p->lock);
00097
00098 other = (p->input == ast ? p->output : p->input);
00099
00100 while (other && ast_channel_trylock(other)) {
00101 ast_mutex_unlock(&p->lock);
00102 do {
00103 CHANNEL_DEADLOCK_AVOIDANCE(ast);
00104 } while (ast_mutex_trylock(&p->lock));
00105 other = (p->input == ast ? p->output : p->input);
00106 }
00107
00108
00109 if (other) {
00110 ast_queue_frame(other, f);
00111 ast_channel_unlock(other);
00112 }
00113
00114 ast_mutex_unlock(&p->lock);
00115
00116 return 0;
00117 }
00118
00119
00120 static int bridge_call(struct ast_channel *ast, char *dest, int timeout)
00121 {
00122 struct bridge_pvt *p = ast->tech_pvt;
00123
00124
00125 if (!ast->bridge) {
00126 return -1;
00127 }
00128
00129
00130 ast_bridge_impart(p->input->bridge, p->output, NULL, NULL);
00131
00132 return 0;
00133 }
00134
00135
00136 static void bridge_queue_hangup(struct bridge_pvt *p, struct ast_channel *us)
00137 {
00138 struct ast_channel *other = (p->input == us ? p->output : p->input);
00139
00140 while (other && ast_channel_trylock(other)) {
00141 ast_mutex_unlock(&p->lock);
00142 do {
00143 CHANNEL_DEADLOCK_AVOIDANCE(us);
00144 } while (ast_mutex_trylock(&p->lock));
00145 other = (p->input == us ? p->output : p->input);
00146 }
00147
00148
00149 if (other) {
00150 ast_queue_hangup(other);
00151 ast_channel_unlock(other);
00152 }
00153
00154 return;
00155 }
00156
00157
00158 static int bridge_hangup(struct ast_channel *ast)
00159 {
00160 struct bridge_pvt *p = ast->tech_pvt;
00161
00162 ast_mutex_lock(&p->lock);
00163
00164
00165 if (p->input == ast) {
00166 if (p->output) {
00167 bridge_queue_hangup(p, ast);
00168 }
00169 p->input = NULL;
00170 } else if (p->output == ast) {
00171 if (p->input) {
00172 bridge_queue_hangup(p, ast);
00173 }
00174 p->output = NULL;
00175 }
00176
00177
00178 ast->tech_pvt = NULL;
00179
00180
00181 if (!p->input && !p->output) {
00182 ast_mutex_unlock(&p->lock);
00183 ast_mutex_destroy(&p->lock);
00184 ast_free(p);
00185 } else {
00186 ast_mutex_unlock(&p->lock);
00187 }
00188
00189 return 0;
00190 }
00191
00192
00193 static struct ast_channel *bridge_request(const char *type, int format, void *data, int *cause)
00194 {
00195 struct bridge_pvt *p = NULL;
00196
00197
00198 if (!(p = ast_calloc(1, sizeof(*p)))) {
00199 return NULL;
00200 }
00201
00202
00203 if (!(p->input = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", 0, "Bridge/%p-input", p))) {
00204 ast_free(p);
00205 return NULL;
00206 }
00207 if (!(p->output = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", 0, "Bridge/%p-output", p))) {
00208 ast_channel_free(p->input);
00209 ast_free(p);
00210 return NULL;
00211 }
00212
00213
00214 ast_mutex_init(&p->lock);
00215
00216
00217 p->input->tech = p->output->tech = &bridge_tech;
00218 p->input->tech_pvt = p->output->tech_pvt = p;
00219 p->input->nativeformats = p->output->nativeformats = AST_FORMAT_SLINEAR;
00220 p->input->readformat = p->output->readformat = AST_FORMAT_SLINEAR;
00221 p->input->rawreadformat = p->output->rawreadformat = AST_FORMAT_SLINEAR;
00222 p->input->writeformat = p->output->writeformat = AST_FORMAT_SLINEAR;
00223 p->input->rawwriteformat = p->output->rawwriteformat = AST_FORMAT_SLINEAR;
00224
00225 return p->input;
00226 }
00227
00228
00229 static int load_module(void)
00230 {
00231
00232 if (ast_channel_register(&bridge_tech)) {
00233 ast_log(LOG_ERROR, "Unable to register channel class 'Bridge'\n");
00234 return AST_MODULE_LOAD_FAILURE;
00235 }
00236 return AST_MODULE_LOAD_SUCCESS;
00237 }
00238
00239
00240 static int unload_module(void)
00241 {
00242 ast_channel_unregister(&bridge_tech);
00243 return 0;
00244 }
00245
00246 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Bridge Interaction Channel");