diff options
Diffstat (limited to 'apps/voice_thread.c')
-rw-r--r-- | apps/voice_thread.c | 279 |
1 files changed, 162 insertions, 117 deletions
diff --git a/apps/voice_thread.c b/apps/voice_thread.c index 6683fcc067..3318bbecb3 100644 --- a/apps/voice_thread.c +++ b/apps/voice_thread.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include "audio.h" | 27 | #include "audio.h" |
28 | #include "playback.h" | 28 | #include "playback.h" |
29 | #include "pcmbuf.h" | 29 | #include "pcmbuf.h" |
30 | #include "pcm.h" | ||
31 | #include "pcm_mixer.h" | ||
30 | #include "codecs/libspeex/speex/speex.h" | 32 | #include "codecs/libspeex/speex/speex.h" |
31 | 33 | ||
32 | /* Define any of these as "1" and uncomment the LOGF_ENABLE line to log | 34 | /* Define any of these as "1" and uncomment the LOGF_ENABLE line to log |
@@ -53,24 +55,50 @@ | |||
53 | #define IBSS_ATTR_VOICE_STACK IBSS_ATTR | 55 | #define IBSS_ATTR_VOICE_STACK IBSS_ATTR |
54 | #endif | 56 | #endif |
55 | 57 | ||
58 | /* Minimum priority needs to be a bit elevated since voice has fairly low | ||
59 | latency */ | ||
60 | #define PRIORITY_VOICE (PRIORITY_PLAYBACK-4) | ||
61 | |||
56 | #define VOICE_FRAME_SIZE 320 /* Samples / frame */ | 62 | #define VOICE_FRAME_SIZE 320 /* Samples / frame */ |
57 | #define VOICE_SAMPLE_RATE 16000 /* Sample rate in HZ */ | 63 | #define VOICE_SAMPLE_RATE 16000 /* Sample rate in HZ */ |
58 | #define VOICE_SAMPLE_DEPTH 16 /* Sample depth in bits */ | 64 | #define VOICE_SAMPLE_DEPTH 16 /* Sample depth in bits */ |
59 | 65 | ||
60 | /* Voice thread variables */ | 66 | /* Voice thread variables */ |
61 | static unsigned int voice_thread_id = 0; | 67 | static unsigned int voice_thread_id = 0; |
62 | static long voice_stack[(DEFAULT_STACK_SIZE + 0x3C0)/sizeof(long)] IBSS_ATTR_VOICE_STACK; | 68 | #ifdef CPU_COLDFIRE |
69 | /* ISR uses any available stack - need a bit more room */ | ||
70 | #define VOICE_STACK_EXTRA 0x400 | ||
71 | #else | ||
72 | #define VOICE_STACK_EXTRA 0x3c0 | ||
73 | #endif | ||
74 | static long voice_stack[(DEFAULT_STACK_SIZE + VOICE_STACK_EXTRA)/sizeof(long)] | ||
75 | IBSS_ATTR_VOICE_STACK; | ||
63 | static const char voice_thread_name[] = "voice"; | 76 | static const char voice_thread_name[] = "voice"; |
64 | 77 | ||
65 | /* Voice thread synchronization objects */ | 78 | /* Voice thread synchronization objects */ |
66 | static struct event_queue voice_queue SHAREDBSS_ATTR; | 79 | static struct event_queue voice_queue SHAREDBSS_ATTR; |
67 | static struct mutex voice_mutex SHAREDBSS_ATTR; | ||
68 | static struct queue_sender_list voice_queue_sender_list SHAREDBSS_ATTR; | 80 | static struct queue_sender_list voice_queue_sender_list SHAREDBSS_ATTR; |
69 | static bool voice_done SHAREDDATA_ATTR = true; | 81 | static bool voice_done SHAREDDATA_ATTR = true; |
70 | 82 | ||
71 | /* Buffer for decoded samples */ | 83 | /* Buffer for decoded samples */ |
72 | static spx_int16_t voice_output_buf[VOICE_FRAME_SIZE] CACHEALIGN_ATTR; | 84 | static spx_int16_t voice_output_buf[VOICE_FRAME_SIZE] CACHEALIGN_ATTR; |
73 | 85 | ||
86 | #define VOICE_PCM_FRAME_COUNT ((NATIVE_FREQUENCY*VOICE_FRAME_SIZE + \ | ||
87 | VOICE_SAMPLE_RATE) / VOICE_SAMPLE_RATE) | ||
88 | #define VOICE_PCM_FRAME_SIZE (VOICE_PCM_FRAME_COUNT*4) | ||
89 | |||
90 | /* Default number of native-frequency PCM frames to queue - adjust as | ||
91 | necessary per-target */ | ||
92 | #define VOICE_FRAMES 3 | ||
93 | |||
94 | /* Might have lookahead and be skipping samples, so size is needed */ | ||
95 | static size_t voicebuf_sizes[VOICE_FRAMES]; | ||
96 | static uint32_t (* voicebuf)[VOICE_PCM_FRAME_COUNT]; | ||
97 | static unsigned int cur_buf_in, cur_buf_out; | ||
98 | |||
99 | /* A delay to not bring audio back to normal level too soon */ | ||
100 | #define QUIET_COUNT 3 | ||
101 | |||
74 | enum voice_thread_states | 102 | enum voice_thread_states |
75 | { | 103 | { |
76 | TSTATE_STOPPED = 0, /* Voice thread is stopped and awaiting commands */ | 104 | TSTATE_STOPPED = 0, /* Voice thread is stopped and awaiting commands */ |
@@ -83,7 +111,6 @@ enum voice_thread_messages | |||
83 | Q_VOICE_NULL = 0, /* A message for thread sync - no effect on state */ | 111 | Q_VOICE_NULL = 0, /* A message for thread sync - no effect on state */ |
84 | Q_VOICE_PLAY, /* Play a clip */ | 112 | Q_VOICE_PLAY, /* Play a clip */ |
85 | Q_VOICE_STOP, /* Stop current clip */ | 113 | Q_VOICE_STOP, /* Stop current clip */ |
86 | Q_VOICE_STATE, /* Query playing state */ | ||
87 | }; | 114 | }; |
88 | 115 | ||
89 | /* Structure to store clip data callback info */ | 116 | /* Structure to store clip data callback info */ |
@@ -98,7 +125,7 @@ struct voice_info | |||
98 | * internal functions */ | 125 | * internal functions */ |
99 | struct voice_thread_data | 126 | struct voice_thread_data |
100 | { | 127 | { |
101 | int state; /* Thread state (TSTATE_*) */ | 128 | volatile int state; /* Thread state (TSTATE_*) */ |
102 | struct queue_event ev; /* Last queue event pulled from queue */ | 129 | struct queue_event ev; /* Last queue event pulled from queue */ |
103 | void *st; /* Decoder instance */ | 130 | void *st; /* Decoder instance */ |
104 | SpeexBits bits; /* Bit cursor */ | 131 | SpeexBits bits; /* Bit cursor */ |
@@ -107,33 +134,79 @@ struct voice_thread_data | |||
107 | const char *src[2]; /* Current output buffer pointers */ | 134 | const char *src[2]; /* Current output buffer pointers */ |
108 | int lookahead; /* Number of samples to drop at start of clip */ | 135 | int lookahead; /* Number of samples to drop at start of clip */ |
109 | int count; /* Count of samples remaining to send to PCM */ | 136 | int count; /* Count of samples remaining to send to PCM */ |
137 | int quiet_counter; /* Countdown until audio goes back to normal */ | ||
110 | }; | 138 | }; |
111 | 139 | ||
112 | /* Audio playback is in a playing state? */ | 140 | /* Number of frames in queue */ |
113 | static inline bool playback_is_playing(void) | 141 | static inline int voice_unplayed_frames(void) |
114 | { | 142 | { |
115 | return (audio_status() & AUDIO_STATUS_PLAY) != 0; | 143 | return cur_buf_in - cur_buf_out; |
144 | } | ||
145 | |||
146 | /* Mixer channel callback */ | ||
147 | static void voice_pcm_callback(unsigned char **start, size_t *size) | ||
148 | { | ||
149 | if (voice_unplayed_frames() == 0) | ||
150 | return; /* Done! */ | ||
151 | |||
152 | unsigned int i = ++cur_buf_out % VOICE_FRAMES; | ||
153 | |||
154 | *start = (unsigned char *)voicebuf[i]; | ||
155 | *size = voicebuf_sizes[i]; | ||
156 | } | ||
157 | |||
158 | /* Start playback of voice channel if not already playing */ | ||
159 | static void voice_start_playback(void) | ||
160 | { | ||
161 | if (mixer_channel_status(PCM_MIXER_CHAN_VOICE) != CHANNEL_STOPPED) | ||
162 | return; | ||
163 | |||
164 | unsigned int i = cur_buf_out % VOICE_FRAMES; | ||
165 | mixer_channel_play_data(PCM_MIXER_CHAN_VOICE, voice_pcm_callback, | ||
166 | (unsigned char *)voicebuf[i], voicebuf_sizes[i]); | ||
167 | } | ||
168 | |||
169 | /* Stop the voice channel */ | ||
170 | static void voice_stop_playback(void) | ||
171 | { | ||
172 | mixer_channel_stop(PCM_MIXER_CHAN_VOICE); | ||
173 | cur_buf_in = cur_buf_out = 0; | ||
174 | } | ||
175 | |||
176 | /* Grab a free PCM frame */ | ||
177 | static uint32_t * voice_buf_get(void) | ||
178 | { | ||
179 | if (voice_unplayed_frames() >= VOICE_FRAMES) | ||
180 | { | ||
181 | /* Full */ | ||
182 | voice_start_playback(); | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | return voicebuf[cur_buf_in % VOICE_FRAMES]; | ||
187 | } | ||
188 | |||
189 | /* Commit a frame returned by voice_buf_get and set the actual size */ | ||
190 | static void voice_buf_commit(size_t size) | ||
191 | { | ||
192 | voicebuf_sizes[cur_buf_in++ % VOICE_FRAMES] = size; | ||
116 | } | 193 | } |
117 | 194 | ||
118 | /* Stop any current clip and start playing a new one */ | 195 | /* Stop any current clip and start playing a new one */ |
119 | void mp3_play_data(const unsigned char* start, int size, | 196 | void mp3_play_data(const unsigned char* start, int size, |
120 | pcm_play_callback_type get_more) | 197 | pcm_play_callback_type get_more) |
121 | { | 198 | { |
122 | /* Shared struct to get data to the thread - once it replies, it has | ||
123 | * safely cached it in its own private data */ | ||
124 | static struct voice_info voice_clip SHAREDBSS_ATTR; | ||
125 | |||
126 | if (get_more != NULL && start != NULL && (ssize_t)size > 0) | 199 | if (get_more != NULL && start != NULL && (ssize_t)size > 0) |
127 | { | 200 | { |
128 | mutex_lock(&voice_mutex); | 201 | struct voice_info voice_clip = |
202 | { | ||
203 | .get_more = get_more, | ||
204 | .start = (unsigned char *)start, | ||
205 | .size = size, | ||
206 | }; | ||
129 | 207 | ||
130 | voice_clip.get_more = get_more; | ||
131 | voice_clip.start = (unsigned char *)start; | ||
132 | voice_clip.size = size; | ||
133 | LOGFQUEUE("mp3 >| voice Q_VOICE_PLAY"); | 208 | LOGFQUEUE("mp3 >| voice Q_VOICE_PLAY"); |
134 | queue_send(&voice_queue, Q_VOICE_PLAY, (intptr_t)&voice_clip); | 209 | queue_send(&voice_queue, Q_VOICE_PLAY, (intptr_t)&voice_clip); |
135 | |||
136 | mutex_unlock(&voice_mutex); | ||
137 | } | 210 | } |
138 | } | 211 | } |
139 | 212 | ||
@@ -143,11 +216,8 @@ void mp3_play_stop(void) | |||
143 | if(!audio_is_thread_ready()) | 216 | if(!audio_is_thread_ready()) |
144 | return; | 217 | return; |
145 | 218 | ||
146 | mutex_lock(&voice_mutex); /* Sync against voice_stop */ | 219 | LOGFQUEUE("mp3 >| voice Q_VOICE_STOP"); |
147 | LOGFQUEUE("mp3 >| voice Q_VOICE_STOP: 1"); | 220 | queue_send(&voice_queue, Q_VOICE_STOP, 0); |
148 | queue_send(&voice_queue, Q_VOICE_STOP, 1); | ||
149 | |||
150 | mutex_unlock(&voice_mutex); | ||
151 | } | 221 | } |
152 | 222 | ||
153 | void mp3_play_pause(bool play) | 223 | void mp3_play_pause(bool play) |
@@ -156,36 +226,19 @@ void mp3_play_pause(bool play) | |||
156 | (void)play; | 226 | (void)play; |
157 | } | 227 | } |
158 | 228 | ||
159 | /* Tell is voice is still in a playing state */ | 229 | /* Tell if voice is still in a playing state */ |
160 | bool mp3_is_playing(void) | 230 | bool mp3_is_playing(void) |
161 | { | 231 | { |
162 | /* TODO: Implement a timeout or state query function for event objects */ | 232 | return !voice_done; |
163 | LOGFQUEUE("mp3 >| voice Q_VOICE_STATE"); | ||
164 | int state = queue_send(&voice_queue, Q_VOICE_STATE, 0); | ||
165 | return state != TSTATE_STOPPED; | ||
166 | } | 233 | } |
167 | 234 | ||
168 | /* This function is meant to be used by the buffer request functions to | 235 | /* This function is meant to be used by the buffer request functions to |
169 | ensure the codec is no longer active */ | 236 | ensure the codec is no longer active */ |
170 | void voice_stop(void) | 237 | void voice_stop(void) |
171 | { | 238 | { |
172 | mutex_lock(&voice_mutex); | ||
173 | |||
174 | /* Stop the output and current clip */ | ||
175 | mp3_play_stop(); | ||
176 | |||
177 | /* Careful if using sync objects in talk.c - make sure locking order is | ||
178 | * observed with one or the other always granted first */ | ||
179 | |||
180 | /* Unqueue all future clips */ | 239 | /* Unqueue all future clips */ |
181 | talk_force_shutup(); | 240 | talk_force_shutup(); |
182 | 241 | } | |
183 | /* Wait for any final queue_post to be processed */ | ||
184 | LOGFQUEUE("mp3 >| voice Q_VOICE_NULL"); | ||
185 | queue_send(&voice_queue, Q_VOICE_NULL, 0); | ||
186 | |||
187 | mutex_unlock(&voice_mutex); | ||
188 | } /* voice_stop */ | ||
189 | 242 | ||
190 | /* Wait for voice to finish speaking. */ | 243 | /* Wait for voice to finish speaking. */ |
191 | void voice_wait(void) | 244 | void voice_wait(void) |
@@ -194,8 +247,7 @@ void voice_wait(void) | |||
194 | * new clip by the time we wait. This should be resolvable if conditions | 247 | * new clip by the time we wait. This should be resolvable if conditions |
195 | * ever require knowing the very clip you requested has finished. */ | 248 | * ever require knowing the very clip you requested has finished. */ |
196 | 249 | ||
197 | /* Wait for PCM buffer to be exhausted. Works only if not playing. */ | 250 | while (!voice_done) |
198 | while(!voice_done || (!playback_is_playing() && pcm_is_playing())) | ||
199 | sleep(1); | 251 | sleep(1); |
200 | } | 252 | } |
201 | 253 | ||
@@ -211,6 +263,9 @@ static void voice_data_init(struct voice_thread_data *td) | |||
211 | dsp_configure(td->dsp, DSP_SET_FREQUENCY, VOICE_SAMPLE_RATE); | 263 | dsp_configure(td->dsp, DSP_SET_FREQUENCY, VOICE_SAMPLE_RATE); |
212 | dsp_configure(td->dsp, DSP_SET_SAMPLE_DEPTH, VOICE_SAMPLE_DEPTH); | 264 | dsp_configure(td->dsp, DSP_SET_SAMPLE_DEPTH, VOICE_SAMPLE_DEPTH); |
213 | dsp_configure(td->dsp, DSP_SET_STEREO_MODE, STEREO_MONO); | 265 | dsp_configure(td->dsp, DSP_SET_STEREO_MODE, STEREO_MONO); |
266 | |||
267 | mixer_channel_set_amplitude(PCM_MIXER_CHAN_VOICE, MIX_AMP_UNITY); | ||
268 | td->quiet_counter = 0; | ||
214 | } | 269 | } |
215 | 270 | ||
216 | /* Voice thread message processing */ | 271 | /* Voice thread message processing */ |
@@ -222,7 +277,6 @@ static void voice_message(struct voice_thread_data *td) | |||
222 | { | 277 | { |
223 | case Q_VOICE_PLAY: | 278 | case Q_VOICE_PLAY: |
224 | LOGFQUEUE("voice < Q_VOICE_PLAY"); | 279 | LOGFQUEUE("voice < Q_VOICE_PLAY"); |
225 | /* Put up a block for completion signal */ | ||
226 | voice_done = false; | 280 | voice_done = false; |
227 | 281 | ||
228 | /* Copy the clip info */ | 282 | /* Copy the clip info */ |
@@ -239,12 +293,17 @@ static void voice_message(struct voice_thread_data *td) | |||
239 | /* Boost CPU now */ | 293 | /* Boost CPU now */ |
240 | trigger_cpu_boost(); | 294 | trigger_cpu_boost(); |
241 | } | 295 | } |
242 | else if (!playback_is_playing()) | 296 | else |
243 | { | 297 | { |
244 | /* Just voice, stop any clip still playing */ | 298 | /* Stop any clip still playing */ |
245 | pcmbuf_play_stop(); | 299 | voice_stop_playback(); |
246 | } | 300 | } |
247 | 301 | ||
302 | /* Make audio play more softly and set delay to return to normal | ||
303 | playback level */ | ||
304 | pcmbuf_soft_mode(true); | ||
305 | td->quiet_counter = QUIET_COUNT; | ||
306 | |||
248 | /* Clean-start the decoder */ | 307 | /* Clean-start the decoder */ |
249 | td->st = speex_decoder_init(&speex_wb_mode); | 308 | td->st = speex_decoder_init(&speex_wb_mode); |
250 | 309 | ||
@@ -255,30 +314,32 @@ static void voice_message(struct voice_thread_data *td) | |||
255 | td->state = TSTATE_DECODE; | 314 | td->state = TSTATE_DECODE; |
256 | return; | 315 | return; |
257 | 316 | ||
258 | case Q_VOICE_STOP: | 317 | case SYS_TIMEOUT: |
259 | LOGFQUEUE("voice < Q_VOICE_STOP: %ld", (long)td->ev.data); | 318 | if (voice_unplayed_frames()) |
319 | { | ||
320 | /* Waiting for PCM to finish */ | ||
321 | break; | ||
322 | } | ||
260 | 323 | ||
261 | if (td->ev.data != 0 && !playback_is_playing()) | 324 | /* Drop through and stop the first time after clip runs out */ |
325 | if (td->quiet_counter-- != QUIET_COUNT) | ||
262 | { | 326 | { |
263 | /* If not playing, it's just voice so stop pcm playback */ | 327 | if (td->quiet_counter <= 0) |
264 | pcmbuf_play_stop(); | 328 | pcmbuf_soft_mode(false); |
329 | |||
330 | break; | ||
265 | } | 331 | } |
266 | 332 | ||
267 | /* Cancel boost */ | 333 | /* Fall-through */ |
268 | cancel_cpu_boost(); | 334 | case Q_VOICE_STOP: |
335 | LOGFQUEUE("voice < Q_VOICE_STOP"); | ||
269 | 336 | ||
270 | td->state = TSTATE_STOPPED; | 337 | td->state = TSTATE_STOPPED; |
271 | voice_done = true; | 338 | voice_done = true; |
272 | break; | ||
273 | |||
274 | case Q_VOICE_STATE: | ||
275 | LOGFQUEUE("voice < Q_VOICE_STATE"); | ||
276 | queue_reply(&voice_queue, td->state); | ||
277 | |||
278 | if (td->state == TSTATE_STOPPED) | ||
279 | break; /* Not in a playback state */ | ||
280 | 339 | ||
281 | return; | 340 | cancel_cpu_boost(); |
341 | voice_stop_playback(); | ||
342 | break; | ||
282 | 343 | ||
283 | default: | 344 | default: |
284 | /* Default messages get a reply and thread continues with no | 345 | /* Default messages get a reply and thread continues with no |
@@ -286,20 +347,24 @@ static void voice_message(struct voice_thread_data *td) | |||
286 | LOGFQUEUE("voice < default"); | 347 | LOGFQUEUE("voice < default"); |
287 | 348 | ||
288 | if (td->state == TSTATE_STOPPED) | 349 | if (td->state == TSTATE_STOPPED) |
289 | break; /* Not in playback state */ | 350 | break; /* Not in (active) playback state */ |
290 | 351 | ||
291 | queue_reply(&voice_queue, 0); | 352 | queue_reply(&voice_queue, 0); |
292 | return; | 353 | return; |
293 | } | 354 | } |
294 | 355 | ||
295 | queue_wait(&voice_queue, &td->ev); | 356 | if (td->quiet_counter > 0) |
357 | queue_wait_w_tmo(&voice_queue, &td->ev, HZ/10); | ||
358 | else | ||
359 | queue_wait(&voice_queue, &td->ev); | ||
296 | } | 360 | } |
297 | } | 361 | } |
298 | 362 | ||
299 | /* Voice thread entrypoint */ | 363 | /* Voice thread entrypoint */ |
300 | static void voice_thread(void) | 364 | static void NORETURN_ATTR voice_thread(void) |
301 | { | 365 | { |
302 | struct voice_thread_data td; | 366 | struct voice_thread_data td; |
367 | char *dest; | ||
303 | 368 | ||
304 | voice_data_init(&td); | 369 | voice_data_init(&td); |
305 | 370 | ||
@@ -361,19 +426,10 @@ static void voice_thread(void) | |||
361 | } | 426 | } |
362 | 427 | ||
363 | /* If all clips are done and not playing, force pcm playback. */ | 428 | /* If all clips are done and not playing, force pcm playback. */ |
364 | if (!pcm_is_playing()) | 429 | voice_start_playback(); |
365 | pcmbuf_play_start(); | 430 | |
366 | 431 | td.state = TSTATE_STOPPED; | |
367 | /* Synthesize a stop request */ | 432 | td.ev.id = SYS_TIMEOUT; |
368 | /* NOTE: We have no way to know when the pcm data placed in the | ||
369 | * buffer is actually consumed and playback has reached the end | ||
370 | * so until the info is available or inferred somehow, this will | ||
371 | * not be accurate and the stopped signal will come too soon. | ||
372 | * ie. You may not hear the "Shutting Down" splash even though | ||
373 | * it waits for voice to stop. */ | ||
374 | td.ev.id = Q_VOICE_STOP; | ||
375 | td.ev.data = 0; /* Let PCM drain by itself */ | ||
376 | yield(); | ||
377 | goto message_process; | 433 | goto message_process; |
378 | } | 434 | } |
379 | 435 | ||
@@ -385,62 +441,39 @@ static void voice_thread(void) | |||
385 | td.src[1] = NULL; | 441 | td.src[1] = NULL; |
386 | td.lookahead -= MIN(VOICE_FRAME_SIZE, td.lookahead); | 442 | td.lookahead -= MIN(VOICE_FRAME_SIZE, td.lookahead); |
387 | 443 | ||
444 | if (td.count <= 0) | ||
445 | continue; | ||
446 | |||
447 | td.state = TSTATE_BUFFER_INSERT; | ||
448 | |||
388 | buffer_insert: | 449 | buffer_insert: |
389 | /* Process the PCM samples in the DSP and send out for mixing */ | 450 | /* Process the PCM samples in the DSP and send out for mixing */ |
390 | td.state = TSTATE_BUFFER_INSERT; | ||
391 | 451 | ||
392 | while (td.count > 0) | 452 | while (1) |
393 | { | 453 | { |
394 | int out_count = dsp_output_count(td.dsp, td.count); | 454 | if (!queue_empty(&voice_queue)) |
395 | int inp_count; | 455 | goto message_wait; |
396 | char *dest; | ||
397 | 456 | ||
398 | while (1) | 457 | if ((dest = (char *)voice_buf_get()) != NULL) |
399 | { | ||
400 | if (!queue_empty(&voice_queue)) | ||
401 | goto message_wait; | ||
402 | |||
403 | if ((dest = pcmbuf_request_voice_buffer(&out_count)) != NULL) | ||
404 | break; | ||
405 | |||
406 | yield(); | ||
407 | } | ||
408 | |||
409 | /* Get the real input_size for output_size bytes, guarding | ||
410 | * against resampling buffer overflows. */ | ||
411 | inp_count = dsp_input_count(td.dsp, out_count); | ||
412 | |||
413 | if (inp_count <= 0) | ||
414 | break; | ||
415 | |||
416 | /* Input size has grown, no error, just don't write more than | ||
417 | * length */ | ||
418 | if (inp_count > td.count) | ||
419 | inp_count = td.count; | ||
420 | |||
421 | out_count = dsp_process(td.dsp, dest, td.src, inp_count); | ||
422 | |||
423 | if (out_count <= 0) | ||
424 | break; | 458 | break; |
425 | 459 | ||
426 | pcmbuf_write_voice_complete(out_count); | 460 | yield(); |
427 | td.count -= inp_count; | ||
428 | } | 461 | } |
429 | 462 | ||
430 | yield(); | 463 | voice_buf_commit(dsp_process(td.dsp, dest, td.src, td.count) |
464 | * sizeof (int32_t)); | ||
431 | } /* end while */ | 465 | } /* end while */ |
432 | } /* voice_thread */ | 466 | } |
433 | 467 | ||
434 | /* Initialize all synchronization objects create the thread */ | 468 | /* Initialize all synchronization objects create the thread */ |
435 | void voice_thread_init(void) | 469 | void voice_thread_init(void) |
436 | { | 470 | { |
437 | logf("Starting voice thread"); | 471 | logf("Starting voice thread"); |
438 | queue_init(&voice_queue, false); | 472 | queue_init(&voice_queue, false); |
439 | mutex_init(&voice_mutex); | ||
440 | 473 | ||
441 | voice_thread_id = create_thread(voice_thread, voice_stack, | 474 | voice_thread_id = create_thread(voice_thread, voice_stack, |
442 | sizeof(voice_stack), CREATE_THREAD_FROZEN, | 475 | sizeof(voice_stack), CREATE_THREAD_FROZEN, |
443 | voice_thread_name IF_PRIO(, PRIORITY_PLAYBACK) IF_COP(, CPU)); | 476 | voice_thread_name IF_PRIO(, PRIORITY_VOICE) IF_COP(, CPU)); |
444 | 477 | ||
445 | queue_enable_queue_send(&voice_queue, &voice_queue_sender_list, | 478 | queue_enable_queue_send(&voice_queue, &voice_queue_sender_list, |
446 | voice_thread_id); | 479 | voice_thread_id); |
@@ -457,6 +490,18 @@ void voice_thread_resume(void) | |||
457 | /* Set the voice thread priority */ | 490 | /* Set the voice thread priority */ |
458 | void voice_thread_set_priority(int priority) | 491 | void voice_thread_set_priority(int priority) |
459 | { | 492 | { |
493 | if (priority > PRIORITY_VOICE) | ||
494 | priority = PRIORITY_VOICE; | ||
495 | |||
460 | thread_set_priority(voice_thread_id, priority); | 496 | thread_set_priority(voice_thread_id, priority); |
461 | } | 497 | } |
462 | #endif | 498 | #endif |
499 | |||
500 | /* Initialize voice PCM buffer and return size, allocated from the end */ | ||
501 | size_t voicebuf_init(unsigned char *bufend) | ||
502 | { | ||
503 | size_t size = VOICE_FRAMES * VOICE_PCM_FRAME_SIZE; | ||
504 | cur_buf_out = cur_buf_in = 0; | ||
505 | voicebuf = (uint32_t (*)[VOICE_PCM_FRAME_COUNT])(bufend - size); | ||
506 | return size; | ||
507 | } | ||