format_g729.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Save to raw, headerless G729 data.
  5. *
  6. * Copyright (C) 1999, Mark Spencer
  7. *
  8. * Mark Spencer <markster@linux-support.net>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #include <asterisk/lock.h>
  14. #include <asterisk/channel.h>
  15. #include <asterisk/file.h>
  16. #include <asterisk/logger.h>
  17. #include <asterisk/sched.h>
  18. #include <asterisk/module.h>
  19. #include <netinet/in.h>
  20. #include <arpa/inet.h>
  21. #include <stdlib.h>
  22. #include <sys/time.h>
  23. #include <stdio.h>
  24. #include <unistd.h>
  25. #include <errno.h>
  26. #include <string.h>
  27. #include "asterisk/endian.h"
  28. /* Some Ideas for this code came from makeg729e.c by Jeffrey Chilton */
  29. /* Portions of the conversion code are by guido@sienanet.it */
  30. struct ast_filestream {
  31. void *reserved[AST_RESERVED_POINTERS];
  32. /* Believe it or not, we must decode/recode to account for the
  33. weird MS format */
  34. /* This is what a filestream means to us */
  35. int fd; /* Descriptor */
  36. struct ast_frame fr; /* Frame information */
  37. char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
  38. char empty; /* Empty character */
  39. unsigned char g729[20]; /* Two Real G729 Frames */
  40. };
  41. AST_MUTEX_DEFINE_STATIC(g729_lock);
  42. static int glistcnt = 0;
  43. static char *name = "g729";
  44. static char *desc = "Raw G729 data";
  45. static char *exts = "g729";
  46. static struct ast_filestream *g729_open(int fd)
  47. {
  48. /* We don't have any header to read or anything really, but
  49. if we did, it would go here. We also might want to check
  50. and be sure it's a valid file. */
  51. struct ast_filestream *tmp;
  52. if ((tmp = malloc(sizeof(struct ast_filestream)))) {
  53. memset(tmp, 0, sizeof(struct ast_filestream));
  54. if (ast_mutex_lock(&g729_lock)) {
  55. ast_log(LOG_WARNING, "Unable to lock g729 list\n");
  56. free(tmp);
  57. return NULL;
  58. }
  59. tmp->fd = fd;
  60. tmp->fr.data = tmp->g729;
  61. tmp->fr.frametype = AST_FRAME_VOICE;
  62. tmp->fr.subclass = AST_FORMAT_G729A;
  63. /* datalen will vary for each frame */
  64. tmp->fr.src = name;
  65. tmp->fr.mallocd = 0;
  66. glistcnt++;
  67. ast_mutex_unlock(&g729_lock);
  68. ast_update_use_count();
  69. }
  70. return tmp;
  71. }
  72. static struct ast_filestream *g729_rewrite(int fd, char *comment)
  73. {
  74. /* We don't have any header to read or anything really, but
  75. if we did, it would go here. We also might want to check
  76. and be sure it's a valid file. */
  77. struct ast_filestream *tmp;
  78. if ((tmp = malloc(sizeof(struct ast_filestream)))) {
  79. memset(tmp, 0, sizeof(struct ast_filestream));
  80. if (ast_mutex_lock(&g729_lock)) {
  81. ast_log(LOG_WARNING, "Unable to lock g729 list\n");
  82. free(tmp);
  83. return NULL;
  84. }
  85. tmp->fd = fd;
  86. glistcnt++;
  87. ast_mutex_unlock(&g729_lock);
  88. ast_update_use_count();
  89. } else
  90. ast_log(LOG_WARNING, "Out of memory\n");
  91. return tmp;
  92. }
  93. static void g729_close(struct ast_filestream *s)
  94. {
  95. if (ast_mutex_lock(&g729_lock)) {
  96. ast_log(LOG_WARNING, "Unable to lock g729 list\n");
  97. return;
  98. }
  99. glistcnt--;
  100. ast_mutex_unlock(&g729_lock);
  101. ast_update_use_count();
  102. close(s->fd);
  103. free(s);
  104. s = NULL;
  105. }
  106. static struct ast_frame *g729_read(struct ast_filestream *s, int *whennext)
  107. {
  108. int res;
  109. /* Send a frame from the file to the appropriate channel */
  110. s->fr.frametype = AST_FRAME_VOICE;
  111. s->fr.subclass = AST_FORMAT_G729A;
  112. s->fr.offset = AST_FRIENDLY_OFFSET;
  113. s->fr.samples = 160;
  114. s->fr.datalen = 20;
  115. s->fr.mallocd = 0;
  116. s->fr.data = s->g729;
  117. if ((res = read(s->fd, s->g729, 20)) != 20) {
  118. if (res && (res != 10))
  119. ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
  120. return NULL;
  121. }
  122. *whennext = s->fr.samples;
  123. return &s->fr;
  124. }
  125. static int g729_write(struct ast_filestream *fs, struct ast_frame *f)
  126. {
  127. int res;
  128. if (f->frametype != AST_FRAME_VOICE) {
  129. ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
  130. return -1;
  131. }
  132. if (f->subclass != AST_FORMAT_G729A) {
  133. ast_log(LOG_WARNING, "Asked to write non-G729 frame (%d)!\n", f->subclass);
  134. return -1;
  135. }
  136. if (f->datalen % 10) {
  137. ast_log(LOG_WARNING, "Invalid data length, %d, should be multiple of 10\n", f->datalen);
  138. return -1;
  139. }
  140. if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
  141. ast_log(LOG_WARNING, "Bad write (%d/10): %s\n", res, strerror(errno));
  142. return -1;
  143. }
  144. return 0;
  145. }
  146. static char *g729_getcomment(struct ast_filestream *s)
  147. {
  148. return NULL;
  149. }
  150. static int g729_seek(struct ast_filestream *fs, long sample_offset, int whence)
  151. {
  152. long bytes;
  153. off_t min,cur,max,offset=0;
  154. min = 0;
  155. cur = lseek(fs->fd, 0, SEEK_CUR);
  156. max = lseek(fs->fd, 0, SEEK_END);
  157. bytes = 20 * (sample_offset / 160);
  158. if (whence == SEEK_SET)
  159. offset = bytes;
  160. else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
  161. offset = cur + bytes;
  162. else if (whence == SEEK_END)
  163. offset = max - bytes;
  164. if (whence != SEEK_FORCECUR) {
  165. offset = (offset > max)?max:offset;
  166. }
  167. // protect against seeking beyond begining.
  168. offset = (offset < min)?min:offset;
  169. if (lseek(fs->fd, offset, SEEK_SET) < 0)
  170. return -1;
  171. return 0;
  172. }
  173. static int g729_trunc(struct ast_filestream *fs)
  174. {
  175. /* Truncate file to current length */
  176. if (ftruncate(fs->fd, lseek(fs->fd, 0, SEEK_CUR)) < 0)
  177. return -1;
  178. return 0;
  179. }
  180. static long g729_tell(struct ast_filestream *fs)
  181. {
  182. off_t offset;
  183. offset = lseek(fs->fd, 0, SEEK_CUR);
  184. return (offset/20)*160;
  185. }
  186. int load_module()
  187. {
  188. return ast_format_register(name, exts, AST_FORMAT_G729A,
  189. g729_open,
  190. g729_rewrite,
  191. g729_write,
  192. g729_seek,
  193. g729_trunc,
  194. g729_tell,
  195. g729_read,
  196. g729_close,
  197. g729_getcomment);
  198. }
  199. int unload_module()
  200. {
  201. return ast_format_unregister(name);
  202. }
  203. int usecount()
  204. {
  205. int res;
  206. if (ast_mutex_lock(&g729_lock)) {
  207. ast_log(LOG_WARNING, "Unable to lock g729 list\n");
  208. return -1;
  209. }
  210. res = glistcnt;
  211. ast_mutex_unlock(&g729_lock);
  212. return res;
  213. }
  214. char *description()
  215. {
  216. return desc;
  217. }
  218. char *key()
  219. {
  220. return ASTERISK_GPL_KEY;
  221. }