summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2010-05-17 12:34:05 +0000
committerMichael Sevakis <jethead71@rockbox.org>2010-05-17 12:34:05 +0000
commitfcf36dd4f9879a82342e5606535d2dcf46d1de2a (patch)
tree21ed249c7a6f9d0bd7e2049c7a9f9e0708ba28f8
parent9fde12676b382a31a10c58e2473edfde460e4d73 (diff)
downloadrockbox-fcf36dd4f9879a82342e5606535d2dcf46d1de2a.tar.gz
rockbox-fcf36dd4f9879a82342e5606535d2dcf46d1de2a.zip
Simplify mpegplayer a bit and use array-based lists rather than linked lists for stream management. Move a couple useful functions to handle pointer arrays from kernel.c into general.c; mpeglayer now makes use of them.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26101 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.c5
-rw-r--r--apps/plugin.h7
-rw-r--r--apps/plugins/mpegplayer/SOURCES1
-rw-r--r--apps/plugins/mpegplayer/disk_buf.c37
-rw-r--r--apps/plugins/mpegplayer/mpeg_linkedlist.c151
-rw-r--r--apps/plugins/mpegplayer/mpeg_linkedlist.h71
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.c60
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.h26
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.h4
-rw-r--r--apps/plugins/mpegplayer/stream_mgr.c52
-rw-r--r--apps/plugins/mpegplayer/stream_mgr.h4
-rw-r--r--apps/plugins/mpegplayer/stream_thread.h7
-rw-r--r--firmware/export/general.h15
-rw-r--r--firmware/general.c37
-rw-r--r--firmware/kernel.c35
15 files changed, 199 insertions, 313 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index 90380a0039..b45220acdb 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -724,6 +724,11 @@ static const struct plugin_api rockbox_api = {
724#ifdef AUDIOHW_HAVE_EQ 724#ifdef AUDIOHW_HAVE_EQ
725 sound_enum_hw_eq_band_setting, 725 sound_enum_hw_eq_band_setting,
726#endif 726#endif
727
728#if CONFIG_CODEC == SWCODEC
729 find_array_ptr,
730 remove_array_ptr,
731#endif
727}; 732};
728 733
729int plugin_load(const char* plugin, const void* parameter) 734int plugin_load(const char* plugin, const void* parameter)
diff --git a/apps/plugin.h b/apps/plugin.h
index 108a283596..785ba6f6a2 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -142,7 +142,7 @@ void* plugin_get_buffer(size_t *buffer_size);
142#define PLUGIN_MAGIC 0x526F634B /* RocK */ 142#define PLUGIN_MAGIC 0x526F634B /* RocK */
143 143
144/* increase this every time the api struct changes */ 144/* increase this every time the api struct changes */
145#define PLUGIN_API_VERSION 185 145#define PLUGIN_API_VERSION 186
146 146
147/* update this to latest version if a change to the api struct breaks 147/* update this to latest version if a change to the api struct breaks
148 backwards compatibility (and please take the opportunity to sort in any 148 backwards compatibility (and please take the opportunity to sort in any
@@ -889,6 +889,11 @@ int (*round_value_to_list32)(unsigned long value,
889 int (*sound_enum_hw_eq_band_setting)(unsigned int band, 889 int (*sound_enum_hw_eq_band_setting)(unsigned int band,
890 unsigned int band_setting); 890 unsigned int band_setting);
891#endif /* AUDIOHW_HAVE_EQ */ 891#endif /* AUDIOHW_HAVE_EQ */
892
893#if CONFIG_CODEC == SWCODEC
894 void ** (*find_array_ptr)(void **arr, void *ptr);
895 int (*remove_array_ptr)(void **arr, void *ptr);
896#endif
892}; 897};
893 898
894/* plugin header */ 899/* plugin header */
diff --git a/apps/plugins/mpegplayer/SOURCES b/apps/plugins/mpegplayer/SOURCES
index 5ca0fcd86e..cf1e54aff5 100644
--- a/apps/plugins/mpegplayer/SOURCES
+++ b/apps/plugins/mpegplayer/SOURCES
@@ -29,6 +29,5 @@ disk_buf.c
29mpeg_settings.c 29mpeg_settings.c
30stream_mgr.c 30stream_mgr.c
31mpegplayer.c 31mpegplayer.c
32mpeg_linkedlist.c
33mpeg_parser.c 32mpeg_parser.c
34mpeg_misc.c 33mpeg_misc.c
diff --git a/apps/plugins/mpegplayer/disk_buf.c b/apps/plugins/mpegplayer/disk_buf.c
index af349c302a..4d0f98e5a3 100644
--- a/apps/plugins/mpegplayer/disk_buf.c
+++ b/apps/plugins/mpegplayer/disk_buf.c
@@ -30,7 +30,7 @@ static struct queue_sender_list disk_buf_queue_send SHAREDBSS_ATTR;
30static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)]; 30static uint32_t disk_buf_stack[DEFAULT_STACK_SIZE*2/sizeof(uint32_t)];
31 31
32struct disk_buf disk_buf SHAREDBSS_ATTR; 32struct disk_buf disk_buf SHAREDBSS_ATTR;
33static struct list_item nf_list; 33static void *nf_list[MPEGPLAYER_MAX_STREAMS+1];
34 34
35static inline void disk_buf_lock(void) 35static inline void disk_buf_lock(void)
36{ 36{
@@ -45,13 +45,12 @@ static inline void disk_buf_unlock(void)
45static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh) 45static inline void disk_buf_on_clear_data_notify(struct stream_hdr *sh)
46{ 46{
47 DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n", 47 DEBUGF("DISK_BUF_CLEAR_DATA_NOTIFY: 0x%02X (cleared)\n",
48 STR_FROM_HEADER(sh)->id); 48 STR_FROM_HDR(sh)->id);
49 list_remove_item(&sh->nf); 49 list_remove_item(nf_list, sh);
50} 50}
51 51
52
53inline bool disk_buf_is_data_ready(struct stream_hdr *sh, 52inline bool disk_buf_is_data_ready(struct stream_hdr *sh,
54 ssize_t margin) 53 ssize_t margin)
55{ 54{
56 /* Data window available? */ 55 /* Data window available? */
57 off_t right = sh->win_right; 56 off_t right = sh->win_right;
@@ -71,7 +70,7 @@ void dbuf_l2_init(struct dbuf_l2_cache *l2_p)
71 70
72static int disk_buf_on_data_notify(struct stream_hdr *sh) 71static int disk_buf_on_data_notify(struct stream_hdr *sh)
73{ 72{
74 DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HEADER(sh)->id); 73 DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X ", STR_FROM_HDR(sh)->id);
75 74
76 if (sh->win_left <= sh->win_right) 75 if (sh->win_left <= sh->win_right)
77 { 76 {
@@ -85,7 +84,7 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh)
85 sh->win_left, sh->win_right, 84 sh->win_left, sh->win_right,
86 disk_buf.win_left, disk_buf.win_right); 85 disk_buf.win_left, disk_buf.win_right);
87 /* Be sure it's not listed though if multiple requests were made */ 86 /* Be sure it's not listed though if multiple requests were made */
88 list_remove_item(&sh->nf); 87 list_remove_item(nf_list, sh);
89 return DISK_BUF_NOTIFY_OK; 88 return DISK_BUF_NOTIFY_OK;
90 } 89 }
91 90
@@ -95,7 +94,7 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh)
95 case TSTATE_BUFFERING: 94 case TSTATE_BUFFERING:
96 case TSTATE_INIT: 95 case TSTATE_INIT:
97 disk_buf.state = TSTATE_BUFFERING; 96 disk_buf.state = TSTATE_BUFFERING;
98 list_add_item(&nf_list, &sh->nf); 97 list_add_item(nf_list, sh);
99 DEBUGF("(registered)\n" 98 DEBUGF("(registered)\n"
100 " swl:%lu swr:%lu\n" 99 " swl:%lu swr:%lu\n"
101 " dwl:%lu dwr:%lu\n", 100 " dwl:%lu dwr:%lu\n",
@@ -109,20 +108,17 @@ static int disk_buf_on_data_notify(struct stream_hdr *sh)
109 return DISK_BUF_NOTIFY_ERROR; 108 return DISK_BUF_NOTIFY_ERROR;
110} 109}
111 110
112static bool check_data_notifies_callback(struct list_item *item, 111static bool check_data_notifies_callback(struct stream_hdr *sh, intptr_t data)
113 intptr_t data)
114{ 112{
115 struct stream_hdr *sh = TYPE_FROM_MEMBER(struct stream_hdr, item, nf);
116
117 if (disk_buf_is_data_ready(sh, 0)) 113 if (disk_buf_is_data_ready(sh, 0))
118 { 114 {
119 /* Remove from list then post notification - post because send 115 /* Remove from list then post notification - post because send
120 * could result in a wait for each thread to finish resulting 116 * could result in a wait for each thread to finish resulting
121 * in deadlock */ 117 * in deadlock */
122 list_remove_item(item); 118 list_remove_item(nf_list, sh);
123 str_post_msg(STR_FROM_HEADER(sh), DISK_BUF_DATA_NOTIFY, 0); 119 str_post_msg(STR_FROM_HDR(sh), DISK_BUF_DATA_NOTIFY, 0);
124 DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n", 120 DEBUGF("DISK_BUF_DATA_NOTIFY: 0x%02X (notified)\n",
125 STR_FROM_HEADER(sh)->id); 121 STR_FROM_HDR(sh)->id);
126 } 122 }
127 123
128 return true; 124 return true;
@@ -130,15 +126,17 @@ static bool check_data_notifies_callback(struct list_item *item,
130} 126}
131 127
132/* Check registered streams and notify them if their data is available */ 128/* Check registered streams and notify them if their data is available */
133static void check_data_notifies(void) 129static inline void check_data_notifies(void)
134{ 130{
135 list_enum_items(&nf_list, check_data_notifies_callback, 0); 131 list_enum_items(nf_list,
132 (list_enum_callback_t)check_data_notifies_callback,
133 0);
136} 134}
137 135
138/* Clear all registered notifications - do not post them */ 136/* Clear all registered notifications - do not post them */
139static inline void clear_data_notifies(void) 137static inline void clear_data_notifies(void)
140{ 138{
141 list_clear_all(&nf_list); 139 list_clear_all(nf_list);
142} 140}
143 141
144/* Background buffering when streaming */ 142/* Background buffering when streaming */
@@ -492,7 +490,7 @@ static void disk_buf_thread(void)
492 disk_buf_buffer(); 490 disk_buf_buffer();
493 491
494 /* Check for any due notifications if any are pending */ 492 /* Check for any due notifications if any are pending */
495 if (nf_list.next != NULL) 493 if (*nf_list != NULL)
496 check_data_notifies(); 494 check_data_notifies();
497 495
498 /* Still more data left? */ 496 /* Still more data left? */
@@ -915,7 +913,6 @@ void disk_buf_reply_msg(intptr_t retval)
915bool disk_buf_init(void) 913bool disk_buf_init(void)
916{ 914{
917 disk_buf.thread = 0; 915 disk_buf.thread = 0;
918 list_initialize(&nf_list);
919 916
920 rb->mutex_init(&disk_buf_mtx); 917 rb->mutex_init(&disk_buf_mtx);
921 918
diff --git a/apps/plugins/mpegplayer/mpeg_linkedlist.c b/apps/plugins/mpegplayer/mpeg_linkedlist.c
deleted file mode 100644
index f2d01ee493..0000000000
--- a/apps/plugins/mpegplayer/mpeg_linkedlist.c
+++ /dev/null
@@ -1,151 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Linked list API definitions
11 *
12 * Copyright (c) 2007 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 "plugin.h"
24#include "mpegplayer.h"
25#include "mpeg_linkedlist.h"
26
27/* Initialize a master list head */
28void list_initialize(struct list_item *master_list_head)
29{
30 master_list_head->prev = master_list_head->next = NULL;
31}
32
33/* Are there items after the head item? */
34bool list_is_empty(struct list_item *head_item)
35{
36 return head_item->next == NULL;
37}
38
39/* Does the item belong to a list? */
40bool list_is_item_listed(struct list_item *item)
41{
42 return item->prev != NULL;
43}
44
45/* Is the item a member in a particular list? */
46bool list_is_member(struct list_item *master_list_head,
47 struct list_item *item)
48{
49 if (item != master_list_head && item->prev != NULL)
50 {
51 struct list_item *curr = master_list_head->next;
52
53 while (curr != NULL)
54 {
55 if (item != curr)
56 {
57 curr = curr->next;
58 continue;
59 }
60
61 return true;
62 }
63 }
64
65 return false;
66}
67
68/* Remove an item from a list - no head item needed */
69void list_remove_item(struct list_item *item)
70{
71 if (item->prev == NULL)
72 {
73 /* Not in a list - no change - could be the master list head
74 * as well which cannot be removed */
75 return;
76 }
77
78 item->prev->next = item->next;
79
80 if (item->next != NULL)
81 {
82 /* Not last item */
83 item->next->prev = item->prev;
84 }
85
86 /* Mark as not in a list */
87 item->prev = NULL;
88}
89
90/* Add a list item after the base item */
91void list_add_item(struct list_item *head_item,
92 struct list_item *item)
93{
94 if (item->prev != NULL)
95 {
96 /* Already in a list - no change */
97 DEBUGF("list_add_item: item already in a list\n");
98 return;
99 }
100
101 if (item == head_item)
102 {
103 /* Cannot add the item to itself */
104 DEBUGF("list_add_item: item == head_item\n");
105 return;
106 }
107
108 /* Insert first */
109 item->prev = head_item;
110 item->next = head_item->next;
111
112 if (head_item->next != NULL)
113 {
114 /* Not first item */
115 head_item->next->prev = item;
116 }
117
118 head_item->next = item;
119}
120
121/* Clear list items after the head item */
122void list_clear_all(struct list_item *head_item)
123{
124 struct list_item *curr = head_item->next;
125
126 while (curr != NULL)
127 {
128 list_remove_item(curr);
129 curr = head_item->next;
130 }
131}
132
133/* Enumerate all items after the head item - passing each item in turn
134 * to the callback as well as the data value. The current item may be
135 * safely removed. Items added after the current position will be enumated
136 * but not ones added before it. The callback may return false to stop
137 * the enumeration. */
138void list_enum_items(struct list_item *head_item,
139 list_enum_callback_t callback,
140 intptr_t data)
141{
142 struct list_item *next = head_item->next;
143
144 while (next != NULL)
145 {
146 struct list_item *curr = next;
147 next = curr->next;
148 if (!callback(curr, data))
149 break;
150 }
151}
diff --git a/apps/plugins/mpegplayer/mpeg_linkedlist.h b/apps/plugins/mpegplayer/mpeg_linkedlist.h
deleted file mode 100644
index d4f8305d7d..0000000000
--- a/apps/plugins/mpegplayer/mpeg_linkedlist.h
+++ /dev/null
@@ -1,71 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Linked list API declarations
11 *
12 * Copyright (c) 2007 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 MPEG_LINKEDLIST_H
24#define MPEG_LINKEDLIST_H
25
26struct list_item
27{
28 struct list_item *prev; /* previous item in list */
29 struct list_item *next; /* next item in list */
30};
31
32/* Utility macros to help get the actual structure pointer back */
33#define OFFSETOF(type, membername) ((off_t)&((type *)0)->membername)
34#define TYPE_FROM_MEMBER(type, memberptr, membername) \
35 ((type *)((intptr_t)(memberptr) - OFFSETOF(type, membername)))
36
37/* Initialize a master list head */
38void list_initialize(struct list_item *master_list_head);
39
40/* Are there items after the head item? */
41bool list_is_empty(struct list_item *head_item);
42
43/* Does the item belong to a list? */
44bool list_is_item_listed(struct list_item *item);
45
46/* Is the item a member in a particular list? */
47bool list_is_member(struct list_item *master_list_head,
48 struct list_item *item);
49
50/* Remove an item from a list - no head item needed */
51void list_remove_item(struct list_item *item);
52
53/* Add a list item after the base item */
54void list_add_item(struct list_item *head_item,
55 struct list_item *item);
56
57/* Clear list items after the head item */
58void list_clear_all(struct list_item *head_item);
59
60/* Enumerate all items after the head item - passing each item in turn
61 * to the callback as well as the data value. The current item may be
62 * safely removed. Items added after the current position will be enumated
63 * but not ones added before it. The callback may return false to stop
64 * the enumeration. */
65typedef bool (*list_enum_callback_t)(struct list_item *item, intptr_t data);
66
67void list_enum_items(struct list_item *head_item,
68 list_enum_callback_t callback,
69 intptr_t data);
70
71#endif /* MPEG_LINKEDLIST_H */
diff --git a/apps/plugins/mpegplayer/mpeg_misc.c b/apps/plugins/mpegplayer/mpeg_misc.c
index 8e6ccf650f..e201aa69c7 100644
--- a/apps/plugins/mpegplayer/mpeg_misc.c
+++ b/apps/plugins/mpegplayer/mpeg_misc.c
@@ -102,3 +102,63 @@ uint32_t muldiv_uint32(uint32_t multiplicand,
102 102
103 return UINT32_MAX; /* Saturate */ 103 return UINT32_MAX; /* Saturate */
104} 104}
105
106
107/** Lists **/
108
109/* Does the list have any members? */
110bool list_is_empty(void **list)
111{
112 return *list == NULL;
113}
114
115/* Is the item inserted into a particular list? */
116bool list_is_member(void **list, void *item)
117{
118 return *rb->find_array_ptr(list, item) != NULL;
119}
120
121/* Removes an item from a list - returns true if item was found
122 * and thus removed. */
123bool list_remove_item(void **list, void *item)
124{
125 return rb->remove_array_ptr(list, item) != -1;
126}
127
128/* Adds a list item, insert last, if not already present. */
129void list_add_item(void **list, void *item)
130{
131 void **item_p = rb->find_array_ptr(list, item);
132 if (*item_p == NULL)
133 *item_p = item;
134}
135
136/* Clears the entire list. */
137void list_clear_all(void **list)
138{
139 while (*list != NULL)
140 *list++ = NULL;
141}
142
143/* Enumerate all items in the array, passing each item in turn to the
144 * callback as well as the data value. The current item may be safely
145 * removed. Other changes during enumeration are undefined. The callback
146 * may return 'false' to stop the enumeration early. */
147void list_enum_items(void **list,
148 list_enum_callback_t callback,
149 intptr_t data)
150{
151 for (;;)
152 {
153 void *item = *list;
154
155 if (item == NULL)
156 break;
157
158 if (callback != NULL && !callback(item, data))
159 break;
160
161 if (*list == item)
162 list++; /* Item still there */
163 }
164}
diff --git a/apps/plugins/mpegplayer/mpeg_misc.h b/apps/plugins/mpegplayer/mpeg_misc.h
index 5f60193d52..c36f4faddc 100644
--- a/apps/plugins/mpegplayer/mpeg_misc.h
+++ b/apps/plugins/mpegplayer/mpeg_misc.h
@@ -202,4 +202,30 @@ uint32_t muldiv_uint32(uint32_t multiplicand,
202 uint32_t multiplier, 202 uint32_t multiplier,
203 uint32_t divisor); 203 uint32_t divisor);
204 204
205
206/** Lists **/
207
208/* Does the list have any members? */
209bool list_is_empty(void **list);
210
211/* Is the item inserted into a particular list? */
212bool list_is_member(void **list, void *item);
213
214/* Removes an item from a list - returns true if item was found
215 * and thus removed. */
216bool list_remove_item(void **list, void *item);
217
218/* Adds a list item, insert last, if not already present. */
219void list_add_item(void **list, void *item);
220
221/* Clears the entire list. */
222void list_clear_all(void **list);
223
224/* Enumerate all items in the array. */
225typedef bool (*list_enum_callback_t)(void *item, intptr_t data);
226
227void list_enum_items(void **list,
228 list_enum_callback_t callback,
229 intptr_t data);
230
205#endif /* MPEG_MISC_H */ 231#endif /* MPEG_MISC_H */
diff --git a/apps/plugins/mpegplayer/mpegplayer.h b/apps/plugins/mpegplayer/mpegplayer.h
index bf223c3330..f6617cedff 100644
--- a/apps/plugins/mpegplayer/mpegplayer.h
+++ b/apps/plugins/mpegplayer/mpegplayer.h
@@ -31,6 +31,9 @@
31#endif 31#endif
32/* #else function-like empty macros are defined in the headers */ 32/* #else function-like empty macros are defined in the headers */
33 33
34/* Should be enough for now */
35#define MPEGPLAYER_MAX_STREAMS 4
36
34/* Memory allotments for various subsystems */ 37/* Memory allotments for various subsystems */
35#define MIN_MEMMARGIN (4*1024) 38#define MIN_MEMMARGIN (4*1024)
36 39
@@ -85,7 +88,6 @@
85#include "mpeg2.h" 88#include "mpeg2.h"
86#include "video_out.h" 89#include "video_out.h"
87#include "mpeg_stream.h" 90#include "mpeg_stream.h"
88#include "mpeg_linkedlist.h"
89#include "mpeg_misc.h" 91#include "mpeg_misc.h"
90#include "mpeg_alloc.h" 92#include "mpeg_alloc.h"
91#include "stream_thread.h" 93#include "stream_thread.h"
diff --git a/apps/plugins/mpegplayer/stream_mgr.c b/apps/plugins/mpegplayer/stream_mgr.c
index 065843a344..2eed3d355d 100644
--- a/apps/plugins/mpegplayer/stream_mgr.c
+++ b/apps/plugins/mpegplayer/stream_mgr.c
@@ -148,21 +148,21 @@ void stream_add_stream(struct stream *str)
148{ 148{
149 actl_lock(); 149 actl_lock();
150 150
151 list_remove_item(&str->l); 151 list_remove_item(stream_mgr.strl, str);
152 list_add_item(&stream_mgr.strl, &str->l); 152 list_add_item(stream_mgr.strl, str);
153 153
154 actl_unlock(); 154 actl_unlock();
155} 155}
156 156
157/* Callback for various list-moving operations */ 157/* Callback for various list-moving operations */
158static bool strl_enum_callback(struct list_item *item, intptr_t data) 158static bool strl_enum_callback(struct stream *str, intptr_t data)
159{ 159{
160 actl_lock(); 160 actl_lock();
161 161
162 list_remove_item(item); 162 list_remove_item(stream_mgr.strl, str);
163 163
164 if (data == 1) 164 if (data == 1)
165 list_add_item(&stream_mgr.actl, item); 165 list_add_item(stream_mgr.actl, str);
166 166
167 actl_unlock(); 167 actl_unlock();
168 168
@@ -172,38 +172,38 @@ static bool strl_enum_callback(struct list_item *item, intptr_t data)
172/* Clear all streams from active and playback pools */ 172/* Clear all streams from active and playback pools */
173void stream_remove_streams(void) 173void stream_remove_streams(void)
174{ 174{
175 list_enum_items(&stream_mgr.strl, strl_enum_callback, 0); 175 list_enum_items(stream_mgr.strl,
176 (list_enum_callback_t)strl_enum_callback, 0);
176} 177}
177 178
178/* Move the playback pool to the active list */ 179/* Move the playback pool to the active list */
179void move_strl_to_actl(void) 180void move_strl_to_actl(void)
180{ 181{
181 list_enum_items(&stream_mgr.strl, strl_enum_callback, 1); 182 list_enum_items(stream_mgr.strl,
183 (list_enum_callback_t)strl_enum_callback, 1);
182} 184}
183 185
184/* Remove a stream from the active list and return it to the pool */ 186/* Remove a stream from the active list and return it to the pool */
185static bool actl_stream_remove(struct stream *str) 187static bool actl_stream_remove(struct stream *str)
186{ 188{
187 if (list_is_member(&stream_mgr.actl, &str->l)) 189 bool retval;
188 {
189 actl_lock();
190 190
191 list_remove_item(&str->l); 191 actl_lock();
192 list_add_item(&stream_mgr.strl, &str->l);
193 192
194 actl_unlock(); 193 retval = list_remove_item(stream_mgr.actl, str);
195 return true; 194
196 } 195 if (retval)
196 list_add_item(stream_mgr.strl, str);
197 197
198 return false; 198 actl_unlock();
199
200 return retval;
199} 201}
200 202
201/* Broadcast a message to all active streams */ 203/* Broadcast a message to all active streams */
202static bool actl_stream_broadcast_callback(struct list_item *item, 204static bool actl_stream_broadcast_callback(struct stream *str,
203 struct str_broadcast_data *sbd) 205 struct str_broadcast_data *sbd)
204{ 206{
205 struct stream *str = TYPE_FROM_MEMBER(struct stream, item, l);
206
207 switch (sbd->cmd) 207 switch (sbd->cmd)
208 { 208 {
209 case STREAM_PLAY: 209 case STREAM_PLAY:
@@ -215,8 +215,8 @@ static bool actl_stream_broadcast_callback(struct list_item *item,
215 { 215 {
216 actl_lock(); 216 actl_lock();
217 217
218 list_remove_item(item); 218 list_remove_item(stream_mgr.actl, str);
219 list_add_item(&stream_mgr.strl, item); 219 list_add_item(stream_mgr.strl, str);
220 220
221 actl_unlock(); 221 actl_unlock();
222 sbd->data = 0; 222 sbd->data = 0;
@@ -236,7 +236,7 @@ static void actl_stream_broadcast(int cmd, intptr_t data)
236 struct str_broadcast_data sbd; 236 struct str_broadcast_data sbd;
237 sbd.cmd = cmd; 237 sbd.cmd = cmd;
238 sbd.data = data; 238 sbd.data = data;
239 list_enum_items(&stream_mgr.actl, 239 list_enum_items(stream_mgr.actl,
240 (list_enum_callback_t)actl_stream_broadcast_callback, 240 (list_enum_callback_t)actl_stream_broadcast_callback,
241 (intptr_t)&sbd); 241 (intptr_t)&sbd);
242} 242}
@@ -623,7 +623,7 @@ static void stream_on_ev_complete(struct stream *str)
623 { 623 {
624 /* No - remove this stream from the active list */ 624 /* No - remove this stream from the active list */
625 DEBUGF(" finished: 0x%02x\n", str->id); 625 DEBUGF(" finished: 0x%02x\n", str->id);
626 if (list_is_empty(&stream_mgr.actl)) 626 if (list_is_empty(stream_mgr.actl))
627 { 627 {
628 /* All streams have acked - stop playback */ 628 /* All streams have acked - stop playback */
629 stream_on_stop(false); 629 stream_on_stop(false);
@@ -820,10 +820,9 @@ void stream_wait_status(void)
820 820
821/* Returns the smallest file window that includes all active streams' 821/* Returns the smallest file window that includes all active streams'
822 * windows */ 822 * windows */
823static bool stream_get_window_callback(struct list_item *item, 823static bool stream_get_window_callback(struct stream *str,
824 struct stream_window *sw) 824 struct stream_window *sw)
825{ 825{
826 struct stream *str = TYPE_FROM_MEMBER(struct stream, item, l);
827 off_t swl = str->hdr.win_left; 826 off_t swl = str->hdr.win_left;
828 off_t swr = str->hdr.win_right; 827 off_t swr = str->hdr.win_right;
829 828
@@ -845,7 +844,7 @@ bool stream_get_window(struct stream_window *sw)
845 sw->right = LONG_MIN; 844 sw->right = LONG_MIN;
846 845
847 actl_lock(); 846 actl_lock();
848 list_enum_items(&stream_mgr.actl, 847 list_enum_items(stream_mgr.actl,
849 (list_enum_callback_t)stream_get_window_callback, 848 (list_enum_callback_t)stream_get_window_callback,
850 (intptr_t)sw); 849 (intptr_t)sw);
851 actl_unlock(); 850 actl_unlock();
@@ -981,7 +980,6 @@ int stream_init(void)
981 980
982 stream_mgr.status = STREAM_STOPPED; 981 stream_mgr.status = STREAM_STOPPED;
983 stream_mgr_init_state(); 982 stream_mgr_init_state();
984 list_initialize(&stream_mgr.actl);
985 983
986 /* Initialize our window to the outside world first */ 984 /* Initialize our window to the outside world first */
987 rb->mutex_init(&stream_mgr.str_mtx); 985 rb->mutex_init(&stream_mgr.str_mtx);
diff --git a/apps/plugins/mpegplayer/stream_mgr.h b/apps/plugins/mpegplayer/stream_mgr.h
index a00b39f189..a07305a847 100644
--- a/apps/plugins/mpegplayer/stream_mgr.h
+++ b/apps/plugins/mpegplayer/stream_mgr.h
@@ -35,8 +35,8 @@ struct stream_mgr
35 bool seeked; /* A seek happened and things must be 35 bool seeked; /* A seek happened and things must be
36 resynced */ 36 resynced */
37 int status; /* Current playback status */ 37 int status; /* Current playback status */
38 struct list_item strl; /* List of available streams */ 38 void *strl[MPEGPLAYER_MAX_STREAMS+1]; /* List of available streams */
39 struct list_item actl; /* List of active streams */ 39 void *actl[MPEGPLAYER_MAX_STREAMS+1]; /* List of active streams */
40 struct mutex str_mtx; /* Main stream manager mutex */ 40 struct mutex str_mtx; /* Main stream manager mutex */
41 struct mutex actl_mtx; /* Lock for current-streams list */ 41 struct mutex actl_mtx; /* Lock for current-streams list */
42 union /* A place for reusable non-cacheable parameters */ 42 union /* A place for reusable non-cacheable parameters */
diff --git a/apps/plugins/mpegplayer/stream_thread.h b/apps/plugins/mpegplayer/stream_thread.h
index 30bf46e6ff..1d3a445735 100644
--- a/apps/plugins/mpegplayer/stream_thread.h
+++ b/apps/plugins/mpegplayer/stream_thread.h
@@ -39,7 +39,6 @@ struct stream_hdr
39 off_t pos; /* Start/current position for random-access read */ 39 off_t pos; /* Start/current position for random-access read */
40 }; 40 };
41 off_t limit; /* Limit for random-access read */ 41 off_t limit; /* Limit for random-access read */
42 struct list_item nf; /* List for data notification */
43}; 42};
44 43
45struct stream 44struct stream
@@ -48,8 +47,6 @@ struct stream
48 unsigned int thread; /* Stream's thread */ 47 unsigned int thread; /* Stream's thread */
49 uint8_t* curr_packet; /* Current stream packet beginning */ 48 uint8_t* curr_packet; /* Current stream packet beginning */
50 uint8_t* curr_packet_end; /* Current stream packet end */ 49 uint8_t* curr_packet_end; /* Current stream packet end */
51 struct list_item l; /* List of streams - either reserve pool
52 or active pool */
53 int state; /* State machine parsing mode */ 50 int state; /* State machine parsing mode */
54 uint32_t start_pts; /* First timestamp for stream */ 51 uint32_t start_pts; /* First timestamp for stream */
55 uint32_t end_pts; /* Last timestamp for stream */ 52 uint32_t end_pts; /* Last timestamp for stream */
@@ -58,6 +55,8 @@ struct stream
58 unsigned id; /* Stream identifier */ 55 unsigned id; /* Stream identifier */
59}; 56};
60 57
58#define STR_FROM_HDR(sh) ((struct stream *)(sh))
59
61/* Make sure there there is always enough data buffered ahead for 60/* Make sure there there is always enough data buffered ahead for
62 * the worst possible case - regardless of whether a valid stream 61 * the worst possible case - regardless of whether a valid stream
63 * would actually produce that */ 62 * would actually produce that */
@@ -145,8 +144,6 @@ enum stream_status
145 STREAM_NOT_FOUND, /* Match not found */ 144 STREAM_NOT_FOUND, /* Match not found */
146}; 145};
147 146
148#define STR_FROM_HEADER(sh) ((struct stream *)(sh))
149
150/* Clip time to range for a particular stream */ 147/* Clip time to range for a particular stream */
151static inline uint32_t clip_time(struct stream *str, uint32_t time) 148static inline uint32_t clip_time(struct stream *str, uint32_t time)
152{ 149{
diff --git a/firmware/export/general.h b/firmware/export/general.h
index 8da4a0ad59..16c824086b 100644
--- a/firmware/export/general.h
+++ b/firmware/export/general.h
@@ -72,4 +72,19 @@ char *create_datetime_filename(char *buffer, const char *path,
72 bool unique_time); 72 bool unique_time);
73#endif /* CONFIG_RTC */ 73#endif /* CONFIG_RTC */
74 74
75/***
76 ** Compacted pointer lists
77 **
78 ** N-length list requires N+1 elements to ensure NULL-termination.
79 **/
80
81/* Find a pointer in a pointer array. Returns the addess of the element if
82 found or the address of the terminating NULL otherwise. This can be used
83 to bounds check and add items. */
84void ** find_array_ptr(void **arr, void *ptr);
85
86/* Remove a pointer from a pointer array if it exists. Compacts it so that
87 no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
88int remove_array_ptr(void **arr, void *ptr);
89
75#endif /* GENERAL_H */ 90#endif /* GENERAL_H */
diff --git a/firmware/general.c b/firmware/general.c
index fa1025492b..20b0277c09 100644
--- a/firmware/general.c
+++ b/firmware/general.c
@@ -196,3 +196,40 @@ char *create_datetime_filename(char *buffer, const char *path,
196 return buffer; 196 return buffer;
197} 197}
198#endif /* CONFIG_RTC */ 198#endif /* CONFIG_RTC */
199
200/***
201 ** Compacted pointer lists
202 **
203 ** N-length list requires N+1 elements to ensure NULL-termination.
204 **/
205
206/* Find a pointer in a pointer array. Returns the addess of the element if
207 * found or the address of the terminating NULL otherwise. This can be used
208 * to bounds check and add items. */
209void ** find_array_ptr(void **arr, void *ptr)
210{
211 void *curr;
212 for (curr = *arr; curr != NULL && curr != ptr; curr = *(++arr));
213 return arr;
214}
215
216/* Remove a pointer from a pointer array if it exists. Compacts it so that
217 * no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
218int remove_array_ptr(void **arr, void *ptr)
219{
220 void *curr;
221 arr = find_array_ptr(arr, ptr);
222
223 if (*arr == NULL)
224 return -1;
225
226 /* Found. Slide up following items. */
227 do
228 {
229 void **arr1 = arr + 1;
230 *arr++ = curr = *arr1;
231 }
232 while (curr != NULL);
233
234 return 0;
235}
diff --git a/firmware/kernel.c b/firmware/kernel.c
index d8c67e8485..fe40c35002 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -27,6 +27,7 @@
27#include "system.h" 27#include "system.h"
28#include "panic.h" 28#include "panic.h"
29#include "debug.h" 29#include "debug.h"
30#include "general.h"
30 31
31/* Make this nonzero to enable more elaborate checks on objects */ 32/* Make this nonzero to enable more elaborate checks on objects */
32#if defined(DEBUG) || defined(SIMULATOR) 33#if defined(DEBUG) || defined(SIMULATOR)
@@ -62,40 +63,6 @@ static struct
62} all_queues SHAREDBSS_ATTR; 63} all_queues SHAREDBSS_ATTR;
63 64
64/**************************************************************************** 65/****************************************************************************
65 * Common utilities
66 ****************************************************************************/
67
68/* Find a pointer in a pointer array. Returns the addess of the element if
69 * found or the address of the terminating NULL otherwise. */
70static void ** find_array_ptr(void **arr, void *ptr)
71{
72 void *curr;
73 for(curr = *arr; curr != NULL && curr != ptr; curr = *(++arr));
74 return arr;
75}
76
77/* Remove a pointer from a pointer array if it exists. Compacts it so that
78 * no gaps exist. Returns 0 on success and -1 if the element wasn't found. */
79static int remove_array_ptr(void **arr, void *ptr)
80{
81 void *curr;
82 arr = find_array_ptr(arr, ptr);
83
84 if(*arr == NULL)
85 return -1;
86
87 /* Found. Slide up following items. */
88 do
89 {
90 void **arr1 = arr + 1;
91 *arr++ = curr = *arr1;
92 }
93 while(curr != NULL);
94
95 return 0;
96}
97
98/****************************************************************************
99 * Standard kernel stuff 66 * Standard kernel stuff
100 ****************************************************************************/ 67 ****************************************************************************/
101void kernel_init(void) 68void kernel_init(void)