2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
21 * \brief Save to raw, headerless G729 data.
22 * \note This is not an encoder/decoder. The codec fo g729 is only
23 * available with a commercial license from Digium, due to patent
24 * restrictions. Check http://www.digium.com for information.
25 * \arg Extensions: g729
31 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
42 #include "asterisk/lock.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/file.h"
45 #include "asterisk/logger.h"
46 #include "asterisk/sched.h"
47 #include "asterisk/module.h"
48 #include "asterisk/endian.h"
50 /* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */
52 /* Portions of the conversion code are by guido@sienanet.it */
54 #define BUF_SIZE 20 /* two G729 frames */
55 #define G729A_SAMPLES 160
57 static struct ast_frame
*g729_read(struct ast_filestream
*s
, int *whennext
)
60 /* Send a frame from the file to the appropriate channel */
61 s
->fr
.frametype
= AST_FRAME_VOICE
;
62 s
->fr
.subclass
= AST_FORMAT_G729A
;
64 s
->fr
.samples
= G729A_SAMPLES
;
65 AST_FRAME_SET_BUFFER(&s
->fr
, s
->buf
, AST_FRIENDLY_OFFSET
, BUF_SIZE
);
66 if ((res
= fread(s
->fr
.data
, 1, s
->fr
.datalen
, s
->f
)) != s
->fr
.datalen
) {
67 if (res
&& (res
!= 10)) /* XXX what for ? */
68 ast_log(LOG_WARNING
, "Short read (%d) (%s)!\n", res
, strerror(errno
));
71 *whennext
= s
->fr
.samples
;
75 static int g729_write(struct ast_filestream
*fs
, struct ast_frame
*f
)
78 if (f
->frametype
!= AST_FRAME_VOICE
) {
79 ast_log(LOG_WARNING
, "Asked to write non-voice frame!\n");
82 if (f
->subclass
!= AST_FORMAT_G729A
) {
83 ast_log(LOG_WARNING
, "Asked to write non-G729 frame (%d)!\n", f
->subclass
);
86 if (f
->datalen
% 10) {
87 ast_log(LOG_WARNING
, "Invalid data length, %d, should be multiple of 10\n", f
->datalen
);
90 if ((res
= fwrite(f
->data
, 1, f
->datalen
, fs
->f
)) != f
->datalen
) {
91 ast_log(LOG_WARNING
, "Bad write (%d/10): %s\n", res
, strerror(errno
));
97 static int g729_seek(struct ast_filestream
*fs
, off_t sample_offset
, int whence
)
100 off_t min
,cur
,max
,offset
=0;
103 fseeko(fs
->f
, 0, SEEK_END
);
106 bytes
= BUF_SIZE
* (sample_offset
/ G729A_SAMPLES
);
107 if (whence
== SEEK_SET
)
109 else if (whence
== SEEK_CUR
|| whence
== SEEK_FORCECUR
)
110 offset
= cur
+ bytes
;
111 else if (whence
== SEEK_END
)
112 offset
= max
- bytes
;
113 if (whence
!= SEEK_FORCECUR
) {
114 offset
= (offset
> max
)?max
:offset
;
116 /* protect against seeking beyond begining. */
117 offset
= (offset
< min
)?min
:offset
;
118 if (fseeko(fs
->f
, offset
, SEEK_SET
) < 0)
123 static int g729_trunc(struct ast_filestream
*fs
)
125 /* Truncate file to current length */
126 if (ftruncate(fileno(fs
->f
), ftello(fs
->f
)) < 0)
131 static off_t
g729_tell(struct ast_filestream
*fs
)
133 off_t offset
= ftello(fs
->f
);
134 return (offset
/BUF_SIZE
)*G729A_SAMPLES
;
137 static const struct ast_format g729_f
= {
140 .format
= AST_FORMAT_G729A
,
146 .buf_size
= BUF_SIZE
+ AST_FRIENDLY_OFFSET
,
149 static int load_module(void)
151 return ast_format_register(&g729_f
);
154 static int unload_module(void)
156 return ast_format_unregister(g729_f
.name
);
159 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Raw G729 data");