format_vox.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Flat, binary, ADPCM vox file format.
  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. #define BUF_SIZE 80 /* 160 samples */
  29. struct ast_filestream {
  30. void *reserved[AST_RESERVED_POINTERS];
  31. /* This is what a filestream means to us */
  32. int fd; /* Descriptor */
  33. struct ast_frame fr; /* Frame information */
  34. char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
  35. char empty; /* Empty character */
  36. unsigned char buf[BUF_SIZE]; /* Output Buffer */
  37. int lasttimeout;
  38. struct timeval last;
  39. short signal; /* Signal level (file side) */
  40. short ssindex; /* Signal ssindex (file side) */
  41. unsigned char zero_count; /* counter of consecutive zero samples */
  42. unsigned char next_flag;
  43. };
  44. AST_MUTEX_DEFINE_STATIC(vox_lock);
  45. static int glistcnt = 0;
  46. static char *name = "vox";
  47. static char *desc = "Dialogic VOX (ADPCM) File Format";
  48. static char *exts = "vox";
  49. static struct ast_filestream *vox_open(int fd)
  50. {
  51. /* We don't have any header to read or anything really, but
  52. if we did, it would go here. We also might want to check
  53. and be sure it's a valid file. */
  54. struct ast_filestream *tmp;
  55. if ((tmp = malloc(sizeof(struct ast_filestream)))) {
  56. memset(tmp, 0, sizeof(struct ast_filestream));
  57. if (ast_mutex_lock(&vox_lock)) {
  58. ast_log(LOG_WARNING, "Unable to lock vox list\n");
  59. free(tmp);
  60. return NULL;
  61. }
  62. tmp->fd = fd;
  63. tmp->fr.data = tmp->buf;
  64. tmp->fr.frametype = AST_FRAME_VOICE;
  65. tmp->fr.subclass = AST_FORMAT_ADPCM;
  66. /* datalen will vary for each frame */
  67. tmp->fr.src = name;
  68. tmp->fr.mallocd = 0;
  69. tmp->lasttimeout = -1;
  70. glistcnt++;
  71. ast_mutex_unlock(&vox_lock);
  72. ast_update_use_count();
  73. }
  74. return tmp;
  75. }
  76. static struct ast_filestream *vox_rewrite(int fd, char *comment)
  77. {
  78. /* We don't have any header to read or anything really, but
  79. if we did, it would go here. We also might want to check
  80. and be sure it's a valid file. */
  81. struct ast_filestream *tmp;
  82. if ((tmp = malloc(sizeof(struct ast_filestream)))) {
  83. memset(tmp, 0, sizeof(struct ast_filestream));
  84. if (ast_mutex_lock(&vox_lock)) {
  85. ast_log(LOG_WARNING, "Unable to lock vox list\n");
  86. free(tmp);
  87. return NULL;
  88. }
  89. tmp->fd = fd;
  90. glistcnt++;
  91. ast_mutex_unlock(&vox_lock);
  92. ast_update_use_count();
  93. } else
  94. ast_log(LOG_WARNING, "Out of memory\n");
  95. return tmp;
  96. }
  97. static void vox_close(struct ast_filestream *s)
  98. {
  99. if (ast_mutex_lock(&vox_lock)) {
  100. ast_log(LOG_WARNING, "Unable to lock vox list\n");
  101. return;
  102. }
  103. glistcnt--;
  104. ast_mutex_unlock(&vox_lock);
  105. ast_update_use_count();
  106. close(s->fd);
  107. free(s);
  108. s = NULL;
  109. }
  110. static struct ast_frame *vox_read(struct ast_filestream *s, int *whennext)
  111. {
  112. int res;
  113. /* Send a frame from the file to the appropriate channel */
  114. s->fr.frametype = AST_FRAME_VOICE;
  115. s->fr.subclass = AST_FORMAT_ADPCM;
  116. s->fr.offset = AST_FRIENDLY_OFFSET;
  117. s->fr.mallocd = 0;
  118. s->fr.data = s->buf;
  119. if ((res = read(s->fd, s->buf, BUF_SIZE)) < 1) {
  120. if (res)
  121. ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
  122. return NULL;
  123. }
  124. s->fr.samples = res * 2;
  125. s->fr.datalen = res;
  126. *whennext = s->fr.samples;
  127. return &s->fr;
  128. }
  129. static int vox_write(struct ast_filestream *fs, struct ast_frame *f)
  130. {
  131. int res;
  132. if (f->frametype != AST_FRAME_VOICE) {
  133. ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
  134. return -1;
  135. }
  136. if (f->subclass != AST_FORMAT_ADPCM) {
  137. ast_log(LOG_WARNING, "Asked to write non-ADPCM frame (%d)!\n", f->subclass);
  138. return -1;
  139. }
  140. if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
  141. ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
  142. return -1;
  143. }
  144. return 0;
  145. }
  146. static char *vox_getcomment(struct ast_filestream *s)
  147. {
  148. return NULL;
  149. }
  150. static int vox_seek(struct ast_filestream *fs, long sample_offset, int whence)
  151. {
  152. off_t offset=0,min,cur,max,distance;
  153. min = 0;
  154. cur = lseek(fs->fd, 0, SEEK_CUR);
  155. max = lseek(fs->fd, 0, SEEK_END);
  156. /* have to fudge to frame here, so not fully to sample */
  157. distance = sample_offset/2;
  158. if(whence == SEEK_SET)
  159. offset = distance;
  160. else if(whence == SEEK_CUR || whence == SEEK_FORCECUR)
  161. offset = distance + cur;
  162. else if(whence == SEEK_END)
  163. offset = max - distance;
  164. if (whence != SEEK_FORCECUR) {
  165. offset = (offset > max)?max:offset;
  166. offset = (offset < min)?min:offset;
  167. }
  168. return lseek(fs->fd, offset, SEEK_SET);
  169. }
  170. static int vox_trunc(struct ast_filestream *fs)
  171. {
  172. return ftruncate(fs->fd, lseek(fs->fd,0,SEEK_CUR));
  173. }
  174. static long vox_tell(struct ast_filestream *fs)
  175. {
  176. off_t offset;
  177. offset = lseek(fs->fd, 0, SEEK_CUR);
  178. return offset;
  179. }
  180. int load_module()
  181. {
  182. return ast_format_register(name, exts, AST_FORMAT_ADPCM,
  183. vox_open,
  184. vox_rewrite,
  185. vox_write,
  186. vox_seek,
  187. vox_trunc,
  188. vox_tell,
  189. vox_read,
  190. vox_close,
  191. vox_getcomment);
  192. }
  193. int unload_module()
  194. {
  195. return ast_format_unregister(name);
  196. }
  197. int usecount()
  198. {
  199. int res;
  200. if (ast_mutex_lock(&vox_lock)) {
  201. ast_log(LOG_WARNING, "Unable to lock vox list\n");
  202. return -1;
  203. }
  204. res = glistcnt;
  205. ast_mutex_unlock(&vox_lock);
  206. return res;
  207. }
  208. char *description()
  209. {
  210. return desc;
  211. }
  212. char *key()
  213. {
  214. return ASTERISK_GPL_KEY;
  215. }