Asterisk - The Open Source Telephony Project  18.5.0
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 <[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 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 #include "asterisk/mod_format.h"
33 #include "asterisk/module.h"
34 #include "asterisk/endian.h"
35 #include "asterisk/format_cache.h"
36 
37 #include "msgsm.h"
38 
39 /* Some Ideas for this code came from makegsme.c by Jeffrey Chilton */
40 
41 /* Portions of the conversion code are by [email protected] */
42 
43 #define GSM_FRAME_SIZE 33
44 #define GSM_SAMPLES 160
45 
46 /* silent gsm frame */
47 /* begin binary data: */
48 static const char gsm_silence[] = /* 33 */
49 {0xD8,0x20,0xA2,0xE1,0x5A,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49
50 ,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24,0x92,0x49,0x24,0x50,0x00,0x49,0x24
51 ,0x92,0x49,0x24};
52 /* end binary data. size = 33 bytes */
53 
54 static struct ast_frame *gsm_read(struct ast_filestream *s, int *whennext)
55 {
56  size_t res;
57 
59  if ((res = fread(s->fr.data.ptr, 1, GSM_FRAME_SIZE, s->f)) != GSM_FRAME_SIZE) {
60  if (res) {
61  ast_log(LOG_WARNING, "Short read of %s data (expected %d bytes, read %zu): %s\n",
63  strerror(errno));
64  }
65  return NULL;
66  }
67  *whennext = s->fr.samples = GSM_SAMPLES;
68  return &s->fr;
69 }
70 
71 static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
72 {
73  int res;
74  unsigned char gsm[2*GSM_FRAME_SIZE];
75 
76  if (!(f->datalen % 65)) {
77  /* This is in MSGSM format, need to be converted */
78  int len=0;
79  while(len < f->datalen) {
80  conv65(f->data.ptr + len, gsm);
81  if ((res = fwrite(gsm, 1, 2*GSM_FRAME_SIZE, fs->f)) != 2*GSM_FRAME_SIZE) {
82  ast_log(LOG_WARNING, "Bad write (%d/66): %s\n", res, strerror(errno));
83  return -1;
84  }
85  len += 65;
86  }
87  } else {
88  if (f->datalen % GSM_FRAME_SIZE) {
89  ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 33\n", f->datalen);
90  return -1;
91  }
92  if ((res = fwrite(f->data.ptr, 1, f->datalen, fs->f)) != f->datalen) {
93  ast_log(LOG_WARNING, "Bad write (%d/33): %s\n", res, strerror(errno));
94  return -1;
95  }
96  }
97  return 0;
98 }
99 
100 static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
101 {
102  off_t offset = 0, min = 0, cur, max, distance;
103 
104  if ((cur = ftello(fs->f)) < 0) {
105  ast_log(AST_LOG_WARNING, "Unable to determine current position in g719 filestream %p: %s\n", fs, strerror(errno));
106  return -1;
107  }
108 
109  if (fseeko(fs->f, 0, SEEK_END) < 0) {
110  ast_log(AST_LOG_WARNING, "Unable to seek to end of g719 filestream %p: %s\n", fs, strerror(errno));
111  return -1;
112  }
113 
114  if ((max = ftello(fs->f)) < 0) {
115  ast_log(AST_LOG_WARNING, "Unable to determine max position in g719 filestream %p: %s\n", fs, strerror(errno));
116  return -1;
117  }
118 
119  /* have to fudge to frame here, so not fully to sample */
120  distance = (sample_offset / GSM_SAMPLES) * GSM_FRAME_SIZE;
121  if (whence == SEEK_SET) {
122  offset = distance;
123  } else if (whence == SEEK_CUR || whence == SEEK_FORCECUR) {
124  offset = distance + cur;
125  } else if (whence == SEEK_END) {
126  offset = max - distance;
127  }
128 
129  /* Always protect against seeking past the begining. */
130  offset = (offset < min)?min:offset;
131  if (whence != SEEK_FORCECUR) {
132  offset = (offset > max)?max:offset;
133  } else if (offset > max) {
134  int i;
135  fseeko(fs->f, 0, SEEK_END);
136  for (i=0; i< (offset - max) / GSM_FRAME_SIZE; i++) {
137  if (fwrite(gsm_silence, 1, GSM_FRAME_SIZE, fs->f) != GSM_FRAME_SIZE) {
138  ast_log(LOG_WARNING, "fwrite() failed: %s\n", strerror(errno));
139  }
140  }
141  }
142  return fseeko(fs->f, offset, SEEK_SET);
143 }
144 
145 static int gsm_trunc(struct ast_filestream *fs)
146 {
147  int fd;
148  off_t cur;
149 
150  if ((fd = fileno(fs->f)) < 0) {
151  ast_log(AST_LOG_WARNING, "Unable to determine file descriptor for gsm filestream %p: %s\n", fs, strerror(errno));
152  return -1;
153  }
154  if ((cur = ftello(fs->f)) < 0) {
155  ast_log(AST_LOG_WARNING, "Unable to determine current position in gsm filestream %p: %s\n", fs, strerror(errno));
156  return -1;
157  }
158  /* Truncate file to current length */
159  return ftruncate(fd, cur);
160 }
161 
162 static off_t gsm_tell(struct ast_filestream *fs)
163 {
164  off_t offset = ftello(fs->f);
165 
166  if (offset < 0) {
167  ast_log(AST_LOG_WARNING, "Unable to determine offset for gsm filestream %p: %s\n", fs, strerror(errno));
168  return 0;
169  }
170 
171  return (offset / GSM_FRAME_SIZE) * GSM_SAMPLES;
172 }
173 
174 static struct ast_format_def gsm_f = {
175  .name = "gsm",
176  .exts = "gsm",
177  .write = gsm_write,
178  .seek = gsm_seek,
179  .trunc = gsm_trunc,
180  .tell = gsm_tell,
181  .read = gsm_read,
182  .buf_size = 2*GSM_FRAME_SIZE + AST_FRIENDLY_OFFSET, /* 2 gsm frames */
183 };
184 
185 static int load_module(void)
186 {
187  gsm_f.format = ast_format_gsm;
188  if (ast_format_def_register(&gsm_f))
191 }
192 
193 static int unload_module(void)
194 {
195  return ast_format_def_unregister(gsm_f.name);
196 }
197 
199  .support_level = AST_MODULE_SUPPORT_CORE,
200  .load = load_module,
201  .unload = unload_module,
202  .load_pri = AST_MODPRI_APP_DEPEND
203 );
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_frame * gsm_read(struct ast_filestream *s, int *whennext)
Definition: format_gsm.c:54
static int gsm_seek(struct ast_filestream *fs, off_t sample_offset, int whence)
Definition: format_gsm.c:100
#define GSM_FRAME_SIZE
Definition: format_gsm.c:43
#define LOG_WARNING
Definition: logger.h:274
#define AST_LOG_WARNING
Definition: logger.h:279
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
static int gsm_trunc(struct ast_filestream *fs)
Definition: format_gsm.c:145
#define NULL
Definition: resample.c:96
Each supported file format is described by the following structure.
Definition: mod_format.h:43
struct ast_frame_subclass subclass
Header for providers of file and format handling routines. Clients of these routines should include "...
static off_t gsm_tell(struct ast_filestream *fs)
Definition: format_gsm.c:162
int ast_format_def_unregister(const char *name)
Unregisters a file format.
Definition: file.c:162
#define ast_log
Definition: astobj2.c:42
static int gsm_write(struct ast_filestream *fs, struct ast_frame *f)
Definition: format_gsm.c:71
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Asterisk architecture endianess compatibility definitions.
#define ast_format_def_register(f)
Definition: mod_format.h:136
struct ast_format * ast_format_gsm
Built-in cached gsm format.
Definition: format_cache.c:101
struct ast_frame fr
frame produced by read, typically
Definition: mod_format.h:122
static void conv65(wav_byte *c, gsm_byte *d)
Definition: msgsm.h:457
struct ast_format * format
Definition: mod_format.h:48
static int load_module(void)
Definition: format_gsm.c:185
#define AST_FRAME_SET_BUFFER(fr, _base, _ofs, _datalen)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
char name[80]
Definition: mod_format.h:44
static struct ast_format_def gsm_f
Definition: format_gsm.c:174
#define SEEK_FORCECUR
Definition: file.h:51
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Definition: mod_format.h:101
static int unload_module(void)
Definition: format_gsm.c:193
Data structure associated with a single frame of data.
static const char gsm_silence[]
Definition: format_gsm.c:48
union ast_frame::@263 data
struct ast_format * format
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define GSM_SAMPLES
Definition: format_gsm.c:44
#define min(a, b)
Definition: f2c.h:197
Media Format Cache API.
#define max(a, b)
Definition: f2c.h:198