diff options
Diffstat (limited to 'apps/audio_thread.c')
-rw-r--r-- | apps/audio_thread.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/apps/audio_thread.c b/apps/audio_thread.c new file mode 100644 index 0000000000..2f01f7a8c2 --- /dev/null +++ b/apps/audio_thread.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005-2007 Miika Pekkarinen | ||
11 | * Copyright (C) 2007-2008 Nicolas Pennequin | ||
12 | * Copyright (C) 2011-2013 Michael Sevakis | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or | ||
15 | * modify it under the terms of the GNU General Public License | ||
16 | * as published by the Free Software Foundation; either version 2 | ||
17 | * of the License, or (at your option) any later version. | ||
18 | * | ||
19 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
20 | * KIND, either express or implied. | ||
21 | * | ||
22 | ****************************************************************************/ | ||
23 | #include "config.h" | ||
24 | #include "system.h" | ||
25 | #include "kernel.h" | ||
26 | #include "logf.h" | ||
27 | #include "usb.h" | ||
28 | #include "pcm.h" | ||
29 | #include "sound.h" | ||
30 | #include "audio_thread.h" | ||
31 | #ifdef AUDIO_HAVE_RECORDING | ||
32 | #include "pcm_record.h" | ||
33 | #endif | ||
34 | #include "codec_thread.h" | ||
35 | #include "voice_thread.h" | ||
36 | #include "talk.h" | ||
37 | #include "settings.h" | ||
38 | |||
39 | /* Macros to enable logf for queues | ||
40 | logging on SYS_TIMEOUT can be disabled */ | ||
41 | #ifdef SIMULATOR | ||
42 | /* Define this for logf output of all queuing except SYS_TIMEOUT */ | ||
43 | #define AUDIO_LOGQUEUES | ||
44 | /* Define this to logf SYS_TIMEOUT messages */ | ||
45 | /*#define AUDIO_LOGQUEUES_SYS_TIMEOUT*/ | ||
46 | #endif | ||
47 | |||
48 | #ifdef AUDIO_LOGQUEUES | ||
49 | #define LOGFQUEUE logf | ||
50 | #else | ||
51 | #define LOGFQUEUE(...) | ||
52 | #endif | ||
53 | |||
54 | bool audio_is_initialized = false; | ||
55 | |||
56 | /* Event queues */ | ||
57 | struct event_queue audio_queue SHAREDBSS_ATTR; | ||
58 | static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR; | ||
59 | |||
60 | /* Audio thread */ | ||
61 | static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; | ||
62 | static const char audio_thread_name[] = "audio"; | ||
63 | unsigned int audio_thread_id = 0; | ||
64 | |||
65 | static void NORETURN_ATTR audio_thread(void) | ||
66 | { | ||
67 | struct queue_event ev; | ||
68 | ev.id = SYS_TIMEOUT; /* something not in switch below */ | ||
69 | |||
70 | pcm_postinit(); | ||
71 | |||
72 | while (1) | ||
73 | { | ||
74 | switch (ev.id) | ||
75 | { | ||
76 | /* Starts the playback engine branch */ | ||
77 | case Q_AUDIO_PLAY: | ||
78 | LOGFQUEUE("audio < Q_AUDIO_PLAY"); | ||
79 | audio_playback_handler(&ev); | ||
80 | continue; | ||
81 | |||
82 | #ifdef AUDIO_HAVE_RECORDING | ||
83 | /* Starts the recording engine branch */ | ||
84 | case Q_AUDIO_INIT_RECORDING: | ||
85 | LOGFQUEUE("audio < Q_AUDIO_INIT_RECORDING"); | ||
86 | audio_recording_handler(&ev); | ||
87 | continue; | ||
88 | #endif | ||
89 | |||
90 | /* All return upon USB */ | ||
91 | case SYS_USB_CONNECTED: | ||
92 | LOGFQUEUE("audio < SYS_USB_CONNECTED"); | ||
93 | voice_stop(); | ||
94 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
95 | usb_wait_for_disconnect(&audio_queue); | ||
96 | break; | ||
97 | } | ||
98 | |||
99 | queue_wait(&audio_queue, &ev); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /* Return the playback and recording status */ | ||
104 | int audio_status(void) | ||
105 | { | ||
106 | return playback_status() | ||
107 | #ifdef AUDIO_HAVE_RECORDING | ||
108 | | pcm_rec_status() | ||
109 | #endif | ||
110 | ; | ||
111 | } | ||
112 | |||
113 | /* Clear all accumulated audio errors for playback and recording */ | ||
114 | void audio_error_clear(void) | ||
115 | { | ||
116 | #ifdef AUDIO_HAVE_RECORDING | ||
117 | pcm_rec_error_clear(); | ||
118 | #endif | ||
119 | } | ||
120 | |||
121 | /** -- Startup -- **/ | ||
122 | |||
123 | /* Initialize the audio system - called from init() in main.c */ | ||
124 | void audio_init(void) | ||
125 | { | ||
126 | /* Can never do this twice */ | ||
127 | if (audio_is_initialized) | ||
128 | { | ||
129 | logf("audio: already initialized"); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | logf("audio: initializing"); | ||
134 | |||
135 | playback_init(); | ||
136 | |||
137 | /* Recording doesn't need init call */ | ||
138 | |||
139 | /* Initialize queues before giving control elsewhere in case it likes | ||
140 | to send messages. Thread creation will be delayed however so nothing | ||
141 | starts running until ready if something yields such as talk_init. */ | ||
142 | queue_init(&audio_queue, true); | ||
143 | codec_thread_init(); | ||
144 | |||
145 | /* This thread does buffer, so match its priority */ | ||
146 | audio_thread_id = create_thread(audio_thread, audio_stack, | ||
147 | sizeof(audio_stack), 0, audio_thread_name | ||
148 | IF_PRIO(, MIN(PRIORITY_BUFFERING, PRIORITY_USER_INTERFACE)) | ||
149 | IF_COP(, CPU)); | ||
150 | |||
151 | queue_enable_queue_send(&audio_queue, &audio_queue_sender_list, | ||
152 | audio_thread_id); | ||
153 | |||
154 | /* ...now...audio_reset_buffer must know the size of voicefile buffer so | ||
155 | init talk first which will init the buffers */ | ||
156 | talk_init(); | ||
157 | |||
158 | /* Probably safe to say */ | ||
159 | audio_is_initialized = true; | ||
160 | |||
161 | sound_settings_apply(); | ||
162 | } | ||