format_pcm.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Flat, binary, ulaw PCM 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 160 /* 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_channel *owner;
  34. struct ast_frame fr; /* Frame information */
  35. char waste[AST_FRIENDLY_OFFSET]; /* Buffer for sending frames, etc */
  36. char empty; /* Empty character */
  37. unsigned char buf[BUF_SIZE]; /* Output Buffer */
  38. struct timeval last;
  39. };
  40. AST_MUTEX_DEFINE_STATIC(pcm_lock);
  41. static int glistcnt = 0;
  42. static char *name = "pcm";
  43. static char *desc = "Raw uLaw 8khz Audio support (PCM)";
  44. static char *exts = "pcm|ulaw|ul|mu";
  45. static struct ast_filestream *pcm_open(int fd)
  46. {
  47. /* We don't have any header to read or anything really, but
  48. if we did, it would go here. We also might want to check
  49. and be sure it's a valid file. */
  50. struct ast_filestream *tmp;
  51. if ((tmp = malloc(sizeof(struct ast_filestream)))) {
  52. memset(tmp, 0, sizeof(struct ast_filestream));
  53. if (ast_mutex_lock(&pcm_lock)) {
  54. ast_log(LOG_WARNING, "Unable to lock pcm list\n");
  55. free(tmp);
  56. return NULL;
  57. }
  58. tmp->fd = fd;
  59. tmp->fr.data = tmp->buf;
  60. tmp->fr.frametype = AST_FRAME_VOICE;
  61. tmp->fr.subclass = AST_FORMAT_ULAW;
  62. /* datalen will vary for each frame */
  63. tmp->fr.src = name;
  64. tmp->fr.mallocd = 0;
  65. glistcnt++;
  66. ast_mutex_unlock(&pcm_lock);
  67. ast_update_use_count();
  68. }
  69. return tmp;
  70. }
  71. static struct ast_filestream *pcm_rewrite(int fd, char *comment)
  72. {
  73. /* We don't have any header to read or anything really, but
  74. if we did, it would go here. We also might want to check
  75. and be sure it's a valid file. */
  76. struct ast_filestream *tmp;
  77. if ((tmp = malloc(sizeof(struct ast_filestream)))) {
  78. memset(tmp, 0, sizeof(struct ast_filestream));
  79. if (ast_mutex_lock(&pcm_lock)) {
  80. ast_log(LOG_WARNING, "Unable to lock pcm list\n");
  81. free(tmp);
  82. return NULL;
  83. }
  84. tmp->fd = fd;
  85. glistcnt++;
  86. ast_mutex_unlock(&pcm_lock);
  87. ast_update_use_count();
  88. } else
  89. ast_log(LOG_WARNING, "Out of memory\n");
  90. return tmp;
  91. }
  92. static void pcm_close(struct ast_filestream *s)
  93. {
  94. if (ast_mutex_lock(&pcm_lock)) {
  95. ast_log(LOG_WARNING, "Unable to lock pcm list\n");
  96. return;
  97. }
  98. glistcnt--;
  99. ast_mutex_unlock(&pcm_lock);
  100. ast_update_use_count();
  101. close(s->fd);
  102. free(s);
  103. s = NULL;
  104. }
  105. static struct ast_frame *pcm_read(struct ast_filestream *s, int *whennext)
  106. {
  107. int res;
  108. int delay;
  109. /* Send a frame from the file to the appropriate channel */
  110. s->fr.frametype = AST_FRAME_VOICE;
  111. s->fr.subclass = AST_FORMAT_ULAW;
  112. s->fr.offset = AST_FRIENDLY_OFFSET;
  113. s->fr.mallocd = 0;
  114. s->fr.data = s->buf;
  115. if ((res = read(s->fd, s->buf, BUF_SIZE)) < 1) {
  116. if (res)
  117. ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno));
  118. return NULL;
  119. }
  120. s->fr.samples = res;
  121. s->fr.datalen = res;
  122. delay = s->fr.samples;
  123. *whennext = delay;
  124. return &s->fr;
  125. }
  126. static int pcm_write(struct ast_filestream *fs, struct ast_frame *f)
  127. {
  128. int res;
  129. if (f->frametype != AST_FRAME_VOICE) {
  130. ast_log(LOG_WARNING, "Asked to write non-voice frame!\n");
  131. return -1;
  132. }
  133. if (f->subclass != AST_FORMAT_ULAW) {
  134. ast_log(LOG_WARNING, "Asked to write non-ulaw frame (%d)!\n", f->subclass);
  135. return -1;
  136. }
  137. if ((res = write(fs->fd, f->data, f->datalen)) != f->datalen) {
  138. ast_log(LOG_WARNING, "Bad write (%d/%d): %s\n", res, f->datalen, strerror(errno));
  139. return -1;
  140. }
  141. return 0;
  142. }
  143. static int pcm_seek(struct ast_filestream *fs, long sample_offset, int whence)
  144. {
  145. off_t offset=0,min,cur,max;
  146. min = 0;
  147. cur = lseek(fs->fd, 0, SEEK_CUR);
  148. max = lseek(fs->fd, 0, SEEK_END);
  149. if (whence == SEEK_SET)
  150. offset = sample_offset;
  151. else if (whence == SEEK_CUR || whence == SEEK_FORCECUR)
  152. offset = sample_offset + cur;
  153. else if (whence == SEEK_END)
  154. offset = max - sample_offset;
  155. if (whence != SEEK_FORCECUR) {
  156. offset = (offset > max)?max:offset;
  157. }
  158. // always protect against seeking past begining.
  159. offset = (offset < min)?min:offset;
  160. return lseek(fs->fd, offset, SEEK_SET);
  161. }
  162. static int pcm_trunc(struct ast_filestream *fs)
  163. {
  164. return ftruncate(fs->fd, lseek(fs->fd,0,SEEK_CUR));
  165. }
  166. static long pcm_tell(struct ast_filestream *fs)
  167. {
  168. off_t offset;
  169. offset = lseek(fs->fd, 0, SEEK_CUR);
  170. return offset;
  171. }
  172. static char *pcm_getcomment(struct ast_filestream *s)
  173. {
  174. return NULL;
  175. }
  176. int load_module()
  177. {
  178. return ast_format_register(name, exts, AST_FORMAT_ULAW,
  179. pcm_open,
  180. pcm_rewrite,
  181. pcm_write,
  182. pcm_seek,
  183. pcm_trunc,
  184. pcm_tell,
  185. pcm_read,
  186. pcm_close,
  187. pcm_getcomment);
  188. }
  189. int unload_module()
  190. {
  191. return ast_format_unregister(name);
  192. }
  193. int usecount()
  194. {
  195. int res;
  196. if (ast_mutex_lock(&pcm_lock)) {
  197. ast_log(LOG_WARNING, "Unable to lock pcm list\n");
  198. return -1;
  199. }
  200. res = glistcnt;
  201. ast_mutex_unlock(&pcm_lock);
  202. return res;
  203. }
  204. char *description()
  205. {
  206. return desc;
  207. }
  208. char *key()
  209. {
  210. return ASTERISK_GPL_KEY;
  211. }