Asterisk - The Open Source Telephony Project  18.5.0
func_scramble.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2021, Naveen Albert
5  *
6  * Naveen Albert <[email protected]>
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 Frequency inverter
22  *
23  * \author Naveen Albert <[email protected]>
24  *
25  * \ingroup functions
26  *
27  */
28 
29 /*** MODULEINFO
30  <support_level>extended</support_level>
31  ***/
32 
33 /*** DOCUMENTATION
34  <function name="SCRAMBLE" language="en_US">
35  <synopsis>
36  Scrambles audio on a channel.
37  </synopsis>
38  <syntax>
39  <parameter name="direction" required="false">
40  <para>Must be <literal>TX</literal> or <literal>RX</literal>
41  to limit to a specific direction, or <literal>both</literal>
42  for both directions. <literal>remove</literal>
43  will remove an existing scrambler.</para>
44  </parameter>
45  </syntax>
46  <description>
47  <para>Scrambles audio on a channel using whole spectrum inversion.
48  This is not intended to be used for securely scrambling
49  audio. It merely renders audio unintelligible on a channel
50  as a privacy enhancement.</para>
51  </description>
52  <see-also>
53  <ref type="application">ChanSpy</ref>
54  </see-also>
55  </function>
56  ***/
57 
58 #include "asterisk.h"
59 
60 #include "asterisk/module.h"
61 #include "asterisk/channel.h"
62 #include "asterisk/pbx.h"
63 #include "asterisk/utils.h"
64 #include "asterisk/audiohook.h"
65 #include "asterisk/app.h"
66 
67 #include <stdio.h>
68 #include <string.h>
69 
72  unsigned short int tx;
73  unsigned short int rx;
74  unsigned short int state;
75 };
76 
77 static void destroy_callback(void *data)
78 {
79  struct scramble_information *ni = data;
80 
81  /* Destroy the audiohook, and destroy ourselves */
86  ast_free(ni);
87 
88  return;
89 }
90 
91 /*! \brief Static structure for datastore information */
92 static const struct ast_datastore_info scramble_datastore = {
93  .type = "scramble",
94  .destroy = destroy_callback
95 };
96 
97 /* return 0 if nothing detected, 1 if lack of tone, 2 if presence of tone */
98 /* modifies buffer pointed to by 'amp' with inverted values */
99 static inline void freq_invert(short *amp, int samples)
100 {
101  int i;
102  /* invert every other sample by 1 */
103  for (i = 0; i < samples; i += 2)
104  amp[i] = -amp[i];
105 }
106 
108 {
109  struct ast_datastore *datastore = NULL;
110  struct scramble_information *ni = NULL;
111 
112  /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
113  if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
114  return 0;
115 
116  /* Grab datastore which contains our gain information */
117  if (!(datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL)))
118  return 0;
119 
120  if (frame->frametype == AST_FRAME_VOICE) { /* only invert voice frequencies */
121  /* Based on direction of frame, and confirm it is applicable */
122  if (!(direction == AST_AUDIOHOOK_DIRECTION_READ ? &ni->rx : &ni->tx))
123  return 0;
124  /* Scramble the sample now */
125  freq_invert(frame->data.ptr, frame->samples);
126  }
127  return 0;
128 }
129 
130 /*! \internal \brief Disable scrambling on the channel */
131 static int remove_scrambler(struct ast_channel *chan)
132 {
133  struct ast_datastore *datastore = NULL;
134  struct scramble_information *data;
135  SCOPED_CHANNELLOCK(chan_lock, chan);
136 
137  datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL);
138  if (!datastore) {
139  ast_log(AST_LOG_WARNING, "Cannot remove SCRAMBLE from %s: SCRAMBLE not currently enabled\n",
140  ast_channel_name(chan));
141  return -1;
142  }
143  data = datastore->data;
144 
145  if (ast_audiohook_remove(chan, &data->audiohook)) {
146  ast_log(AST_LOG_WARNING, "Failed to remove SCRAMBLE audiohook from channel %s\n", ast_channel_name(chan));
147  return -1;
148  }
149 
150  if (ast_channel_datastore_remove(chan, datastore)) {
151  ast_log(AST_LOG_WARNING, "Failed to remove SCRAMBLE datastore from channel %s\n",
152  ast_channel_name(chan));
153  return -1;
154  }
155  ast_datastore_free(datastore);
156 
157  return 0;
158 }
159 
160 static int scramble_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
161 {
162  char *parse;
163  struct ast_datastore *datastore = NULL;
164  struct scramble_information *ni = NULL;
165  int is_new = 0;
166 
169  );
170 
171  if (!chan) {
172  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
173  return -1;
174  }
175 
176  parse = ast_strdupa(value);
177  AST_STANDARD_APP_ARGS(args, parse);
178 
179  ast_channel_lock(chan);
180  if (!(datastore = ast_channel_datastore_find(chan, &scramble_datastore, NULL))) {
181  ast_channel_unlock(chan);
182  /* Allocate a new datastore to hold the reference to this audiohook information */
183  if (!(datastore = ast_datastore_alloc(&scramble_datastore, NULL)))
184  return 0;
185  if (!(ni = ast_calloc(1, sizeof(*ni)))) {
186  ast_datastore_free(datastore);
187  return 0;
188  }
191  is_new = 1;
192  } else {
193  ast_channel_unlock(chan);
194  ni = datastore->data;
195  }
196 
197  if (!strcasecmp(args.direction, "tx")) {
198  ni->tx = 1;
199  ni->rx = 0;
200  } else if (!strcasecmp(args.direction, "rx")) {
201  ni->rx = 0;
202  ni->tx = 1;
203  } else if (!strcasecmp(args.direction, "both")) {
204  ni->rx = 1;
205  ni->tx = 1;
206  } else if (!strcasecmp(args.direction, "remove")) {
207  return remove_scrambler(chan);
208  } else {
209  ast_log(LOG_ERROR, "Direction must be either RX, TX or remove\n");
210  return -1;
211  }
212 
213  if (is_new) {
214  datastore->data = ni;
215  ast_channel_lock(chan);
216  ast_channel_datastore_add(chan, datastore);
217  ast_channel_unlock(chan);
218  ast_audiohook_attach(chan, &ni->audiohook);
219  }
220 
221  return 0;
222 }
223 
225  .name = "SCRAMBLE",
226  .write = scramble_write,
227 };
228 
229 static int unload_module(void)
230 {
231  return ast_custom_function_unregister(&scramble_function);
232 }
233 
234 static int load_module(void)
235 {
236  return ast_custom_function_register(&scramble_function);
237 }
238 
239 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Frequency inverting voice scrambler");
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
static const struct ast_datastore_info scramble_datastore
Static structure for datastore information.
Definition: func_scramble.c:92
Asterisk main include file. File version handling, generic pbx functions.
unsigned short int rx
Definition: func_scramble.c:73
static void destroy_callback(void *data)
Definition: func_scramble.c:77
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int scramble_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Audiohooks Architecture.
int ast_audiohook_remove(struct ast_channel *chan, struct ast_audiohook *audiohook)
Remove an audiohook from a specified channel.
Definition: audiohook.c:764
#define AST_LOG_WARNING
Definition: logger.h:279
Structure for a data store type.
Definition: datastore.h:31
int ast_audiohook_attach(struct ast_channel *chan, struct ast_audiohook *audiohook)
Attach audiohook to channel.
Definition: audiohook.c:501
Structure for a data store object.
Definition: datastore.h:68
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2404
const char * args
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
int ast_audiohook_destroy(struct ast_audiohook *audiohook)
Destroys an audiohook structure.
Definition: audiohook.c:133
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
Utility functions.
ast_audiohook_manipulate_callback manipulate_callback
Definition: audiohook.h:117
int ast_audiohook_init(struct ast_audiohook *audiohook, enum ast_audiohook_type type, const char *source, enum ast_audiohook_init_flags flags)
Initialize an audiohook structure.
Definition: audiohook.c:108
#define ast_audiohook_unlock(ah)
Unlock an audiohook.
Definition: audiohook.h:300
#define ast_log
Definition: astobj2.c:42
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
Definition: lock.h:617
General Asterisk PBX channel definitions.
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
unsigned short int tx
Definition: func_scramble.c:72
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int remove_scrambler(struct ast_channel *chan)
Core PBX routines and definitions.
static struct ast_custom_function scramble_function
int ast_audiohook_detach(struct ast_audiohook *audiohook)
Detach audiohook from channel.
Definition: audiohook.c:579
#define LOG_ERROR
Definition: logger.h:285
unsigned short int state
Definition: func_scramble.c:74
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
static void freq_invert(short *amp, int samples)
Definition: func_scramble.c:99
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_audiohook audiohook
Definition: func_scramble.c:71
ast_audiohook_direction
Definition: audiohook.h:48
static int scramble_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
void * data
Definition: datastore.h:70
const char * ast_channel_name(const struct ast_channel *chan)
Data structure associated with a single frame of data.
enum ast_audiohook_status status
Definition: audiohook.h:107
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
union ast_frame::@263 data
enum ast_frame_type frametype
static int unload_module(void)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
direction
#define ast_audiohook_lock(ah)
Lock an audiohook.
Definition: audiohook.h:295
Asterisk module definitions.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
static int load_module(void)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
Definition: channel.c:2399
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define AST_APP_ARG(name)
Define an application argument.