diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-05-31 02:41:02 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2013-05-31 03:20:35 -0400 |
commit | 5857c44017a1641fce7f00da7f16c143daacbaf6 (patch) | |
tree | b8a7ff134977ee8dd6b25b5591f4eb81172f74ab | |
parent | df6e1bcce5071e02b5cd46736bff87ca0dcceffe (diff) | |
download | rockbox-5857c44017a1641fce7f00da7f16c143daacbaf6.tar.gz rockbox-5857c44017a1641fce7f00da7f16c143daacbaf6.zip |
Refactor audio thread to run both recording and playback.
Eliminates the pcmrec thread and keeps playback and recording engine
operation mutually-exclusive.
audio_thread.c contains the audio thread which branches to the
correct engine depending upon the request. It also handles the main
audio initialization.
Moves pcm_init into main.c just before dsp_init because I don't want
that one in audio_init in the new file.
(Also makes revision df6e1bc pointless ;)
Change-Id: Ifc1db24404e6d8dd9ac42d9f4dfbc207aa9a26e1
-rw-r--r-- | apps/SOURCES | 1 | ||||
-rw-r--r-- | apps/audio_thread.c | 162 | ||||
-rw-r--r-- | apps/audio_thread.h | 102 | ||||
-rw-r--r-- | apps/codec_thread.c | 1 | ||||
-rw-r--r-- | apps/main.c | 11 | ||||
-rw-r--r-- | apps/playback.c | 342 | ||||
-rw-r--r-- | apps/playback.h | 64 | ||||
-rw-r--r-- | apps/recorder/pcm_record.c | 305 | ||||
-rw-r--r-- | apps/recorder/pcm_record.h | 4 | ||||
-rw-r--r-- | apps/recorder/recording.c | 9 | ||||
-rw-r--r-- | firmware/export/thread.h | 22 |
11 files changed, 506 insertions, 517 deletions
diff --git a/apps/SOURCES b/apps/SOURCES index 4b28f8888b..b22f597b4a 100644 --- a/apps/SOURCES +++ b/apps/SOURCES | |||
@@ -163,6 +163,7 @@ radio/radioart.c | |||
163 | #if INPUT_SRC_CAPS != 0 | 163 | #if INPUT_SRC_CAPS != 0 |
164 | audio_path.c | 164 | audio_path.c |
165 | #endif /* INPUT_SRC_CAPS != 0 */ | 165 | #endif /* INPUT_SRC_CAPS != 0 */ |
166 | audio_thread.c | ||
166 | pcmbuf.c | 167 | pcmbuf.c |
167 | codec_thread.c | 168 | codec_thread.c |
168 | playback.c | 169 | playback.c |
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 | } | ||
diff --git a/apps/audio_thread.h b/apps/audio_thread.h new file mode 100644 index 0000000000..7e0ad28849 --- /dev/null +++ b/apps/audio_thread.h | |||
@@ -0,0 +1,102 @@ | |||
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 | #ifndef AUDIO_THREAD_H | ||
24 | #define AUDIO_THREAD_H | ||
25 | |||
26 | /* Define one constant that includes recording related functionality */ | ||
27 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | ||
28 | #define AUDIO_HAVE_RECORDING | ||
29 | #endif | ||
30 | |||
31 | enum | ||
32 | { | ||
33 | Q_NULL = 0, /* reserved */ | ||
34 | |||
35 | /* -> audio */ | ||
36 | Q_AUDIO_PLAY, | ||
37 | Q_AUDIO_STOP, | ||
38 | Q_AUDIO_PAUSE, | ||
39 | Q_AUDIO_SKIP, | ||
40 | Q_AUDIO_PRE_FF_REWIND, | ||
41 | Q_AUDIO_FF_REWIND, | ||
42 | Q_AUDIO_FLUSH, | ||
43 | Q_AUDIO_DIR_SKIP, | ||
44 | |||
45 | /* pcmbuf -> audio */ | ||
46 | Q_AUDIO_TRACK_CHANGED, | ||
47 | |||
48 | /* audio -> audio */ | ||
49 | Q_AUDIO_FILL_BUFFER, /* continue buffering next track */ | ||
50 | |||
51 | /* buffering -> audio */ | ||
52 | Q_AUDIO_BUFFERING, /* some buffer event */ | ||
53 | Q_AUDIO_FINISH_LOAD_TRACK, /* metadata is buffered */ | ||
54 | Q_AUDIO_HANDLE_FINISHED, /* some other type is buffered */ | ||
55 | |||
56 | /* codec -> audio (*) */ | ||
57 | Q_AUDIO_CODEC_SEEK_COMPLETE, | ||
58 | Q_AUDIO_CODEC_COMPLETE, | ||
59 | |||
60 | /* audio -> codec */ | ||
61 | Q_CODEC_LOAD, | ||
62 | Q_CODEC_RUN, | ||
63 | Q_CODEC_PAUSE, | ||
64 | Q_CODEC_SEEK, | ||
65 | Q_CODEC_STOP, | ||
66 | Q_CODEC_UNLOAD, | ||
67 | |||
68 | /* -> codec */ | ||
69 | Q_CODEC_DO_CALLBACK, | ||
70 | |||
71 | /* -> recording */ | ||
72 | #ifdef HAVE_RECORDING | ||
73 | Q_AUDIO_INIT_RECORDING, | ||
74 | Q_AUDIO_CLOSE_RECORDING, | ||
75 | Q_AUDIO_RECORDING_OPTIONS, | ||
76 | Q_AUDIO_RECORD, | ||
77 | Q_AUDIO_RESUME, | ||
78 | #endif | ||
79 | |||
80 | /*- settings -*/ | ||
81 | |||
82 | #ifdef HAVE_DISK_STORAGE | ||
83 | /* -> audio */ | ||
84 | Q_AUDIO_UPDATE_WATERMARK, /* buffering watermark needs updating */ | ||
85 | #endif | ||
86 | /* -> audio */ | ||
87 | Q_AUDIO_REMAKE_AUDIO_BUFFER, /* buffer needs to be reinitialized */ | ||
88 | }; | ||
89 | |||
90 | /* (*) If you change these, you must check audio_clear_track_notifications | ||
91 | in playback.c for correctness */ | ||
92 | |||
93 | void audio_init(void); | ||
94 | void playback_init(void); | ||
95 | unsigned int playback_status(void); | ||
96 | |||
97 | void audio_playback_handler(struct queue_event *ev); | ||
98 | #ifdef AUDIO_HAVE_RECORDING | ||
99 | void audio_recording_handler(struct queue_event *ev); | ||
100 | #endif | ||
101 | |||
102 | #endif /* AUDIO_THREAD_H */ | ||
diff --git a/apps/codec_thread.c b/apps/codec_thread.c index 308b2ff982..54bc28e19a 100644 --- a/apps/codec_thread.c +++ b/apps/codec_thread.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "codecs.h" | 26 | #include "codecs.h" |
27 | #include "codec_thread.h" | 27 | #include "codec_thread.h" |
28 | #include "pcmbuf.h" | 28 | #include "pcmbuf.h" |
29 | #include "audio_thread.h" | ||
29 | #include "playback.h" | 30 | #include "playback.h" |
30 | #include "buffering.h" | 31 | #include "buffering.h" |
31 | #include "dsp_core.h" | 32 | #include "dsp_core.h" |
diff --git a/apps/main.c b/apps/main.c index 6b6566c7ca..57257aff66 100644 --- a/apps/main.c +++ b/apps/main.c | |||
@@ -87,6 +87,7 @@ | |||
87 | #endif | 87 | #endif |
88 | 88 | ||
89 | #if (CONFIG_CODEC == SWCODEC) | 89 | #if (CONFIG_CODEC == SWCODEC) |
90 | #include "audio_thread.h" | ||
90 | #include "playback.h" | 91 | #include "playback.h" |
91 | #include "tdspeed.h" | 92 | #include "tdspeed.h" |
92 | #endif | 93 | #endif |
@@ -386,6 +387,7 @@ static void init(void) | |||
386 | 387 | ||
387 | storage_init(); | 388 | storage_init(); |
388 | #if CONFIG_CODEC == SWCODEC | 389 | #if CONFIG_CODEC == SWCODEC |
390 | pcm_init(); | ||
389 | dsp_init(); | 391 | dsp_init(); |
390 | #endif | 392 | #endif |
391 | settings_reset(); | 393 | settings_reset(); |
@@ -422,10 +424,6 @@ static void init(void) | |||
422 | 424 | ||
423 | audio_init(); | 425 | audio_init(); |
424 | 426 | ||
425 | #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) | ||
426 | pcm_rec_init(); | ||
427 | #endif | ||
428 | |||
429 | settings_apply_skins(); | 427 | settings_apply_skins(); |
430 | } | 428 | } |
431 | 429 | ||
@@ -641,6 +639,7 @@ static void init(void) | |||
641 | } | 639 | } |
642 | 640 | ||
643 | #if CONFIG_CODEC == SWCODEC | 641 | #if CONFIG_CODEC == SWCODEC |
642 | pcm_init(); | ||
644 | dsp_init(); | 643 | dsp_init(); |
645 | #endif | 644 | #endif |
646 | 645 | ||
@@ -727,10 +726,6 @@ static void init(void) | |||
727 | audio_init(); | 726 | audio_init(); |
728 | CHART("<audio_init"); | 727 | CHART("<audio_init"); |
729 | 728 | ||
730 | #if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) | ||
731 | pcm_rec_init(); | ||
732 | #endif | ||
733 | |||
734 | /* runtime database has to be initialized after audio_init() */ | 729 | /* runtime database has to be initialized after audio_init() */ |
735 | cpu_boost(false); | 730 | cpu_boost(false); |
736 | 731 | ||
diff --git a/apps/playback.c b/apps/playback.c index 15a3fe9a61..01fa7a9dda 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include "core_alloc.h" | 27 | #include "core_alloc.h" |
28 | #include "sound.h" | 28 | #include "sound.h" |
29 | #include "ata.h" | 29 | #include "ata.h" |
30 | #include "usb.h" | ||
31 | #include "codecs.h" | 30 | #include "codecs.h" |
32 | #include "codec_thread.h" | 31 | #include "codec_thread.h" |
33 | #include "voice_thread.h" | 32 | #include "voice_thread.h" |
@@ -38,6 +37,7 @@ | |||
38 | #include "playlist.h" | 37 | #include "playlist.h" |
39 | #include "abrepeat.h" | 38 | #include "abrepeat.h" |
40 | #include "pcmbuf.h" | 39 | #include "pcmbuf.h" |
40 | #include "audio_thread.h" | ||
41 | #include "playback.h" | 41 | #include "playback.h" |
42 | #include "misc.h" | 42 | #include "misc.h" |
43 | #include "settings.h" | 43 | #include "settings.h" |
@@ -46,10 +46,6 @@ | |||
46 | #include "tagcache.h" | 46 | #include "tagcache.h" |
47 | #endif | 47 | #endif |
48 | 48 | ||
49 | #ifdef AUDIO_HAVE_RECORDING | ||
50 | #include "pcm_record.h" | ||
51 | #endif | ||
52 | |||
53 | #ifdef HAVE_LCD_BITMAP | 49 | #ifdef HAVE_LCD_BITMAP |
54 | #ifdef HAVE_ALBUMART | 50 | #ifdef HAVE_ALBUMART |
55 | #include "albumart.h" | 51 | #include "albumart.h" |
@@ -104,8 +100,10 @@ | |||
104 | */ | 100 | */ |
105 | 101 | ||
106 | /** Miscellaneous **/ | 102 | /** Miscellaneous **/ |
107 | bool audio_is_initialized = false; /* (A,O-) */ | 103 | extern unsigned int audio_thread_id; /* from audio_thread.c */ |
108 | extern struct codec_api ci; /* (A,C) */ | 104 | extern struct event_queue audio_queue; /* from audio_thread.c */ |
105 | extern bool audio_is_initialized; /* from audio_thread.c */ | ||
106 | extern struct codec_api ci; /* from codecs.c */ | ||
109 | 107 | ||
110 | /** Possible arrangements of the main buffer **/ | 108 | /** Possible arrangements of the main buffer **/ |
111 | static enum audio_buffer_state | 109 | static enum audio_buffer_state |
@@ -190,7 +188,6 @@ static enum filling_state | |||
190 | STATE_FINISHED, /* all remaining tracks are fully buffered */ | 188 | STATE_FINISHED, /* all remaining tracks are fully buffered */ |
191 | STATE_ENDING, /* audio playback is ending */ | 189 | STATE_ENDING, /* audio playback is ending */ |
192 | STATE_ENDED, /* audio playback is done */ | 190 | STATE_ENDED, /* audio playback is done */ |
193 | STATE_USB, /* USB mode, ignore most messages */ | ||
194 | } filling = STATE_IDLE; | 191 | } filling = STATE_IDLE; |
195 | 192 | ||
196 | /* Track info - holds information about each track in the buffer */ | 193 | /* Track info - holds information about each track in the buffer */ |
@@ -330,15 +327,6 @@ static int codec_skip_status; | |||
330 | static bool codec_seeking = false; /* Codec seeking ack expected? */ | 327 | static bool codec_seeking = false; /* Codec seeking ack expected? */ |
331 | static unsigned int position_key = 0; | 328 | static unsigned int position_key = 0; |
332 | 329 | ||
333 | /* Event queues */ | ||
334 | static struct event_queue audio_queue SHAREDBSS_ATTR; | ||
335 | |||
336 | /* Audio thread */ | ||
337 | static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR; | ||
338 | static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; | ||
339 | static const char audio_thread_name[] = "audio"; | ||
340 | static unsigned int audio_thread_id = 0; | ||
341 | |||
342 | /* Forward declarations */ | 330 | /* Forward declarations */ |
343 | enum audio_start_playback_flags | 331 | enum audio_start_playback_flags |
344 | { | 332 | { |
@@ -2985,228 +2973,170 @@ static void audio_on_audio_flush(void) | |||
2985 | } | 2973 | } |
2986 | } | 2974 | } |
2987 | 2975 | ||
2988 | #ifdef AUDIO_HAVE_RECORDING | 2976 | /* Called by audio thread when playback is started */ |
2989 | /* Load the requested encoder type | 2977 | void audio_playback_handler(struct queue_event *ev) |
2990 | (Q_AUDIO_LOAD_ENCODER) */ | ||
2991 | static void audio_on_load_encoder(int afmt) | ||
2992 | { | ||
2993 | bool res = true; | ||
2994 | |||
2995 | if (play_status != PLAY_STOPPED) | ||
2996 | audio_stop_playback(); /* Can't load both types at once */ | ||
2997 | else | ||
2998 | codec_unload(); /* Encoder still loaded, stop and unload it */ | ||
2999 | |||
3000 | if (afmt != AFMT_UNKNOWN) | ||
3001 | { | ||
3002 | res = codec_load(-1, afmt | CODEC_TYPE_ENCODER); | ||
3003 | if (res) | ||
3004 | codec_go(); /* These are run immediately */ | ||
3005 | } | ||
3006 | |||
3007 | queue_reply(&audio_queue, res); | ||
3008 | } | ||
3009 | #endif /* AUDIO_HAVE_RECORDING */ | ||
3010 | |||
3011 | static void audio_thread(void) | ||
3012 | { | 2978 | { |
3013 | struct queue_event ev; | ||
3014 | |||
3015 | pcm_postinit(); | ||
3016 | |||
3017 | while (1) | 2979 | while (1) |
3018 | { | 2980 | { |
3019 | switch (filling) | 2981 | switch (ev->id) |
3020 | { | ||
3021 | /* Active states */ | ||
3022 | case STATE_FULL: | ||
3023 | case STATE_END_OF_PLAYLIST: | ||
3024 | if (buf_get_watermark() == 0) | ||
3025 | { | ||
3026 | /* End of buffering for now, let's calculate the watermark, | ||
3027 | register for a low buffer event and unboost */ | ||
3028 | audio_update_filebuf_watermark(0); | ||
3029 | add_event(BUFFER_EVENT_BUFFER_LOW, true, | ||
3030 | buffer_event_buffer_low_callback); | ||
3031 | } | ||
3032 | /* Fall-through */ | ||
3033 | case STATE_FINISHED: | ||
3034 | /* All data was buffered */ | ||
3035 | cancel_cpu_boost(); | ||
3036 | /* Fall-through */ | ||
3037 | case STATE_FILLING: | ||
3038 | case STATE_ENDING: | ||
3039 | if (audio_pcmbuf_track_change_scan()) | ||
3040 | { | ||
3041 | /* Transfer notification to audio queue event */ | ||
3042 | ev.id = Q_AUDIO_TRACK_CHANGED; | ||
3043 | ev.data = 1; | ||
3044 | } | ||
3045 | else | ||
3046 | { | ||
3047 | /* If doing auto skip, poll pcmbuf track notifications a bit | ||
3048 | faster to promply detect the transition */ | ||
3049 | queue_wait_w_tmo(&audio_queue, &ev, | ||
3050 | skip_pending == TRACK_SKIP_NONE ? | ||
3051 | HZ/2 : HZ/10); | ||
3052 | } | ||
3053 | break; | ||
3054 | |||
3055 | /* Idle states */ | ||
3056 | default: | ||
3057 | queue_wait(&audio_queue, &ev); | ||
3058 | |||
3059 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) | ||
3060 | switch (ev.id) | ||
3061 | { | ||
3062 | #ifdef AUDIO_HAVE_RECORDING | ||
3063 | /* Must monitor the encoder message for recording so it can remove | ||
3064 | it if we process the insertion before it does. It cannot simply | ||
3065 | be removed from under recording however. */ | ||
3066 | case Q_AUDIO_LOAD_ENCODER: | ||
3067 | break; | ||
3068 | #endif | ||
3069 | case SYS_USB_DISCONNECTED: | ||
3070 | filling = STATE_IDLE; | ||
3071 | break; | ||
3072 | |||
3073 | default: | ||
3074 | if (filling == STATE_USB) | ||
3075 | continue; | ||
3076 | } | ||
3077 | #endif /* CONFIG_PLATFORM */ | ||
3078 | } | ||
3079 | |||
3080 | switch (ev.id) | ||
3081 | { | 2982 | { |
3082 | /** Codec and track change messages **/ | 2983 | /** Codec and track change messages **/ |
3083 | case Q_AUDIO_CODEC_COMPLETE: | 2984 | case Q_AUDIO_CODEC_COMPLETE: |
3084 | /* Codec is done processing track and has gone idle */ | 2985 | /* Codec is done processing track and has gone idle */ |
3085 | LOGFQUEUE("audio < Q_AUDIO_CODEC_COMPLETE: %ld", (long)ev.data); | 2986 | LOGFQUEUE("playback < Q_AUDIO_CODEC_COMPLETE: %ld", |
3086 | audio_on_codec_complete(ev.data); | 2987 | (long)ev->data); |
2988 | audio_on_codec_complete(ev->data); | ||
3087 | break; | 2989 | break; |
3088 | 2990 | ||
3089 | case Q_AUDIO_CODEC_SEEK_COMPLETE: | 2991 | case Q_AUDIO_CODEC_SEEK_COMPLETE: |
3090 | /* Codec is done seeking */ | 2992 | /* Codec is done seeking */ |
3091 | LOGFQUEUE("audio < Q_AUDIO_SEEK_COMPLETE"); | 2993 | LOGFQUEUE("playback < Q_AUDIO_SEEK_COMPLETE"); |
3092 | audio_on_codec_seek_complete(); | 2994 | audio_on_codec_seek_complete(); |
3093 | break; | 2995 | break; |
3094 | 2996 | ||
3095 | case Q_AUDIO_TRACK_CHANGED: | 2997 | case Q_AUDIO_TRACK_CHANGED: |
3096 | /* PCM track change done */ | 2998 | /* PCM track change done */ |
3097 | LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED"); | 2999 | LOGFQUEUE("playback < Q_AUDIO_TRACK_CHANGED"); |
3098 | audio_on_track_changed(); | 3000 | audio_on_track_changed(); |
3099 | break; | 3001 | break; |
3100 | 3002 | ||
3101 | /** Control messages **/ | 3003 | /** Control messages **/ |
3102 | case Q_AUDIO_PLAY: | 3004 | case Q_AUDIO_PLAY: |
3103 | LOGFQUEUE("audio < Q_AUDIO_PLAY"); | 3005 | LOGFQUEUE("playback < Q_AUDIO_PLAY"); |
3104 | audio_start_playback(ev.data, 0); | 3006 | audio_start_playback(ev->data, 0); |
3105 | break; | 3007 | break; |
3106 | 3008 | ||
3009 | #ifdef AUDIO_HAVE_RECORDING | ||
3010 | /* So we can go straight from playback to recording */ | ||
3011 | case Q_AUDIO_INIT_RECORDING: | ||
3012 | #endif | ||
3013 | case SYS_USB_CONNECTED: | ||
3107 | case Q_AUDIO_STOP: | 3014 | case Q_AUDIO_STOP: |
3108 | LOGFQUEUE("audio < Q_AUDIO_STOP"); | 3015 | LOGFQUEUE("playback < Q_AUDIO_STOP"); |
3109 | audio_stop_playback(); | 3016 | audio_stop_playback(); |
3110 | if (ev.data != 0) | 3017 | if (ev->data != 0) |
3111 | queue_clear(&audio_queue); | 3018 | queue_clear(&audio_queue); |
3112 | break; | 3019 | return; /* no more playback */ |
3113 | 3020 | ||
3114 | case Q_AUDIO_PAUSE: | 3021 | case Q_AUDIO_PAUSE: |
3115 | LOGFQUEUE("audio < Q_AUDIO_PAUSE"); | 3022 | LOGFQUEUE("playback < Q_AUDIO_PAUSE"); |
3116 | audio_on_pause(ev.data); | 3023 | audio_on_pause(ev->data); |
3117 | break; | 3024 | break; |
3118 | 3025 | ||
3119 | case Q_AUDIO_SKIP: | 3026 | case Q_AUDIO_SKIP: |
3120 | LOGFQUEUE("audio < Q_AUDIO_SKIP"); | 3027 | LOGFQUEUE("playback < Q_AUDIO_SKIP"); |
3121 | audio_on_skip(); | 3028 | audio_on_skip(); |
3122 | break; | 3029 | break; |
3123 | 3030 | ||
3124 | case Q_AUDIO_DIR_SKIP: | 3031 | case Q_AUDIO_DIR_SKIP: |
3125 | LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP"); | 3032 | LOGFQUEUE("playback < Q_AUDIO_DIR_SKIP"); |
3126 | audio_on_dir_skip(ev.data); | 3033 | audio_on_dir_skip(ev->data); |
3127 | break; | 3034 | break; |
3128 | 3035 | ||
3129 | case Q_AUDIO_PRE_FF_REWIND: | 3036 | case Q_AUDIO_PRE_FF_REWIND: |
3130 | LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND"); | 3037 | LOGFQUEUE("playback < Q_AUDIO_PRE_FF_REWIND"); |
3131 | audio_on_pre_ff_rewind(); | 3038 | audio_on_pre_ff_rewind(); |
3132 | break; | 3039 | break; |
3133 | 3040 | ||
3134 | case Q_AUDIO_FF_REWIND: | 3041 | case Q_AUDIO_FF_REWIND: |
3135 | LOGFQUEUE("audio < Q_AUDIO_FF_REWIND"); | 3042 | LOGFQUEUE("playback < Q_AUDIO_FF_REWIND"); |
3136 | audio_on_ff_rewind(ev.data); | 3043 | audio_on_ff_rewind(ev->data); |
3137 | break; | 3044 | break; |
3138 | 3045 | ||
3139 | case Q_AUDIO_FLUSH: | 3046 | case Q_AUDIO_FLUSH: |
3140 | LOGFQUEUE("audio < Q_AUDIO_FLUSH: %d", (int)ev.data); | 3047 | LOGFQUEUE("playback < Q_AUDIO_FLUSH: %d", (int)ev->data); |
3141 | audio_on_audio_flush(); | 3048 | audio_on_audio_flush(); |
3142 | break; | 3049 | break; |
3143 | 3050 | ||
3144 | /** Buffering messages **/ | 3051 | /** Buffering messages **/ |
3145 | case Q_AUDIO_BUFFERING: | 3052 | case Q_AUDIO_BUFFERING: |
3146 | /* some buffering event */ | 3053 | /* some buffering event */ |
3147 | LOGFQUEUE("audio < Q_AUDIO_BUFFERING: %d", (int)ev.data); | 3054 | LOGFQUEUE("playback < Q_AUDIO_BUFFERING: %d", (int)ev->data); |
3148 | audio_on_buffering(ev.data); | 3055 | audio_on_buffering(ev->data); |
3149 | break; | 3056 | break; |
3150 | 3057 | ||
3151 | case Q_AUDIO_FILL_BUFFER: | 3058 | case Q_AUDIO_FILL_BUFFER: |
3152 | /* continue buffering next track */ | 3059 | /* continue buffering next track */ |
3153 | LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER"); | 3060 | LOGFQUEUE("playback < Q_AUDIO_FILL_BUFFER"); |
3154 | audio_on_fill_buffer(); | 3061 | audio_on_fill_buffer(); |
3155 | break; | 3062 | break; |
3156 | 3063 | ||
3157 | case Q_AUDIO_FINISH_LOAD_TRACK: | 3064 | case Q_AUDIO_FINISH_LOAD_TRACK: |
3158 | /* metadata is buffered */ | 3065 | /* metadata is buffered */ |
3159 | LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD_TRACK"); | 3066 | LOGFQUEUE("playback < Q_AUDIO_FINISH_LOAD_TRACK"); |
3160 | audio_on_finish_load_track(ev.data); | 3067 | audio_on_finish_load_track(ev->data); |
3161 | break; | 3068 | break; |
3162 | 3069 | ||
3163 | case Q_AUDIO_HANDLE_FINISHED: | 3070 | case Q_AUDIO_HANDLE_FINISHED: |
3164 | /* some other type is buffered */ | 3071 | /* some other type is buffered */ |
3165 | LOGFQUEUE("audio < Q_AUDIO_HANDLE_FINISHED"); | 3072 | LOGFQUEUE("playback < Q_AUDIO_HANDLE_FINISHED"); |
3166 | audio_on_handle_finished(ev.data); | 3073 | audio_on_handle_finished(ev->data); |
3167 | break; | 3074 | break; |
3168 | 3075 | ||
3169 | /** Miscellaneous messages **/ | 3076 | /** Miscellaneous messages **/ |
3170 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: | 3077 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: |
3171 | /* buffer needs to be reinitialized */ | 3078 | /* buffer needs to be reinitialized */ |
3172 | LOGFQUEUE("audio < Q_AUDIO_REMAKE_AUDIO_BUFFER"); | 3079 | LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); |
3173 | audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF); | 3080 | audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF); |
3174 | break; | 3081 | break; |
3175 | 3082 | ||
3176 | #ifdef HAVE_DISK_STORAGE | 3083 | #ifdef HAVE_DISK_STORAGE |
3177 | case Q_AUDIO_UPDATE_WATERMARK: | 3084 | case Q_AUDIO_UPDATE_WATERMARK: |
3178 | /* buffering watermark needs updating */ | 3085 | /* buffering watermark needs updating */ |
3179 | LOGFQUEUE("audio < Q_AUDIO_UPDATE_WATERMARK: %d", (int)ev.data); | 3086 | LOGFQUEUE("playback < Q_AUDIO_UPDATE_WATERMARK: %d", |
3180 | audio_update_filebuf_watermark(ev.data); | 3087 | (int)ev->data); |
3088 | audio_update_filebuf_watermark(ev->data); | ||
3181 | break; | 3089 | break; |
3182 | #endif /* HAVE_DISK_STORAGE */ | 3090 | #endif /* HAVE_DISK_STORAGE */ |
3183 | 3091 | ||
3184 | #ifdef AUDIO_HAVE_RECORDING | 3092 | case SYS_TIMEOUT: |
3185 | case Q_AUDIO_LOAD_ENCODER: | 3093 | LOGFQUEUE_SYS_TIMEOUT("playback < SYS_TIMEOUT"); |
3186 | /* load an encoder for recording */ | ||
3187 | LOGFQUEUE("audio < Q_AUDIO_LOAD_ENCODER: %d", (int)ev.data); | ||
3188 | audio_on_load_encoder(ev.data); | ||
3189 | break; | 3094 | break; |
3190 | #endif /* AUDIO_HAVE_RECORDING */ | ||
3191 | 3095 | ||
3192 | case SYS_USB_CONNECTED: | 3096 | default: |
3193 | LOGFQUEUE("audio < SYS_USB_CONNECTED"); | 3097 | /* LOGFQUEUE("audio < default : %08lX", ev->id); */ |
3194 | audio_stop_playback(); | ||
3195 | #ifdef PLAYBACK_VOICE | ||
3196 | voice_stop(); | ||
3197 | #endif | ||
3198 | filling = STATE_USB; | ||
3199 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
3200 | break; | 3098 | break; |
3099 | } /* end switch */ | ||
3201 | 3100 | ||
3202 | case SYS_TIMEOUT: | 3101 | switch (filling) |
3203 | LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT"); | 3102 | { |
3103 | /* Active states */ | ||
3104 | case STATE_FULL: | ||
3105 | case STATE_END_OF_PLAYLIST: | ||
3106 | if (buf_get_watermark() == 0) | ||
3107 | { | ||
3108 | /* End of buffering for now, let's calculate the watermark, | ||
3109 | register for a low buffer event and unboost */ | ||
3110 | audio_update_filebuf_watermark(0); | ||
3111 | add_event(BUFFER_EVENT_BUFFER_LOW, true, | ||
3112 | buffer_event_buffer_low_callback); | ||
3113 | } | ||
3114 | /* Fall-through */ | ||
3115 | case STATE_FINISHED: | ||
3116 | /* All data was buffered */ | ||
3117 | cancel_cpu_boost(); | ||
3118 | /* Fall-through */ | ||
3119 | case STATE_FILLING: | ||
3120 | case STATE_ENDING: | ||
3121 | if (audio_pcmbuf_track_change_scan()) | ||
3122 | { | ||
3123 | /* Transfer notification to audio queue event */ | ||
3124 | ev->id = Q_AUDIO_TRACK_CHANGED; | ||
3125 | ev->data = 1; | ||
3126 | } | ||
3127 | else | ||
3128 | { | ||
3129 | /* If doing auto skip, poll pcmbuf track notifications a bit | ||
3130 | faster to promply detect the transition */ | ||
3131 | queue_wait_w_tmo(&audio_queue, ev, | ||
3132 | skip_pending == TRACK_SKIP_NONE ? HZ/2 : HZ/10); | ||
3133 | } | ||
3204 | break; | 3134 | break; |
3205 | 3135 | ||
3136 | /* Idle states */ | ||
3206 | default: | 3137 | default: |
3207 | /* LOGFQUEUE("audio < default : %08lX", ev.id); */ | 3138 | queue_wait(&audio_queue, ev); |
3208 | break; | 3139 | } |
3209 | } /* end switch */ | ||
3210 | } /* end while */ | 3140 | } /* end while */ |
3211 | } | 3141 | } |
3212 | 3142 | ||
@@ -3356,27 +3286,6 @@ bool audio_pcmbuf_may_play(void) | |||
3356 | 3286 | ||
3357 | /** -- External interfaces -- **/ | 3287 | /** -- External interfaces -- **/ |
3358 | 3288 | ||
3359 | /* Return the playback and recording status */ | ||
3360 | int audio_status(void) | ||
3361 | { | ||
3362 | unsigned int ret = play_status; | ||
3363 | |||
3364 | #ifdef AUDIO_HAVE_RECORDING | ||
3365 | /* Do this here for constitency with mpeg.c version */ | ||
3366 | ret |= pcm_rec_status(); | ||
3367 | #endif | ||
3368 | |||
3369 | return (int)ret; | ||
3370 | } | ||
3371 | |||
3372 | /* Clear all accumulated audio errors for playback and recording */ | ||
3373 | void audio_error_clear(void) | ||
3374 | { | ||
3375 | #ifdef AUDIO_HAVE_RECORDING | ||
3376 | pcm_rec_error_clear(); | ||
3377 | #endif | ||
3378 | } | ||
3379 | |||
3380 | /* Get a copy of the id3 data for the for current track + offset + skip delta */ | 3289 | /* Get a copy of the id3 data for the for current track + offset + skip delta */ |
3381 | bool audio_peek_track(struct mp3entry *id3, int offset) | 3290 | bool audio_peek_track(struct mp3entry *id3, int offset) |
3382 | { | 3291 | { |
@@ -3599,7 +3508,7 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) | |||
3599 | { | 3508 | { |
3600 | unsigned char *buf; | 3509 | unsigned char *buf; |
3601 | 3510 | ||
3602 | if (audio_is_initialized) | 3511 | if (audio_is_initialized && thread_self() != audio_thread_id) |
3603 | { | 3512 | { |
3604 | audio_hard_stop(); | 3513 | audio_hard_stop(); |
3605 | } | 3514 | } |
@@ -3656,15 +3565,6 @@ unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size) | |||
3656 | return buf; | 3565 | return buf; |
3657 | } | 3566 | } |
3658 | 3567 | ||
3659 | #ifdef HAVE_RECORDING | ||
3660 | /* Stop audio, voice and obtain all available buffer space */ | ||
3661 | unsigned char * audio_get_recording_buffer(size_t *buffer_size) | ||
3662 | { | ||
3663 | audio_hard_stop(); | ||
3664 | return audio_get_buffer(true, buffer_size); | ||
3665 | } | ||
3666 | #endif /* HAVE_RECORDING */ | ||
3667 | |||
3668 | /* Restore audio buffer to a particular state (promoting status) */ | 3568 | /* Restore audio buffer to a particular state (promoting status) */ |
3669 | bool audio_restore_playback(int type) | 3569 | bool audio_restore_playback(int type) |
3670 | { | 3570 | { |
@@ -3755,30 +3655,6 @@ void playback_release_aa_slot(int slot) | |||
3755 | } | 3655 | } |
3756 | #endif /* HAVE_ALBUMART */ | 3656 | #endif /* HAVE_ALBUMART */ |
3757 | 3657 | ||
3758 | |||
3759 | #ifdef HAVE_RECORDING | ||
3760 | /* Load an encoder and run it */ | ||
3761 | bool audio_load_encoder(int afmt) | ||
3762 | { | ||
3763 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) | ||
3764 | LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: %d", afmt); | ||
3765 | return audio_queue_send(Q_AUDIO_LOAD_ENCODER, afmt) != 0; | ||
3766 | #else | ||
3767 | (void)afmt; | ||
3768 | return true; | ||
3769 | #endif | ||
3770 | } | ||
3771 | |||
3772 | /* Stop an encoder and unload it */ | ||
3773 | void audio_remove_encoder(void) | ||
3774 | { | ||
3775 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) | ||
3776 | LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: NULL"); | ||
3777 | audio_queue_send(Q_AUDIO_LOAD_ENCODER, AFMT_UNKNOWN); | ||
3778 | #endif | ||
3779 | } | ||
3780 | #endif /* HAVE_RECORDING */ | ||
3781 | |||
3782 | /* Is an automatic skip in progress? If called outside transition callbacks, | 3658 | /* Is an automatic skip in progress? If called outside transition callbacks, |
3783 | indicates the last skip type at the time it was processed and isn't very | 3659 | indicates the last skip type at the time it was processed and isn't very |
3784 | meaningful. */ | 3660 | meaningful. */ |
@@ -3866,58 +3742,24 @@ void audio_set_crossfade(int enable) | |||
3866 | } | 3742 | } |
3867 | #endif /* HAVE_CROSSFADE */ | 3743 | #endif /* HAVE_CROSSFADE */ |
3868 | 3744 | ||
3745 | unsigned int playback_status(void) | ||
3746 | { | ||
3747 | return play_status; | ||
3748 | } | ||
3869 | 3749 | ||
3870 | /** -- Startup -- **/ | 3750 | /** -- Startup -- **/ |
3871 | 3751 | void playback_init(void) | |
3872 | /* Initialize the audio system - called from init() in main.c */ | ||
3873 | void audio_init(void) | ||
3874 | { | 3752 | { |
3875 | /* Can never do this twice */ | 3753 | logf("playback: initializing"); |
3876 | if (audio_is_initialized) | ||
3877 | { | ||
3878 | logf("audio: already initialized"); | ||
3879 | return; | ||
3880 | } | ||
3881 | |||
3882 | logf("audio: initializing"); | ||
3883 | |||
3884 | /* Initialize queues before giving control elsewhere in case it likes | ||
3885 | to send messages. Thread creation will be delayed however so nothing | ||
3886 | starts running until ready if something yields such as talk_init. */ | ||
3887 | queue_init(&audio_queue, true); | ||
3888 | |||
3889 | mutex_init(&id3_mutex); | ||
3890 | |||
3891 | pcm_init(); | ||
3892 | |||
3893 | codec_thread_init(); | ||
3894 | |||
3895 | /* This thread does buffer, so match its priority */ | ||
3896 | audio_thread_id = create_thread(audio_thread, audio_stack, | ||
3897 | sizeof(audio_stack), 0, audio_thread_name | ||
3898 | IF_PRIO(, MIN(PRIORITY_BUFFERING, PRIORITY_USER_INTERFACE)) | ||
3899 | IF_COP(, CPU)); | ||
3900 | |||
3901 | queue_enable_queue_send(&audio_queue, &audio_queue_sender_list, | ||
3902 | audio_thread_id); | ||
3903 | 3754 | ||
3904 | /* Initialize the track buffering system */ | 3755 | /* Initialize the track buffering system */ |
3756 | mutex_init(&id3_mutex); | ||
3905 | track_list_init(); | 3757 | track_list_init(); |
3906 | buffering_init(); | 3758 | buffering_init(); |
3907 | |||
3908 | #ifdef HAVE_CROSSFADE | 3759 | #ifdef HAVE_CROSSFADE |
3909 | /* Set crossfade setting for next buffer init which should be about... */ | 3760 | /* Set crossfade setting for next buffer init which should be about... */ |
3910 | pcmbuf_request_crossfade_enable(global_settings.crossfade); | 3761 | pcmbuf_request_crossfade_enable(global_settings.crossfade); |
3911 | #endif | 3762 | #endif |
3912 | |||
3913 | /* ...now...audio_reset_buffer must know the size of voicefile buffer so | ||
3914 | init talk first which will init the buffers */ | ||
3915 | talk_init(); | ||
3916 | |||
3917 | /* Probably safe to say */ | ||
3918 | audio_is_initialized = true; | ||
3919 | |||
3920 | sound_settings_apply(); | ||
3921 | #ifdef HAVE_DISK_STORAGE | 3763 | #ifdef HAVE_DISK_STORAGE |
3922 | audio_set_buffer_margin(global_settings.buffer_margin); | 3764 | audio_set_buffer_margin(global_settings.buffer_margin); |
3923 | #endif | 3765 | #endif |
diff --git a/apps/playback.h b/apps/playback.h index 5135c988cb..865e9a313b 100644 --- a/apps/playback.h +++ b/apps/playback.h | |||
@@ -92,68 +92,6 @@ size_t audio_get_filebuflen(void); | |||
92 | otherwise the result is undefined. */ | 92 | otherwise the result is undefined. */ |
93 | bool audio_automatic_skip(void); | 93 | bool audio_automatic_skip(void); |
94 | 94 | ||
95 | /* Define one constant that includes recording related functionality */ | 95 | unsigned int playback_status(void); |
96 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | ||
97 | #define AUDIO_HAVE_RECORDING | ||
98 | #endif | ||
99 | |||
100 | enum { | ||
101 | Q_NULL = 0, /* reserved */ | ||
102 | |||
103 | /* -> audio */ | ||
104 | Q_AUDIO_PLAY = 1, | ||
105 | Q_AUDIO_STOP, | ||
106 | Q_AUDIO_PAUSE, | ||
107 | Q_AUDIO_SKIP, | ||
108 | Q_AUDIO_PRE_FF_REWIND, | ||
109 | Q_AUDIO_FF_REWIND, | ||
110 | Q_AUDIO_FLUSH, | ||
111 | Q_AUDIO_DIR_SKIP, | ||
112 | |||
113 | /* pcmbuf -> audio */ | ||
114 | Q_AUDIO_TRACK_CHANGED, | ||
115 | |||
116 | /* audio -> audio */ | ||
117 | Q_AUDIO_FILL_BUFFER, /* continue buffering next track */ | ||
118 | |||
119 | /* buffering -> audio */ | ||
120 | Q_AUDIO_BUFFERING, /* some buffer event */ | ||
121 | Q_AUDIO_FINISH_LOAD_TRACK, /* metadata is buffered */ | ||
122 | Q_AUDIO_HANDLE_FINISHED, /* some other type is buffered */ | ||
123 | |||
124 | /* codec -> audio (*) */ | ||
125 | Q_AUDIO_CODEC_SEEK_COMPLETE, | ||
126 | Q_AUDIO_CODEC_COMPLETE, | ||
127 | |||
128 | /* audio -> codec */ | ||
129 | Q_CODEC_LOAD, | ||
130 | Q_CODEC_RUN, | ||
131 | Q_CODEC_PAUSE, | ||
132 | Q_CODEC_SEEK, | ||
133 | Q_CODEC_STOP, | ||
134 | Q_CODEC_UNLOAD, | ||
135 | |||
136 | |||
137 | /*- miscellanous -*/ | ||
138 | #ifdef AUDIO_HAVE_RECORDING | ||
139 | /* -> codec */ | ||
140 | Q_AUDIO_LOAD_ENCODER, /* load an encoder for recording */ | ||
141 | #endif | ||
142 | /* -> codec */ | ||
143 | Q_CODEC_DO_CALLBACK, | ||
144 | |||
145 | |||
146 | /*- settings -*/ | ||
147 | |||
148 | #ifdef HAVE_DISK_STORAGE | ||
149 | /* -> audio */ | ||
150 | Q_AUDIO_UPDATE_WATERMARK, /* buffering watermark needs updating */ | ||
151 | #endif | ||
152 | /* -> audio */ | ||
153 | Q_AUDIO_REMAKE_AUDIO_BUFFER, /* buffer needs to be reinitialized */ | ||
154 | }; | ||
155 | |||
156 | /* (*) If you change these, you must check audio_clear_track_notifications | ||
157 | in playback.c for correctness */ | ||
158 | 96 | ||
159 | #endif /* _PLAYBACK_H */ | 97 | #endif /* _PLAYBACK_H */ |
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c index fe7a54a565..a45dcc2d11 100644 --- a/apps/recorder/pcm_record.c +++ b/apps/recorder/pcm_record.c | |||
@@ -38,11 +38,13 @@ | |||
38 | #ifdef HAVE_SPDIF_IN | 38 | #ifdef HAVE_SPDIF_IN |
39 | #include "spdif.h" | 39 | #include "spdif.h" |
40 | #endif | 40 | #endif |
41 | #include "audio_thread.h" | ||
41 | 42 | ||
42 | /***************************************************************************/ | 43 | /***************************************************************************/ |
43 | 44 | ||
45 | extern struct event_queue audio_queue; | ||
46 | |||
44 | /** General recording state **/ | 47 | /** General recording state **/ |
45 | static bool is_initialized = false; /* Subsystem ready? */ | ||
46 | static bool is_recording; /* We are recording */ | 48 | static bool is_recording; /* We are recording */ |
47 | static bool is_paused; /* We have paused */ | 49 | static bool is_paused; /* We have paused */ |
48 | static unsigned long errors; /* An error has occured */ | 50 | static unsigned long errors; /* An error has occured */ |
@@ -230,14 +232,6 @@ enum | |||
230 | 232 | ||
231 | /***************************************************************************/ | 233 | /***************************************************************************/ |
232 | 234 | ||
233 | static struct event_queue pcmrec_queue SHAREDBSS_ATTR; | ||
234 | static struct queue_sender_list pcmrec_queue_send SHAREDBSS_ATTR; | ||
235 | static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)]; | ||
236 | static const char pcmrec_thread_name[] = "pcmrec"; | ||
237 | static unsigned int pcmrec_thread_id = 0; | ||
238 | |||
239 | static void pcmrec_thread(void); | ||
240 | |||
241 | enum | 235 | enum |
242 | { | 236 | { |
243 | PCMREC_NULL = 0, | 237 | PCMREC_NULL = 0, |
@@ -248,14 +242,23 @@ enum | |||
248 | PCMREC_STOP, /* stop the current recording */ | 242 | PCMREC_STOP, /* stop the current recording */ |
249 | PCMREC_PAUSE, /* pause the current recording */ | 243 | PCMREC_PAUSE, /* pause the current recording */ |
250 | PCMREC_RESUME, /* resume the current recording */ | 244 | PCMREC_RESUME, /* resume the current recording */ |
251 | #if 0 | ||
252 | PCMREC_FLUSH_NUM, /* flush a number of files out */ | ||
253 | #endif | ||
254 | }; | 245 | }; |
255 | 246 | ||
256 | /*******************************************************************/ | 247 | /*******************************************************************/ |
257 | /* Functions that are not executing in the pcmrec_thread first */ | 248 | /* Functions that are not executing in the audio thread first */ |
258 | /*******************************************************************/ | 249 | /*******************************************************************/ |
250 | |||
251 | static void pcmrec_raise_error_status(unsigned long e) | ||
252 | { | ||
253 | pcm_rec_lock(); /* DMA sets this too */ | ||
254 | errors |= e; | ||
255 | pcm_rec_unlock(); | ||
256 | } | ||
257 | |||
258 | static void pcmrec_raise_warning_status(unsigned long w) | ||
259 | { | ||
260 | warnings |= w; | ||
261 | } | ||
259 | 262 | ||
260 | /* Callback for when more data is ready - called in interrupt context */ | 263 | /* Callback for when more data is ready - called in interrupt context */ |
261 | static void pcm_rec_have_more(void **start, size_t *size) | 264 | static void pcm_rec_have_more(void **start, size_t *size) |
@@ -268,7 +271,7 @@ static void pcm_rec_have_more(void **start, size_t *size) | |||
268 | /* set pcm ovf if processing start position is inside current | 271 | /* set pcm ovf if processing start position is inside current |
269 | write chunk */ | 272 | write chunk */ |
270 | if ((unsigned)(pcm_enc_pos - next_pos) < PCM_CHUNK_SIZE) | 273 | if ((unsigned)(pcm_enc_pos - next_pos) < PCM_CHUNK_SIZE) |
271 | warnings |= PCMREC_W_PCM_BUFFER_OVF; | 274 | pcmrec_raise_warning_status(PCMREC_W_PCM_BUFFER_OVF); |
272 | 275 | ||
273 | dma_wr_pos = next_pos; | 276 | dma_wr_pos = next_pos; |
274 | } | 277 | } |
@@ -285,7 +288,7 @@ static enum pcm_dma_status pcm_rec_status_callback(enum pcm_dma_status status) | |||
285 | if (status == PCM_DMAST_ERR_DMA) | 288 | if (status == PCM_DMAST_ERR_DMA) |
286 | { | 289 | { |
287 | /* Flush recorded data to disk and stop recording */ | 290 | /* Flush recorded data to disk and stop recording */ |
288 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | 291 | errors |= PCMREC_E_DMA; |
289 | return status; | 292 | return status; |
290 | } | 293 | } |
291 | /* else try again next transmission - frame is invalid */ | 294 | /* else try again next transmission - frame is invalid */ |
@@ -315,9 +318,9 @@ void pcm_rec_error_clear(void) | |||
315 | /** | 318 | /** |
316 | * Check mode, errors and warnings | 319 | * Check mode, errors and warnings |
317 | */ | 320 | */ |
318 | unsigned long pcm_rec_status(void) | 321 | unsigned int pcm_rec_status(void) |
319 | { | 322 | { |
320 | unsigned long ret = 0; | 323 | unsigned int ret = 0; |
321 | 324 | ||
322 | if (is_recording) | 325 | if (is_recording) |
323 | ret |= AUDIO_STATUS_RECORD; | 326 | ret |= AUDIO_STATUS_RECORD; |
@@ -379,20 +382,6 @@ unsigned long pcm_rec_sample_rate(void) | |||
379 | } /* audio_get_sample_rate */ | 382 | } /* audio_get_sample_rate */ |
380 | #endif | 383 | #endif |
381 | 384 | ||
382 | /** | ||
383 | * Creates pcmrec_thread | ||
384 | */ | ||
385 | void pcm_rec_init(void) | ||
386 | { | ||
387 | queue_init(&pcmrec_queue, true); | ||
388 | pcmrec_thread_id = | ||
389 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), | ||
390 | 0, pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING) | ||
391 | IF_COP(, CPU)); | ||
392 | queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send, | ||
393 | pcmrec_thread_id); | ||
394 | } /* pcm_rec_init */ | ||
395 | |||
396 | /** audio_* group **/ | 385 | /** audio_* group **/ |
397 | 386 | ||
398 | /** | 387 | /** |
@@ -401,7 +390,7 @@ void pcm_rec_init(void) | |||
401 | void audio_init_recording(void) | 390 | void audio_init_recording(void) |
402 | { | 391 | { |
403 | logf("audio_init_recording"); | 392 | logf("audio_init_recording"); |
404 | queue_send(&pcmrec_queue, PCMREC_INIT, 0); | 393 | queue_send(&audio_queue, Q_AUDIO_INIT_RECORDING, 1); |
405 | logf("audio_init_recording done"); | 394 | logf("audio_init_recording done"); |
406 | } /* audio_init_recording */ | 395 | } /* audio_init_recording */ |
407 | 396 | ||
@@ -411,7 +400,7 @@ void audio_init_recording(void) | |||
411 | void audio_close_recording(void) | 400 | void audio_close_recording(void) |
412 | { | 401 | { |
413 | logf("audio_close_recording"); | 402 | logf("audio_close_recording"); |
414 | queue_send(&pcmrec_queue, PCMREC_CLOSE, 0); | 403 | queue_send(&audio_queue, Q_AUDIO_CLOSE_RECORDING, 0); |
415 | logf("audio_close_recording done"); | 404 | logf("audio_close_recording done"); |
416 | } /* audio_close_recording */ | 405 | } /* audio_close_recording */ |
417 | 406 | ||
@@ -421,7 +410,7 @@ void audio_close_recording(void) | |||
421 | void audio_set_recording_options(struct audio_recording_options *options) | 410 | void audio_set_recording_options(struct audio_recording_options *options) |
422 | { | 411 | { |
423 | logf("audio_set_recording_options"); | 412 | logf("audio_set_recording_options"); |
424 | queue_send(&pcmrec_queue, PCMREC_OPTIONS, (intptr_t)options); | 413 | queue_send(&audio_queue, Q_AUDIO_RECORDING_OPTIONS, (intptr_t)options); |
425 | logf("audio_set_recording_options done"); | 414 | logf("audio_set_recording_options done"); |
426 | } /* audio_set_recording_options */ | 415 | } /* audio_set_recording_options */ |
427 | 416 | ||
@@ -432,7 +421,7 @@ void audio_record(const char *filename) | |||
432 | { | 421 | { |
433 | logf("audio_record: %s", filename); | 422 | logf("audio_record: %s", filename); |
434 | flush_interrupt(); | 423 | flush_interrupt(); |
435 | queue_send(&pcmrec_queue, PCMREC_RECORD, (intptr_t)filename); | 424 | queue_send(&audio_queue, Q_AUDIO_RECORD, (intptr_t)filename); |
436 | logf("audio_record_done"); | 425 | logf("audio_record_done"); |
437 | } /* audio_record */ | 426 | } /* audio_record */ |
438 | 427 | ||
@@ -451,7 +440,7 @@ void audio_stop_recording(void) | |||
451 | { | 440 | { |
452 | logf("audio_stop_recording"); | 441 | logf("audio_stop_recording"); |
453 | flush_interrupt(); | 442 | flush_interrupt(); |
454 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | 443 | queue_post(&audio_queue, Q_AUDIO_STOP, 0); |
455 | logf("audio_stop_recording done"); | 444 | logf("audio_stop_recording done"); |
456 | } /* audio_stop_recording */ | 445 | } /* audio_stop_recording */ |
457 | 446 | ||
@@ -462,7 +451,7 @@ void audio_pause_recording(void) | |||
462 | { | 451 | { |
463 | logf("audio_pause_recording"); | 452 | logf("audio_pause_recording"); |
464 | flush_interrupt(); | 453 | flush_interrupt(); |
465 | queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); | 454 | queue_post(&audio_queue, Q_AUDIO_PAUSE, 0); |
466 | logf("audio_pause_recording done"); | 455 | logf("audio_pause_recording done"); |
467 | } /* audio_pause_recording */ | 456 | } /* audio_pause_recording */ |
468 | 457 | ||
@@ -472,7 +461,7 @@ void audio_pause_recording(void) | |||
472 | void audio_resume_recording(void) | 461 | void audio_resume_recording(void) |
473 | { | 462 | { |
474 | logf("audio_resume_recording"); | 463 | logf("audio_resume_recording"); |
475 | queue_post(&pcmrec_queue, PCMREC_RESUME, 0); | 464 | queue_post(&audio_queue, Q_AUDIO_RESUME, 0); |
476 | logf("audio_resume_recording done"); | 465 | logf("audio_resume_recording done"); |
477 | } /* audio_resume_recording */ | 466 | } /* audio_resume_recording */ |
478 | 467 | ||
@@ -517,10 +506,46 @@ unsigned long audio_num_recorded_bytes(void) | |||
517 | 506 | ||
518 | /***************************************************************************/ | 507 | /***************************************************************************/ |
519 | /* */ | 508 | /* */ |
520 | /* Functions that execute in the context of pcmrec_thread */ | 509 | /* Functions that execute in the context of audio thread */ |
521 | /* */ | 510 | /* */ |
522 | /***************************************************************************/ | 511 | /***************************************************************************/ |
523 | 512 | ||
513 | static void pcmrec_init_state(void) | ||
514 | { | ||
515 | flush_interrupts = 0; | ||
516 | |||
517 | /* warings and errors */ | ||
518 | warnings = | ||
519 | errors = 0; | ||
520 | |||
521 | /* pcm FIFO */ | ||
522 | dma_lock = true; | ||
523 | pcm_rd_pos = 0; | ||
524 | dma_wr_pos = 0; | ||
525 | pcm_enc_pos = 0; | ||
526 | |||
527 | /* encoder FIFO */ | ||
528 | enc_wr_index = 0; | ||
529 | enc_rd_index = 0; | ||
530 | |||
531 | /* filename queue */ | ||
532 | fnq_rd_pos = 0; | ||
533 | fnq_wr_pos = 0; | ||
534 | |||
535 | /* stats */ | ||
536 | num_rec_bytes = 0; | ||
537 | num_rec_samples = 0; | ||
538 | #if 0 | ||
539 | accum_rec_bytes = 0; | ||
540 | accum_pcm_samples = 0; | ||
541 | #endif | ||
542 | |||
543 | pre_record_ticks = 0; | ||
544 | |||
545 | is_recording = false; | ||
546 | is_paused = false; | ||
547 | } /* pcmrec_init_state */ | ||
548 | |||
524 | /** Filename Queue **/ | 549 | /** Filename Queue **/ |
525 | 550 | ||
526 | /* returns true if the queue is empty */ | 551 | /* returns true if the queue is empty */ |
@@ -594,7 +619,7 @@ static void pcmrec_close_file(int *fd_p) | |||
594 | return; /* preserve error */ | 619 | return; /* preserve error */ |
595 | 620 | ||
596 | if (close(*fd_p) != 0) | 621 | if (close(*fd_p) != 0) |
597 | errors |= PCMREC_E_IO; | 622 | pcmrec_raise_error_status(PCMREC_E_IO); |
598 | 623 | ||
599 | *fd_p = -1; | 624 | *fd_p = -1; |
600 | } /* pcmrec_close_file */ | 625 | } /* pcmrec_close_file */ |
@@ -646,7 +671,7 @@ static void pcmrec_start_file(void) | |||
646 | { | 671 | { |
647 | logf("start file: fnq empty"); | 672 | logf("start file: fnq empty"); |
648 | *filename = '\0'; | 673 | *filename = '\0'; |
649 | errors |= PCMREC_E_FNQ_DESYNC; | 674 | pcmrec_raise_error_status(PCMREC_E_FNQ_DESYNC); |
650 | } | 675 | } |
651 | else if (errors != 0) | 676 | else if (errors != 0) |
652 | { | 677 | { |
@@ -656,7 +681,7 @@ static void pcmrec_start_file(void) | |||
656 | { | 681 | { |
657 | /* Any previous file should have been closed */ | 682 | /* Any previous file should have been closed */ |
658 | logf("start file: file already open"); | 683 | logf("start file: file already open"); |
659 | errors |= PCMREC_E_FNQ_DESYNC; | 684 | pcmrec_raise_error_status(PCMREC_E_FNQ_DESYNC); |
660 | } | 685 | } |
661 | 686 | ||
662 | if (errors != 0) | 687 | if (errors != 0) |
@@ -671,7 +696,7 @@ static void pcmrec_start_file(void) | |||
671 | if (errors == 0 && (rec_fdata.chunk->flags & CHUNKF_ERROR)) | 696 | if (errors == 0 && (rec_fdata.chunk->flags & CHUNKF_ERROR)) |
672 | { | 697 | { |
673 | logf("start file: enc error"); | 698 | logf("start file: enc error"); |
674 | errors |= PCMREC_E_ENCODER; | 699 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
675 | } | 700 | } |
676 | 701 | ||
677 | if (errors != 0) | 702 | if (errors != 0) |
@@ -706,7 +731,7 @@ static inline void pcmrec_write_chunk(void) | |||
706 | { | 731 | { |
707 | logf("wr chk enc error %lu %lu", | 732 | logf("wr chk enc error %lu %lu", |
708 | rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); | 733 | rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); |
709 | errors |= PCMREC_E_ENCODER; | 734 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
710 | } | 735 | } |
711 | } /* pcmrec_write_chunk */ | 736 | } /* pcmrec_write_chunk */ |
712 | 737 | ||
@@ -725,7 +750,7 @@ static void pcmrec_end_file(void) | |||
725 | if (rec_fdata.chunk->flags & CHUNKF_ERROR) | 750 | if (rec_fdata.chunk->flags & CHUNKF_ERROR) |
726 | { | 751 | { |
727 | logf("end file: enc error"); | 752 | logf("end file: enc error"); |
728 | errors |= PCMREC_E_ENCODER; | 753 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
729 | } | 754 | } |
730 | else | 755 | else |
731 | { | 756 | { |
@@ -946,7 +971,7 @@ static void pcmrec_flush(unsigned flush_num) | |||
946 | 971 | ||
947 | /* sync file */ | 972 | /* sync file */ |
948 | if (rec_fdata.rec_file >= 0 && fsync(rec_fdata.rec_file) != 0) | 973 | if (rec_fdata.rec_file >= 0 && fsync(rec_fdata.rec_file) != 0) |
949 | errors |= PCMREC_E_IO; | 974 | pcmrec_raise_error_status(PCMREC_E_IO); |
950 | 975 | ||
951 | cpu_boost(false); | 976 | cpu_boost(false); |
952 | 977 | ||
@@ -1001,7 +1026,7 @@ static void pcmrec_new_stream(const char *filename, /* next file name */ | |||
1001 | 1026 | ||
1002 | if (filename) | 1027 | if (filename) |
1003 | strlcpy(path, filename, MAX_PATH); | 1028 | strlcpy(path, filename, MAX_PATH); |
1004 | queue_reply(&pcmrec_queue, 0); /* We have all we need */ | 1029 | queue_reply(&audio_queue, 0); /* We have all we need */ |
1005 | 1030 | ||
1006 | data.pre_chunk = NULL; | 1031 | data.pre_chunk = NULL; |
1007 | data.chunk = GET_ENC_CHUNK(enc_wr_index); | 1032 | data.chunk = GET_ENC_CHUNK(enc_wr_index); |
@@ -1129,51 +1154,18 @@ static void pcmrec_new_stream(const char *filename, /* next file name */ | |||
1129 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH); | 1154 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH); |
1130 | } /* pcmrec_new_stream */ | 1155 | } /* pcmrec_new_stream */ |
1131 | 1156 | ||
1157 | |||
1132 | /** event handlers for pcmrec thread */ | 1158 | /** event handlers for pcmrec thread */ |
1133 | 1159 | ||
1134 | /* PCMREC_INIT */ | 1160 | /* PCMREC_INIT */ |
1135 | static void pcmrec_init(void) | 1161 | static void pcmrec_init(void) |
1136 | { | 1162 | { |
1137 | is_initialized = true; | ||
1138 | |||
1139 | unsigned char *buffer; | ||
1140 | send_event(RECORDING_EVENT_START, NULL); | 1163 | send_event(RECORDING_EVENT_START, NULL); |
1141 | |||
1142 | /* warings and errors */ | ||
1143 | warnings = | ||
1144 | errors = 0; | ||
1145 | |||
1146 | pcmrec_close_file(&rec_fdata.rec_file); | 1164 | pcmrec_close_file(&rec_fdata.rec_file); |
1147 | rec_fdata.rec_file = -1; | ||
1148 | 1165 | ||
1149 | /* pcm FIFO */ | 1166 | pcmrec_init_state(); |
1150 | dma_lock = true; | ||
1151 | pcm_rd_pos = 0; | ||
1152 | dma_wr_pos = 0; | ||
1153 | pcm_enc_pos = 0; | ||
1154 | 1167 | ||
1155 | /* encoder FIFO */ | 1168 | unsigned char *buffer = audio_get_buffer(true, &rec_buffer_size); |
1156 | enc_wr_index = 0; | ||
1157 | enc_rd_index = 0; | ||
1158 | |||
1159 | /* filename queue */ | ||
1160 | fnq_rd_pos = 0; | ||
1161 | fnq_wr_pos = 0; | ||
1162 | |||
1163 | /* stats */ | ||
1164 | num_rec_bytes = 0; | ||
1165 | num_rec_samples = 0; | ||
1166 | #if 0 | ||
1167 | accum_rec_bytes = 0; | ||
1168 | accum_pcm_samples = 0; | ||
1169 | #endif | ||
1170 | |||
1171 | pre_record_ticks = 0; | ||
1172 | |||
1173 | is_recording = false; | ||
1174 | is_paused = false; | ||
1175 | |||
1176 | buffer = audio_get_recording_buffer(&rec_buffer_size); | ||
1177 | 1169 | ||
1178 | /* Line align pcm_buffer 2^5=32 bytes */ | 1170 | /* Line align pcm_buffer 2^5=32 bytes */ |
1179 | pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 5); | 1171 | pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 5); |
@@ -1188,23 +1180,25 @@ static void pcmrec_init(void) | |||
1188 | /* PCMREC_CLOSE */ | 1180 | /* PCMREC_CLOSE */ |
1189 | static void pcmrec_close(void) | 1181 | static void pcmrec_close(void) |
1190 | { | 1182 | { |
1191 | is_initialized = false; | ||
1192 | dma_lock = true; | 1183 | dma_lock = true; |
1193 | pre_record_ticks = 0; /* Can't be prerecording any more */ | 1184 | pre_record_ticks = 0; /* Can't be prerecording any more */ |
1194 | warnings = 0; | 1185 | warnings = 0; |
1186 | codec_unload(); | ||
1195 | pcm_close_recording(); | 1187 | pcm_close_recording(); |
1196 | reset_hardware(); | 1188 | reset_hardware(); |
1197 | audio_remove_encoder(); | ||
1198 | send_event(RECORDING_EVENT_STOP, NULL); | 1189 | send_event(RECORDING_EVENT_STOP, NULL); |
1199 | } /* pcmrec_close */ | 1190 | } /* pcmrec_close */ |
1200 | 1191 | ||
1201 | /* PCMREC_OPTIONS */ | 1192 | /* PCMREC_OPTIONS */ |
1202 | static void pcmrec_set_recording_options( | 1193 | static void pcmrec_set_recording_options( |
1194 | struct event_queue *q, | ||
1203 | struct audio_recording_options *options) | 1195 | struct audio_recording_options *options) |
1204 | { | 1196 | { |
1205 | /* stop DMA transfer */ | 1197 | /* stop everything */ |
1206 | dma_lock = true; | 1198 | dma_lock = true; |
1199 | codec_unload(); | ||
1207 | pcm_stop_recording(); | 1200 | pcm_stop_recording(); |
1201 | pcmrec_init_state(); | ||
1208 | 1202 | ||
1209 | rec_frequency = options->rec_frequency; | 1203 | rec_frequency = options->rec_frequency; |
1210 | rec_source = options->rec_source; | 1204 | rec_source = options->rec_source; |
@@ -1243,10 +1237,13 @@ static void pcmrec_set_recording_options( | |||
1243 | /* apply hardware setting to start monitoring now */ | 1237 | /* apply hardware setting to start monitoring now */ |
1244 | pcm_apply_settings(); | 1238 | pcm_apply_settings(); |
1245 | 1239 | ||
1246 | queue_reply(&pcmrec_queue, 0); /* Release sender */ | 1240 | if (codec_load(-1, enc_config.afmt | CODEC_TYPE_ENCODER)) |
1247 | |||
1248 | if (audio_load_encoder(enc_config.afmt)) | ||
1249 | { | 1241 | { |
1242 | queue_reply(q, true); | ||
1243 | |||
1244 | /* run immediately */ | ||
1245 | codec_go(); | ||
1246 | |||
1250 | /* start DMA transfer */ | 1247 | /* start DMA transfer */ |
1251 | dma_lock = pre_record_ticks == 0; | 1248 | dma_lock = pre_record_ticks == 0; |
1252 | pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback, | 1249 | pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback, |
@@ -1255,7 +1252,7 @@ static void pcmrec_set_recording_options( | |||
1255 | else | 1252 | else |
1256 | { | 1253 | { |
1257 | logf("set rec opt: enc load failed"); | 1254 | logf("set rec opt: enc load failed"); |
1258 | errors |= PCMREC_E_LOAD_ENCODER; | 1255 | pcmrec_raise_error_status(PCMREC_E_LOAD_ENCODER); |
1259 | } | 1256 | } |
1260 | } /* pcmrec_set_recording_options */ | 1257 | } /* pcmrec_set_recording_options */ |
1261 | 1258 | ||
@@ -1468,97 +1465,65 @@ static void pcmrec_resume(void) | |||
1468 | logf("pcmrec_resume done"); | 1465 | logf("pcmrec_resume done"); |
1469 | } /* pcmrec_resume */ | 1466 | } /* pcmrec_resume */ |
1470 | 1467 | ||
1471 | static void pcmrec_thread(void) NORETURN_ATTR; | 1468 | /* Called by audio thread when recording is initialized */ |
1472 | static void pcmrec_thread(void) | 1469 | void audio_recording_handler(struct queue_event *ev) |
1473 | { | 1470 | { |
1474 | struct queue_event ev; | 1471 | logf("audio recording start"); |
1475 | |||
1476 | logf("thread pcmrec start"); | ||
1477 | 1472 | ||
1478 | while(1) | 1473 | while (1) |
1479 | { | 1474 | { |
1480 | if (is_recording) | 1475 | switch (ev->id) |
1481 | { | 1476 | { |
1482 | /* Poll periodically to flush data */ | 1477 | case Q_AUDIO_INIT_RECORDING: |
1483 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ/5); | 1478 | pcmrec_init(); |
1484 | 1479 | break; | |
1485 | if (ev.id == SYS_TIMEOUT) | ||
1486 | { | ||
1487 | /* Messages that interrupt this will complete it */ | ||
1488 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH | | ||
1489 | PCMREC_FLUSH_INTERRUPTABLE); | ||
1490 | continue; | ||
1491 | } | ||
1492 | } | ||
1493 | else | ||
1494 | { | ||
1495 | /* Not doing anything - sit and wait for commands */ | ||
1496 | queue_wait(&pcmrec_queue, &ev); | ||
1497 | |||
1498 | /* Some messages must be handled even if not initialized */ | ||
1499 | switch (ev.id) | ||
1500 | { | ||
1501 | case PCMREC_INIT: | ||
1502 | case SYS_USB_CONNECTED: | ||
1503 | break; | ||
1504 | default: | ||
1505 | if (!is_initialized) | ||
1506 | continue; | ||
1507 | } | ||
1508 | } | ||
1509 | |||
1510 | switch (ev.id) | ||
1511 | { | ||
1512 | case PCMREC_INIT: | ||
1513 | pcmrec_init(); | ||
1514 | break; | ||
1515 | |||
1516 | case PCMREC_CLOSE: | ||
1517 | pcmrec_close(); | ||
1518 | break; | ||
1519 | 1480 | ||
1520 | case PCMREC_OPTIONS: | 1481 | case SYS_USB_CONNECTED: |
1521 | pcmrec_set_recording_options( | 1482 | if (is_recording) |
1522 | (struct audio_recording_options *)ev.data); | ||
1523 | break; | 1483 | break; |
1484 | /* Fall-through */ | ||
1485 | case Q_AUDIO_CLOSE_RECORDING: | ||
1486 | pcmrec_close(); | ||
1487 | return; /* no more recording */ | ||
1488 | |||
1489 | case Q_AUDIO_RECORDING_OPTIONS: | ||
1490 | pcmrec_set_recording_options(&audio_queue, | ||
1491 | (struct audio_recording_options *)ev->data); | ||
1492 | break; | ||
1524 | 1493 | ||
1525 | case PCMREC_RECORD: | 1494 | case Q_AUDIO_RECORD: |
1526 | clear_flush_interrupt(); | 1495 | clear_flush_interrupt(); |
1527 | pcmrec_record((const char *)ev.data); | 1496 | pcmrec_record((const char *)ev->data); |
1528 | break; | 1497 | break; |
1529 | 1498 | ||
1530 | case PCMREC_STOP: | 1499 | case Q_AUDIO_STOP: |
1531 | clear_flush_interrupt(); | 1500 | clear_flush_interrupt(); |
1532 | pcmrec_stop(); | 1501 | pcmrec_stop(); |
1533 | break; | 1502 | break; |
1534 | 1503 | ||
1535 | case PCMREC_PAUSE: | 1504 | case Q_AUDIO_PAUSE: |
1536 | clear_flush_interrupt(); | 1505 | clear_flush_interrupt(); |
1537 | pcmrec_pause(); | 1506 | pcmrec_pause(); |
1538 | break; | 1507 | break; |
1539 | 1508 | ||
1540 | case PCMREC_RESUME: | 1509 | case Q_AUDIO_RESUME: |
1541 | pcmrec_resume(); | 1510 | pcmrec_resume(); |
1542 | break; | 1511 | break; |
1543 | #if 0 | ||
1544 | case PCMREC_FLUSH_NUM: | ||
1545 | pcmrec_flush((unsigned)ev.data); | ||
1546 | break; | ||
1547 | #endif | ||
1548 | case SYS_USB_CONNECTED: | ||
1549 | if (is_recording) | ||
1550 | break; | ||
1551 | 1512 | ||
1552 | if (is_initialized) | 1513 | case SYS_TIMEOUT: |
1553 | pcmrec_close(); | 1514 | /* Messages that interrupt this will complete it */ |
1515 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH | | ||
1516 | PCMREC_FLUSH_INTERRUPTABLE); | ||
1554 | 1517 | ||
1555 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 1518 | if (errors & PCMREC_E_DMA) |
1556 | usb_wait_for_disconnect(&pcmrec_queue); | 1519 | queue_post(&audio_queue, Q_AUDIO_STOP, 0); |
1557 | flush_interrupts = 0; | 1520 | break; |
1558 | break; | ||
1559 | } /* end switch */ | 1521 | } /* end switch */ |
1522 | |||
1523 | queue_wait_w_tmo(&audio_queue, ev, | ||
1524 | is_recording ? HZ/5 : TIMEOUT_BLOCK); | ||
1560 | } /* end while */ | 1525 | } /* end while */ |
1561 | } /* pcmrec_thread */ | 1526 | } /* audio_recording_handler */ |
1562 | 1527 | ||
1563 | /****************************************************************************/ | 1528 | /****************************************************************************/ |
1564 | /* */ | 1529 | /* */ |
@@ -1696,7 +1661,7 @@ struct enc_chunk_hdr * enc_get_chunk(void) | |||
1696 | #ifdef DEBUG | 1661 | #ifdef DEBUG |
1697 | if (chunk->id != ENC_CHUNK_MAGIC || *wrap_id_p != ENC_CHUNK_MAGIC) | 1662 | if (chunk->id != ENC_CHUNK_MAGIC || *wrap_id_p != ENC_CHUNK_MAGIC) |
1698 | { | 1663 | { |
1699 | errors |= PCMREC_E_CHUNK_OVF; | 1664 | pcmrec_raise_error_status(PCMREC_E_CHUNK_OVF); |
1700 | logf("finish chk ovf: %d", enc_wr_index); | 1665 | logf("finish chk ovf: %d", enc_wr_index); |
1701 | } | 1666 | } |
1702 | #endif | 1667 | #endif |
@@ -1718,7 +1683,7 @@ void enc_finish_chunk(void) | |||
1718 | if ((long)chunk->flags < 0) | 1683 | if ((long)chunk->flags < 0) |
1719 | { | 1684 | { |
1720 | /* encoder set error flag */ | 1685 | /* encoder set error flag */ |
1721 | errors |= PCMREC_E_ENCODER; | 1686 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
1722 | logf("finish chk enc error"); | 1687 | logf("finish chk enc error"); |
1723 | } | 1688 | } |
1724 | 1689 | ||
@@ -1737,7 +1702,7 @@ void enc_finish_chunk(void) | |||
1737 | else if (is_recording) /* buffer full */ | 1702 | else if (is_recording) /* buffer full */ |
1738 | { | 1703 | { |
1739 | /* keep current position and put up warning flag */ | 1704 | /* keep current position and put up warning flag */ |
1740 | warnings |= PCMREC_W_ENC_BUFFER_OVF; | 1705 | pcmrec_raise_warning_status(PCMREC_W_ENC_BUFFER_OVF); |
1741 | logf("enc_buffer ovf"); | 1706 | logf("enc_buffer ovf"); |
1742 | DEC_ENC_INDEX(enc_wr_index); | 1707 | DEC_ENC_INDEX(enc_wr_index); |
1743 | if (pcmrec_context) | 1708 | if (pcmrec_context) |
diff --git a/apps/recorder/pcm_record.h b/apps/recorder/pcm_record.h index 1ac6faefb2..bff7881605 100644 --- a/apps/recorder/pcm_record.h +++ b/apps/recorder/pcm_record.h | |||
@@ -42,6 +42,8 @@ | |||
42 | /* encoder has written past end of allocated space */ | 42 | /* encoder has written past end of allocated space */ |
43 | #define PCMREC_E_CHUNK_OVF 0x80010000 | 43 | #define PCMREC_E_CHUNK_OVF 0x80010000 |
44 | #endif /* DEBUG */ | 44 | #endif /* DEBUG */ |
45 | /* DMA callback has reported an error */ | ||
46 | #define PCMREC_E_DMA 0x80020000 | ||
45 | 47 | ||
46 | /** General functions for high level codec recording **/ | 48 | /** General functions for high level codec recording **/ |
47 | /* pcm_rec_error_clear is deprecated for general use. audio_error_clear | 49 | /* pcm_rec_error_clear is deprecated for general use. audio_error_clear |
@@ -49,7 +51,7 @@ | |||
49 | void pcm_rec_error_clear(void); | 51 | void pcm_rec_error_clear(void); |
50 | /* pcm_rec_status is deprecated for general use. audio_status merges the | 52 | /* pcm_rec_status is deprecated for general use. audio_status merges the |
51 | results for consistency with the hardware codec version */ | 53 | results for consistency with the hardware codec version */ |
52 | unsigned long pcm_rec_status(void); | 54 | unsigned int pcm_rec_status(void); |
53 | unsigned long pcm_rec_get_warnings(void); | 55 | unsigned long pcm_rec_get_warnings(void); |
54 | void pcm_rec_init(void) INIT_ATTR; | 56 | void pcm_rec_init(void) INIT_ATTR; |
55 | int pcm_rec_current_bitrate(void); | 57 | int pcm_rec_current_bitrate(void); |
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c index 203c7101b7..53dc5cbf95 100644 --- a/apps/recorder/recording.c +++ b/apps/recorder/recording.c | |||
@@ -1074,10 +1074,6 @@ bool recording_screen(bool no_source) | |||
1074 | #endif | 1074 | #endif |
1075 | 1075 | ||
1076 | #if CONFIG_CODEC == SWCODEC | 1076 | #if CONFIG_CODEC == SWCODEC |
1077 | /* This should be done before touching audio settings */ | ||
1078 | while (!pcm_is_initialized()) | ||
1079 | sleep(0); | ||
1080 | |||
1081 | /* recording_menu gets messed up: so prevent manus talking */ | 1077 | /* recording_menu gets messed up: so prevent manus talking */ |
1082 | talk_disable(true); | 1078 | talk_disable(true); |
1083 | /* audio_init_recording stops anything playing when it takes the audio | 1079 | /* audio_init_recording stops anything playing when it takes the audio |
@@ -1209,11 +1205,6 @@ bool recording_screen(bool no_source) | |||
1209 | trig_width[i] = vp_top[i].width - pm_x[i]; | 1205 | trig_width[i] = vp_top[i].width - pm_x[i]; |
1210 | } | 1206 | } |
1211 | 1207 | ||
1212 | #if CONFIG_CODEC == SWCODEC | ||
1213 | audio_close_recording(); | ||
1214 | audio_init_recording(); | ||
1215 | #endif | ||
1216 | |||
1217 | rec_init_recording_options(&rec_options); | 1208 | rec_init_recording_options(&rec_options); |
1218 | rec_set_recording_options(&rec_options); | 1209 | rec_set_recording_options(&rec_options); |
1219 | 1210 | ||
diff --git a/firmware/export/thread.h b/firmware/export/thread.h index 577cdc1e61..da395b8ffa 100644 --- a/firmware/export/thread.h +++ b/firmware/export/thread.h | |||
@@ -64,23 +64,13 @@ | |||
64 | #define IO_PRIORITY_BACKGROUND 32 | 64 | #define IO_PRIORITY_BACKGROUND 32 |
65 | 65 | ||
66 | #if CONFIG_CODEC == SWCODEC | 66 | #if CONFIG_CODEC == SWCODEC |
67 | 67 | # ifdef HAVE_HARDWARE_CLICK | |
68 | #ifdef HAVE_RECORDING | 68 | # define BASETHREADS 17 |
69 | #ifdef HAVE_HARDWARE_CLICK | 69 | # else |
70 | #define BASETHREADS 18 | 70 | # define BASETHREADS 16 |
71 | #else | 71 | # endif |
72 | #define BASETHREADS 17 | ||
73 | #endif | ||
74 | #else | ||
75 | #ifdef HAVE_HARDWARE_CLICK | ||
76 | #define BASETHREADS 17 | ||
77 | #else | ||
78 | #define BASETHREADS 16 | ||
79 | #endif | ||
80 | #endif | ||
81 | |||
82 | #else | 72 | #else |
83 | #define BASETHREADS 11 | 73 | # define BASETHREADS 11 |
84 | #endif /* CONFIG_CODE == * */ | 74 | #endif /* CONFIG_CODE == * */ |
85 | 75 | ||
86 | #ifndef TARGET_EXTRA_THREADS | 76 | #ifndef TARGET_EXTRA_THREADS |