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 <signal.h>
11 
12 #include "uvoice_os.h"
13 #include "uvoice_types.h"
14 #include "uvoice_recorder.h"
15 
16 #include "uvoice_common.h"
17 #include "uvoice_record.h"
18 
19 #include "opensource/speex/include/speex/speex_callbacks.h"
20 
21 
22 typedef struct {
23 	void *speex;
24 	SpeexBits bits;
25 	int frame_size;
26 } spx_encoder_t;
27 
spx_encode_process(void * priv,uint8_t * buffer,int nbytes)28 static int spx_encode_process(void *priv, uint8_t *buffer, int nbytes)
29 {
30 	media_encoder_t *mencoder = (media_encoder_t *)priv;
31 	if (!mencoder) {
32 		M_LOGE("mencoder null !\n");
33 		return -1;
34 	}
35 
36 	spx_encoder_t *spx = mencoder->encoder;
37 	if (!spx) {
38 		M_LOGE("speex null !\n");
39 		return -1;
40 	}
41 
42 	spx_int16_t *ptr;
43 	int samples = nbytes / sizeof(short);
44 	int encode_sum = 0;
45 	int frame_size = 0;
46 	int ret;
47 	int i;
48 
49 	int time_ms = os_current_time();
50 
51 	for (i = 0; i < samples; i += spx->frame_size) {
52 		speex_bits_reset(&spx->bits);
53 		ptr = (spx_int16_t *)buffer + i;
54 		speex_encode_int(spx->speex, ptr, &spx->bits);
55 		frame_size = speex_bits_write(&spx->bits, buffer + encode_sum + sizeof(int),
56 			spx->frame_size * sizeof(spx_int16_t));
57 		if (frame_size + sizeof(int) >= spx->frame_size * sizeof(spx_int16_t)) {
58 			M_LOGE("encoded data overflow !\n");
59 			return -1;
60 		}
61 		snd_memcpy(buffer + encode_sum, &frame_size, sizeof(int));
62 		encode_sum += frame_size + sizeof(int);
63 	}
64 
65 	//time_ms = os_current_time() - time_ms;
66 	//M_LOGD("time %dms ratio %d/%d\n", time_ms, frame_size, nbytes);
67 
68 	return encode_sum;
69 }
70 
spx_encode_action(void * priv,recorder_action_t action,void * arg)71 static int spx_encode_action(void *priv, recorder_action_t action, void *arg)
72 {
73 	media_encoder_t *mencoder = (media_encoder_t *)priv;
74 	spx_encoder_t *spx;
75 	int ret;
76 
77 	if (!mencoder) {
78 		M_LOGE("mencoder null !\n");
79 		return -1;
80 	}
81 
82 	spx = mencoder->encoder;
83 	if (!spx) {
84 		M_LOGE("spx encoder null !\n");
85 		return -1;
86 	}
87 
88 	if (action == RECORDER_START) {
89 		if ((mencoder->frames * mencoder->channels) % spx->frame_size != 0) {
90 			M_LOGE("frame size is not integral multiple of %d !\n",
91 				spx->frame_size);
92 			return -1;
93 		}
94 	}
95 
96 	return 0;
97 }
98 
spx_encoder_create(media_encoder_t * mencoder)99 int spx_encoder_create(media_encoder_t *mencoder)
100 {
101 	spx_encoder_t *spx;
102 	spx_int32_t temp;
103 
104 	if (!mencoder) {
105 		M_LOGE("mencoder null !\n");
106 		return -1;
107 	}
108 
109 	spx = snd_zalloc(sizeof(spx_encoder_t), AFM_MAIN);
110 	if (!spx) {
111 		M_LOGE("alloc speex encoder failed !\n");
112 		return -1;
113 	}
114 
115 	spx->speex = speex_encoder_init(
116 		speex_lib_get_mode(SPEEX_MODEID_NB)); //nb_encoder_init()
117 	if (!spx->speex) {
118 		M_LOGE("init speex failed !\n");
119 		snd_free(spx);
120 		return -1;
121 	}
122 
123 	temp = 0;
124 	speex_encoder_ctl(spx->speex, SPEEX_SET_VBR, &temp); //nb_encoder_ctl()
125 	temp = 2;
126 	speex_encoder_ctl(spx->speex, SPEEX_SET_QUALITY, &temp);
127 	temp = 2;
128 	speex_encoder_ctl(spx->speex, SPEEX_SET_COMPLEXITY, &temp);
129 
130 	speex_encoder_ctl(spx->speex, SPEEX_GET_FRAME_SIZE, &spx->frame_size);
131 	M_LOGD("speex frame size %d\n", spx->frame_size); /* frame size in sizeof(short) */
132 
133 	speex_bits_init(&spx->bits);
134 
135 	mencoder->encoder = spx;
136 	mencoder->encode = spx_encode_process;
137 	mencoder->action = spx_encode_action;
138 
139 	M_LOGI("speex encoder create\n");
140 	return 0;
141 }
142 
spx_encoder_release(media_encoder_t * mencoder)143 int spx_encoder_release(media_encoder_t *mencoder)
144 {
145 	spx_encoder_t *spx;
146 
147 	if (!mencoder) {
148 		M_LOGE("mencoder null !\n");
149 		return -1;
150 	}
151 
152 	spx = mencoder->encoder;
153 	if (!spx) {
154 		M_LOGE("speex encoder null !\n");
155 		return -1;
156 	}
157 
158 	speex_bits_destroy(&spx->bits);
159 	speex_encoder_destroy(spx->speex);
160 	snd_free(spx);
161 	mencoder->encoder = NULL;
162 
163 	M_LOGI("speex encoder release\n");
164 	return 0;
165 }