summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES1
-rw-r--r--apps/audio_thread.c162
-rw-r--r--apps/audio_thread.h102
-rw-r--r--apps/codec_thread.c1
-rw-r--r--apps/main.c11
-rw-r--r--apps/playback.c342
-rw-r--r--apps/playback.h64
-rw-r--r--apps/recorder/pcm_record.c305
-rw-r--r--apps/recorder/pcm_record.h4
-rw-r--r--apps/recorder/recording.c9
10 files changed, 500 insertions, 501 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
164audio_path.c 164audio_path.c
165#endif /* INPUT_SRC_CAPS != 0 */ 165#endif /* INPUT_SRC_CAPS != 0 */
166audio_thread.c
166pcmbuf.c 167pcmbuf.c
167codec_thread.c 168codec_thread.c
168playback.c 169playback.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
54bool audio_is_initialized = false;
55
56/* Event queues */
57struct event_queue audio_queue SHAREDBSS_ATTR;
58static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
59
60/* Audio thread */
61static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
62static const char audio_thread_name[] = "audio";
63unsigned int audio_thread_id = 0;
64
65static 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 */
104int 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 */
114void 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 */
124void 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
31enum
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
93void audio_init(void);
94void playback_init(void);
95unsigned int playback_status(void);
96
97void audio_playback_handler(struct queue_event *ev);
98#ifdef AUDIO_HAVE_RECORDING
99void 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 **/
107bool audio_is_initialized = false; /* (A,O-) */ 103extern unsigned int audio_thread_id; /* from audio_thread.c */
108extern struct codec_api ci; /* (A,C) */ 104extern struct event_queue audio_queue; /* from audio_thread.c */
105extern bool audio_is_initialized; /* from audio_thread.c */
106extern struct codec_api ci; /* from codecs.c */
109 107
110/** Possible arrangements of the main buffer **/ 108/** Possible arrangements of the main buffer **/
111static enum audio_buffer_state 109static 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;
330static bool codec_seeking = false; /* Codec seeking ack expected? */ 327static bool codec_seeking = false; /* Codec seeking ack expected? */
331static unsigned int position_key = 0; 328static unsigned int position_key = 0;
332 329
333/* Event queues */
334static struct event_queue audio_queue SHAREDBSS_ATTR;
335
336/* Audio thread */
337static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
338static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
339static const char audio_thread_name[] = "audio";
340static unsigned int audio_thread_id = 0;
341
342/* Forward declarations */ 330/* Forward declarations */
343enum audio_start_playback_flags 331enum 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 2977void audio_playback_handler(struct queue_event *ev)
2990 (Q_AUDIO_LOAD_ENCODER) */
2991static 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
3011static 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 */
3360int 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 */
3373void 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 */
3381bool audio_peek_track(struct mp3entry *id3, int offset) 3290bool 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 */
3661unsigned 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) */
3669bool audio_restore_playback(int type) 3569bool 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 */
3761bool 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 */
3773void 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
3745unsigned int playback_status(void)
3746{
3747 return play_status;
3748}
3869 3749
3870/** -- Startup -- **/ 3750/** -- Startup -- **/
3871 3751void playback_init(void)
3872/* Initialize the audio system - called from init() in main.c */
3873void 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. */
93bool audio_automatic_skip(void); 93bool audio_automatic_skip(void);
94 94
95/* Define one constant that includes recording related functionality */ 95unsigned int playback_status(void);
96#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
97#define AUDIO_HAVE_RECORDING
98#endif
99
100enum {
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
45extern struct event_queue audio_queue;
46
44/** General recording state **/ 47/** General recording state **/
45static bool is_initialized = false; /* Subsystem ready? */
46static bool is_recording; /* We are recording */ 48static bool is_recording; /* We are recording */
47static bool is_paused; /* We have paused */ 49static bool is_paused; /* We have paused */
48static unsigned long errors; /* An error has occured */ 50static unsigned long errors; /* An error has occured */
@@ -230,14 +232,6 @@ enum
230 232
231/***************************************************************************/ 233/***************************************************************************/
232 234
233static struct event_queue pcmrec_queue SHAREDBSS_ATTR;
234static struct queue_sender_list pcmrec_queue_send SHAREDBSS_ATTR;
235static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)];
236static const char pcmrec_thread_name[] = "pcmrec";
237static unsigned int pcmrec_thread_id = 0;
238
239static void pcmrec_thread(void);
240
241enum 235enum
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
251static 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
258static 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 */
261static void pcm_rec_have_more(void **start, size_t *size) 264static 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 */
318unsigned long pcm_rec_status(void) 321unsigned 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 */
385void 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)
401void audio_init_recording(void) 390void 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)
411void audio_close_recording(void) 400void 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)
421void audio_set_recording_options(struct audio_recording_options *options) 410void 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)
472void audio_resume_recording(void) 461void 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
513static 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 */
1135static void pcmrec_init(void) 1161static 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 */
1189static void pcmrec_close(void) 1181static 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 */
1202static void pcmrec_set_recording_options( 1193static 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
1471static void pcmrec_thread(void) NORETURN_ATTR; 1468/* Called by audio thread when recording is initialized */
1472static void pcmrec_thread(void) 1469void 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 @@
49void pcm_rec_error_clear(void); 51void 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 */
52unsigned long pcm_rec_status(void); 54unsigned int pcm_rec_status(void);
53unsigned long pcm_rec_get_warnings(void); 55unsigned long pcm_rec_get_warnings(void);
54void pcm_rec_init(void) INIT_ATTR; 56void pcm_rec_init(void) INIT_ATTR;
55int pcm_rec_current_bitrate(void); 57int 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