audioaec.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #include "precompile.h"
  2. #include "audioaec.h"
  3. #include "audioengine.h"
  4. #include <speex/speex_echo.h>
  5. static apr_status_t read_frame(void *self, audioframe_t *frame)
  6. {
  7. audioaec_t *aec = CONTAINING_RECORD(self, audioaec_t, base);
  8. apr_status_t status = APR_SUCCESS;
  9. if (aec->opt & AUDIO_AEC_OPT_READ_AS_CAPTURE) {
  10. aec->tmp_capture_frame.size = SUGGEST_FRAME_SIZE;
  11. status = aec->base.downstream->vtbl->read_frame(aec->base.downstream, &aec->tmp_capture_frame);
  12. if (status == 0) {
  13. if (aec->tmp_capture_frame.size == 0) {
  14. memset(aec->tmp_capture_frame.buffer, 0, aec->psize);
  15. }
  16. frame->dtmf = aec->tmp_capture_frame.dtmf;
  17. frame->size = aec->psize;
  18. speex_echo_capture(aec->state, (short*)aec->tmp_capture_frame.buffer, (short*)frame->buffer);
  19. }
  20. } else {
  21. status = aec->base.downstream->vtbl->read_frame(aec->base.downstream, frame);
  22. if (status != 0 || frame->size == 0) {
  23. memset(frame->buffer, 0, aec->psize);
  24. frame->size = aec->psize;
  25. }
  26. speex_echo_playback(aec->state, (short*)frame->buffer);
  27. }
  28. return status;
  29. }
  30. static apr_status_t write_frame(void *self, const audioframe_t *frame)
  31. {
  32. audioaec_t *aec = CONTAINING_RECORD(self, audioaec_t, base);
  33. apr_status_t status = APR_SUCCESS;
  34. if (aec->opt & AUDIO_AEC_OPT_READ_AS_CAPTURE) {
  35. aec->tmp_capture_frame.dtmf = frame->dtmf;
  36. if (frame->size == 0) {
  37. aec->tmp_capture_frame.size = aec->psize;
  38. memset(aec->tmp_capture_frame.buffer, 0, aec->psize);
  39. speex_echo_playback(aec->state, (short*)aec->tmp_capture_frame.buffer);
  40. status = aec->base.downstream->vtbl->write_frame(aec->base.downstream, &aec->tmp_capture_frame);
  41. } else {
  42. speex_echo_playback(aec->state, (short*)frame->buffer);
  43. status = aec->base.downstream->vtbl->write_frame(aec->base.downstream, frame);
  44. }
  45. } else {
  46. if (frame->size == 0) {
  47. memset((void*)frame->buffer, 0, aec->psize); // because size is zero, so buffer can be use
  48. }
  49. aec->tmp_capture_frame.dtmf = frame->dtmf;
  50. aec->tmp_capture_frame.size = aec->psize;
  51. speex_echo_capture(aec->state, (short*)frame->buffer, (short*)aec->tmp_capture_frame.buffer);
  52. status = aec->base.downstream->vtbl->write_frame(aec->base.downstream, &aec->tmp_capture_frame);
  53. }
  54. return status;
  55. }
  56. static audiostream_vtbl_t g_stream_vtbl = {
  57. &read_frame,
  58. &write_frame,
  59. };
  60. apr_status_t audioaec_create(apr_pool_t *pool, audioengine_t *engine, int clock, int ptime, int opt, int latency, audioaec_t **p_aec)
  61. {
  62. audioaec_t *aec;
  63. if (latency == 0)
  64. latency = 300;
  65. aec = apr_palloc(pool, sizeof(audioaec_t));
  66. memset(aec, 0, sizeof(audioaec_t));
  67. audiostream_init(engine, &g_stream_vtbl, &aec->base);
  68. aec->opt = opt;
  69. aec->clock = clock;
  70. aec->ptime = ptime;
  71. aec->psize = ptime * clock / 1000 * 2;
  72. aec->tmp_capture_frame.size = SUGGEST_FRAME_SIZE;
  73. aec->tmp_capture_frame.buffer = apr_palloc(pool, SUGGEST_FRAME_SIZE);
  74. aec->tmp_capture_frame.dtmf = 0;
  75. /* Set EC latency to 3/4 of output latency to reduce the
  76. * possibility of missing/late reference frame.
  77. */
  78. {
  79. //unsigned uLlatency = 440 * 3/4;
  80. int uLlatency = latency * 3 / 4;
  81. aec->state = speex_echo_state_init(ptime * clock /1000,clock * uLlatency / 1000);
  82. }
  83. *p_aec = aec;
  84. return APR_SUCCESS;
  85. }
  86. void audioaec_destroy(audioaec_t *aec)
  87. {
  88. speex_echo_state_destroy(aec->state);
  89. }