1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  *
4  */
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include <stdarg.h>
11 #include <signal.h>
12 
13 #include "uvoice_types.h"
14 #include "uvoice_os.h"
15 
16 #include "uvoice_common.h"
17 #include "uvoice_audio.h"
18 
19 #include "audio_common.h"
20 #include "audio_stream.h"
21 #include "audio_aec.h"
22 
23 
24 #define AEC_REFER_DELAY_MS        10
25 
26 
audio_aec_refer_conserve(struct aec_handler * aec,uint8_t * buffer,int nbytes)27 int audio_aec_refer_conserve(struct aec_handler *aec, uint8_t *buffer, int nbytes)
28 {
29     if (!aec) {
30         snd_err("aec handler null !\n");
31         return -1;
32     }
33 
34     os_mutex_lock(aec->lock, OS_WAIT_FOREVER);
35 
36     if (uvoice_ringbuff_freesize(&aec->rb) >= nbytes)
37         uvoice_ringbuff_fill(&aec->rb, buffer, nbytes);
38 
39     os_mutex_unlock(aec->lock);
40 
41 __exit:
42     return 0;
43 }
44 
audio_aec_process(struct aec_handler * aec,uint8_t * buffer,int nbytes)45 int audio_aec_process(struct aec_handler *aec, uint8_t *buffer, int nbytes)
46 {
47     if (!aec) {
48         snd_err("aec handler null !\n");
49         return -1;
50     }
51 
52     os_mutex_lock(aec->lock, OS_WAIT_FOREVER);
53     if (!aec->start)
54         goto __exit;
55 
56     if (uvoice_ringbuff_dirtysize(&aec->rb) >= nbytes) {
57         uvoice_ringbuff_read(&aec->rb, aec->echo_buffer, nbytes);
58 
59         if (echo_cancellation_process(aec, buffer, aec->echo_buffer, nbytes)) {
60             snd_err("aec process failed !\n");
61             os_mutex_unlock(aec->lock);
62             return -1;
63         }
64     }
65 
66 __exit:
67     os_mutex_unlock(aec->lock);
68     return 0;
69 }
70 
audio_aec_init(struct in_stream * in)71 int audio_aec_init(struct in_stream *in)
72 {
73     struct aec_handler *aec;
74     struct pcm_config *config;
75     int bits;
76 
77     if (!in) {
78         snd_err("in stream null !\n");
79         return -1;
80     }
81 
82     config = &in->pcm.config;
83     bits = pcm_format_to_bits(config->format);
84 
85     aec = snd_zalloc(sizeof(struct aec_handler), AFM_EXTN);
86     if (!aec) {
87         snd_err("alloc echo cancellation struct failed !\n");
88         return -1;
89     }
90 
91     aec->echo_buffer_size = period_samples_to_bytes(&in->pcm.config);
92     aec->echo_buffer = snd_zalloc(aec->echo_buffer_size, AFM_MAIN);
93     if (!aec->echo_buffer) {
94         snd_err("alloc echo buffer failed !\n");
95         snd_free(aec);
96         return -1;
97     }
98 
99      aec->refer_pool_size = aec->echo_buffer_size;
100     aec->refer_pool = snd_zalloc(aec->refer_pool_size, AFM_EXTN);
101     if (!aec->refer_pool) {
102         snd_err("alloc refer pool failed !\n");
103         snd_free(aec->echo_buffer);
104         snd_free(aec);
105         return -1;
106     }
107 
108     if (echo_cancellation_create(aec,
109             config->rate, bits, config->period_size)) {
110         snd_err("create aec failed !\n");
111         snd_free(aec->refer_pool);
112         snd_free(aec->echo_buffer);
113         snd_free(aec);
114         return -1;
115     }
116 
117     uvoice_ringbuff_init(&aec->rb, aec->refer_pool, aec->refer_pool_size);
118     aec->lock = os_mutex_new();
119     aec->rd_sem = os_sem_new(0);
120     aec->wr_sem = os_sem_new(0);
121 
122     in->aec = aec;
123     snd_debug("aec init\n");
124     return 0;
125 }
126 
audio_aec_deinit(struct in_stream * in)127 int audio_aec_deinit(struct in_stream *in)
128 {
129     struct aec_handler *aec;
130 
131     aec = in->aec;
132     if (!aec) {
133         snd_err("aec handler null !\n");
134         return -1;
135     }
136 
137     echo_cancellation_release(aec);
138     os_sem_free(aec->wr_sem);
139     os_sem_free(aec->rd_sem);
140     os_mutex_free(aec->lock);
141     snd_free(aec->refer_pool);
142     snd_free(aec->echo_buffer);
143     snd_free(aec);
144     in->aec = NULL;
145 
146     snd_debug("aec free\n");
147     return 0;
148 }
149 
150