1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "py/builtin.h"
6 #include "py/mperrno.h"
7 #include "py/obj.h"
8 #include "py/runtime.h"
9 #include "py/stackctrl.h"
10 #include "ulog/ulog.h"
11 #include "utility.h"
12 #include "uvoice_alios.h"
13 #include "uvoice_event.h"
14 #include "uvoice_init.h"
15 #include "uvoice_tts.h"
16 #include "uvoice_types.h"
17 
18 #define LOG_TAG "UVOICE_TTS"
19 
20 #define TTS_CHECK_PARAMS()                                               \
21     uvocie_tts_obj_t *self = (uvocie_tts_obj_t *)MP_OBJ_TO_PTR(self_in); \
22     do {                                                                 \
23         if (self == NULL || self->tts_obj == NULL) {                     \
24             mp_raise_OSError(EINVAL);                                    \
25             return mp_const_none;                                        \
26         }                                                                \
27     } while (0)
28 
29 #define TTS_RECV_CB_URL   (0)
30 #define TTS_RECV_CB_DATA  (1)
31 #define TTS_RECV_CB_EVENT (2)
32 
33 extern const mp_obj_type_t uvoice_tts_type;
34 
35 static mp_obj_t callback_url = mp_const_none;
36 static mp_obj_t callback_data = mp_const_none;
37 static mp_obj_t callback_event = mp_const_none;
38 
39 // this is the actual C-structure for our new object
40 typedef struct {
41     // base represents some basic information, like type
42     mp_obj_base_t base;
43 
44     // a member created by us
45     char *modName;
46     uvoice_tts_t *tts_obj;
47 } uvocie_tts_obj_t;
48 
uvoice_tts_print(const mp_print_t * print,mp_obj_t self_in,mp_print_kind_t kind)49 void uvoice_tts_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
50 {
51     uvocie_tts_obj_t *self = MP_OBJ_TO_PTR(self_in);
52     mp_printf(print, "modName(%s)", self->modName);
53 }
54 
uvoice_tts_new(const mp_obj_type_t * type,size_t n_args,size_t n_kw,const mp_obj_t * args)55 STATIC mp_obj_t uvoice_tts_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args)
56 {
57     uvocie_tts_obj_t *uvocie_tts_com_obj = m_new_obj(uvocie_tts_obj_t);
58     if (!uvocie_tts_com_obj) {
59         mp_raise_OSError(MP_ENOMEM);
60         return mp_const_none;
61     }
62     memset(uvocie_tts_com_obj, 0, sizeof(uvocie_tts_obj_t));
63 
64     uvocie_tts_com_obj->base.type = &uvoice_tts_type;
65     uvocie_tts_com_obj->modName = "uvoice-tts";
66 
67     return MP_OBJ_FROM_PTR(uvocie_tts_com_obj);
68 }
69 
alicoud_tts_event(tts_event_e event,char * info)70 STATIC mp_int_t alicoud_tts_event(tts_event_e event, char *info)
71 {
72     if (callback_event != mp_const_none) {
73         mp_obj_t event_dict = mp_obj_new_dict(2);
74         mp_obj_dict_store(event_dict, MP_OBJ_NEW_QSTR(qstr_from_str("event")), mp_obj_new_int(event));
75         mp_obj_dict_store(event_dict, MP_OBJ_NEW_QSTR(qstr_from_str("info")), mp_obj_new_strn(info));
76 
77         callback_to_python(callback_event, event_dict);
78     }
79 }
80 
alicloud_tts_recv_data(uint8_t * buffer,mp_int_t nbytes,mp_int_t index)81 STATIC mp_int_t alicloud_tts_recv_data(uint8_t *buffer, mp_int_t nbytes, mp_int_t index)
82 {
83     if (callback_data != mp_const_none) {
84         mp_obj_t data_dict = mp_obj_new_dict(3);
85         mp_obj_dict_store(data_dict, MP_OBJ_NEW_QSTR(qstr_from_str("buffer")), mp_obj_new_bytes(buffer, nbytes));
86         mp_obj_dict_store(data_dict, MP_OBJ_NEW_QSTR(qstr_from_str("nbytes")), mp_obj_new_int(nbytes));
87         mp_obj_dict_store(data_dict, MP_OBJ_NEW_QSTR(qstr_from_str("index")), mp_obj_new_int(index));
88 
89         callback_to_python(callback_data, data_dict);
90     }
91 }
92 
alicloud_tts_recv_url(char * tts_url)93 STATIC mp_int_t alicloud_tts_recv_url(char *tts_url)
94 {
95     if (callback_url != mp_const_none) {
96         callback_to_python(callback_url, mp_obj_new_str(tts_url, strlen(tts_url)));
97     }
98 }
99 
uvoice_tts_init(mp_obj_t self_in,mp_obj_t aicloud_type_in,mp_obj_t config_in)100 STATIC mp_obj_t uvoice_tts_init(mp_obj_t self_in, mp_obj_t aicloud_type_in, mp_obj_t config_in)
101 {
102     TTS_CHECK_PARAMS();
103 
104     tts_aicloud_type_e aicloud_type = (tts_aicloud_type_e)mp_obj_get_int(aicloud_type_in);
105 
106     tts_config_t config = { 0 };
107     config.app_key = (char *)get_str_from_dict(config_in, "app_key");
108     config.token = (char *)get_str_from_dict(config_in, "token");
109     config.format = (media_format_t)get_int_from_dict(config_in, "format");
110     config.sample_rate = get_int_from_dict(config_in, "sample_rate");
111     config.voice = (char *)get_str_from_dict(config_in, "voice");
112     config.volume = get_int_from_dict(config_in, "volume");
113     config.speech_rate = get_int_from_dict(config_in, "speech_rate");
114     config.pitch_rate = get_int_from_dict(config_in, "pitch_rate");
115     config.text_encode_type = (tts_encode_type_e)get_int_from_dict(config_in, "text_encode_type");
116 
117     LOGD(LOG_TAG,
118          "app_key=%s, token=%s, format=%d, sample_rate=%d, voice=%s, "
119          "volume=%d, speech_rate=%d, pitch_rate=%d, text_encode_type=%d\n",
120          config.app_key, config.token, config.format, config.sample_rate, config.voice, config.volume,
121          config.speech_rate, config.pitch_rate, config.text_encode_type);
122 
123     mp_int_t status = self->tts_obj->tts_init(aicloud_type, &config);
124     return mp_obj_new_int(status);
125 }
126 STATIC MP_DEFINE_CONST_FUN_OBJ_3(uvoice_tts_init_obj, uvoice_tts_init);
127 
128 static tts_recv_callback_t recv_cb = {
129     .event = alicoud_tts_event,
130     .recv_data = alicloud_tts_recv_data,
131     .recv_url = alicloud_tts_recv_url,
132 };
133 
uvoice_tts_request(size_t n_args,const mp_obj_t * args)134 STATIC mp_obj_t uvoice_tts_request(size_t n_args, const mp_obj_t *args)
135 {
136     if (n_args < 3) {
137         LOGE(LOG_TAG, "%s: args num is illegal :n_args = %d;\n", __func__, n_args);
138         return mp_const_none;
139     }
140 
141     mp_obj_t self_in = args[0];
142     TTS_CHECK_PARAMS();
143 
144     char *text = (char *)mp_obj_str_get_str(args[1]);
145     int recv_type = mp_obj_get_int(args[2]);
146 
147     LOGD(LOG_TAG, "text=%s, recv_type=%d", text, recv_type);
148 
149     mp_int_t status = self->tts_obj->tts_request(text, recv_type, &recv_cb);
150     return mp_obj_new_int(status);
151 }
152 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(uvoice_tts_request_obj, 3, uvoice_tts_request);
153 
uvoice_tts_stop(mp_obj_t self_in)154 STATIC mp_obj_t uvoice_tts_stop(mp_obj_t self_in)
155 {
156     TTS_CHECK_PARAMS();
157 
158     mp_int_t status = self->tts_obj->tts_stop();
159     return mp_obj_new_int(status);
160 }
161 STATIC MP_DEFINE_CONST_FUN_OBJ_1(uvoice_tts_stop_obj, uvoice_tts_stop);
162 
uvoice_create(mp_obj_t self_in)163 STATIC mp_obj_t uvoice_create(mp_obj_t self_in)
164 {
165     uvocie_tts_obj_t *self = (uvocie_tts_obj_t *)MP_OBJ_TO_PTR(self_in);
166     if (self == NULL) {
167         LOGE(LOG_TAG, "uvocie_tts_obj_t NULL");
168         return mp_const_none;
169     }
170 
171     self->tts_obj = uvoice_tts_create();
172     if (self->tts_obj == NULL) {
173         LOGE(LOG_TAG, "create tts failed !\n");
174     }
175 
176     return mp_const_none;
177 }
178 STATIC MP_DEFINE_CONST_FUN_OBJ_1(uvoice_tts_create_obj, uvoice_create);
179 
uvoice_release(mp_obj_t self_in)180 STATIC mp_obj_t uvoice_release(mp_obj_t self_in)
181 {
182     TTS_CHECK_PARAMS();
183     mp_int_t status = uvoice_tts_release(self->tts_obj);
184 
185     callback_url = mp_const_none;
186     callback_data = mp_const_none;
187     callback_event = mp_const_none;
188 
189     return mp_obj_new_int(status);
190 }
191 STATIC MP_DEFINE_CONST_FUN_OBJ_1(uvoice_tts_release_obj, uvoice_release);
192 
uvoice_tts_set_callback(mp_obj_t self_in,mp_obj_t type_in,mp_obj_t callback_fun)193 STATIC mp_obj_t uvoice_tts_set_callback(mp_obj_t self_in, mp_obj_t type_in, mp_obj_t callback_fun)
194 {
195     TTS_CHECK_PARAMS();
196 
197     if (mp_obj_is_fun(callback_fun) == false) {
198         LOGE(LOG_TAG, "Obj is not function\n");
199         return mp_const_none;
200     }
201 
202     int type = mp_obj_get_int(type_in);
203     if (type == TTS_RECV_CB_URL) {
204         callback_url = callback_fun;
205     } else if (type == TTS_RECV_CB_DATA) {
206         callback_data = callback_fun;
207     } else if (type == TTS_RECV_CB_EVENT) {
208         callback_event = callback_fun;
209     }
210 
211     return mp_const_none;
212 }
213 STATIC MP_DEFINE_CONST_FUN_OBJ_3(uvoice_tts_set_callback_obj, uvoice_tts_set_callback);
214 
uvoice_tts_cb_test(mp_obj_t self_in,mp_obj_t type_in)215 STATIC mp_obj_t uvoice_tts_cb_test(mp_obj_t self_in, mp_obj_t type_in)
216 {
217     TTS_CHECK_PARAMS();
218 
219     int type = mp_obj_get_int(type_in);
220     LOGD(LOG_TAG, "type=%d", type);
221 
222     if (type == TTS_RECV_CB_URL) {
223         alicloud_tts_recv_url("test_url");
224     } else if (type == TTS_RECV_CB_DATA) {
225         char buf[8] = { 0, 1, 2, 3, 4, 5, 6, 7 };
226         alicloud_tts_recv_data(buf, 8, 10);
227     } else if (type == TTS_RECV_CB_EVENT) {
228         alicoud_tts_event(10, "test_info");
229     }
230 
231     return mp_const_none;
232 }
233 
234 STATIC const mp_rom_map_elem_t uvoice_module_tts_globals_table[] = {
235     { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&uvoice_tts_stop_obj) },
236     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&uvoice_tts_create_obj) },
237     { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&uvoice_tts_release_obj) },
238     { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&uvoice_tts_set_callback_obj) },
239     { MP_ROM_QSTR(MP_QSTR_prepare), MP_ROM_PTR(&uvoice_tts_init_obj) },
240     { MP_ROM_QSTR(MP_QSTR_request), MP_ROM_PTR(&uvoice_tts_request_obj) },
241     { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&uvoice_tts_stop_obj) },
242 
243     { MP_ROM_QSTR(MP_QSTR_CB_ENUM_URL), MP_ROM_INT(TTS_RECV_CB_URL) },
244     { MP_ROM_QSTR(MP_QSTR_CB_ENUM_DATA), MP_ROM_INT(TTS_RECV_CB_DATA) },
245     { MP_ROM_QSTR(MP_QSTR_CB_ENUM_EVENT), MP_ROM_INT(TTS_RECV_CB_EVENT) },
246 };
247 STATIC MP_DEFINE_CONST_DICT(uvoice_module_tts_globals, uvoice_module_tts_globals_table);
248 
249 const mp_obj_type_t uvoice_tts_type = {
250     .base = { &mp_type_type },
251     .name = MP_QSTR_Tts,
252     .print = uvoice_tts_print,
253     .make_new = uvoice_tts_new,
254     .locals_dict = (mp_obj_dict_t *)&uvoice_module_tts_globals,
255 };
256