46e074b2064be9d1eafce9373f596607451670e0
[asterisk/asterisk.git] / apps / confbridge / conf_chan_announce.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013 Digium, Inc.
5  *
6  * Richard Mudgett <rmudgett@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 /*!
20  * \file
21  * \brief ConfBridge announcer channel driver
22  *
23  * \author Richard Mudgett <rmudgett@digium.com>
24  *
25  * See Also:
26  * \arg \ref AstCREDITS
27  */
28
29
30 #include "asterisk.h"
31
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33
34 #include "asterisk/channel.h"
35 #include "asterisk/bridging.h"
36 #include "asterisk/core_unreal.h"
37 #include "include/confbridge.h"
38
39 /* ------------------------------------------------------------------- */
40
41 /*! ConfBridge announcer channel private. */
42 struct announce_pvt {
43         /*! Unreal channel driver base class values. */
44         struct ast_unreal_pvt base;
45         /*! Conference bridge associated with this announcer. */
46         struct ast_bridge *bridge;
47 };
48
49 static int announce_call(struct ast_channel *chan, const char *addr, int timeout)
50 {
51         /* Make sure anyone calling ast_call() for this channel driver is going to fail. */
52         return -1;
53 }
54
55 static int announce_hangup(struct ast_channel *ast)
56 {
57         struct announce_pvt *p = ast_channel_tech_pvt(ast);
58         int res;
59
60         if (!p) {
61                 return -1;
62         }
63
64         /* give the pvt a ref to fulfill calling requirements. */
65         ao2_ref(p, +1);
66         res = ast_unreal_hangup(&p->base, ast);
67         ao2_ref(p, -1);
68
69         return res;
70 }
71
72 static void announce_pvt_destructor(void *vdoomed)
73 {
74         struct announce_pvt *doomed = vdoomed;
75
76         ao2_cleanup(doomed->bridge);
77         doomed->bridge = NULL;
78 }
79
80 static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause)
81 {
82         struct ast_channel *chan;
83         const char *conf_name = data;
84         RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
85         RAII_VAR(struct announce_pvt *, pvt, NULL, ao2_cleanup);
86
87         conference = ao2_find(conference_bridges, conf_name, OBJ_KEY);
88         if (!conference) {
89                 return NULL;
90         }
91         ast_assert(conference->bridge != NULL);
92
93         /* Allocate a new private structure and then Asterisk channels */
94         pvt = (struct announce_pvt *) ast_unreal_alloc(sizeof(*pvt), announce_pvt_destructor,
95                 cap);
96         if (!pvt) {
97                 return NULL;
98         }
99         ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
100         ast_copy_string(pvt->base.name, conf_name, sizeof(pvt->base.name));
101         pvt->bridge = conference->bridge;
102         ao2_ref(pvt->bridge, +1);
103
104         chan = ast_unreal_new_channels(&pvt->base, conf_announce_get_tech(),
105                 AST_STATE_UP, AST_STATE_UP, NULL, NULL, requestor, NULL);
106         if (chan) {
107                 ast_answer(pvt->base.owner);
108                 ast_answer(pvt->base.chan);
109                 if (ast_channel_add_bridge_role(pvt->base.chan, "announcer")) {
110                         ast_hangup(chan);
111                         chan = NULL;
112                 }
113         }
114
115         return chan;
116 }
117
118 static struct ast_channel_tech announce_tech = {
119         .type = "CBAnn",
120         .description = "Conference Bridge Announcing Channel",
121         .requester = announce_request,
122         .call = announce_call,
123         .hangup = announce_hangup,
124
125         .send_digit_begin = ast_unreal_digit_begin,
126         .send_digit_end = ast_unreal_digit_end,
127         .read = ast_unreal_read,
128         .write = ast_unreal_write,
129         .write_video = ast_unreal_write,
130         .exception = ast_unreal_read,
131         .indicate = ast_unreal_indicate,
132         .fixup = ast_unreal_fixup,
133         .send_html = ast_unreal_sendhtml,
134         .send_text = ast_unreal_sendtext,
135         .queryoption = ast_unreal_queryoption,
136         .setoption = ast_unreal_setoption,
137 };
138
139 struct ast_channel_tech *conf_announce_get_tech(void)
140 {
141         return &announce_tech;
142 }
143
144 void conf_announce_channel_depart(struct ast_channel *chan)
145 {
146         struct announce_pvt *p = ast_channel_tech_pvt(chan);
147
148         if (!p) {
149                 return;
150         }
151
152         ao2_ref(p, +1);
153         ao2_lock(p);
154         if (!ast_test_flag(&p->base, AST_UNREAL_CARETAKER_THREAD)) {
155                 ao2_unlock(p);
156                 ao2_ref(p, -1);
157                 return;
158         }
159         ast_clear_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
160         chan = p->base.chan;
161         if (chan) {
162                 ast_channel_ref(chan);
163         }
164         ao2_unlock(p);
165         ao2_ref(p, -1);
166         if (chan) {
167                 ast_bridge_depart(chan);
168                 ast_channel_unref(chan);
169         }
170 }
171
172 int conf_announce_channel_push(struct ast_channel *ast)
173 {
174         struct ast_bridge_features *features;
175         RAII_VAR(struct announce_pvt *, p, NULL, ao2_cleanup);
176         RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_unref);
177
178         {
179                 SCOPED_CHANNELLOCK(lock, ast);
180
181                 p = ast_channel_tech_pvt(ast);
182                 if (!p) {
183                         return -1;
184                 }
185                 ao2_ref(p, +1);
186                 chan = p->base.chan;
187                 if (!chan) {
188                         return -1;
189                 }
190                 ast_channel_ref(chan);
191         }
192
193         features = ast_bridge_features_new();
194         if (!features) {
195                 return -1;
196         }
197         ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE);
198
199         /* Impart the output channel into the bridge */
200         if (ast_bridge_impart(p->bridge, chan, NULL, features, 0)) {
201                 return -1;
202         }
203         ao2_lock(p);
204         ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
205         ao2_unlock(p);
206         return 0;
207 }