Separate out voice options for .talk clips (FS #7249). This removes the assumptions...
[Rockbox.git] / apps / plugin.c
bloba63e5cd6eec445901dcd88bd53fe2a268a82d62e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "plugin.h"
20 #include <ctype.h>
21 #include <string.h>
22 #include <sprintf.h>
23 #include <atoi.h>
24 #include "debug.h"
25 #include "i2c.h"
26 #include "lang.h"
27 #include "keyboard.h"
28 #include "buffer.h"
29 #include "backlight.h"
30 #include "sound_menu.h"
31 #include "mp3data.h"
32 #include "powermgmt.h"
33 #include "splash.h"
34 #include "logf.h"
36 #if CONFIG_CHARGING
37 #include "power.h"
38 #endif
40 #ifdef HAVE_LCD_BITMAP
41 #include "scrollbar.h"
42 #include "peakmeter.h"
43 #include "bmp.h"
44 #include "bidi.h"
45 #endif
47 #ifdef SIMULATOR
48 static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
49 void *sim_plugin_load(char *plugin, void **pd);
50 void sim_plugin_close(void *pd);
51 void sim_lcd_ex_init(int shades, unsigned long (*getpixel)(int, int));
52 void sim_lcd_ex_update_rect(int x, int y, int width, int height);
53 #else
54 #define sim_plugin_close(x)
55 extern unsigned char pluginbuf[];
56 #include "bitswap.h"
57 #endif
59 /* for actual plugins only, not for codecs */
60 static bool plugin_loaded = false;
61 static int plugin_size = 0;
62 static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
63 static char current_plugin[MAX_PATH];
65 extern struct thread_entry threads[MAXTHREADS];
67 static const struct plugin_api rockbox_api = {
69 /* lcd */
70 lcd_set_contrast,
71 lcd_update,
72 lcd_clear_display,
73 lcd_setmargins,
74 lcd_getstringsize,
75 lcd_putsxy,
76 lcd_puts,
77 lcd_puts_scroll,
78 lcd_stop_scroll,
79 #ifdef HAVE_LCD_CHARCELLS
80 lcd_define_pattern,
81 lcd_get_locked_pattern,
82 lcd_unlock_pattern,
83 lcd_putc,
84 lcd_put_cursor,
85 lcd_remove_cursor,
86 lcd_icon,
87 lcd_double_height,
88 #else
89 lcd_set_drawmode,
90 lcd_get_drawmode,
91 lcd_setfont,
92 lcd_drawpixel,
93 lcd_drawline,
94 lcd_hline,
95 lcd_vline,
96 lcd_drawrect,
97 lcd_fillrect,
98 lcd_mono_bitmap_part,
99 lcd_mono_bitmap,
100 #if LCD_DEPTH > 1
101 lcd_set_foreground,
102 lcd_get_foreground,
103 lcd_set_background,
104 lcd_get_background,
105 lcd_bitmap_part,
106 lcd_bitmap,
107 lcd_set_backdrop,
108 #endif
109 #if LCD_DEPTH == 16
110 lcd_bitmap_transparent_part,
111 lcd_bitmap_transparent,
112 #endif
113 bidi_l2v,
114 font_get_bits,
115 font_load,
116 lcd_puts_style,
117 lcd_puts_scroll_style,
118 &lcd_framebuffer[0][0],
119 lcd_blit,
120 lcd_update_rect,
121 gui_scrollbar_draw,
122 font_get,
123 font_getstringsize,
124 font_get_width,
125 #endif
126 backlight_on,
127 backlight_off,
128 backlight_set_timeout,
129 gui_syncsplash,
130 #ifdef HAVE_REMOTE_LCD
131 /* remote lcd */
132 lcd_remote_set_contrast,
133 lcd_remote_clear_display,
134 lcd_remote_puts,
135 lcd_remote_puts_scroll,
136 lcd_remote_stop_scroll,
137 lcd_remote_set_drawmode,
138 lcd_remote_get_drawmode,
139 lcd_remote_setfont,
140 lcd_remote_getstringsize,
141 lcd_remote_drawpixel,
142 lcd_remote_drawline,
143 lcd_remote_hline,
144 lcd_remote_vline,
145 lcd_remote_drawrect,
146 lcd_remote_fillrect,
147 lcd_remote_mono_bitmap_part,
148 lcd_remote_mono_bitmap,
149 lcd_remote_putsxy,
150 lcd_remote_puts_style,
151 lcd_remote_puts_scroll_style,
152 &lcd_remote_framebuffer[0][0],
153 lcd_remote_update,
154 lcd_remote_update_rect,
156 remote_backlight_on,
157 remote_backlight_off,
158 #endif
159 #if NB_SCREENS == 2
160 {&screens[SCREEN_MAIN], &screens[SCREEN_REMOTE]},
161 #else
162 {&screens[SCREEN_MAIN]},
163 #endif
164 #if defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
165 lcd_remote_set_foreground,
166 lcd_remote_get_foreground,
167 lcd_remote_set_background,
168 lcd_remote_get_background,
169 lcd_remote_bitmap_part,
170 lcd_remote_bitmap,
171 #endif
173 #if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR)
174 lcd_yuv_blit,
175 #endif
176 /* list */
177 gui_synclist_init,
178 gui_synclist_set_nb_items,
179 gui_synclist_set_icon_callback,
180 gui_synclist_get_nb_items,
181 gui_synclist_get_sel_pos,
182 gui_synclist_draw,
183 gui_synclist_select_item,
184 gui_synclist_add_item,
185 gui_synclist_del_item,
186 gui_synclist_limit_scroll,
187 gui_synclist_flash,
188 gui_synclist_do_button,
189 gui_synclist_set_title,
191 /* button */
192 button_get,
193 button_get_w_tmo,
194 button_status,
195 button_clear_queue,
196 #ifdef HAS_BUTTON_HOLD
197 button_hold,
198 #endif
200 /* file */
201 (open_func)PREFIX(open),
202 close,
203 (read_func)read,
204 PREFIX(lseek),
205 (creat_func)PREFIX(creat),
206 (write_func)write,
207 PREFIX(remove),
208 PREFIX(rename),
209 PREFIX(ftruncate),
210 PREFIX(filesize),
211 fdprintf,
212 read_line,
213 settings_parseline,
214 #ifndef SIMULATOR
215 ata_sleep,
216 ata_disk_is_active,
217 #endif
218 ata_spindown,
219 reload_directory,
221 /* dir */
222 PREFIX(opendir),
223 PREFIX(closedir),
224 PREFIX(readdir),
225 PREFIX(mkdir),
226 PREFIX(rmdir),
228 /* dir, cached */
229 #ifdef HAVE_DIRCACHE
230 opendir_cached,
231 readdir_cached,
232 closedir_cached,
233 #endif
235 /* kernel/ system */
236 PREFIX(sleep),
237 yield,
238 #ifdef HAVE_PRIORITY_SCHEDULING
239 priority_yield,
240 #endif
241 &current_tick,
242 default_event_handler,
243 default_event_handler_ex,
244 create_thread,
245 remove_thread,
246 reset_poweroff_timer,
247 #ifndef SIMULATOR
248 system_memory_guard,
249 &cpu_frequency,
251 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
252 #ifdef CPU_BOOST_LOGGING
253 cpu_boost_,
254 #else
255 cpu_boost,
256 #endif
257 #endif
258 timer_register,
259 timer_unregister,
260 timer_set_period,
261 #endif
262 queue_init,
263 queue_delete,
264 queue_post,
265 queue_wait_w_tmo,
266 usb_acknowledge,
267 #ifdef RB_PROFILE
268 profile_thread,
269 profstop,
270 profile_func_enter,
271 profile_func_exit,
272 #endif
274 #ifdef SIMULATOR
275 /* special simulator hooks */
276 #if defined(HAVE_LCD_BITMAP) && LCD_DEPTH < 8
277 sim_lcd_ex_init,
278 sim_lcd_ex_update_rect,
279 #endif
280 #endif
282 /* strings and memory */
283 snprintf,
284 vsnprintf,
285 strcpy,
286 strncpy,
287 strlen,
288 strrchr,
289 strcmp,
290 strncmp,
291 strcasecmp,
292 strncasecmp,
293 memset,
294 memcpy,
295 memmove,
296 _ctype_,
297 atoi,
298 strchr,
299 strcat,
300 memchr,
301 memcmp,
302 strcasestr,
303 strtok_r,
304 /* unicode stuff */
305 utf8decode,
306 iso_decode,
307 utf16LEdecode,
308 utf16BEdecode,
309 utf8encode,
310 utf8length,
311 utf8seek,
313 /* sound */
314 #if CONFIG_CODEC == SWCODEC
315 sound_default,
316 #endif
317 sound_set,
318 set_sound,
320 sound_min,
321 sound_max,
322 #ifndef SIMULATOR
323 mp3_play_data,
324 mp3_play_pause,
325 mp3_play_stop,
326 mp3_is_playing,
327 #if CONFIG_CODEC != SWCODEC
328 bitswap,
329 #endif
330 #endif
331 #if CONFIG_CODEC == SWCODEC
332 &audio_master_sampr_list[0],
333 &hw_freq_sampr[0],
334 pcm_apply_settings,
335 pcm_play_data,
336 pcm_play_stop,
337 pcm_set_frequency,
338 pcm_is_playing,
339 pcm_is_paused,
340 pcm_play_pause,
341 pcm_get_bytes_waiting,
342 pcm_calculate_peaks,
343 #ifdef HAVE_RECORDING
344 &rec_freq_sampr[0],
345 pcm_init_recording,
346 pcm_close_recording,
347 pcm_record_data,
348 pcm_record_more,
349 pcm_stop_recording,
350 pcm_calculate_rec_peaks,
351 audio_set_recording_gain,
352 audio_set_output_source,
353 rec_set_source,
354 #endif /* HAVE_RECORDING */
356 #endif
358 /* playback control */
359 playlist_amount,
360 playlist_resume,
361 playlist_start,
362 PREFIX(audio_play),
363 audio_stop,
364 audio_pause,
365 audio_resume,
366 audio_next,
367 audio_prev,
368 audio_ff_rewind,
369 audio_next_track,
370 audio_status,
371 audio_has_changed_track,
372 audio_current_track,
373 audio_flush_and_reload_tracks,
374 audio_get_file_pos,
375 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
376 mpeg_get_last_header,
377 #endif
378 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) || \
379 (CONFIG_CODEC == SWCODEC)
380 sound_set_pitch,
381 #endif
383 #if !defined(SIMULATOR) && (CONFIG_CODEC != SWCODEC)
384 /* MAS communication */
385 mas_readmem,
386 mas_writemem,
387 mas_readreg,
388 mas_writereg,
389 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
390 mas_codec_writereg,
391 mas_codec_readreg,
392 i2c_begin,
393 i2c_end,
394 i2c_write,
395 #endif
396 #endif /* !SIMULATOR && CONFIG_CODEC != SWCODEC */
398 /* menu */
399 do_menu,
400 /* statusbars */
401 &statusbars,
402 gui_syncstatusbar_draw,
403 /* options */
404 set_option,
405 set_int,
406 set_bool,
408 /* action handling */
409 get_custom_action,
410 get_action,
411 action_signalscreenchange,
412 action_userabort,
414 /* power */
415 battery_level,
416 battery_level_safe,
417 battery_time,
418 #ifndef SIMULATOR
419 battery_voltage,
420 #endif
421 #if CONFIG_CHARGING
422 charger_inserted,
423 # if CONFIG_CHARGING == CHARGING_MONITOR
424 charging_state,
425 # endif
426 #endif
427 #ifdef HAVE_USB_POWER
428 usb_powered,
429 #endif
431 /* misc */
432 srand,
433 rand,
434 (qsort_func)qsort,
435 kbd_input,
436 get_time,
437 set_time,
438 plugin_get_buffer,
439 plugin_get_audio_buffer,
440 plugin_tsr,
441 #ifdef IRAM_STEAL
442 plugin_iram_init,
443 #endif
444 #if defined(DEBUG) || defined(SIMULATOR)
445 debugf,
446 #endif
447 #ifdef ROCKBOX_HAS_LOGF
448 _logf,
449 #endif
450 &global_settings,
451 &global_status,
452 mp3info,
453 count_mp3_frames,
454 create_xing_header,
455 find_next_frame,
456 #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
457 peak_meter_scale_value,
458 peak_meter_set_use_dbfs,
459 peak_meter_get_use_dbfs,
460 #endif
461 #ifdef HAVE_LCD_BITMAP
462 read_bmp_file,
463 screen_dump_set_hook,
464 #endif
465 show_logo,
466 tree_get_context,
468 #ifdef HAVE_WHEEL_POSITION
469 wheel_status,
470 wheel_send_events,
471 #endif
472 #if LCD_DEPTH > 1
473 lcd_get_backdrop,
474 #endif
476 /* new stuff at the end, sort into place next time
477 the API gets incompatible */
479 #ifdef IRIVER_H100_SERIES
480 /* Routines for the iriver_flash -plugin. */
481 detect_original_firmware,
482 detect_flashed_ramimage,
483 detect_flashed_romimage,
484 #endif
486 #if NUM_CORES > 1
487 spinlock_init,
488 spinlock_lock,
489 spinlock_unlock,
490 #endif
492 #if (CONFIG_CODEC == SWCODEC)
493 codec_load_file,
494 get_metadata,
495 get_codec_filename,
496 #endif
497 threads,
498 create_numbered_filename,
501 int plugin_load(const char* plugin, void* parameter)
503 int rc;
504 struct plugin_header *hdr;
505 const char *p = strrchr(plugin,'/');
506 #ifdef SIMULATOR
507 void *pd;
508 #else
509 int fd;
510 ssize_t readsize;
511 #endif
512 int xm, ym;
513 #ifdef HAVE_REMOTE_LCD
514 int rxm, rym;
515 #endif
517 #if LCD_DEPTH > 1
518 fb_data* old_backdrop;
519 #endif
521 if (!p)
522 p = plugin;
523 action_signalscreenchange();
525 if (pfn_tsr_exit != NULL) /* if we have a resident old plugin: */
527 if (pfn_tsr_exit(!strcmp(current_plugin,p)) == false )
529 /* not allowing another plugin to load */
530 return PLUGIN_OK;
532 pfn_tsr_exit = NULL;
533 plugin_loaded = false;
536 gui_syncsplash(0, str(LANG_WAIT));
537 strcpy(current_plugin,p);
539 #ifdef SIMULATOR
540 hdr = sim_plugin_load((char *)plugin, &pd);
541 if (pd == NULL) {
542 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
543 return -1;
545 if (hdr == NULL
546 || hdr->magic != PLUGIN_MAGIC
547 || hdr->target_id != TARGET_ID) {
548 sim_plugin_close(pd);
549 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
550 return -1;
552 if (hdr->api_version > PLUGIN_API_VERSION
553 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
554 sim_plugin_close(pd);
555 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
556 return -1;
558 #else
559 fd = open(plugin, O_RDONLY);
560 if (fd < 0) {
561 gui_syncsplash(HZ*2, str(LANG_PLUGIN_CANT_OPEN), plugin);
562 return fd;
565 readsize = read(fd, pluginbuf, PLUGIN_BUFFER_SIZE);
566 close(fd);
568 if (readsize < 0) {
569 gui_syncsplash(HZ*2, str(LANG_READ_FAILED), plugin);
570 return -1;
572 hdr = (struct plugin_header *)pluginbuf;
574 if ((unsigned)readsize <= sizeof(struct plugin_header)
575 || hdr->magic != PLUGIN_MAGIC
576 || hdr->target_id != TARGET_ID
577 || hdr->load_addr != pluginbuf
578 || hdr->end_addr > pluginbuf + PLUGIN_BUFFER_SIZE) {
579 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_MODEL));
580 return -1;
582 if (hdr->api_version > PLUGIN_API_VERSION
583 || hdr->api_version < PLUGIN_MIN_API_VERSION) {
584 gui_syncsplash(HZ*2, str(LANG_PLUGIN_WRONG_VERSION));
585 return -1;
587 plugin_size = hdr->end_addr - pluginbuf;
589 /* zero out bss area only, above guards end of pluginbuf */
590 if (plugin_size > readsize)
591 memset(pluginbuf + readsize, 0, plugin_size - readsize);
592 #endif
594 plugin_loaded = true;
596 xm = lcd_getxmargin();
597 ym = lcd_getymargin();
598 lcd_setmargins(0,0);
600 #if defined HAVE_LCD_BITMAP && LCD_DEPTH > 1
601 old_backdrop = lcd_get_backdrop();
602 #endif
603 lcd_clear_display();
604 lcd_update();
606 #ifdef HAVE_REMOTE_LCD
607 rxm = lcd_remote_getxmargin();
608 rym = lcd_remote_getymargin();
609 lcd_remote_setmargins(0, 0);
610 lcd_remote_clear_display();
611 lcd_remote_update();
612 #endif
614 invalidate_icache();
616 rc = hdr->entry_point((struct plugin_api*) &rockbox_api, parameter);
617 /* explicitly casting the pointer here to avoid touching every plugin. */
619 action_signalscreenchange();
620 button_clear_queue();
622 #ifdef HAVE_LCD_BITMAP
623 #if LCD_DEPTH > 1
624 lcd_set_backdrop(old_backdrop);
625 #ifdef HAVE_LCD_COLOR
626 lcd_set_drawinfo(DRMODE_SOLID, global_settings.fg_color,
627 global_settings.bg_color);
628 #else
629 lcd_set_drawinfo(DRMODE_SOLID, LCD_DEFAULT_FG, LCD_DEFAULT_BG);
630 #endif
631 #else /* LCD_DEPTH == 1 */
632 lcd_set_drawmode(DRMODE_SOLID);
633 #endif /* LCD_DEPTH */
634 #endif /* HAVE_LCD_BITMAP */
636 /* restore margins */
637 lcd_setmargins(xm,ym);
638 lcd_clear_display();
639 lcd_update();
641 #ifdef HAVE_REMOTE_LCD
642 #if LCD_REMOTE_DEPTH > 1
643 lcd_remote_set_drawinfo(DRMODE_SOLID, LCD_REMOTE_DEFAULT_FG,
644 LCD_REMOTE_DEFAULT_BG);
645 #else
646 lcd_remote_set_drawmode(DRMODE_SOLID);
647 #endif
648 lcd_remote_setmargins(rxm, rym);
649 lcd_remote_clear_display();
650 lcd_remote_update();
651 #endif
653 if (pfn_tsr_exit == NULL)
654 plugin_loaded = false;
656 sim_plugin_close(pd);
658 switch (rc) {
659 case PLUGIN_OK:
660 break;
662 case PLUGIN_USB_CONNECTED:
663 return PLUGIN_USB_CONNECTED;
665 default:
666 gui_syncsplash(HZ*2, str(LANG_PLUGIN_ERROR));
667 break;
669 return PLUGIN_OK;
672 /* Returns a pointer to the portion of the plugin buffer that is not already
673 being used. If no plugin is loaded, returns the entire plugin buffer */
674 void* plugin_get_buffer(size_t *buffer_size)
676 int buffer_pos;
678 if (plugin_loaded)
680 if (plugin_size >= PLUGIN_BUFFER_SIZE)
681 return NULL;
683 *buffer_size = PLUGIN_BUFFER_SIZE-plugin_size;
684 buffer_pos = plugin_size;
686 else
688 *buffer_size = PLUGIN_BUFFER_SIZE;
689 buffer_pos = 0;
692 return &pluginbuf[buffer_pos];
695 /* Returns a pointer to the mp3 buffer.
696 Playback gets stopped, to avoid conflicts.
697 Talk buffer is stolen as well.
699 void* plugin_get_audio_buffer(size_t *buffer_size)
701 #if CONFIG_CODEC == SWCODEC
702 return audio_get_buffer(true, buffer_size);
703 #else
704 audio_stop();
705 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
706 *buffer_size = audiobufend - audiobuf;
707 return audiobuf;
708 #endif
711 #ifdef IRAM_STEAL
712 /* Initializes plugin IRAM */
713 void plugin_iram_init(char *iramstart, char *iramcopy, size_t iram_size,
714 char *iedata, size_t iedata_size)
716 audio_iram_steal();
717 memcpy(iramstart, iramcopy, iram_size);
718 memset(iedata, 0, iedata_size);
719 memset(iramcopy, 0, iram_size);
721 #endif /* IRAM_STEAL */
723 /* The plugin wants to stay resident after leaving its main function, e.g.
724 runs from timer or own thread. The callback is registered to later
725 instruct it to free its resources before a new plugin gets loaded. */
726 void plugin_tsr(bool (*exit_callback)(bool))
728 pfn_tsr_exit = exit_callback; /* remember the callback for later */