Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


format_gsm.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, 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 Save to raw, headerless GSM data.
22  * \arg File name extension: gsm
23  * \ingroup formats
24  */
25 
26 /*** MODULEINFO
27  <support_level>core</support_level>
28  ***/
29 
30 #include "asterisk.h"
31 
32 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 364578 $")
33 
34 #include "asterisk/mod_format.h"
35 #include "asterisk/module.h"
36 #include "asterisk/endian.h"
37 
38 #include "msgsm.h"
39 
40 /* Some Ideas for this code came from makegsme.c by Jeffrey Chilton */
41 
42 /* Portions of the conversion code are by guido@sienanet.it */
43 
44 #define GSM_FRAME_SIZE 33
45 #define GSM_SAMPLES 160
46 
47 /* silent gsm frame */
48 /* begin binary data: */
49 static const char gsm_silence[] = /* 33 */
50 {0xD8,0x20,0xA2,0xE1,0x5A,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49
51 ,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24
52 ,0x92,0x49,0x24};
53 /* end binary data. size = 33 bytes */
54 
55 static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext)
56 {
57  int res;
58 
62  s->fr.mallocd = 0;
63  if ((res = fread(s->fr.data.ptr, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) {
64  if (res)
65  ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
66  return NULL;
67  }
68  *whennext = s->fr.samples = GSM_SAMPLES;
69  return &s->fr;
70 }
71 
72 static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
73 {
74  int res;
75  unsigned char gsm[2*GSM_FRAME_SIZE];
76 
77  if (f->frametype != AST_FRAME_VOICE) {
78  ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
79  return -1;
80  }
81  if (f->subclass.codec != AST_FORMAT_GSM) {
82  ast_log(LOG_WARNING, "Asked to write non-GSM frame (%s)!\n", ast_getformatname(f->subclass.codec));
83  return -1;
84  }
85  if (!(f->datalen % 65)) {
86  /* This is in MSGSM format, need to be converted */
87  int len=0;
88  while(len < f->datalen) {
89  conv65(f->data.ptr + len, gsm);
90  if ((res = fwrite(gsm, 1, 2*GSM_FRAME_SIZE, fs->f)) != 2*GSM_FRAME_SIZE) {
91  ast_log(LOG_WARNING, "Bad write (%d/66): %s\n", res, strerror(errno));
92  return -1;
93  }
94  len += 65;
95  }
96  } else {
97  if (f->datalen % GSM_FRAME_SIZE) {
98  ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 33\n", f->datalen);
99  return -1;
100  }
101  if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
102  ast_log(LOG_WARNING, "Bad write (%d/33): %s\n", res, strerror(errno));
103  return -1;
104  }
105  }
106  return 0;
107 }
108 
109 static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
110 {
111  off_t offset = 0, min = 0, cur, max, distance;
112 
113  if ((cur = ftello(fs->f)) < 0) {
114  ast_log(AST_LOG_WARNING, "Unable to determine current position in g719 filestream %p: %s\n", fs, strerror(errno));
115  return -1;
116  }
117 
118  if (fseeko(fs->f, 0, SEEK_END) < 0) {
119  ast_log(AST_LOG_WARNING, "Unable to seek to end of g719 filestream %p: %s\n", fs, strerror(errno));
120  return -1;
121  }
122 
123  if ((max = ftello(fs->f)) < 0) {
124  ast_log(AST_LOG_WARNING, "Unable to determine max position in g719 filestream %p: %s\n", fs, strerror(errno));
125  return -1;
126  }
127 
128  /* have to fudge to frame here, so not fully to sample */
129  distance = (sample_offset / GSM_SAMPLES) * GSM_FRAME_SIZE;
130  if (whence == SEEK_SET) {
131  offset = distance;
132  } else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) {
133  offset = distance + cur;
134  } else if (whence == SEEK_END) {
135  offset = max - distance;
136  }
137 
138  /* Always protect against seeking past the begining. */
139  offset = (offset < min)?min:offset;
140  if (whence != SEEK_FORCECUR) {
141  offset = (offset > max)?max:offset;
142  } else if (offset > max) {
143  int i;
144  fseeko(fs->f, 0, SEEK_END);
145  for (i=0; i< (offset - max) / GSM_FRAME_SIZE; i++) {
146  if (!fwrite(gsm_silence, 1, GSM_FRAME_SIZE, fs->f)) {
147  ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
148  }
149  }
150  }
151  return fseeko(fs->f, offset, SEEK_SET);
152 }
153 
154 static int gsm_trunc(struct ast_filestream *fs)
155 {
156  int fd;
157  off_t cur;
158 
159  if ((fd = fileno(fs->f)) < 0) {
160  ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for gsm filestream %p: %s\n", fs, strerror(errno));
161  return -1;
162  }
163  if ((cur = ftello(fs->f)) < 0) {
164  ast_log(AST_LOG_WARNING, "Unable to determine current position in gsm filestream %p: %s\n", fs, strerror(errno));
165  return -1;
166  }
167  /* Truncate file to current length */
168  return ftruncate(fd, cur);
169 }
170 
171 static off_t gsm_tell(struct ast_filestream *fs)
172 {
173  off_t offset = ftello(fs->f);
174 
175  if (offset < 0) {
176  ast_log(AST_LOG_WARNING, "Unable to determine offset for gsm filestream %p: %s\n", fs, strerror(errno));
177  return 0;
178  }
179 
180  return (offset / GSM_FRAME_SIZE) * GSM_SAMPLES;
181 }
182 
183 static const struct ast_format gsm_f = {
184  .name = "gsm",
185  .exts = "gsm",
186  .format = AST_FORMAT_GSM,
187  .write = gsm_write,
188  .seek = gsm_seek,
189  .trunc = gsm_trunc,
190  .tell = gsm_tell,
191  .read = gsm_read,
192  .buf_size = 2*GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET, /* 2 gsm frames */
193 };
194 
195 static int load_module(void)
196 {
197  if (ast_format_register(&gsm_f))
200 }
201 
202 static int unload_module(void)
203 {
204  return ast_format_unregister(gsm_f.name);
205 }
206 
208  .load = load_module,
209  .unload = unload_module,
210  .load_pri = AST_MODPRI_APP_DEPEND
211 );
union ast_frame_subclass subclass
Definition: frame.h:146
Asterisk main include file. File version handling, generic pbx functions.
#define ast_format_register(f)
Definition: mod_format.h:131
int offset
Definition: frame.h:156
static struct ast_frame * gsm_read(struct ast_filestream *s, int *whennext)
Definition: format_gsm.c:55
static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
Definition: format_gsm.c:109
#define GSM_FRAME_SIZE
Definition: format_gsm.c:44
void * ptr
Definition: frame.h:160
#define LOG_WARNING
Definition: logger.h:144
#define AST_LOG_WARNING
Definition: logger.h:149
Each supported file format is described by the following structure.
Definition: mod_format.h:43
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:374
format_t codec
Definition: frame.h:137
static int gsm_trunc(struct ast_filestream *fs)
Definition: format_gsm.c:154
static off_t gsm_tell(struct ast_filestream *fs)
Definition: format_gsm.c:171
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
Definition: frame.h:183
static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
Definition: format_gsm.c:72
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Definition: frame.h:204
Asterisk architecture endianess compatibility definitions.
int datalen
Definition: frame.h:148
struct ast_frame fr
Definition: mod_format.h:117
static void conv65(wav_byte *c, gsm_byte *d)
Definition: msgsm.h:455
static int load_module(void)
Definition: format_gsm.c:195
int ast_format_unregister(const char *name)
Unregisters a file format.
Definition: file.c:104
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
char name[80]
Definition: mod_format.h:44
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
#define SEEK_FORCECUR
Definition: file.h:50
static struct ast_format f[]
Definition: format_g726.c:181
int mallocd
Definition: frame.h:152
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:100
static int unload_module(void)
Definition: format_gsm.c:202
Data structure associated with a single frame of data.
Definition: frame.h:142
static const char gsm_silence[]
Definition: format_gsm.c:49
enum ast_frame_type frametype
Definition: frame.h:144
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
#define GSM_SAMPLES
Definition: format_gsm.c:45
union ast_frame::@172 data
#define AST_FORMAT_GSM
Definition: frame.h:244
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int samples
Definition: frame.h:150
static struct ast_format gsm_f
Definition: format_gsm.c:183