Compare commits

..

33 commits
master ... v3.9

Author SHA1 Message Date
Alex Parker
0f1b77dae8 Backport r30323/r30169 - perl use if/elsif/else so that it'll build with both new and old perl.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30406 a1c6a512-1295-4272-9138-f99709370657
2011-09-01 14:25:05 +00:00
Alex Parker
7eef227154 Bump release date for 3.9.1, better late than never.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30405 a1c6a512-1295-4272-9138-f99709370657
2011-09-01 13:41:23 +00:00
Thomas Martitz
bddea666f5 Fix FS#12239, data abort after going from FMS to WPS.
The data abort was in find_handle() because current_handle was corrupted. This
most probably happened due to the FMS allocating Radio AA on the buffer without
resetting the buffer, corrupting buffering/playback state.

The fix is to grab buffer control explicitely.

r30308 isn't actually related, regardless of the task title.

git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30343 a1c6a512-1295-4272-9138-f99709370657
2011-08-24 07:02:29 +00:00
Frank Gevaerts
ed0198a7c2 Add a 100ms delay before calling disk_mount_all(). Some players (especially some gigabeat Fs) seem to need a delay after disabling USB if we want disk access to work.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30317 a1c6a512-1295-4272-9138-f99709370657
2011-08-15 14:38:44 +00:00
Alex Parker
f16bb13271 Bump versions for 3.9.1
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30295 a1c6a512-1295-4272-9138-f99709370657
2011-08-14 10:30:13 +00:00
Andree Buschmann
18db18c34d Backport r30259: Fix replaygain for wma files.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30260 a1c6a512-1295-4272-9138-f99709370657
2011-08-06 09:24:23 +00:00
Michael Hohmuth
1bb1052925 Database: Bug fix: The filename seek index is invalid if FLAG_DIRCACHE
is set on a database entry and the dircache went offline.  In this
case, retrieve() and get_next() need to abort and take the ramcache
offline as well.

git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30257 a1c6a512-1295-4272-9138-f99709370657
2011-08-04 23:22:26 +00:00
Michael Hohmuth
211c082d91 Database: find_entry_ram: Avoid dircache use if it's not ready
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30256 a1c6a512-1295-4272-9138-f99709370657
2011-08-04 23:22:15 +00:00
Michael Hohmuth
3049a6bd04 Database: Fixed a potential buffer overrun in format_str. From
FS#12132 patch 8.

git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30252 a1c6a512-1295-4272-9138-f99709370657
2011-08-04 12:13:16 +00:00
Michael Hohmuth
6196925915 Database: Fix array-bounds calculation when applying a format using
%strip to partially loaded (chunked) database results.

git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30251 a1c6a512-1295-4272-9138-f99709370657
2011-08-04 12:13:12 +00:00
Michael Hohmuth
92a578c6a7 Database: Fix memory-area bounds checking during database reload.
Check free space before reading new data from disk, and do not forget
to account for the RAM-cache header.

git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30250 a1c6a512-1295-4272-9138-f99709370657
2011-08-04 12:13:02 +00:00
Magnus Holmgren
e6d21f1d10 Backport r30149 (AAC gapless fix) to 3.9 branch.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30245 a1c6a512-1295-4272-9138-f99709370657
2011-08-03 18:35:24 +00:00
Frank Gevaerts
dfafd22ec5 Lower the maximum brightness of the fuzev2 backlight even more.
The previous maximum (20) still causes excessive heat for some people, and measurements (using a digital camera and a white screen) show that the maximum brightness in the OF corresponds to 12 in rockbox, so we use 12 now.



git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30228 a1c6a512-1295-4272-9138-f99709370657
2011-07-31 15:33:57 +00:00
Andree Buschmann
be32b990f8 Backport r30202. Fixes musepack resume for resume positions > 7:30m.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30203 a1c6a512-1295-4272-9138-f99709370657
2011-07-23 21:05:47 +00:00
Mustapha Senhaji
09885c3403 Update the french translation, shorten string for Archos Player.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30129 a1c6a512-1295-4272-9138-f99709370657
2011-07-06 20:45:23 +00:00
Mustapha Senhaji
0965f79bc1 FS#12173 Romanian translation update by Sergiu Rotaru.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30127 a1c6a512-1295-4272-9138-f99709370657
2011-07-06 20:34:30 +00:00
Bertrik Sikken
73ffc047e8 FS#12172 - Update for serbian translation by Ivan Pesic
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30095 a1c6a512-1295-4272-9138-f99709370657
2011-06-28 21:19:12 +00:00
Bertrik Sikken
919697d3b2 FS#12171 - Polish translation update by Wojciech Lesniak
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30092 a1c6a512-1295-4272-9138-f99709370657
2011-06-28 21:07:30 +00:00
Jonas Häggqvist
583ac1c708 Update Danish translation
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30083 a1c6a512-1295-4272-9138-f99709370657
2011-06-27 12:11:35 +00:00
Michael Chicoine
7af20f70e0 FS#12168 - Update Simp Chinese translation by Li Jie
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30082 a1c6a512-1295-4272-9138-f99709370657
2011-06-26 20:21:10 +00:00
Bertrik Sikken
7e209cd739 Fix missing strings in nederlands translation
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30079 a1c6a512-1295-4272-9138-f99709370657
2011-06-26 12:23:36 +00:00
Jens Arnold
c709aedb9a Update US English translation
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30077 a1c6a512-1295-4272-9138-f99709370657
2011-06-26 11:18:21 +00:00
Jens Arnold
28cff95ffc Update German translation
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30076 a1c6a512-1295-4272-9138-f99709370657
2011-06-26 11:18:10 +00:00
Alex Parker
b9c407a918 Bump versions for release.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30073 a1c6a512-1295-4272-9138-f99709370657
2011-06-26 10:52:00 +00:00
Jens Arnold
1a3d05eae9 (Heavily) shorten the .lang string shown when generating the database
for the Player in order to make it fit on the small LCD.


git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30067 a1c6a512-1295-4272-9138-f99709370657
2011-06-25 00:01:37 +00:00
Michael Sevakis
66fee3eb55 Backport r30063 to the v3.9 branch. SPC Codec: Restore correct FIR buffer alignment when an address mask is used. It must be FIR_BUF_ALIGN. Fix Coldfire assembly constraint where an input parameter was also being written.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30064 a1c6a512-1295-4272-9138-f99709370657
2011-06-24 11:52:17 +00:00
Andree Buschmann
6472bcde65 Backport r30052 to v3.9 branch. Fixes build problems for win32 cross compilation and cygwin.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30062 a1c6a512-1295-4272-9138-f99709370657
2011-06-24 10:00:06 +00:00
Andree Buschmann
3562e0fb1f Backport r30060 to v3.9 branch. Fixes a possible RealAudio decoder failure.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30061 a1c6a512-1295-4272-9138-f99709370657
2011-06-24 09:29:25 +00:00
Miika Pekkarinen
d348615dee Fixed a regression caused in r30021: tagnavi_custom.config parsing
fails if lines ended with <CR><LF> sequence.


git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30059 a1c6a512-1295-4272-9138-f99709370657
2011-06-23 21:27:08 +00:00
Alex Parker
27cdcb61bf Update US English by Steven Panek.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30046 a1c6a512-1295-4272-9138-f99709370657
2011-06-20 21:14:44 +00:00
Alex Parker
3b1926a8d5 Add US English by Steven Panek.
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30042 a1c6a512-1295-4272-9138-f99709370657
2011-06-20 20:21:55 +00:00
Alex Parker
36e309cbe7 Bump release scripts to 3.9RC
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30023 a1c6a512-1295-4272-9138-f99709370657
2011-06-20 17:32:25 +00:00
Alex Parker
f2e123efd5 Branch for 3.9
git-svn-id: svn://svn.rockbox.org/rockbox/branches/v3_9@30022 a1c6a512-1295-4272-9138-f99709370657
2011-06-20 17:20:13 +00:00
7922 changed files with 378156 additions and 1678603 deletions

16
.gitattributes vendored
View file

@ -1,16 +0,0 @@
* text=auto
*.bmp binary
*.cat -text
*.dll binary
*.fnt binary
*.icns binary
*.ico binary
*.inf -text
*.jpg binary
*.pdf binary
*.png binary
*.svg binary
*.sys binary
*.vcproj -text
*.wav binary
*.xcf binary

303
.gitignore vendored
View file

@ -1,303 +0,0 @@
# /
/build*
/sim*
/output
*.elf
*.exe
*.so
*.o
*.a
*~
__pycache__
# Intermediate language files
/apps/lang/*.update
/apps/lang/*.new
# checkwps
/tools/checkwps/output
/tools/checkwps/Makefile
/tools/checkwps/autoconf.h
/tools/checkwps/make.dep
/tools/checkwps/rockbox-info.txt
/tools/checkwps/checkwps.failures
# android: java build system
/android/bin
/android/data
/android/gen
/android/libs
/android/local.properties
# android: our build system
/android/autoconf.h
/android/Makefile
/android/make.dep
/android/apps
/android/bitmaps
/android/pluginbitmaps
/android/firmware
/android/lang
/android/lib
/android/rockbox.*
/android/rockbox-info.txt
/android/sysfont.c
/android/sysfont.h
/android/version.h
/android/credits.raw
# android: eclipse stuff
/android/.settings
# buflib test code
/firmware/test/buflib/test_main
/firmware/test/buflib/test_main2
/firmware/test/buflib/test_max
/firmware/test/buflib/test_move
/firmware/test/buflib/test_move2
/firmware/test/buflib/test_shrink
/firmware/test/buflib/test_shrink_cb
/firmware/test/buflib/test_shrink_startchanged
/firmware/test/buflib/test_shrink_unaligned
# /utils/
/utils/Makefile
/utils/rbutil
# /utils/ipodpatcher/
/utils/ipodpatcher/ipodpatcher
# /utils/chinachippatcher/
/utils/chinachippatcher/chinachip
# /utils/bspatch/
/utils/bspatch/bspatch
# /utils/rbutilqt/
/utils/rbutilqt/build
/utils/rbutilqt/RockboxUtility
/utils/rbutilqt/RockboxUtility.*
/utils/rbutilqt/Makefile
/utils/rbutilqt/*.qm
/utils/rbutilqt/release
/utils/rbutilqt/debug
/utils/rbutilqt/*.Debug
/utils/rbutilqt/*.Release
/utils/rbutilqt/tags
/utils/rbutilqt/.qmake.stash
# /utils/rbutilqt/lang/
/utils/rbutilqt/lang/*.qm
# More rbutil
/utils/*/buildposix
/utils/*/uninstall_script.[ch]
/utils/*/install_script.[ch]
/utils/mkimxboot/mkimxboot
/utils/mknwzboot/mknwzboot
/utils/mkzenboot/mkzenboot
/utils/sansapatcher/sansapatcher
/utils/jztool/jztool
/utils/tools/bin2c
# /tools/
/tools/bdf2bmp
/tools/scramble
/tools/generate_rocklatin
/tools/descramble
/tools/convbdf
/tools/bmp2rb
/tools/codepages
/tools/rdf2binary
/tools/mkboot
/tools/uclpack
/tools/ipod_fw
/tools/wavtrim
/tools/voicefont
/tools/rbspeexenc
/tools/rbspeexdec
/tools/mknkboot
/tools/mktccboot
/tools/mkzenboot
/tools/mkspl-x1000
/tools/iaudio_bl_flash.c
/tools/iaudio_bl_flash.h
/tools/.vagrant
/tools/*-console.log
# /tools/database/
/tools/database/database
# /tools/rbspeex/
/tools/rbspeex/build*
/tools/rbspeex/libspeex.a
/tools/rbspeex/librbspeex.a
/tools/rbspeex/dep-speex
# /tools/ucl/src/
/tools/ucl/src/libucl.a
# /utils/MTP/
/utils/MTP/sendfirm
# /utils/MTP/beastpatcher/
/utils/MTP/beastpatcher/bootimg.*
/utils/MTP/beastpatcher/beastpatcher
/utils/MTP/beastpatcher/bin2c*
# /utils/MTP/beastpatcher/vs2005/
/utils/MTP/beastpatcher/vs2005/*.ncb
/utils/MTP/beastpatcher/vs2005/*.suo
/utils/MTP/beastpatcher/vs2005/*.user
/utils/MTP/beastpatcher/vs2005/Debug
/utils/MTP/beastpatcher/vs2005/Release
# /utils/jz4740_tools/
/utils/jz4740_tools/HXFreplace
/utils/jz4740_tools/HXF2IHFS
/utils/jz4740_tools/usbtool
/utils/jz4740_tools/DLanalyser
/utils/jz4740_tools/HXFsplit
/utils/jz4740_tools/HXFmerge
/utils/jz4740_tools/IHFSsplit
/utils/jz4740_tools/jz_xloader.*
/utils/jz4740_tools/bin2c
# /utils/jz4760_tools
/utils/jz4760_tools/packtools
/utils/jz4760_tools/usbboot
# /utils/ingenic_tools
/utils/ingenic_tools/usbboot
# /utils/nwztools
/utils/nwztools/scsitools/scsitool
/utils/nwztools/upgtools/upgtool
# utils/rk27utils
/utils/rk27utils/rkboottool/rkboottool
# /utils/themeeditor/
/utils/themeeditor/debug
/utils/themeeditor/release
/utils/themeeditor/build
/utils/themeeditor/Makefile*
/utils/themeeditor/object_script*
/utils/themeeditor/rbthemeeditor
# /utils/zenutils/
/utils/zenutils/build
/utils/zenutils/bin
/utils/zenutils/CMakeCache.txt
/utils/zenutils/CMakeFiles
/utils/zenutils/cmake_install.cmake
/utils/zenutils/Makefile
# /utils/zenutils/libraries/
/utils/zenutils/libraries/CMakeCache.txt
/utils/zenutils/libraries/CMakeFiles
/utils/zenutils/libraries/cmake_install.cmake
/utils/zenutils/libraries/Makefile
# /utils/zenutils/libraries/beecrypt-4.1.2/
/utils/zenutils/libraries/beecrypt-4.1.2/CMakeCache.txt
/utils/zenutils/libraries/beecrypt-4.1.2/CMakeFiles
/utils/zenutils/libraries/beecrypt-4.1.2/cmake_install.cmake
/utils/zenutils/libraries/beecrypt-4.1.2/Makefile
# /utils/zenutils/libraries/beecrypt-4.1.2/beecrypt/
/utils/zenutils/libraries/beecrypt-4.1.2/beecrypt/CMakeCache.txt
/utils/zenutils/libraries/beecrypt-4.1.2/beecrypt/CMakeFiles
/utils/zenutils/libraries/beecrypt-4.1.2/beecrypt/cmake_install.cmake
/utils/zenutils/libraries/beecrypt-4.1.2/beecrypt/Makefile
# /utils/zenutils/libraries/getpot-c++-1.1.18/
/utils/zenutils/libraries/getpot-c++-1.1.18/CMakeCache.txt
/utils/zenutils/libraries/getpot-c++-1.1.18/CMakeFiles
/utils/zenutils/libraries/getpot-c++-1.1.18/cmake_install.cmake
/utils/zenutils/libraries/getpot-c++-1.1.18/Makefile
# /utils/zenutils/libraries/getpot-c++-1.1.18/getpot/
/utils/zenutils/libraries/getpot-c++-1.1.18/getpot/CMakeCache.txt
/utils/zenutils/libraries/getpot-c++-1.1.18/getpot/CMakeFiles
/utils/zenutils/libraries/getpot-c++-1.1.18/getpot/cmake_install.cmake
/utils/zenutils/libraries/getpot-c++-1.1.18/getpot/Makefile
# /utils/zenutils/libraries/pelib-0.9/
/utils/zenutils/libraries/pelib-0.9/CMakeCache.txt
/utils/zenutils/libraries/pelib-0.9/CMakeFiles
/utils/zenutils/libraries/pelib-0.9/cmake_install.cmake
/utils/zenutils/libraries/pelib-0.9/Makefile
# /utils/zenutils/libraries/pelib-0.9/pelib/
/utils/zenutils/libraries/pelib-0.9/pelib/CMakeCache.txt
/utils/zenutils/libraries/pelib-0.9/pelib/CMakeFiles
/utils/zenutils/libraries/pelib-0.9/pelib/cmake_install.cmake
/utils/zenutils/libraries/pelib-0.9/pelib/Makefile
# /utils/zenutils/libraries/pelib-0.9/pelib/buffer/
/utils/zenutils/libraries/pelib-0.9/pelib/buffer/CMakeCache.txt
/utils/zenutils/libraries/pelib-0.9/pelib/buffer/CMakeFiles
/utils/zenutils/libraries/pelib-0.9/pelib/buffer/cmake_install.cmake
/utils/zenutils/libraries/pelib-0.9/pelib/buffer/Makefile
# /utils/zenutils/libraries/zlib123/
/utils/zenutils/libraries/zlib123/CMakeCache.txt
/utils/zenutils/libraries/zlib123/CMakeFiles
/utils/zenutils/libraries/zlib123/cmake_install.cmake
/utils/zenutils/libraries/zlib123/Makefile
# /utils/zenutils/libraries/zlib123/zlib/
/utils/zenutils/libraries/zlib123/zlib/CMakeCache.txt
/utils/zenutils/libraries/zlib123/zlib/CMakeFiles
/utils/zenutils/libraries/zlib123/zlib/cmake_install.cmake
/utils/zenutils/libraries/zlib123/zlib/Makefile
# /utils/zenutils/source/
/utils/zenutils/source/CMakeCache.txt
/utils/zenutils/source/CMakeFiles
/utils/zenutils/source/cmake_install.cmake
/utils/zenutils/source/Makefile
# /utils/zenutils/source/firmware_extract/
/utils/zenutils/source/firmware_extract/CMakeCache.txt
/utils/zenutils/source/firmware_extract/CMakeFiles
/utils/zenutils/source/firmware_extract/cmake_install.cmake
/utils/zenutils/source/firmware_extract/Makefile
# /utils/zenutils/source/firmware_make/
/utils/zenutils/source/firmware_make/CMakeCache.txt
/utils/zenutils/source/firmware_make/CMakeFiles
/utils/zenutils/source/firmware_make/cmake_install.cmake
/utils/zenutils/source/firmware_make/Makefile
# /utils/zenutils/source/shared/
/utils/zenutils/source/shared/CMakeCache.txt
/utils/zenutils/source/shared/CMakeFiles
/utils/zenutils/source/shared/cmake_install.cmake
/utils/zenutils/source/shared/Makefile
# /utils/zenutils/source/update_extract/
/utils/zenutils/source/update_extract/CMakeCache.txt
/utils/zenutils/source/update_extract/CMakeFiles
/utils/zenutils/source/update_extract/cmake_install.cmake
/utils/zenutils/source/update_extract/Makefile
# /utils/zenutils/source/update_patch/
/utils/zenutils/source/update_patch/CMakeCache.txt
/utils/zenutils/source/update_patch/CMakeFiles
/utils/zenutils/source/update_patch/cmake_install.cmake
/utils/zenutils/source/update_patch/Makefile
# /utils/zenutils/source/zen_crypt/
/utils/zenutils/source/zen_crypt/CMakeCache.txt
/utils/zenutils/source/zen_crypt/CMakeFiles
/utils/zenutils/source/zen_crypt/cmake_install.cmake
/utils/zenutils/source/zen_crypt/Makefile
# /utils/regtools/
/utils/regtools/headergen_v1
/utils/regtools/headergen_v2
/utils/regtools/regtool
/utils/regtools/swiss_knife
/utils/regtools/tester_v1

View file

@ -1,5 +0,0 @@
[gerrit]
host=gerrit.rockbox.org
port=29418
project=rockbox.git
defaultbranch=master

View file

@ -3,7 +3,5 @@
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View file

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<stringAttribute key="org.eclipse.debug.core.ATTR_REFRESH_SCOPE" value="${workspace}"/>
<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="false"/>
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/make"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,incremental,auto,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="libs NODEPS=''"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:/Rockbox}"/>
</launchConfiguration>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND" value="false"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_BUILDER_ENABLED" value="false"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${project_loc}/../tools/configure"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS" value="full,"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="--target=201 --type=ad --lcdwidth=320 --lcdheight=480"/>
<booleanAttribute key="org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED" value="true"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${project_loc}"/>
</launchConfiguration>

View file

@ -5,26 +5,6 @@
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/tools_configure.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>auto,full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/make libs.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>

View file

@ -80,7 +80,7 @@
</application>
<uses-sdk android:minSdkVersion="5" />
<uses-sdk android:minSdkVersion="4" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
</manifest>

View file

@ -7,85 +7,64 @@
# $Id$
#
PACKAGE=org.rockbox
PACKAGE_PATH=org/rockbox
BINLIB_DIR=$(BUILDDIR)/libs/$(ANDROID_ARCH)
ANDROID_DIR=$(ROOTDIR)/android
# this is a glibc compatibility hack to provide a get_nprocs() replacement.
# The NDK ships cpu-features.c which has a compatible function android_getCpuCount()
CPUFEAT = $(ANDROID_NDK_PATH)/sources/android/cpufeatures
CPUFEAT_BUILD = $(BUILDDIR)
INCLUDES += -I$(CPUFEAT)
OTHER_SRC += $(CPUFEAT)/cpu-features.c
CLEANOBJS += $(CPUFEAT_BUILD)/cpu-features.o
$(CPUFEAT_BUILD)/cpu-features.o: $(CPUFEAT)/cpu-features.c
$(SILENT)mkdir -p $(dir $@)
$(call PRINTS,CC $(subst $(CPUFEAT)/,,$<))$(CC) -o $@ -c $^ $(GCCOPTS) -Wno-unused
.SECONDEXPANSION: # $$(JAVA_OBJ) is not populated until after this
.SECONDEXPANSION: # $$(OBJ) is not populated until after this
.PHONY: apk classes clean dex dirs libs jar
$(BUILDDIR)/$(BINARY): $$(OBJ) $(VOICESPEEXLIB) $(FIRMLIB) $(SKINLIB)
$(call PRINTS,LD $(BINARY))$(CC) -o $@ $^ $(LDOPTS) $(GLOBAL_LDOPTS)
PACKAGE=org.rockbox
PACKAGE_PATH=org/rockbox
ANDROID_DIR=$(ROOTDIR)/android
BINLIB_DIR=$(BUILDDIR)/libs/armeabi
java2class = $(addsuffix .class,$(basename $(subst $(ANDROID_DIR),$(BUILDDIR),$(1))))
# API version
#ANDROID_PLATFORM_VERSION=19 # Set by configure script
ANDROID_PLATFORM_VERSION=11
ANDROID_PLATFORM=$(ANDROID_SDK_PATH)/platforms/android-$(ANDROID_PLATFORM_VERSION)
# Use oldest version available..
BUILD_TOOLS_VERSION=$(notdir $(firstword $(wildcard $(ANDROID_SDK_PATH)/build-tools/*)))
# android tools
AAPT=$(ANDROID_SDK_PATH)/build-tools/$(BUILD_TOOLS_VERSION)/aapt
DX=$(ANDROID_SDK_PATH)/build-tools/$(BUILD_TOOLS_VERSION)/dx
ifneq ("$(wildcard $(ANDROID_SDK_PATH)/tools/zipalign)","")
ZIPALIGN=$(ANDROID_SDK_PATH)/tools/zipalign
else
ZIPALIGN=$(ANDROID_SDK_PATH)/build-tools/$(BUILD_TOOLS_VERSION)/zipalign
endif
AAPT=$(ANDROID_SDK_PATH)/platform-tools/aapt
DX=$(ANDROID_SDK_PATH)/platform-tools/dx
APKBUILDER=$(ANDROID_SDK_PATH)/tools/apkbuilder
ZIPALIGN=$(ANDROID_SDK_PATH)/tools/zipalign
KEYSTORE=$(HOME)/.android/debug.keystore
ADB=$(ANDROID_SDK_PATH)/platform-tools/adb
BUILDAPK=$(ANDROID_DIR)/buildapk.sh
CLASSPATH := $(BUILDDIR)/bin/classes
MANIFEST := $(BUILDDIR)/bin/AndroidManifest.xml
MANIFEST_SRC := $(ANDROID_DIR)/AndroidManifest.xml
R_JAVA := $(BUILDDIR)/gen/$(PACKAGE_PATH)/R.java
R_OBJ := $(CLASSPATH)/$(PACKAGE_PATH)/R.class
R_OBJ := $(BUILDDIR)/bin/$(PACKAGE_PATH)/R.class
JAVA_SRC := $(wildcard $(ANDROID_DIR)/src/$(PACKAGE_PATH)/*.java)
JAVA_SRC += $(wildcard $(ANDROID_DIR)/src/$(PACKAGE_PATH)/Helper/*.java)
JAVA_SRC := $(wildcard $(ANDROID_DIR)/src/$(PACKAGE_PATH)/Helper/*.java)
JAVA_SRC += $(wildcard $(ANDROID_DIR)/src/$(PACKAGE_PATH)/*.java)
JAVA_SRC += $(wildcard $(ANDROID_DIR)/src/$(PACKAGE_PATH)/widgets/*.java)
JAVA_SRC += $(wildcard $(ANDROID_DIR)/src/$(PACKAGE_PATH)/monitors/*.java)
java2class = $(addsuffix .class,$(basename $(subst $(ANDROID_DIR)/src,$(CLASSPATH),$(1))))
JAVA_OBJ := $(call java2class,$(JAVA_SRC))
JAVA_OBJ := $(call java2class,$(subst $(ANDROID)/src/$(PACKAGE_PATH),$(ANDROID)/bin/$(PACKAGE_PATH),$(JAVA_SRC)))
LIBS := $(BINLIB_DIR)/$(BINARY) $(BINLIB_DIR)/libmisc.so
LIBS += $(addprefix $(BINLIB_DIR)/lib,$(patsubst %.codec,%.so,$(notdir $(CODECS))))
TEMP_APK := $(BUILDDIR)/bin/_rockbox.apk
TEMP_APK2 := $(BUILDDIR)/bin/__rockbox.apk
DEX := $(BUILDDIR)/bin/classes.dex
JAR := $(BUILDDIR)/bin/classes.jar
AP_ := $(BUILDDIR)/bin/resources.ap_
APK := $(BUILDDIR)/rockbox.apk
DEX := $(BUILDDIR)/bin/classes.dex
JAR := $(BUILDDIR)/bin/classes.jar
AP_ := $(BUILDDIR)/bin/resources.ap_
APK := $(BUILDDIR)/rockbox.apk
_DIRS := $(BUILDDIR)/___/$(PACKAGE_PATH)
DIRS := $(subst ___,bin,$(_DIRS))
DIRS += $(subst ___,gen,$(_DIRS))
DIRS += $(subst ___,data,$(_DIRS))
DIRS += $(BUILDDIR)/libs/$(ANDROID_ARCH)
DIRS += $(CPUFEAT_BUILD)
DIRS += $(CLASSPATH)
DIRS += $(BUILDDIR)/libs/armeabi
RES := $(wildcard $(ANDROID_DIR)/res/*/*)
CLEANOBJS += bin gen libs data
JAVAC_OPTS += -source 1.6 -target 1.6 -implicit:none -classpath $(ANDROID_PLATFORM)/android.jar:$(CLASSPATH)
JAVAC_OPTS += -implicit:none -classpath $(ANDROID_PLATFORM)/android.jar:$(BUILDDIR)/bin
.PHONY:
$(MANIFEST): $(MANIFEST_SRC) $(DIRS)
@ -96,18 +75,21 @@ $(R_JAVA) $(AP_): $(MANIFEST) $(RES) | $(DIRS)
-J $(BUILDDIR)/gen -M $(MANIFEST) -S $(ANDROID_DIR)/res \
-I $(ANDROID_PLATFORM)/android.jar -F $(AP_)
$(CLASSPATH)/$(PACKAGE_PATH)/R.class: $(R_JAVA)
$(BUILDDIR)/bin/$(PACKAGE_PATH)/R.class: $(R_JAVA)
$(call PRINTS,JAVAC $(subst $(ROOTDIR)/,,$<))javac -d $(BUILDDIR)/bin \
$(JAVAC_OPTS) -sourcepath $(ANDROID_DIR)/gen $<
$(JAVAC_OPTS) \
-sourcepath $(ANDROID_DIR)/gen $<
$(CLASSPATH)/$(PACKAGE_PATH)/%.class: $(ANDROID_DIR)/src/$(PACKAGE_PATH)/%.java $(CLASSPATH)/$(PACKAGE_PATH)/R.class
$(call PRINTS,JAVAC $(subst $(ROOTDIR)/,,$<))javac -d $(CLASSPATH) \
$(JAVAC_OPTS) -sourcepath $(ANDROID_DIR)/src $<
$(BUILDDIR)/bin/$(PACKAGE_PATH)/%.class: $(ANDROID_DIR)/src/$(PACKAGE_PATH)/%.java $(BUILDDIR)/bin/$(PACKAGE_PATH)/R.class
$(call PRINTS,JAVAC $(subst $(ROOTDIR)/,,$<))javac -d $(BUILDDIR)/bin \
$(JAVAC_OPTS) \
-sourcepath $(ANDROID_DIR)/src $<
$(JAR): $(JAVA_SRC) $(R_JAVA)
$(call PRINTS,JAVAC $(subst $(ROOTDIR)/,,$?))javac -d $(CLASSPATH) \
$(JAVAC_OPTS) -sourcepath $(ANDROID_DIR)/src:$(ANDROID_DIR)/gen $?
$(call PRINTS,JAR $(subst $(BUILDDIR)/,,$@))jar cf $(JAR) -C $(CLASSPATH) org
$(call PRINTS,JAVAC $(subst $(ROOTDIR)/,,$?))javac -d $(BUILDDIR)/bin \
$(JAVAC_OPTS) \
-sourcepath $(ANDROID_DIR)/src:$(ANDROID_DIR)/gen $?
$(call PRINTS,JAR $(subst $(BUILDDIR)/,,$@))jar cf $(JAR) -C $(BUILDDIR)/bin org
jar: $(JAR)
@ -120,43 +102,33 @@ dex: $(DEX)
classes: $(R_OBJ) $(JAVA_OBJ)
$(BUILDDIR)/$(BINARY): $$(OBJ) $(FIRMLIB) $(VOICESPEEXLIB) $(CORE_LIBS) $(CPUFEAT_BUILD)/cpu-features.o
$(call PRINTS,LD $(BINARY))$(CC) -o $@ $^ $(LDOPTS) $(GLOBAL_LDOPTS) -Wl,-Map,$(BUILDDIR)/rockbox.map
$(call PRINTS,OC $(@F))$(call objcopy,$@,$@)
$(BINLIB_DIR)/$(BINARY): $(BUILDDIR)/$(BINARY)
$(call PRINTS,CP $(BINARY))cp $^ $@
$(BINLIB_DIR)/libmisc.so: $(BUILDDIR)/rockbox.zip
$(call PRINTS,CP rockbox.zip)cp $^ $@
$(BINLIB_DIR)/lib%.so: $(RBCODEC_BLD)/codecs/%.codec
$(BINLIB_DIR)/lib%.so: $(BUILDDIR)/apps/codecs/%.codec
$(call PRINTS,CP $(@F))cp $^ $@
libs: $(DIRS) $(LIBS)
libs: $(LIBS)
$(TEMP_APK): $(AP_) $(LIBS) $(DEX) | $(DIRS)
$(call PRINTS,APK $(subst $(BUILDDIR)/,,$@))$(BUILDAPK) $(BUILDDIR) $(notdir $@) $(BUILD_TOOLS_VERSION)
$(call PRINTS,APK $(subst $(BUILDDIR)/,,$@))$(APKBUILDER) $@ \
-u -z $(AP_) -f $(DEX) -nf $(BUILDDIR)/libs
$(KEYSTORE):
$(SILENT)mkdir -p $(HOME)/.android
$(call PRINTS,KEYTOOL debug.keystore)keytool -genkey \
-alias androiddebugkey -keystore $@ \
-storepass android -keypass android -validity 365 \
-sigalg MD5withRSA -keyalg RSA -keysize 1024 \
-dname "CN=Android Debug,O=Android,C=US"
ifdef NODEPS
$(APK): $(TEMP_APK) $(KEYSTORE)
else
$(APK): $(TEMP_APK) $(BUILDDIR)/rockbox.zip $(KEYSTORE)
endif
$(SILENT)rm -f $@
$(call PRINTS,SIGN $(subst $(BUILDDIR)/,,$@))jarsigner \
-keystore "$(KEYSTORE)" -storepass "android" -keypass "android" \
-signedjar $(TEMP_APK2) $(TEMP_APK) "androiddebugkey" \
-sigalg MD5withRSA -digestalg SHA1
-signedjar $(TEMP_APK2) $(TEMP_APK) "androiddebugkey"
$(SILENT)$(ZIPALIGN) -v 4 $(TEMP_APK2) $@ > /dev/null
$(DIRS):

View file

@ -1,12 +0,0 @@
# Override some props according to android.make
# see $ANDROID_SDK_PATH/tools/ant/build.xml for what's overridable
# Once we can build signed *release* builds, we should have a different
# names for the debug builds
# the signed, unzipaligned file is bin/__rockbox.apk
out.packaged.file=bin/__${ant.project.name}.apk
# the final file is rockbox.apk, in the build dir
out.packaged.file=${ant.project.name}.apk

View file

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="rockbox" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
unless="sdk.dir"
/>
<!-- extension targets. Uncomment the ones where you want to do custom work
in between standard targets -->
<!--
<target name="-pre-build">
</target>
<target name="-pre-compile">
</target>
/* This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir} */
<target name="-post-compile">
</target>
-->
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View file

@ -1,19 +0,0 @@
#!/bin/sh
BUILDDIR=$1
APK=$2
SDKV=$3
[ -z $ANDROID_SDK_PATH ] && exit 1
[ -z $BUILDDIR ] && exit 1
[ -d $BUILDDIR ] || exit 1
# need to cd into the bin dir and create a symlink to the libraries
# so that aapt puts the libraries with the correct prefix into the apk
cd $BUILDDIR/bin
ln -nfs $BUILDDIR/libs lib
cp resources.ap_ $APK
$ANDROID_SDK_PATH/build-tools/$SDKV/aapt add $APK classes.dex > /dev/null
$ANDROID_SDK_PATH/build-tools/$SDKV/aapt add $APK lib/*/* > /dev/null
exit 0

View file

@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-11

View file

@ -6,32 +6,32 @@
# it stopped
set -e
SDK_DOWNLOAD_URL="http://developer.android.com/sdk/index.html"
NDK_DOWNLOAD_URL="http://developer.android.com/sdk/ndk/index.html"
find_url() {
base_url="$1"
os="$2"
wget -q -O - $base_url | grep dl.google.com | sed 's/.*"\(http:\/\/.*\)".*/\1/' | grep $os | grep -v bundle | grep -v .exe # Windows hack
}
# http://developer.android.com/sdk/index.html
SDK_URL_LNX="http://dl.google.com/android/android-sdk_r11-linux_x86.tgz"
SDK_URL_MAC="http://dl.google.com/android/android-sdk_r11-mac_x86.zip"
SDK_URL_WIN="http://dl.google.com/android/android-sdk_r11-windows.zip"
# http://developer.android.com/sdk/ndk/index.html
NDK_URL_LNX="http://dl.google.com/android/ndk/android-ndk-r5c-linux-x86.tar.bz2"
NDK_URL_MAC="http://dl.google.com/android/ndk/android-ndk-r5c-darwin-x86.tar.bz2"
NDK_URL_WIN="http://dl.google.com/android/ndk/android-ndk-r5c-windows.zip"
OS=`uname`
case $OS in
Linux)
SDK_URL=$(find_url $SDK_DOWNLOAD_URL linux)
NDK_URL=$(find_url $NDK_DOWNLOAD_URL linux)
SDK_URL=$SDK_URL_LNX
NDK_URL=$NDK_URL_LNX
ANDROID=tools/android
;;
Darwin)
SDK_URL=$(find_url $SDK_DOWNLOAD_URL mac)
NDK_URL=$(find_url $NDK_DOWNLOAD_URL darwin)
SDK_URL=$SDK_URL_MAC
NDK_URL=$NDK_URL_MAC
ANDROID=tools/android
;;
CYGWIN*)
SDK_URL=$(find_url $SDK_DOWNLOAD_URL windows)
NDK_URL=$(find_url $NDK_DOWNLOAD_URL windows)
SDK_URL=$SDK_URL_WIN
NDK_URL=$NDK_URL_WIN
ANDROID=tools/android.bat
;;
esac
@ -52,14 +52,14 @@ download_and_extract() {
fi
echo " * Extracting $name..."
case ${local_file} in
*.zip)
case ${local_file#*.} in
zip)
unzip -qo -d "$prefix" "$local_file"
;;
*.tgz|*.tar.gz)
(cd $prefix; tar -xzf "$local_file")
tgz|tar.gz)
(cd $prefix; tar -xf "$local_file")
;;
*.tar.bz2)
tar.bz2)
(cd $prefix; tar -xjf "$local_file")
;;
*)
@ -80,7 +80,7 @@ fi
if [ -z "$(find $SDK_PATH/platforms -type d -name 'android-*')" ]; then
echo " * Installing Android platforms..."
$SDK_PATH/$ANDROID update sdk --no-ui --filter platform,platform-tool,tool
$SDK_PATH/$ANDROID update sdk --no-ui --filter platform,tool
fi
cat <<EOF

View file

@ -1,40 +0,0 @@
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}

View file

@ -1,11 +0,0 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-19

View file

@ -8,20 +8,19 @@
android:paddingBottom="0dp"
android:orientation="horizontal">
<ImageView android:id="@+id/artwork"
android:gravity="center"
android:padding="2dp"
android:scaleType="center"
android:adjustViewBounds="false"
android:layout_width="wrap_content"
android:layout_height="fill_parent">
</ImageView>
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView android:src="@drawable/notification_small"
android:gravity="center"
android:paddingTop="2dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
<TextView android:id="@+id/title"
android:layout_width="wrap_content"
@ -39,7 +38,7 @@
<LinearLayout android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="3dp"
android:orientation="horizontal">
android:orientation="vertical">
<TextView android:id="@+id/content"
android:layout_gravity="left"
android:scrollHorizontally="true"

View file

@ -6,7 +6,6 @@
<string name="OK">OK</string>
<string name="Cancel">Cancel</string>
<string name="KbdInputTitle">Rockbox Keyboard Input</string>
<string name="YesNoTitle">Rockbox</string>
<string name="Yes">Yes</string>
<string name="No">No</string>
<string name="error_extraction">Error occured during extraction!</string>

View file

@ -1,48 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 Thomas Martitz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
package org.rockbox.Helper;
import android.util.Log;
public class Logger
{
private static final String TAG = "Rockbox";
public static void i(String s)
{
Log.i(TAG, s);
}
public static void d(String s)
{
Log.d(TAG, s);
}
public static void d(String s, Throwable t)
{
Log.d(TAG, s, t);
}
public static void e(String s)
{
Log.e(TAG, s);
}
}

View file

@ -29,6 +29,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.util.Log;
import android.view.KeyEvent;
public class MediaButtonReceiver
@ -58,7 +59,6 @@ public class MediaButtonReceiver
/* Throwable includes Exception and the expected
* NoClassDefFoundError */
api = new OldApi(c);
Logger.i("MediaButtonReceiver: Falling back to compatibility API");
}
}
@ -69,7 +69,7 @@ public class MediaButtonReceiver
public void unregister()
{
api.unregister();
api.register();
}
/* helper class for the manifest */
@ -88,7 +88,7 @@ public class MediaButtonReceiver
KeyEvent key = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (key.getAction() == KeyEvent.ACTION_UP)
{ /* pass the pressed key to Rockbox, starting it if needed */
RockboxService s = RockboxService.getInstance();
RockboxService s = RockboxService.get_instance();
if (s == null || !s.isRockboxRunning())
startService(context, intent);
else if (RockboxFramebuffer.buttonHandler(key.getKeyCode(), false))
@ -144,7 +144,7 @@ public class MediaButtonReceiver
public void onAudioFocusChange(int focusChange)
{
Logger.d("Audio focus" + ((focusChange>0)?"gained":"lost")+
Log.d("Rockbox", "Audio focus" + ((focusChange>0)?"gained":"lost")+
": "+ focusChange);
if (running)
{ /* Play nice and stop for the the other app */

View file

@ -1,32 +1,24 @@
package org.rockbox.Helper;
import java.lang.reflect.Method;
import org.rockbox.R;
import org.rockbox.RockboxActivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;
import android.widget.RemoteViews;
public class RunForegroundManager
{
/* all below is heavily based on the examples found on
* http://developer.android.com/reference/android/app/Service.html#setForeground(boolean)
*/
private Notification mNotification;
private NotificationManager mNM;
private IRunForeground api;
private Service mCurrentService;
private Handler mServiceHandler;
private Intent mWidgetUpdate;
private int iconheight;
public RunForegroundManager(Service service)
{
@ -38,11 +30,6 @@ public class RunForegroundManager
Intent intent = new Intent(service, RockboxActivity.class);
intent = intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
/* retrieve height of launcher icon. Used to scale down album art. */
Resources resources = service.getResources();
Drawable draw = resources.getDrawable(R.drawable.launcher);
iconheight = draw.getIntrinsicHeight();
mNotification = new Notification();
mNotification.tickerText = service.getString(R.string.notification);
mNotification.icon = R.drawable.notification;
@ -50,99 +37,47 @@ public class RunForegroundManager
mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
mNotification.contentIntent = PendingIntent.getActivity(service, 0, intent, 0);
try {
api = new NewForegroundApi(R.string.notification, mNotification);
} catch (Throwable t) {
/* Throwable includes Exception and the expected
* NoClassDefFoundError for Android 1.x */
try {
api = new OldForegroundApi();
Logger.i("RunForegroundManager: Falling back to compatibility API");
} catch (Exception e) {
Logger.e("Cannot run in foreground: No available API");
}
}
mServiceHandler = new Handler(service.getMainLooper());
initForegroundCompat();
}
private void LOG(CharSequence text)
{
Log.d("Rockbox", (String)text);
}
private void LOG(CharSequence text, Throwable tr)
{
Log.d("Rockbox", (String)text, tr);
}
public void startForeground()
{
/*
* Send the notification.
* We use a layout id because it is a unique number.
* We use it later to cancel.
*/
mNM.notify(R.string.notification, mNotification);
/*
* this call makes the service run as foreground, which
* provides enough cpu time to do music decoding in the
* background
*/
api.startForeground();
startForegroundCompat(R.string.notification, mNotification);
}
public void stopForeground()
{
/* Note to cancel BEFORE changing the
* foreground state, since we could be killed at that point.
*/
mNM.cancel(R.string.notification);
api.stopForeground();
stopForegroundCompat(R.string.notification);
mWidgetUpdate = null;
}
public void updateNotification(final String title, final String artist, final String album, final String albumart)
public void updateNotification(String title, String artist, String album, String albumart)
{
/* do this on the main thread for 2 reasons
* 1) Don't delay track switching with possibly costly albumart
* loading (i.e. off-load from the Rockbox thread)
* 2) Work around a bug in Android where decodeFile() fails outside
* of the main thread (http://stackoverflow.com/q/7228633)
*/
mServiceHandler.post(new Runnable()
{
@Override
public void run()
{
final RemoteViews views = mNotification.contentView;
views.setTextViewText(R.id.title, title);
views.setTextViewText(R.id.content, artist+"\n"+album);
if (artist.equals(""))
mNotification.tickerText = title;
else
mNotification.tickerText = title+" - "+artist;
RemoteViews views = mNotification.contentView;
views.setTextViewText(R.id.title, title);
views.setTextViewText(R.id.content, artist+"\n"+album);
if (artist.equals(""))
mNotification.tickerText = title;
else
mNotification.tickerText = title+" - "+artist;
mNM.notify(R.string.notification, mNotification);
if (albumart != null) {
/* The notification area doesn't have permissions to access the SD card.
* Push the data as Bitmap instead of Uri. Scale down to size of
* launcher icon -- broadcasting the unscaled image may yield in
* too much data, causing UI hangs of Rockbox. */
Bitmap b = BitmapFactory.decodeFile(albumart);
if(b != null) {
/* scale width to keep aspect ratio -- height is the constraint */
int scaledwidth = Math.round(iconheight*((float)b.getWidth()/b.getHeight()));
views.setImageViewBitmap(R.id.artwork,
Bitmap.createScaledBitmap(b, scaledwidth, iconheight, false));
}
else {
views.setImageViewResource(R.id.artwork, R.drawable.launcher);
}
}
else {
views.setImageViewResource(R.id.artwork, R.drawable.launcher);
}
mWidgetUpdate = new Intent("org.rockbox.TrackUpdateInfo");
mWidgetUpdate.putExtra("title", title);
mWidgetUpdate.putExtra("artist", artist);
mWidgetUpdate.putExtra("album", album);
mWidgetUpdate.putExtra("albumart", albumart);
mCurrentService.sendBroadcast(mWidgetUpdate);
/* notify in this runnable to make sure the notification
* has the correct albumart */
mNM.notify(R.string.notification, mNotification);
}
});
mWidgetUpdate = new Intent("org.rockbox.TrackUpdateInfo");
mWidgetUpdate.putExtra("title", title);
mWidgetUpdate.putExtra("artist", artist);
mWidgetUpdate.putExtra("album", album);
mWidgetUpdate.putExtra("albumart", albumart);
mCurrentService.sendBroadcast(mWidgetUpdate);
}
public void resendUpdateNotification()
@ -153,68 +88,78 @@ public class RunForegroundManager
public void finishNotification()
{
Logger.d("TrackFinish");
Log.d("Rockbox", "TrackFinish");
Intent widgetUpdate = new Intent("org.rockbox.TrackFinish");
mCurrentService.sendBroadcast(widgetUpdate);
}
private interface IRunForeground
{
void startForeground();
void stopForeground();
}
/* Loosely based on http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification) */
private static final Class<?>[] mSetForegroundSignature = new Class[] {boolean.class};
private static final Class<?>[] mStartForegroundSignature = new Class[] {int.class, Notification.class};
private static final Class<?>[] mStopForegroundSignature = new Class[] {boolean.class};
private class NewForegroundApi implements IRunForeground
{
int id;
Notification mNotification;
NewForegroundApi(int _id, Notification _notification)
{
id = _id;
mNotification = _notification;
}
private Method mSetForeground;
private Method mStartForeground;
private Method mStopForeground;
public void startForeground()
{
mCurrentService.startForeground(id, mNotification);
}
public void stopForeground()
{
mCurrentService.stopForeground(true);
}
}
private class OldForegroundApi implements IRunForeground
{
/*
* Get the new API through reflection because it's unavailable
* in honeycomb
*/
private Method mSetForeground;
public OldForegroundApi() throws SecurityException, NoSuchMethodException
{
mSetForeground = getClass().getMethod("setForeground",
new Class[] { boolean.class });
}
public void startForeground()
{
private void initForegroundCompat() {
Class<?> serviceClass = mCurrentService.getClass();
try {
mStartForeground = serviceClass.getMethod("startForeground", mStartForegroundSignature);
mStopForeground = serviceClass.getMethod("stopForeground", mStopForegroundSignature);
} catch (NoSuchMethodException e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
try {
mSetForeground.invoke(mCurrentService, Boolean.TRUE);
} catch (Exception e) {
Logger.e("startForeground compat error: " + e.getMessage());
e.printStackTrace();
mSetForeground = serviceClass.getMethod("setForeground", mSetForegroundSignature);
} catch (NoSuchMethodException e2) {
throw new IllegalStateException("OS doesn't have Service.startForeground nor Service.setForeground!", e2);
}
}
public void stopForeground()
{
try {
mSetForeground.invoke(mCurrentService, Boolean.FALSE);
} catch (Exception e) {
Logger.e("stopForeground compat error: " + e.getMessage());
}
}
}
private void invokeMethod(Method method, Object[] args) {
try {
method.invoke(mCurrentService, args);
} catch (Exception e) {
// Should not happen.
Log.w("Rockbox", "Unable to invoke method", e);
}
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
private void startForegroundCompat(int id, Notification notification) {
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
Object[] startForeGroundArgs = new Object[] {Integer.valueOf(id), notification};
invokeMethod(mStartForeground, startForeGroundArgs);
} else {
// Fall back on the old API.
Object[] setForegroundArgs = new Object[] {Boolean.TRUE};
invokeMethod(mSetForeground, setForegroundArgs);
mNM.notify(id, notification);
}
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
private void stopForegroundCompat(int id) {
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
Object[] stopForegroundArgs = new Object[] {Boolean.TRUE};
invokeMethod(mStopForeground, stopForegroundArgs);
} else {
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
mNM.cancel(id);
Object[] setForegroundArgs = new Object[] {Boolean.FALSE};
invokeMethod(mSetForeground, setForegroundArgs);
}
}
}

View file

@ -28,6 +28,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Toast;
@ -42,11 +43,12 @@ public class RockboxActivity extends Activity
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
Intent intent = new Intent(this, RockboxService.class);
intent.setAction(Intent.ACTION_MAIN);
intent.putExtra("callback", new ResultReceiver(new Handler(getMainLooper())) {
private boolean unzip = false;
private ProgressDialog loadingdialog;
private void createProgressDialog()
{
loadingdialog = new ProgressDialog(RockboxActivity.this);
@ -60,32 +62,20 @@ public class RockboxActivity extends Activity
@Override
protected void onReceiveResult(final int resultCode, final Bundle resultData)
{
RockboxFramebuffer fb;
switch (resultCode) {
case RockboxService.RESULT_INVOKING_MAIN:
if (loadingdialog != null)
loadingdialog.dismiss();
fb = new RockboxFramebuffer(RockboxActivity.this);
setContentView(fb);
fb.requestFocus();
break;
case RockboxService.RESULT_LIB_LOAD_PROGRESS:
if (loadingdialog == null)
createProgressDialog();
loadingdialog.setIndeterminate(false);
loadingdialog.setMax(resultData.getInt("max", 100));
loadingdialog.setProgress(resultData.getInt("value", 0));
break;
case RockboxService.RESULT_LIB_LOADED:
unzip = resultData.getBoolean("unzip");
break;
case RockboxService.RESULT_SERVICE_RUNNING:
if (!unzip) /* defer to RESULT_INVOKING_MAIN */
{
fb = new RockboxFramebuffer(RockboxActivity.this);
setContentView(fb);
fb.requestFocus();
}
setServiceActivity(true);
break;
case RockboxService.RESULT_ERROR_OCCURED:
@ -97,21 +87,21 @@ public class RockboxActivity extends Activity
}
}
});
setContentView(new RockboxFramebuffer(this));
startService(intent);
}
private void setServiceActivity(boolean set)
{
RockboxService s = RockboxService.getInstance();
RockboxService s = RockboxService.get_instance();
if (s != null)
s.setActivity(set ? this : null);
s.set_activity(set ? this : null);
}
public void onResume()
{
super.onResume();
setVisible(true);
setServiceActivity(true);
}
/* this is also called when the backlight goes off,
@ -139,4 +129,9 @@ public class RockboxActivity extends Activity
super.onDestroy();
setServiceActivity(false);
}
private void LOG(CharSequence text)
{
Log.d("Rockbox", (String) text);
}
}

View file

@ -28,6 +28,7 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
@ -39,6 +40,7 @@ public class RockboxFramebuffer extends SurfaceView
{
private final DisplayMetrics metrics;
private final ViewConfiguration view_config;
private ByteBuffer native_buf;
private Bitmap btm;
/* first stage init; needs to run from a thread that has a Looper
@ -46,6 +48,7 @@ public class RockboxFramebuffer extends SurfaceView
public RockboxFramebuffer(Context c)
{
super(c);
metrics = c.getResources().getDisplayMetrics();
view_config = ViewConfiguration.get(c);
getHolder().addCallback(this);
@ -57,14 +60,20 @@ public class RockboxFramebuffer extends SurfaceView
setEnabled(false);
}
private void update(ByteBuffer framebuffer)
/* second stage init; called from Rockbox with information about the
* display framebuffer */
private void java_lcd_init(int lcd_width, int lcd_height, ByteBuffer native_fb)
{
btm = Bitmap.createBitmap(lcd_width, lcd_height, Bitmap.Config.RGB_565);
native_buf = native_fb;
setEnabled(true);
}
private void java_lcd_update()
{
SurfaceHolder holder = getHolder();
Canvas c = holder.lockCanvas();
if (c == null)
return;
btm.copyPixelsFromBuffer(framebuffer);
Canvas c = holder.lockCanvas(null);
btm.copyPixelsFromBuffer(native_buf);
synchronized (holder)
{ /* draw */
c.drawBitmap(btm, 0.0f, 0.0f, null);
@ -72,16 +81,14 @@ public class RockboxFramebuffer extends SurfaceView
holder.unlockCanvasAndPost(c);
}
private void update(ByteBuffer framebuffer, Rect dirty)
private void java_lcd_update_rect(int x, int y, int width, int height)
{
SurfaceHolder holder = getHolder();
Rect dirty = new Rect(x, y, x+width, y+height);
Canvas c = holder.lockCanvas(dirty);
if (c == null)
return;
/* can't copy a partial buffer, but it doesn't make a noticeable difference anyway */
btm.copyPixelsFromBuffer(framebuffer);
/* can't copy a partial buffer,
* but it doesn't make a noticeable difference anyway */
btm.copyPixelsFromBuffer(native_buf);
synchronized (holder)
{ /* draw */
c.drawBitmap(btm, dirty, dirty, null);
@ -89,6 +96,11 @@ public class RockboxFramebuffer extends SurfaceView
holder.unlockCanvasAndPost(c);
}
private void LOG(CharSequence text)
{
Log.d("Rockbox", (String) text);
}
public boolean onTouchEvent(MotionEvent me)
{
int x = (int) me.getX();
@ -137,7 +149,5 @@ public class RockboxFramebuffer extends SurfaceView
public native void surfaceDestroyed(SurfaceHolder holder);
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
{
btm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
setEnabled(true);
}
}

View file

@ -35,7 +35,7 @@ public class RockboxKeyboardInput
{
public void kbd_input(final String text, final String ok, final String cancel)
{
final Activity c = RockboxService.getInstance().getActivity();
final Activity c = RockboxService.get_instance().get_activity();
c.runOnUiThread(new Runnable() {
public void run()
@ -74,6 +74,6 @@ public class RockboxKeyboardInput
public boolean is_usable()
{
return RockboxService.getInstance().getActivity() != null;
return RockboxService.get_instance().get_activity() != null;
}
}

View file

@ -22,7 +22,6 @@
package org.rockbox;
import java.util.Arrays;
import org.rockbox.Helper.Logger;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -33,6 +32,7 @@ import android.media.AudioTrack;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
import android.util.Log;
public class RockboxPCM extends AudioTrack
{
@ -40,9 +40,13 @@ public class RockboxPCM extends AudioTrack
private static final int samplerate = 44100;
/* should be CHANNEL_OUT_STEREO in 2.0 and above */
private static final int channels =
AudioFormat.CHANNEL_OUT_STEREO;
AudioFormat.CHANNEL_CONFIGURATION_STEREO;
private static final int encoding =
AudioFormat.ENCODING_PCM_16BIT;
/* 32k is plenty, but some devices may have a higher minimum */
private static final int buf_len =
Math.max(32<<10, 4*getMinBufferSize(samplerate, channels, encoding));
private AudioManager audiomanager;
private RockboxService rbservice;
private byte[] raw_data;
@ -54,24 +58,23 @@ public class RockboxPCM extends AudioTrack
private float curpcmvolume = 0;
private float pcmrange;
/* 8k is plenty, but some devices may have a higher minimum.
* 8k represents 125ms of audio */
private static final int chunkSize =
Math.max(8<<10, getMinBufferSize(samplerate, channels, encoding));
Streamer streamer;
private void LOG(CharSequence text)
{
Log.d("Rockbox", (String) text);
}
public RockboxPCM()
{
super(streamtype, samplerate, channels, encoding,
chunkSize, AudioTrack.MODE_STREAM);
streamer = new Streamer(chunkSize);
streamer.start();
raw_data = new byte[chunkSize]; /* in shorts */
buf_len, AudioTrack.MODE_STREAM);
HandlerThread ht = new HandlerThread("audio thread",
Process.THREAD_PRIORITY_URGENT_AUDIO);
ht.start();
raw_data = new byte[buf_len]; /* in shorts */
Arrays.fill(raw_data, (byte) 0);
/* find cleaner way to get context? */
rbservice = RockboxService.getInstance();
rbservice = RockboxService.get_instance();
audiomanager =
(AudioManager) rbservice.getSystemService(Context.AUDIO_SERVICE);
maxstreamvolume = audiomanager.getStreamMaxVolume(streamtype);
@ -81,80 +84,14 @@ public class RockboxPCM extends AudioTrack
setupVolumeHandler();
postVolume(audiomanager.getStreamVolume(streamtype));
}
refillmark = buf_len / 4; /* higher values don't work on many devices */
/**
* This class does the actual playback work. Its run() method
* continuously writes data to the AudioTrack. This operation blocks
* and should therefore be run on its own thread.
*/
private class Streamer extends Thread
{
byte[] buffer;
private boolean quit = false;
Streamer(int bufsize)
{
super("audio thread");
buffer = new byte[bufsize];
}
@Override
public void run()
{
/* THREAD_PRIORITY_URGENT_AUDIO can only be specified via
* setThreadPriority(), and not via thread.setPriority(). This is
* also how the android's HandlerThread class implements it */
Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_AUDIO);
while (!quit)
{
switch(getPlayState())
{
case PLAYSTATE_PLAYING:
nativeWrite(buffer, buffer.length);
break;
case PLAYSTATE_PAUSED:
case PLAYSTATE_STOPPED:
{
synchronized (this)
{
try
{
wait();
}
catch (InterruptedException e) { e.printStackTrace(); }
break;
}
}
}
}
}
synchronized void quit()
{
quit = true;
notify();
}
synchronized void kick()
{
notify();
}
void quitAndJoin()
{
while(true)
{
try
{
quit();
join();
return;
}
catch (InterruptedException e) { }
}
}
}
/* getLooper() returns null if thread isn't running */
while(!ht.isAlive()) Thread.yield();
setPlaybackPositionUpdateListener(
new PCMListener(buf_len / 2), new Handler(ht.getLooper()));
refillmark = bytes2frames(refillmark);
}
private native void postVolumeChangedEvent(int volume);
@ -162,7 +99,7 @@ public class RockboxPCM extends AudioTrack
{
int rbvolume = ((maxstreamvolume - volume) * -99) /
maxstreamvolume;
Logger.d("java:postVolumeChangedEvent, avol "+volume+" rbvol "+rbvolume);
LOG("java:postVolumeChangedEvent, avol "+volume+" rbvol "+rbvolume);
postVolumeChangedEvent(rbvolume);
}
@ -201,21 +138,24 @@ public class RockboxPCM extends AudioTrack
new IntentFilter("android.media.VOLUME_CHANGED_ACTION"));
}
@SuppressWarnings("unused")
private int bytes2frames(int bytes)
{
/* 1 sample is 2 bytes, 2 samples are 1 frame */
return (bytes/4);
}
@SuppressWarnings("unused")
private int frames2bytes(int frames)
{
/* 1 frame is 2 samples, 1 sample is 2 bytes */
return (frames*4);
}
@SuppressWarnings("unused")
private void play_pause(boolean pause)
{
RockboxService service = RockboxService.getInstance();
RockboxService service = RockboxService.get_instance();
if (pause)
{
Intent widgetUpdate = new Intent("org.rockbox.UpdateState");
@ -232,22 +172,14 @@ public class RockboxPCM extends AudioTrack
service.startForeground();
if (getPlayState() == AudioTrack.PLAYSTATE_STOPPED)
{
setNotificationMarkerPosition(refillmark);
/* need to fill with silence before starting playback */
write(raw_data, 0, raw_data.length);
}
play();
}
}
@Override
public void play() throws IllegalStateException
{
super.play();
/* when stopped or paused the streamer is in a wait() state. need
* it to wake it up */
streamer.kick();
}
@Override
public synchronized void stop() throws IllegalStateException
{
@ -268,27 +200,20 @@ public class RockboxPCM extends AudioTrack
Intent widgetUpdate = new Intent("org.rockbox.UpdateState");
widgetUpdate.putExtra("state", "stop");
RockboxService.getInstance().sendBroadcast(widgetUpdate);
RockboxService.getInstance().stopForeground();
RockboxService.get_instance().sendBroadcast(widgetUpdate);
RockboxService.get_instance().stopForeground();
}
@Override
public void release()
{
super.release();
/* stop streamer if this AudioTrack is destroyed by whomever */
streamer.quitAndJoin();
}
public int setStereoVolume(float leftVolume, float rightVolume)
{
curpcmvolume = leftVolume;
return super.setStereoVolume(leftVolume, rightVolume);
}
@SuppressWarnings("unused")
private void set_volume(int volume)
{
Logger.d("java:set_volume("+volume+")");
LOG("java:set_volume("+volume+")");
/* Rockbox 'volume' is 0..-990 deci-dB attenuation.
Android streams have rather low resolution volume control,
typically 8 or 15 steps.
@ -308,11 +233,47 @@ public class RockboxPCM extends AudioTrack
int oldstreamvolume = audiomanager.getStreamVolume(streamtype);
if (streamvolume != oldstreamvolume) {
Logger.d("java:setStreamVolume("+streamvolume+")");
LOG("java:setStreamVolume("+streamvolume+")");
setstreamvolume = streamvolume;
audiomanager.setStreamVolume(streamtype, streamvolume, 0);
}
}
public native int nativeWrite(byte[] temp, int len);
private class PCMListener implements OnPlaybackPositionUpdateListener
{
byte[] pcm_data;
public PCMListener(int _refill_bufsize)
{
pcm_data = new byte[_refill_bufsize];
}
public void onMarkerReached(AudioTrack track)
{
/* push new data to the hardware */
RockboxPCM pcm = (RockboxPCM)track;
int result = -1;
result = pcm.nativeWrite(pcm_data, pcm_data.length);
if (result >= 0)
{
switch(getPlayState())
{
case PLAYSTATE_PLAYING:
case PLAYSTATE_PAUSED:
setNotificationMarkerPosition(pcm.refillmark);
break;
case PLAYSTATE_STOPPED:
LOG("Stopped");
break;
}
}
else /* stop on error */
stop();
}
public void onPeriodicNotification(AudioTrack track)
{
}
}
}

View file

@ -27,18 +27,25 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Enumeration;
import java.util.Timer;
import java.util.TimerTask;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.rockbox.Helper.Logger;
import org.rockbox.Helper.MediaButtonReceiver;
import org.rockbox.Helper.RunForegroundManager;
import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.util.Log;
import android.view.KeyEvent;
/* This class is used as the main glue between java and c.
@ -47,17 +54,27 @@ import android.view.KeyEvent;
public class RockboxService extends Service
{
/* this Service is really a singleton class - well almost. */
/* this Service is really a singleton class - well almost.
* To do it properly this line should be instance = new RockboxService()
* but apparently that doesnt work with the way android Services are created.
*/
private static RockboxService instance = null;
/* locals needed for the c code and Rockbox state */
/* locals needed for the c code and rockbox state */
private static volatile boolean rockbox_running;
private Activity mCurrentActivity = null;
private RunForegroundManager mFgRunner;
private Activity current_activity = null;
private IntentFilter itf;
private IntentFilter ifh;
private BroadcastReceiver batt_monitor;
private BroadcastReceiver headphone_monitor;
private BroadcastReceiver noisy_monitor;
private RunForegroundManager fg_runner;
private MediaButtonReceiver mMediaButtonReceiver;
private ResultReceiver mResultReceiver;
private int battery_level;
private int headphone_state;
private ResultReceiver resultReceiver;
private RockboxService rbservice;
/* possible result values for intent handling */
public static final int RESULT_INVOKING_MAIN = 0;
public static final int RESULT_LIB_LOAD_PROGRESS = 1;
public static final int RESULT_SERVICE_RUNNING = 3;
@ -70,12 +87,12 @@ public class RockboxService extends Service
{
instance = this;
mMediaButtonReceiver = new MediaButtonReceiver(this);
mFgRunner = new RunForegroundManager(this);
fg_runner = new RunForegroundManager(this);
}
public static RockboxService getInstance()
public static RockboxService get_instance()
{
/* don't call the constructor here, the instances are managed by
/* don't call the construtor here, the instances are managed by
* android, so we can't just create a new one */
return instance;
}
@ -84,46 +101,43 @@ public class RockboxService extends Service
{
return rockbox_running;
}
public Activity getActivity()
public Activity get_activity()
{
return mCurrentActivity;
return current_activity;
}
public void set_activity(Activity a)
{
current_activity = a;
}
public void setActivity(Activity a)
private void do_start(Intent intent)
{
mCurrentActivity = a;
}
private void putResult(int resultCode)
{
putResult(resultCode, null);
}
private void putResult(int resultCode, Bundle resultData)
{
if (mResultReceiver != null)
mResultReceiver.send(resultCode, resultData);
}
private void doStart(Intent intent)
{
Logger.d("Start RockboxService (Intent: " + intent.getAction() + ")");
LOG("Start RockboxService (Intent: " + intent.getAction() + ")");
if (intent.getAction().equals("org.rockbox.ResendTrackUpdateInfo"))
{
if (rockbox_running)
mFgRunner.resendUpdateNotification();
fg_runner.resendUpdateNotification();
return;
}
if (intent.hasExtra("callback"))
mResultReceiver = (ResultReceiver) intent.getParcelableExtra("callback");
resultReceiver = (ResultReceiver) intent.getParcelableExtra("callback");
if (!rockbox_running)
startService();
startservice();
if (resultReceiver != null)
resultReceiver.send(RESULT_LIB_LOADED, null);
if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON))
{
/* give it a bit of time so we can register button presses
* sleeping longer doesn't work here, apparently Android
* surpresses long sleeps during intent handling */
try {
Thread.sleep(50);
} catch (InterruptedException e) { }
KeyEvent kev = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
RockboxFramebuffer.buttonHandler(kev.getKeyCode(),
kev.getAction() == KeyEvent.ACTION_DOWN);
@ -131,26 +145,33 @@ public class RockboxService extends Service
/* (Re-)attach the media button receiver, in case it has been lost */
mMediaButtonReceiver.register();
putResult(RESULT_SERVICE_RUNNING);
if (resultReceiver != null)
resultReceiver.send(RESULT_SERVICE_RUNNING, null);
rockbox_running = true;
}
private void LOG(CharSequence text)
{
Log.d("Rockbox", (String) text);
}
private void LOG(CharSequence text, Throwable tr)
{
Log.d("Rockbox", (String) text, tr);
}
public void onStart(Intent intent, int startId) {
doStart(intent);
do_start(intent);
}
public int onStartCommand(Intent intent, int flags, int startId)
{
/* if null, then the service was most likely restarted by android
* after getting killed for memory pressure earlier */
if (intent == null)
intent = new Intent("org.rockbox.ServiceRestarted");
doStart(intent);
return START_STICKY;
do_start(intent);
return 1; /* old API compatibility: 1 == START_STICKY */
}
private void startService()
private void startservice()
{
final Object lock = new Object();
Thread rb = new Thread(new Runnable()
@ -159,8 +180,13 @@ public class RockboxService extends Service
{
final int BUFFER = 8*1024;
String rockboxDirPath = "/data/data/org.rockbox/app_rockbox/rockbox";
String rockboxCreditsPath = "/data/data/org.rockbox/app_rockbox/rockbox/rocks/viewers";
String rockboxSdDirPath = "/sdcard/rockbox";
File rockboxDir = new File(rockboxDirPath);
/* load library before unzipping which may take a while */
synchronized (lock) {
System.loadLibrary("rockbox");
lock.notify();
}
/* the following block unzips libmisc.so, which contains the files
* we ship, such as themes. It's needed to put it into a .so file
@ -169,32 +195,9 @@ public class RockboxService extends Service
*/
File libMisc = new File("/data/data/org.rockbox/lib/libmisc.so");
/* use arbitrary file to determine whether extracting is needed */
File arbitraryFile = new File(rockboxCreditsPath, "credits.rock");
File rockboxInfoFile = new File(rockboxSdDirPath, "rockbox-info.txt");
/* unzip newer or doesnt exist */
boolean doExtract = !arbitraryFile.exists()
|| (libMisc.lastModified() > arbitraryFile.lastModified());
/* load library before unzipping which may take a while
* but at least tell if unzipping is going to be done before*/
synchronized (lock) {
Bundle bdata = new Bundle();
bdata.putBoolean("unzip", doExtract);
System.loadLibrary("rockbox");
putResult(RESULT_LIB_LOADED, bdata);
lock.notify();
}
if (doExtract)
File arbitraryFile = new File(rockboxDir, "viewers.config");
if (!arbitraryFile.exists() || (libMisc.lastModified() > arbitraryFile.lastModified()))
{
boolean extractToSd = false;
if(rockboxInfoFile.exists()) {
extractToSd = true;
Logger.d("extracting resources to SD card");
}
else {
Logger.d("extracting resources to internal memory");
}
try
{
Bundle progressData = new Bundle();
@ -210,16 +213,7 @@ public class RockboxService extends Service
/* strip off /.rockbox when extracting */
String fileName = entry.getName();
int slashIndex = fileName.indexOf('/', 1);
/* codecs are now stored as libs, only keep rocks on internal */
if(extractToSd == false
|| fileName.substring(slashIndex).startsWith("/rocks"))
{
file = new File(rockboxDirPath + fileName.substring(slashIndex));
}
else
{
file = new File(rockboxSdDirPath + fileName.substring(slashIndex));
}
file = new File(rockboxDirPath + fileName.substring(slashIndex));
if (!entry.isDirectory())
{
@ -242,16 +236,19 @@ public class RockboxService extends Service
is.close();
}
progressData.putInt("value", progressData.getInt("value", 0) + 1);
putResult(RESULT_LIB_LOAD_PROGRESS, progressData);
if (resultReceiver != null) {
progressData.putInt("value", progressData.getInt("value", 0) + 1);
resultReceiver.send(RESULT_LIB_LOAD_PROGRESS, progressData);
}
}
arbitraryFile.setLastModified(libMisc.lastModified());
} catch(Exception e) {
Logger.d("Exception when unzipping", e);
Bundle bundle = new Bundle();
LOG("Exception when unzipping", e);
e.printStackTrace();
bundle.putString("error", getString(R.string.error_extraction));
putResult(RESULT_ERROR_OCCURED, bundle);
if (resultReceiver != null) {
Bundle bundle = new Bundle();
bundle.putString("error", getString(R.string.error_extraction));
resultReceiver.send(RESULT_ERROR_OCCURED, bundle);
}
}
}
@ -270,19 +267,21 @@ public class RockboxService extends Service
strm.write("lang: /.rockbox/langs/" + getString(R.string.rockbox_language_file) + "\n");
strm.close();
} catch(Exception e) {
Logger.d("Exception when writing default config", e);
LOG("Exception when writing default config", e);
}
}
/* Start native code */
putResult(RESULT_INVOKING_MAIN);
if (resultReceiver != null)
resultReceiver.send(RESULT_INVOKING_MAIN, null);
main();
putResult(RESULT_ROCKBOX_EXIT);
if (resultReceiver != null)
resultReceiver.send(RESULT_ROCKBOX_EXIT, null);
Logger.d("Stop service: main() returned");
stopSelf(); /* service is of no use anymore */
LOG("Stop service: main() returned");
stopSelf(); /* serivce is of no use anymore */
}
}, "Rockbox thread");
rb.setDaemon(false);
@ -307,17 +306,84 @@ public class RockboxService extends Service
@Override
public IBinder onBind(Intent intent)
{
// TODO Auto-generated method stub
return null;
}
private void initBatteryMonitor()
{
itf = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
batt_monitor = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
/* we get literally spammed with battery statuses
* if we don't delay the re-attaching
*/
TimerTask tk = new TimerTask()
{
public void run()
{
registerReceiver(batt_monitor, itf);
}
};
Timer t = new Timer();
context.unregisterReceiver(this);
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
if (rawlevel >= 0 && scale > 0)
battery_level = (rawlevel * 100) / scale;
else
battery_level = -1;
/* query every 30s should be sufficient */
t.schedule(tk, 30000);
}
};
registerReceiver(batt_monitor, itf);
}
private void initHeadphoneMonitor()
{
ifh = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
headphone_monitor = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
int state = intent.getIntExtra("state", -1);
LOG("headphone state:" + state);
headphone_state = state;
}
};
registerReceiver(headphone_monitor, ifh);
noisy_monitor = new BroadcastReceiver()
{
@Override
public void onReceive(Context context, Intent intent)
{
LOG("audio becoming noisy");
headphone_state = 0;
}
};
rbservice = RockboxService.get_instance();
/* We're relying on internal API's here,
this can break in the future! */
rbservice.registerReceiver(noisy_monitor,
new IntentFilter("android.media.AUDIO_BECOMING_NOISY"));
}
void startForeground()
{
mFgRunner.startForeground();
fg_runner.startForeground();
}
void stopForeground()
{
mFgRunner.stopForeground();
fg_runner.stopForeground();
}
@Override
@ -325,7 +391,7 @@ public class RockboxService extends Service
{
super.onDestroy();
/* Don't unregister so we can receive them (and startup the service)
* after idle power-off. Hopefully it's OK if mMediaButtonReceiver is
* after idle poweroff. Hopefully it's ok if mMediaButtonReceiver is
* garbage collected.
* mMediaButtonReceiver.unregister(); */
mMediaButtonReceiver = null;

View file

@ -0,0 +1,97 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Thomas Martitz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
package org.rockbox;
import android.content.Context;
import android.os.Handler;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class RockboxTelephony
{
public RockboxTelephony(Context c)
{
final Handler handler = new Handler(c.getMainLooper());
final TelephonyManager tm = (TelephonyManager)
c.getSystemService(Context.TELEPHONY_SERVICE);
handler.post(new Runnable()
{
@Override
public void run()
{ /* need to instantiate from a thread that has a Looper */
tm.listen(new RockboxCallStateListener(), PhoneStateListener.LISTEN_CALL_STATE);
}
});
}
private class RockboxCallStateListener extends PhoneStateListener
{
private int last_state;
public RockboxCallStateListener()
{
super();
/* set artificial initial state,
* we will get an initial event shortly after this,
* so to handle it correctly we need an invalid state set */
last_state = TelephonyManager.CALL_STATE_IDLE - 10;
}
private void handleState(int state)
{
if (state == last_state)
return;
switch (state)
{
case TelephonyManager.CALL_STATE_IDLE:
postCallHungUp();
break;
case TelephonyManager.CALL_STATE_RINGING:
postCallIncoming();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
/* for incoming calls we handled at RINGING already,
* if the previous state was IDLE then
* this is an outgoing call
*/
if (last_state == TelephonyManager.CALL_STATE_IDLE)
{ /* currently handled the same as incoming calls */
postCallIncoming();
}
break;
default:
return;
}
last_state = state;
}
@Override
public void onCallStateChanged(int state, String number)
{
super.onCallStateChanged(state, number);
handleState(state);
}
}
private native void postCallIncoming();
private native void postCallHungUp();
}

View file

@ -27,52 +27,40 @@ import android.content.DialogInterface;
public class RockboxYesno
{
private class Listener implements DialogInterface.OnClickListener, DialogInterface.OnDismissListener
{
/* default to "No" if onClick isn't called at all */
private boolean result = false;
/* called when the user presses the Yes or the No button */
@Override
public void onClick(DialogInterface dialog, int which)
{
result = (which == DialogInterface.BUTTON_POSITIVE);
}
/* onDismiss is (hopefully) also called when the dialog is closed
* for any reason other than clicking yes or no. This should
* avoid the native code waiting for the result indefinitely in
* case the dialog just disappears */
@Override
public void onDismiss(DialogInterface dialog)
{
put_result(result);
}
}
private void yesno_display(final String text, final String yes, final String no)
{
final Activity c = RockboxService.getInstance().getActivity();
final Activity c = RockboxService.get_instance().get_activity();
c.runOnUiThread(new Runnable() {
public void run()
{
Listener l = new Listener();
new AlertDialog.Builder(c)
.setTitle(R.string.YesNoTitle)
.setTitle(R.string.KbdInputTitle)
.setIcon(R.drawable.icon)
.setCancelable(false)
.setMessage(text)
.setPositiveButton(yes, l)
.setNegativeButton(no, l)
.show()
.setOnDismissListener(l);
.setPositiveButton(yes, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
put_result(true);
}
})
.setNegativeButton(no, new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int whichButton)
{
put_result(false);
}
})
.show();
}
});
}
private boolean is_usable()
{
return RockboxService.getInstance().getActivity() != null;
return RockboxService.get_instance().get_activity() != null;
}
private native void put_result(boolean result);

View file

@ -1,74 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 Thomas Martitz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
package org.rockbox.monitors;
import java.util.Timer;
import java.util.TimerTask;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class BatteryMonitor extends BroadcastReceiver
{
private final IntentFilter mBattFilter;
private final Context mContext;
@SuppressWarnings("unused")
private int mBattLevel; /* read by native code */
/*
* We get literally spammed with battery status updates
* Therefore we actually unregister after each onReceive() and
* setup a timer to re-register in 30s */
public BatteryMonitor(Context c)
{
mBattFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
mContext = c;
Timer t = new Timer();
TimerTask task = new TimerTask()
{
public void run()
{
attach();
}
};
t.schedule(task, 5000, 30000);
attach();
}
@Override
public void onReceive(Context arg0, Intent intent)
{
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
if (rawlevel >= 0 && scale > 0)
mBattLevel = (rawlevel * 100) / scale;
else
mBattLevel = -1;
mContext.unregisterReceiver(this);
}
void attach()
{
mContext.registerReceiver(this, mBattFilter);
}
}

View file

@ -1,59 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2011 Thomas Martitz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
package org.rockbox.monitors;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
public class HeadphoneMonitor extends BroadcastReceiver
{
public HeadphoneMonitor(Context c)
{
IntentFilter hpFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
/* caution: hidden API; might break */
IntentFilter noisyFilter = new IntentFilter("android.media.AUDIO_BECOMING_NOISY");
c.registerReceiver(this, hpFilter);
c.registerReceiver(new NoisyMonitor(), noisyFilter);
}
@Override
public void onReceive(Context arg0, Intent intent)
{
int state = intent.getIntExtra("state", -1);
postHpStateChanged(state);
}
/* audio becoming noise acts as headphones extracted */
private class NoisyMonitor extends BroadcastReceiver
{
@Override
public void onReceive(Context arg0, Intent arg1)
{
postHpStateChanged(0);
}
}
private synchronized native void postHpStateChanged(int state);
}

View file

@ -1,97 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2010 Thomas Martitz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
package org.rockbox.monitors;
import android.content.Context;
import android.os.Handler;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class TelephonyMonitor
{
public TelephonyMonitor(Context c)
{
final Handler handler = new Handler(c.getMainLooper());
final TelephonyManager tm = (TelephonyManager)
c.getSystemService(Context.TELEPHONY_SERVICE);
handler.post(new Runnable()
{
@Override
public void run()
{ /* need to instantiate from a thread that has a Looper */
tm.listen(new RockboxCallStateListener(), PhoneStateListener.LISTEN_CALL_STATE);
}
});
}
private class RockboxCallStateListener extends PhoneStateListener
{
private int last_state;
public RockboxCallStateListener()
{
super();
/* set artificial initial state,
* we will get an initial event shortly after this,
* so to handle it correctly we need an invalid state set */
last_state = TelephonyManager.CALL_STATE_IDLE - 10;
}
private void handleState(int state)
{
if (state == last_state)
return;
switch (state)
{
case TelephonyManager.CALL_STATE_IDLE:
postCallHungUp();
break;
case TelephonyManager.CALL_STATE_RINGING:
postCallIncoming();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
/* for incoming calls we handled at RINGING already,
* if the previous state was IDLE then
* this is an outgoing call
*/
if (last_state == TelephonyManager.CALL_STATE_IDLE)
{ /* currently handled the same as incoming calls */
postCallIncoming();
}
break;
default:
return;
}
last_state = state;
}
@Override
public void onCallStateChanged(int state, String number)
{
super.onCallStateChanged(state, number);
handleState(state);
}
}
private native void postCallIncoming();
private native void postCallHungUp();
}

View file

@ -7,7 +7,6 @@ alarm_menu.c
#endif
abrepeat.c
bookmark.c
core_keymap.c
debug_menu.c
filetypes.c
language.c
@ -20,13 +19,17 @@ menus/plugin_menu.c
#if CONFIG_TUNER
menus/radio_menu.c
#endif
#if CONFIG_CODEC == SWCODEC
#ifdef HAVE_WM8978
menus/audiohw_eq_menu.c
#endif
menus/eq_menu.c
buffering.c
voice_thread.c
rbcodec_helpers.c
replaygain.c
#else /* !SWCODEC */
mpeg.c
#endif
menus/main_menu.c
menus/playback_menu.c
menus/playlist_menu.c
@ -39,7 +42,7 @@ menus/sound_menu.c
menus/time_menu.c
#endif
misc.c
open_plugin.c
mp3data.c
onplay.c
playlist.c
playlist_catalog.c
@ -49,7 +52,6 @@ root_menu.c
screens.c
settings.c
settings_list.c
shortcuts.c
status.c
cuesheet.c
talk.c
@ -58,42 +60,39 @@ tree.c
tagtree.c
#endif
filetree.c
scrobbler.c
#ifdef IPOD_ACCESSORY_PROTOCOL
iap/iap-core.c
iap/iap-lingo0.c
#ifdef HAVE_LINE_REC
iap/iap-lingo1.c
#endif
iap/iap-lingo2.c
iap/iap-lingo3.c
iap/iap-lingo4.c
#if CONFIG_TUNER
iap/iap-lingo7.c
#endif
iap.c
#endif
screen_access.c
#ifdef HAVE_BUTTONBAR
gui/buttonbar.c
#endif
#ifdef HAVE_LCD_BITMAP
gui/icon.c
#endif
gui/list.c
gui/line.c
#ifdef HAVE_LCD_BITMAP
gui/bitmap/list.c
gui/bitmap/list-skinned.c
#else
gui/charcell/list.c
#endif
gui/option_select.c
#ifdef HAVE_PITCHCONTROL
#ifdef HAVE_PITCHSCREEN
gui/pitchscreen.c
#endif
#ifdef HAVE_QUICKSCREEN
gui/quickscreen.c
#endif
gui/folder_select.c
#if defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD)
gui/mask_select.c
#endif
gui/wps.c
gui/scrollbar.c
gui/splash.c
gui/statusbar.c
#ifdef HAVE_LCD_BITMAP
gui/statusbar-skinned.c
#endif
#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
hosted/android/yesno.c
hosted/android/notification.c
@ -105,6 +104,9 @@ gui/viewport.c
gui/skin_engine/skin_backdrops.c
gui/skin_engine/skin_display.c
gui/skin_engine/skin_engine.c
#ifdef HAVE_LCD_BITMAP
gui/skin_engine/skin_fonts.c
#endif
gui/skin_engine/skin_parser.c
gui/skin_engine/skin_render.c
gui/skin_engine/skin_tokens.c
@ -116,6 +118,11 @@ gui/skin_engine/skin_touchsupport.c
gui/backdrop.c
#endif
#ifdef HAVE_LCD_CHARCELLS
player/icons.c
player/keyboard.c
#endif
#ifdef HAVE_LCD_BITMAP
recorder/bmp.c
recorder/icons.c
#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
@ -139,7 +146,7 @@ recorder/albumart.c
#ifdef HAVE_LCD_COLOR
gui/color_picker.c
#endif
#endif
#ifdef HAVE_RECORDING
recorder/recording.c
#endif
@ -153,27 +160,71 @@ radio/radioart.c
#endif
#endif
#if CONFIG_CODEC == SWCODEC
#if INPUT_SRC_CAPS != 0
audio_path.c
#endif /* INPUT_SRC_CAPS != 0 */
audio_thread.c
fixedpoint.c
pcmbuf.c
codec_thread.c
playback.c
codecs.c
#ifndef HAVE_HARDWARE_BEEP
beep.c
dsp.c
#ifdef HAVE_PITCHSCREEN
tdspeed.c
#endif
#ifdef HAVE_RECORDING
enc_config.c
recorder/pcm_record.c
#endif
eq.c
#if defined(CPU_COLDFIRE)
dsp_cf.S
eq_cf.S
#elif defined(CPU_ARM)
dsp_arm.S
#if ARM_ARCH >= 6
dsp_arm_v6.S
#endif
eq_arm.S
#endif
#endif
#ifdef USB_ENABLE_HID
usb_keymaps.c
#endif
#ifndef USB_NONE
gui/usb_screen.c
#endif
metadata.c
metadata/id3tags.c
metadata/mp3.c
#if CONFIG_CODEC == SWCODEC
metadata/metadata_common.c
metadata/aiff.c
metadata/ape.c
metadata/asf.c
metadata/adx.c
metadata/flac.c
metadata/monkeys.c
metadata/mp4.c
metadata/mpc.c
metadata/ogg.c
metadata/sid.c
metadata/mod.c
metadata/spc.c
metadata/vorbis.c
metadata/wave.c
metadata/wavpack.c
metadata/a52.c
metadata/asap.c
metadata/rm.c
metadata/nsf.c
metadata/oma.c
metadata/smaf.c
metadata/au.c
metadata/vox.c
metadata/tta.c
#endif
#ifdef HAVE_TAGCACHE
tagcache.c
#endif
@ -187,6 +238,12 @@ keymaps/keymap-h1x0_h3x0.c
|| (CONFIG_KEYPAD == IPOD_3G_PAD) \
|| (CONFIG_KEYPAD == IPOD_1G2G_PAD))
keymaps/keymap-ipod.c
#elif CONFIG_KEYPAD == RECORDER_PAD
keymaps/keymap-recorder.c
#elif CONFIG_KEYPAD == ONDIO_PAD
keymaps/keymap-ondio.c
#elif CONFIG_KEYPAD == PLAYER_PAD
keymaps/keymap-player.c
#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
keymaps/keymap-x5.c
#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
@ -197,6 +254,8 @@ keymaps/keymap-gigabeat.c
keymaps/keymap-gigabeat-s.c
#elif CONFIG_KEYPAD == IRIVER_H10_PAD
keymaps/keymap-h10.c
#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
keymaps/keymap-ifp7xx.c
#elif CONFIG_KEYPAD == SANSA_E200_PAD
keymaps/keymap-e200.c
#elif CONFIG_KEYPAD == SANSA_C200_PAD
@ -205,6 +264,8 @@ keymaps/keymap-c200.c
keymaps/keymap-m200.c
#elif CONFIG_KEYPAD == SANSA_CLIP_PAD
keymaps/keymap-clip.c
#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
keymaps/keymap-av300.c
#elif CONFIG_KEYPAD == MROBE500_PAD
keymaps/keymap-mr500.c
#elif CONFIG_KEYPAD == MROBE100_PAD
@ -219,16 +280,18 @@ keymaps/keymap-meizu-m6sp.c
keymaps/keymap-creativezvm.c
#elif CONFIG_KEYPAD == CREATIVEZV_PAD
keymaps/keymap-creativezv.c
#elif CONFIG_KEYPAD == CREATIVE_ZENXFI2_PAD
keymaps/keymap-zenxfi2.c
#elif CONFIG_KEYPAD == CREATIVE_ZENXFI3_PAD
keymaps/keymap-zenxfi3.c
#elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
keymaps/keymap-sa9200.c
#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
keymaps/keymap-hdd1630.c
#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
keymaps/keymap-hdd6330.c
#elif CONFIG_KEYPAD == IAUDIO67_PAD
keymaps/keymap-iaudio67.c
#elif CONFIG_KEYPAD == SANSA_C100_PAD
keymaps/keymap-c100.c
#elif CONFIG_KEYPAD == LOGIK_DAX_PAD
keymaps/keymap-logikdax.c
#elif CONFIG_KEYPAD == SANSA_FUZE_PAD
keymaps/keymap-fuze.c
#elif CONFIG_KEYPAD == ONDAVX747_PAD
@ -237,8 +300,7 @@ keymaps/keymap-ondavx747.c
keymaps/keymap-ondavx777.c
#elif CONFIG_KEYPAD == ONDAVX767_PAD
keymaps/keymap-ondavx767.c
#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD) \
|| (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
#elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
keymaps/keymap-yh8xx_yh9xx.c
#elif CONFIG_KEYPAD == MINI2440_PAD
keymaps/keymap-mini2440.c
@ -252,50 +314,4 @@ keymaps/keymap-mpio-hd300.c
keymaps/keymap-android.c
#elif CONFIG_KEYPAD == SDL_PAD
keymaps/keymap-sdl.c
#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
keymaps/keymap-fuzeplus.c
#elif CONFIG_KEYPAD == RK27XX_GENERIC_PAD
keymaps/keymap-rk27xx-generic.c
#elif CONFIG_KEYPAD == HM60X_PAD
keymaps/keymap-hm60x.c
#elif CONFIG_KEYPAD == HM801_PAD
keymaps/keymap-hm801.c
#elif CONFIG_KEYPAD == SANSA_CONNECT_PAD
keymaps/keymap-sansa-connect.c
#elif CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
keymaps/keymap-ypr0.c
#elif CONFIG_KEYPAD == CREATIVE_ZEN_PAD
keymaps/keymap-zen.c
#elif CONFIG_KEYPAD == MA_PAD
keymaps/keymap-ma.c
#elif CONFIG_KEYPAD == SONY_NWZ_PAD
keymaps/keymap-nwz.c
#elif CONFIG_KEYPAD == SONY_NWZA860_PAD
keymaps/keymap-nwza860.c
#elif CONFIG_KEYPAD == IHIFI_PAD
keymaps/keymap-ihifi.c
#elif CONFIG_KEYPAD == IHIFI_770_PAD
keymaps/keymap-ihifi770.c
#elif CONFIG_KEYPAD == IHIFI_800_PAD
keymaps/keymap-ihifi800.c
#elif CONFIG_KEYPAD == SAMSUNG_YPR1_PAD
keymaps/keymap-ypr1.c
#elif CONFIG_KEYPAD == DX50_PAD
keymaps/keymap-dx50.c
#elif CONFIG_KEYPAD == AGPTEK_ROCKER_PAD
keymaps/keymap-agptekrocker.c
#elif CONFIG_KEYPAD == XDUOO_X3_PAD
keymaps/keymap-xduoox3.c
#elif CONFIG_KEYPAD == XDUOO_X3II_PAD
keymaps/keymap-xduoox3ii.c
#elif CONFIG_KEYPAD == XDUOO_X20_PAD
keymaps/keymap-xduoox20.c
#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
keymaps/keymap-fiiom3klinux.c
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
keymaps/keymap-fiiom3k.c
#elif CONFIG_KEYPAD == EROSQ_PAD
keymaps/keymap-erosq.c
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
keymaps/keymap-shanlingq1.c
#endif

View file

@ -27,7 +27,6 @@
unsigned int ab_A_marker IDATA_ATTR = AB_MARKER_NONE;
unsigned int ab_B_marker IDATA_ATTR = AB_MARKER_NONE;
static inline bool ab_A_marker_set(void)
{
return ab_A_marker != AB_MARKER_NONE;
@ -38,7 +37,7 @@ static inline bool ab_B_marker_set(void)
return ab_B_marker != AB_MARKER_NONE;
}
#if (CONFIG_CODEC == SWCODEC)
void ab_end_of_track_report(void)
{
if ( ab_A_marker_set() && ! ab_B_marker_set() )
@ -46,6 +45,38 @@ void ab_end_of_track_report(void)
ab_jump_to_A_marker();
}
}
#else
static int ab_audio_event_handler(unsigned short event, unsigned long data)
{
int rc = AUDIO_EVENT_RC_IGNORED;
if ( ab_repeat_mode_enabled() )
{
switch(event)
{
case AUDIO_EVENT_POS_REPORT:
{
if ( ! (audio_status() & AUDIO_STATUS_PAUSE) &&
ab_reached_B_marker(data) )
{
ab_jump_to_A_marker();
rc = AUDIO_EVENT_RC_HANDLED;
}
break;
}
case AUDIO_EVENT_END_OF_TRACK:
{
if ( ab_A_marker_set() && ! ab_B_marker_set() )
{
ab_jump_to_A_marker();
rc = AUDIO_EVENT_RC_HANDLED;
}
break;
}
}
}
return rc;
}
#endif
void ab_repeat_init(void)
{
@ -53,6 +84,10 @@ void ab_repeat_init(void)
if ( ! ab_initialized )
{
ab_initialized = true;
#if (CONFIG_CODEC != SWCODEC)
audio_register_event_handler(ab_audio_event_handler,
AUDIO_EVENT_POS_REPORT | AUDIO_EVENT_END_OF_TRACK );
#endif
}
}
@ -79,7 +114,16 @@ reasonable amount of time for the typical user to react */
void ab_jump_to_A_marker(void)
{
#if (CONFIG_CODEC != SWCODEC)
bool paused = (audio_status() & AUDIO_STATUS_PAUSE) != 0;
if ( ! paused )
audio_pause();
#endif
audio_ff_rewind(ab_A_marker);
#if (CONFIG_CODEC != SWCODEC)
if ( ! paused )
audio_resume();
#endif
}
void ab_reset_markers(void)
@ -114,16 +158,67 @@ void ab_set_B_marker(unsigned int song_position)
ab_A_marker = AB_MARKER_NONE;
}
bool ab_get_A_marker(unsigned *song_position)
#ifdef HAVE_LCD_BITMAP
static int ab_calc_mark_x_pos(int mark, int capacity,
int offset, int size)
{
*song_position = ab_A_marker;
return ab_A_marker_set();
return offset + ( (size * mark) / capacity );
}
bool ab_get_B_marker(unsigned *song_position)
static void ab_draw_vertical_line_mark(struct screen * screen,
int x, int y, int h)
{
*song_position = ab_B_marker;
return ab_B_marker_set();
screen->set_drawmode(DRMODE_COMPLEMENT);
screen->vline(x, y, y+h-1);
}
#define DIRECTION_RIGHT 1
#define DIRECTION_LEFT -1
static void ab_draw_arrow_mark(struct screen * screen,
int x, int y, int h, int direction)
{
/* draw lines in decreasing size until a height of zero is reached */
screen->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
while( h > 0 )
{
screen->vline(x, y, y+h-1);
h -= 2;
y++;
x += direction;
screen->set_drawmode(DRMODE_COMPLEMENT);
}
}
void ab_draw_markers(struct screen * screen, int capacity,
int x, int y, int w, int h)
{
int xa = ab_calc_mark_x_pos(ab_A_marker, capacity, x, w);
int xb = ab_calc_mark_x_pos(ab_B_marker, capacity, x, w);
/* if both markers are set, determine if they're far enough apart
to draw arrows */
if ( ab_A_marker_set() && ab_B_marker_set() )
{
int arrow_width = (h+1) / 2;
if ( (xb-xa) < (arrow_width*2) )
{
ab_draw_vertical_line_mark(screen, xa, y, h);
ab_draw_vertical_line_mark(screen, xb, y, h);
return;
}
}
if (ab_A_marker_set())
{
ab_draw_arrow_mark(screen, xa, y, h, DIRECTION_RIGHT);
}
if (ab_B_marker_set())
{
ab_draw_arrow_mark(screen, xb, y, h, DIRECTION_LEFT);
}
}
#endif /* HAVE_LCD_BITMAP */
#endif /* AB_REPEAT_ENABLE */

View file

@ -20,38 +20,9 @@
****************************************************************************/
#ifndef _ABREPEAT_H_
#define _ABREPEAT_H_
#ifdef AB_REPEAT_ENABLE
#include <stdbool.h>
#ifndef AB_REPEAT_ENABLE /* Dummy functions */
static inline bool ab_repeat_mode_enabled(void)
{
return false;
}
static inline bool ab_bool_dummy_marker(unsigned int song_position)
{
(void) song_position;
return false;
}
static inline void ab_void_dummy_marker(unsigned int song_position)
{
(void) song_position;
}
static inline void ab_dummy_voidfn(void){}
#define ab_repeat_init ab_dummy_voidfn
#define ab_before_A_marker ab_bool_dummy_marker
#define ab_after_A_marker ab_bool_dummy_marker
#define ab_jump_to_A_marker ab_dummy_voidfn
#define ab_reset_markers ab_dummy_voidfn
#define ab_set_A_marker ab_void_dummy_marker
#define ab_set_B_marker ab_void_dummy_marker
#define ab_get_A_marker ab_bool_dummy_marker
#define ab_get_B_marker ab_bool_dummy_marker
#define ab_end_of_track_report ab_dummy_voidfn
#define ab_reached_B_marker ab_bool_dummy_marker
#define ab_position_report ab_void_dummy_marker
#else /*def AB_REPEAT_ENABLE*/
#include "audio.h"
#include "kernel.h" /* needed for HZ */
@ -66,11 +37,14 @@ void ab_jump_to_A_marker(void);
void ab_reset_markers(void);
void ab_set_A_marker(unsigned int song_position);
void ab_set_B_marker(unsigned int song_position);
/* These return whether the marker are actually set.
* The actual positions are returned via output parameter */
bool ab_get_A_marker(unsigned int *song_position);
bool ab_get_B_marker(unsigned int *song_position);
#if (CONFIG_CODEC == SWCODEC)
void ab_end_of_track_report(void);
#endif
#ifdef HAVE_LCD_BITMAP
#include "screen_access.h"
void ab_draw_markers(struct screen * screen, int capacity,
int x, int y, int w, int h);
#endif
/* These functions really need to be inlined for speed */
extern unsigned int ab_A_marker;
@ -86,9 +60,16 @@ static inline bool ab_reached_B_marker(unsigned int song_position)
/* following is the size of the window in which we'll detect that the B marker
was hit; it must be larger than the frequency (in milliseconds) at which this
function is called otherwise detection of the B marker will be unreliable */
#if (CONFIG_CODEC == SWCODEC)
/* On swcodec, the worst case seems to be 9600kHz with 1024 samples between
* calls, meaning ~9 calls per second, look within 1/5 of a second */
#define B_MARKER_DETECT_WINDOW 200
#else
/* we assume that this function will be called on each system tick and derive
the window size from this with a generous margin of error (note: the number
of ticks per second is given by HZ) */
#define B_MARKER_DETECT_WINDOW ((1000/HZ)*10)
#endif
if (ab_B_marker != AB_MARKER_NONE)
{
if ( (song_position >= ab_B_marker)
@ -98,6 +79,7 @@ function is called otherwise detection of the B marker will be unreliable */
return false;
}
#if (CONFIG_CODEC == SWCODEC)
static inline void ab_position_report(unsigned long position)
{
if (ab_repeat_mode_enabled())
@ -109,6 +91,7 @@ static inline void ab_position_report(unsigned long position)
}
}
}
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -28,99 +28,50 @@
#define TIMEOUT_NOBLOCK 0
#define CONTEXT_STOPSEARCHING 0xFFFFFFFF
#define CONTEXT_REMOTE 0x80000000 /* | this against another context to get remote buttons for that context */
#define CONTEXT_CUSTOM 0x40000000 /* | this against anything to get your context number */
#define CONTEXT_CUSTOM2 0x20000000 /* as above */
#define CONTEXT_PLUGIN 0x10000000 /* for plugins using get_custom_action */
#define CONTEXT_REMAPPED 0x08000000 /* marker for key remap context table */
#define CORE_CONTEXT_REMAP(context) (CONTEXT_REMAPPED | context)
#define CONTEXT_LOCKED 0x04000000 /* flag to use alternate keymap when screen is locked */
#define LAST_ITEM_IN_LIST { CONTEXT_STOPSEARCHING, BUTTON_NONE, BUTTON_NONE }
#define LAST_ITEM_IN_LIST__NEXTLIST(a) { a, BUTTON_NONE, BUTTON_NONE }
#if !defined(HAS_BUTTON_HOLD)
#ifndef HAS_BUTTON_HOLD
#define ALLOW_SOFTLOCK 0x08000000 /* will be stripped.. never needed except in calls to get_action() */
#else
#define ALLOW_SOFTLOCK 0
#endif
#if defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD)
/* Selective action selection flags */
#define SEL_ACTION_NONE 0
#define SEL_ACTION_VOL 0x001U
#define SEL_ACTION_PLAY 0x002U
#define SEL_ACTION_SEEK 0x004U
#define SEL_ACTION_SKIP 0x008U
#define SEL_ACTION_NOUNMAPPED 0x010U/* disable backlight on unmapped buttons */
#define SEL_ACTION_ALLNONOTIFY 0x020U/* disable switch for all softlock notifications */
#define SEL_ACTION_ALWAYSAUTOLOCK 0x040U/* always prime autolock, requires autolock enabled */
#define SEL_ACTION_NOTOUCH 0x080U/* disable touch screen/pad on screen lock */
#define SEL_ACTION_AUTOLOCK 0x100U/* autolock on backlight off */
#define SEL_ACTION_NOEXT 0x200U/* disable selective backlight while charge*/
#define SEL_ACTION_NONOTIFY 0x200U/* don't notify user softlock is active */
/* Flags below are internal to selective functions */
#define SEL_ACTION_ALOCK_OK 0x400U/*autolock only active after key lock once*/
#define SEL_ACTION_FFKEYPRESS 0x400U/* backlight Filter First Keypress active*/
#define SEL_ACTION_ENABLED 0x800U
/* Selective Actions flags */
#if !defined(HAS_BUTTON_HOLD)
/* returns true if keys_locked and screen_has_lock */
bool is_keys_locked(void);
/* Enable selected actions to bypass a locked state
* mask is combination of Selective action selection flags */
void set_selective_softlock_actions(bool selective, unsigned int mask);
/* search the standard and wps contexts for ACTION_STD_KEYLOCK,
* load it into unlock_combo if we find it,
* also arm autolock if enabled. */
void action_autosoftlock_init(void);
#endif /* !defined(HAS_BUTTON_HOLD) */
#if defined(HAVE_BACKLIGHT)
/* Enable selected actions to leave the backlight off
* mask is combination of Selective action selection flags */
void set_selective_backlight_actions(bool selective, unsigned int mask,
bool filter_fkp);
#endif
#endif /* defined(HAVE_BACKLIGHT) || !defined(HAS_BUTTON_HOLD) */
enum {
CONTEXT_STD = 0,
/* These CONTEXT_ values were here before me,
their values may have significance, so dont touch! */
there values may have significance, so dont touch! */
CONTEXT_WPS = 1,
CONTEXT_TREE = 2,
CONTEXT_TREE = 2,
CONTEXT_RECORD = 3,
CONTEXT_MAINMENU = 4, /* uses CONTEXT_TREE and ACTION_TREE_* */
CONTEXT_ID3DB = 5,
/* Add new contexts here, no need to explicitly define a value for them */
/* Add new contexts here, no need to explicitly define a value for them */
CONTEXT_LIST,
CONTEXT_SETTINGS, /* regular setting screens (and debug screens) */
/* bellow are setting screens which may need to redefine the standard
/* bellow are setting screens which may need to redefine the standard
setting screen keys, targets should return the CONTEXT_SETTINGS
keymap unless they are not adequate for the screen
NOTE: uses ACTION_STD_[NEXT|PREV] so make sure they are there also
NOTE: uses ACTION_STD_[NEXT|PREV] so make sure they are there also
and (possibly) ACTION_SETTINGS_[INC|DEC] */
CONTEXT_SETTINGS_EQ,
CONTEXT_SETTINGS_COLOURCHOOSER,
CONTEXT_SETTINGS_TIME,
CONTEXT_SETTINGS_EQ,
CONTEXT_SETTINGS_COLOURCHOOSER,
CONTEXT_SETTINGS_TIME,
CONTEXT_SETTINGS_RECTRIGGER,
/* The following contexts should use ACTION_STD_[NEXT|PREV]
and (possibly) ACTION_SETTINGS_[INC|DEC]
and (possibly) ACTION_SETTINGS_[INC|DEC]
Also add any extra actions they need */
CONTEXT_BOOKMARKSCREEN, /* uses ACTION_BMS_ defines */
CONTEXT_ALARMSCREEN, /* uses ACTION_AS_ defines */
CONTEXT_ALARMSCREEN, /* uses ACTION_AS_ defines */
CONTEXT_QUICKSCREEN, /* uses ACTION_QS_ defines below */
CONTEXT_PITCHSCREEN, /* uses ACTION_PS_ defines below */
CONTEXT_YESNOSCREEN, /*NOTE: make sure your target has this and ACTION_YESNO_ACCEPT */
CONTEXT_RECSCREEN,
CONTEXT_KEYBOARD,
@ -131,25 +82,23 @@ enum {
CONTEXT_USB_HID_MODE_PRESENTATION,
CONTEXT_USB_HID_MODE_BROWSER,
CONTEXT_USB_HID_MODE_MOUSE,
LAST_CONTEXT_PLACEHOLDER,
};
enum {
ACTION_NONE = BUTTON_NONE,
ACTION_UNKNOWN,
ACTION_REDRAW, /* returned if keys are locked and we splash()'ed */
ACTION_TOUCHSCREEN,
ACTION_TOUCHSCREEN_MODE, /* toggle the touchscreen mode */
ACTION_TOUCHSCREEN_IGNORE, /* used for the 'none' action in skins */
/* standard actions, use these first */
ACTION_STD_PREV,
ACTION_STD_PREV,
ACTION_STD_PREVREPEAT,
ACTION_STD_NEXT,
ACTION_STD_NEXTREPEAT,
ACTION_STD_OK,
ACTION_STD_CANCEL,
ACTION_STD_CONTEXT,
@ -158,9 +107,10 @@ enum {
ACTION_STD_KEYLOCK,
ACTION_STD_REC,
ACTION_STD_HOTKEY,
ACTION_F3, /* just so everything works again, possibly change me */
/* code context actions */
/* WPS codes */
ACTION_WPS_BROWSE,
ACTION_WPS_PLAY,
@ -178,11 +128,9 @@ enum {
ACTION_WPS_QUICKSCREEN,/* optional */
ACTION_WPS_MENU, /*this should be the same as ACTION_STD_MENU */
ACTION_WPS_VIEW_PLAYLIST,
ACTION_WPS_LIST_BOOKMARKS,/* optional */
ACTION_WPS_CREATE_BOOKMARK,/* optional */
ACTION_WPS_REC,
#if 0
ACTION_WPSAB_SINGLE, /* This needs to be #defined in
ACTION_WPSAB_SINGLE, /* This needs to be #defined in
the config-<target>.h to one of the ACTION_WPS_ actions
so it can be used */
#endif
@ -190,23 +138,23 @@ enum {
ACTION_WPS_ABSETB_NEXTDIR, /* you shouldnt want to change dir in ab-mode */
ACTION_WPS_ABRESET,
ACTION_WPS_HOTKEY,
/* list and tree page up/down */
/* list and tree page up/down */
ACTION_LISTTREE_PGUP,/* optional */
ACTION_LISTTREE_PGDOWN,/* optional */
#ifdef HAVE_VOLUME_IN_LIST
ACTION_LIST_VOLUP,
ACTION_LIST_VOLDOWN,
#endif
/* tree */
/* tree */
ACTION_TREE_ROOT_INIT,
ACTION_TREE_PGLEFT,/* optional */
ACTION_TREE_PGRIGHT,/* optional */
ACTION_TREE_STOP,
ACTION_TREE_WPS,
ACTION_TREE_HOTKEY,
/* radio */
ACTION_FM_MENU,
ACTION_FM_PRESET,
@ -226,7 +174,7 @@ enum {
ACTION_REC_NEWFILE,
ACTION_REC_F2,
ACTION_REC_F3,
/* main menu */
/* These are not strictly actions, but must be here
so they dont conflict with real actions in the menu code */
@ -235,11 +183,11 @@ enum {
ACTION_EXIT_AFTER_THIS_MENUITEM, /* if a menu returns this the menu will exit
once the subitem returns */
ACTION_ENTER_MENUITEM,
/* id3db */
/* list */
/* settings */
ACTION_SETTINGS_INC,
ACTION_SETTINGS_INCREPEAT,
@ -247,19 +195,18 @@ enum {
ACTION_SETTINGS_DEC,
ACTION_SETTINGS_DECREPEAT,
ACTION_SETTINGS_DECBIGSTEP,
ACTION_SETTINGS_RESET,
ACTION_SETTINGS_SET, /* Used by touchscreen targets */
/* bookmark screen */
ACTION_BMS_DELETE,
/* quickscreen */
ACTION_QS_LEFT,
ACTION_QS_RIGHT,
ACTION_QS_DOWN,
ACTION_QS_TOP,
ACTION_QS_VOLUP,
ACTION_QS_VOLDOWN,
/* pitchscreen */
/* obviously ignore if you dont have thise screen */
ACTION_PS_INC_SMALL,
@ -275,10 +222,10 @@ enum {
ACTION_PS_EXIT, /* _STD_* isnt going to work here */
ACTION_PS_SLOWER,
ACTION_PS_FASTER,
/* yesno screen */
ACTION_YESNO_ACCEPT,
/* keyboard screen */
ACTION_KBD_LEFT,
ACTION_KBD_RIGHT,
@ -293,7 +240,7 @@ enum {
ACTION_KBD_DOWN,
ACTION_KBD_MORSE_INPUT,
ACTION_KBD_MORSE_SELECT,
#ifdef HAVE_TOUCHSCREEN
/* the following are helper actions for touchscreen targets,
* These are for actions which are not doable or required if buttons are
@ -303,9 +250,7 @@ enum {
ACTION_TOUCH_MUTE,
ACTION_TOUCH_SCROLLBAR,
ACTION_TOUCH_VOLUME,
ACTION_TOUCH_SOFTLOCK,
ACTION_TOUCH_SETTING,
#endif
#endif
/* USB HID codes */
ACTION_USB_HID_FIRST, /* Place holder */
@ -379,60 +324,11 @@ enum {
LAST_ACTION_PLACEHOLDER, /* custom actions should be this + something */
};
/* act_cur holds action state during get_action() call */
typedef struct
{
int action;
int button;
int context;
int timeout;
const struct button_mapping *items;
const struct button_mapping* (*get_context_map)(int);
bool is_prebutton;
} action_cur_t;
/* act_last holds action state between get_action() calls */
typedef struct
{
int action;
long tick;
int button;
int context;
intptr_t data;
#if defined(HAVE_BACKLIGHT)
unsigned int backlight_mask;
long bl_filter_tick;
#endif
#if !defined(HAS_BUTTON_HOLD)
long sl_filter_tick;
unsigned int softlock_mask;
int unlock_combo;
bool keys_locked;
bool screen_has_lock;
#endif
bool repeated;
bool wait_for_release;
#ifndef DISABLE_ACTION_REMAP
int key_remap;
#endif
#ifdef HAVE_TOUCHSCREEN
bool ts_short_press;
int ts_data;
#endif
} action_last_t;
struct button_mapping {
int action_code;
int button_code;
int pre_button_code;
};
/* use if you want to supply your own button mappings, PLUGINS ONLY */
/* get_context_map is a function which returns a button_mapping* depedning on the given context */
/* custom button_mappings may "chain" to inbuilt CONTEXT's */
@ -446,13 +342,11 @@ bool action_userabort(int timeout);
/* no other code should need this apart from action.c */
const struct button_mapping* get_context_mapping(int context);
#ifndef HAS_BUTTON_HOLD
bool is_keys_locked(void);
#endif
/* load a key map to allow buttons for actions to be remapped see: core_keymap */
int action_set_keymap(struct button_mapping* core_keymap, int count);
/* load keymap in a handle: takes ownership of the handle on success */
int action_set_keymap_handle(int handle, int count);
/* returns the status code variable from action.c for the button just pressed
/* returns the status code variable from action.c for the button just pressed
If button != NULL it will be set to the actual button code */
#define ACTION_REMOTE 0x1 /* remote was pressed */
#define ACTION_REPEAT 0x2 /* action was repeated (NOT button) */
@ -479,27 +373,15 @@ int action_get_touchscreen_press(short *x, short *y);
* the press was within the viewport,
* ACTION_UNKNOWN (and x1, y1 untouched) if the press was outside
* BUTTON_NONE else
*
*
**/
int action_get_touchscreen_press_in_vp(short *x1, short *y1, struct viewport *vp);
#endif
/*******************************************************
* action_wait_for_release will not allow
* get_action(|_custom)() to return
* any ACTION_* values until the current buttons
* have been released.
* SYS_* and BUTTON_NONE will pass through.
* but, any actions relying on _RELEASE won't be seen.
*
* Note this doesn't currently work for
* touchscreen targets if called when the
* screen isn't currently touched because,
* if the touch coordinates change they can send
* normal (non-BUTTON_REPEAT) events repeatedly,
* this cannot be distinguished
* from normal button events.
*/
/* Don't let get_action*() return any ACTION_* values until the current buttons
* have been released. SYS_* and BUTTON_NONE will go through.
* Any actions relying on _RELEASE won't get seen.
*/
void action_wait_for_release(void);
#endif /* __ACTION_H__ */

View file

@ -38,56 +38,161 @@
#include "splash.h"
#include "viewport.h"
int alarm_screen(void)
static void speak_time(int hours, int minutes, bool speak_hours, bool enqueue)
{
bool usb, update;
struct tm *now = get_time();
struct tm atm;
memcpy(&atm, now, sizeof(struct tm));
rtc_get_alarm(&atm.tm_hour, &atm.tm_min);
if (global_settings.talk_menu){
if(speak_hours) {
talk_value(hours, UNIT_HOUR, enqueue);
talk_value(minutes, UNIT_MIN, true);
} else {
talk_value(minutes, UNIT_MIN, enqueue);
}
}
}
bool alarm_screen(void)
{
int h, m;
bool done = false;
struct tm *tm;
int togo;
int button;
int i;
bool update = true;
bool hour_wrapped = false;
struct viewport vp[NB_SCREENS];
rtc_get_alarm(&h, &m);
/* After a battery change the RTC values are out of range */
if (!valid_time(&atm))
memcpy(&atm, now, sizeof(struct tm));
atm.tm_sec = 0;
usb = set_time_screen(str(LANG_ALARM_MOD_TIME), &atm, false);
update = valid_time(&atm); /* set_time returns invalid time if canceled */
if (!usb && update)
if (m > 60 || h > 24) {
m = 0;
h = 12;
} else {
m = m / 5 * 5; /* 5 min accuracy should be enough */
}
FOR_NB_SCREENS(i)
{
viewport_set_defaults(&vp[i], i);
}
now = get_time();
int nmins = now->tm_min + (now->tm_hour * 60);
int amins = atm.tm_min + (atm.tm_hour * 60);
int mins_togo = (amins - nmins + 1440) % 1440;
while(!done) {
if(update)
{
FOR_NB_SCREENS(i)
{
screens[i].set_viewport(&vp[i]);
screens[i].clear_viewport();
screens[i].puts(0, 4, str(LANG_ALARM_MOD_KEYS));
}
/* Talk when entering the wakeup screen */
speak_time(h, m, true, true);
update = false;
}
FOR_NB_SCREENS(i)
{
screens[i].set_viewport(&vp[i]);
screens[i].putsf(0, 1, str(LANG_ALARM_MOD_TIME));
screens[i].putsf(0, 2, "%02d:%02d", h, m);
screens[i].update_viewport();
screens[i].set_viewport(NULL);
}
button = get_action(CONTEXT_SETTINGS,HZ);
switch(button) {
case ACTION_STD_OK:
/* prevent that an alarm occurs in the shutdown procedure */
/* accept alarms only if they are in 2 minutes or more */
if (mins_togo > 1) {
tm = get_time();
togo = (m + h * 60 - tm->tm_min - tm->tm_hour * 60 + 1440) % 1440;
if (togo > 1) {
rtc_init();
rtc_set_alarm(atm.tm_hour,atm.tm_min);
rtc_set_alarm(h,m);
rtc_enable_alarm(true);
if (global_settings.talk_menu)
{
talk_id(LANG_ALARM_MOD_TIME_TO_GO, true);
talk_value(mins_togo / 60, UNIT_HOUR, true);
talk_value(mins_togo % 60, UNIT_MIN, true);
talk_value(togo / 60, UNIT_HOUR, true);
talk_value(togo % 60, UNIT_MIN, true);
talk_force_enqueue_next();
}
splashf(HZ*2, str(LANG_ALARM_MOD_TIME_TO_GO),
mins_togo / 60, mins_togo % 60);
togo / 60, togo % 60);
done = true;
} else {
splash(HZ, ID2P(LANG_ALARM_MOD_ERROR));
update = false;
update = true;
}
}
break;
if (usb || !update)
{
if (!usb)
/* inc(m) */
case ACTION_SETTINGS_INC:
case ACTION_SETTINGS_INCREPEAT:
m += 5;
if (m == 60) {
h += 1;
m = 0;
hour_wrapped = true;
}
if (h == 24)
h = 0;
speak_time(h, m, hour_wrapped, false);
break;
/* dec(m) */
case ACTION_SETTINGS_DEC:
case ACTION_SETTINGS_DECREPEAT:
m -= 5;
if (m == -5) {
h -= 1;
m = 55;
hour_wrapped = true;
}
if (h == -1)
h = 23;
speak_time(h, m, hour_wrapped, false);
break;
/* inc(h) */
case ACTION_STD_NEXT:
case ACTION_STD_NEXTREPEAT:
h = (h+1) % 24;
if (global_settings.talk_menu)
talk_value(h, UNIT_HOUR, false);
break;
/* dec(h) */
case ACTION_STD_PREV:
case ACTION_STD_PREVREPEAT:
h = (h+23) % 24;
if (global_settings.talk_menu)
talk_value(h, UNIT_HOUR, false);
break;
case ACTION_STD_CANCEL:
rtc_enable_alarm(false);
splash(HZ*2, ID2P(LANG_ALARM_MOD_DISABLE));
rtc_enable_alarm(false);
return 1;
done = true;
break;
case ACTION_NONE:
hour_wrapped = false;
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
{
rtc_enable_alarm(false);
return true;
}
break;
}
}
return 0;
return false;
}

View file

@ -21,6 +21,6 @@
#ifndef _ALARM_MENU_H
#define _ALARM_MENU_H
int alarm_screen(void);
bool alarm_screen(void);
#endif

View file

@ -31,36 +31,22 @@
/** Playback events **/
enum {
/* Playback is starting from a stopped state
data = NULL */
/* Playback is starting from a stopped state */
PLAYBACK_EVENT_START_PLAYBACK = (EVENT_CLASS_PLAYBACK|1),
/* Audio has begun buffering for decoding track (or is already completed)
data = &(struct track_event){} */
/* Audio has begun buffering for decoding track (or is already completed) */
PLAYBACK_EVENT_TRACK_BUFFER,
/* Handles for current user track are ready (other than audio or codec)
data = &(struct track_event){} */
/* Handles for current user track are ready (other than audio or codec) */
PLAYBACK_EVENT_CUR_TRACK_READY,
/* Current user track finished
data = &(struct track_event){} */
/* Current user track finished */
PLAYBACK_EVENT_TRACK_FINISH,
/* A new current user track has begun
data = &(struct track_event){} */
/* A new current user track has begun */
PLAYBACK_EVENT_TRACK_CHANGE,
/* A manual skip is about to be processed
data = NULL */
/* A manual skip is about to be processed */
PLAYBACK_EVENT_TRACK_SKIP,
/* Next track medadata was just loaded
data = &(struct track_event){} */
/* Next track medadata was just loaded */
PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
};
/** VOICE events **/
enum {
/* Voice is playing
data = &(bool){true|false} */
VOICE_EVENT_IS_PLAYING = (EVENT_CLASS_VOICE|1),
};
/** Buffering events **/
enum {
BUFFER_EVENT_BUFFER_LOW = (EVENT_CLASS_BUFFERING|1),
@ -68,7 +54,6 @@ enum {
BUFFER_EVENT_CLOSED,
BUFFER_EVENT_MOVED,
BUFFER_EVENT_FINISHED,
BUFFER_EVENT_BUFFER_RESET
};
/** Generic GUI class events **/
@ -76,9 +61,6 @@ enum {
GUI_EVENT_STATUSBAR_TOGGLE = (EVENT_CLASS_GUI|1),
GUI_EVENT_ACTIONUPDATE,
GUI_EVENT_THEME_CHANGED,
/* Called when the UI viewport is cleared in the skin engine to
* notify the current screen that it needs to do an update */
GUI_EVENT_NEED_UI_UPDATE,
};
/** Recording events **/

View file

@ -24,7 +24,7 @@ $(BUILDDIR)/apps/features: $(APPSDIR)/features.txt $(BUILDDIR)/firmware/common/
$(call PRINTS,PP $(<F))
$(SILENT)$(CC) $(PPCFLAGS) \
-E -P -imacros "config.h" -imacros "button.h" -x c $< | \
grep -v "^#" | grep -v "^ *$$" > $(BUILDDIR)/apps/features; \
grep -v "^\#" | grep -v "^ *$$" > $(BUILDDIR)/apps/features; \
$(BUILDDIR)/apps/genlang-features: $(BUILDDIR)/apps/features
$(call PRINTS,GEN $(subst $(BUILDDIR)/,,$@))tr \\n : < $< > $@

View file

@ -34,9 +34,6 @@
#if CONFIG_TUNER
#include "radio.h"
#endif
#if defined(IPOD_ACCESSORY_PROTOCOL) && defined(HAVE_LINE_REC)
#include "iap.h"
#endif
/* Some audio sources may require a boosted CPU */
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
@ -45,8 +42,7 @@
#endif
#endif
#if ((CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) \
|| (defined(SONY_NWZ_LINUX) && !defined(SIMULATOR)))
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
#ifdef AUDIO_CPU_BOOST
static void audio_cpu_boost(bool state)
@ -99,13 +95,6 @@ void audio_set_input_source(int source, unsigned flags)
radio_start();
#endif
#if defined(IPOD_ACCESSORY_PROTOCOL) && defined(HAVE_LINE_REC)
static bool last_rec_onoff = false;
bool onoff = (source == AUDIO_SRC_LINEIN) ? true : false;
if (last_rec_onoff != onoff)
last_rec_onoff = iap_record(onoff);
#endif
/* set hardware inputs */
audio_input_mux(source, flags);
} /* audio_set_source */
@ -165,25 +154,3 @@ int audio_get_spdif_sample_rate(void)
#endif /* HAVE_SPDIF_IN */
#endif /* PLATFORM_NATIVE */
#ifdef HAVE_SPEAKER
void audio_enable_speaker(int mode)
{
#if defined(HAVE_HEADPHONE_DETECTION) || defined(HAVE_LINEOUT_DETECTION)
/* if needed, query jack state */
if(mode == 2)
{
#ifdef HAVE_HEADPHONE_DETECTION
if (headphones_inserted())
mode = 0;
#endif
#ifdef HAVE_LINEOUT_DETECTION
if (lineout_inserted())
mode = 0;
#endif
}
#endif
/* treat any nonzero value as enable */
audiohw_enable_speaker(mode);
}
#endif

View file

@ -1,188 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005-2007 Miika Pekkarinen
* Copyright (C) 2007-2008 Nicolas Pennequin
* Copyright (C) 2011-2013 Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "kernel.h"
#include "logf.h"
#include "usb.h"
#include "pcm.h"
#include "sound.h"
#include "pcmbuf.h"
#include "appevents.h"
#include "audio_thread.h"
#ifdef AUDIO_HAVE_RECORDING
#include "pcm_record.h"
#endif
#include "codec_thread.h"
#include "voice_thread.h"
#include "talk.h"
#include "settings.h"
/* Macros to enable logf for queues
logging on SYS_TIMEOUT can be disabled */
#ifdef SIMULATOR
/* Define this for logf output of all queuing except SYS_TIMEOUT */
#define AUDIO_LOGQUEUES
/* Define this to logf SYS_TIMEOUT messages */
/*#define AUDIO_LOGQUEUES_SYS_TIMEOUT*/
#endif
#ifdef AUDIO_LOGQUEUES
#define LOGFQUEUE logf
#else
#define LOGFQUEUE(...)
#endif
bool audio_is_initialized = false;
/* Event queues */
struct event_queue audio_queue SHAREDBSS_ATTR;
static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
/* Audio thread */
static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
static const char audio_thread_name[] = "audio";
unsigned int audio_thread_id = 0;
static void NORETURN_ATTR audio_thread(void)
{
struct queue_event ev;
ev.id = Q_NULL; /* something not in switch below */
pcm_postinit();
while (1)
{
switch (ev.id)
{
/* Starts the playback engine branch */
case Q_AUDIO_PLAY:
LOGFQUEUE("audio < Q_AUDIO_PLAY");
audio_playback_handler(&ev);
continue;
/* Playback has to handle these, even if not playing */
case Q_AUDIO_REMAKE_AUDIO_BUFFER:
#ifdef HAVE_DISK_STORAGE
case Q_AUDIO_UPDATE_WATERMARK:
#endif
audio_playback_handler(&ev);
break;
#ifdef AUDIO_HAVE_RECORDING
/* Starts the recording engine branch */
case Q_AUDIO_INIT_RECORDING:
LOGFQUEUE("audio < Q_AUDIO_INIT_RECORDING");
audio_recording_handler(&ev);
continue;
#endif
/* All return upon USB */
case SYS_USB_CONNECTED:
LOGFQUEUE("audio < SYS_USB_CONNECTED");
voice_stop();
usb_acknowledge(SYS_USB_CONNECTED_ACK);
usb_wait_for_disconnect(&audio_queue);
break;
}
queue_wait(&audio_queue, &ev);
}
}
void audio_voice_event(unsigned short id, void *data)
{
(void)id;
/* Make audio play softly while voice is speaking */
pcmbuf_soft_mode(*(bool *)data);
}
void audio_queue_post(long id, intptr_t data)
{
queue_post(&audio_queue, id, data);
}
intptr_t audio_queue_send(long id, intptr_t data)
{
return queue_send(&audio_queue, id, data);
}
/* Return the playback and recording status */
int audio_status(void)
{
return playback_status()
#ifdef AUDIO_HAVE_RECORDING
| pcm_rec_status()
#endif
;
}
/* Clear all accumulated audio errors for playback and recording */
void audio_error_clear(void)
{
#ifdef AUDIO_HAVE_RECORDING
pcm_rec_error_clear();
#endif
}
/** -- Startup -- **/
/* Initialize the audio system - called from init() in main.c */
void INIT_ATTR audio_init(void)
{
/* Can never do this twice */
if (audio_is_initialized)
{
logf("audio: already initialized");
return;
}
logf("audio: initializing");
/* Initialize queues before giving control elsewhere in case it likes
to send messages. Thread creation will be delayed however so nothing
starts running until ready if something yields such as talk_init. */
queue_init(&audio_queue, true);
codec_thread_init();
/* This thread does buffer, so match its priority */
audio_thread_id = create_thread(audio_thread, audio_stack,
sizeof(audio_stack), 0, audio_thread_name
IF_PRIO(, MIN(PRIORITY_BUFFERING, PRIORITY_USER_INTERFACE))
IF_COP(, CPU));
queue_enable_queue_send(&audio_queue, &audio_queue_sender_list,
audio_thread_id);
playback_init();
#ifdef AUDIO_HAVE_RECORDING
recording_init();
#endif
add_event(VOICE_EVENT_IS_PLAYING, audio_voice_event);
/* Probably safe to say */
audio_is_initialized = true;
sound_settings_apply();
}

View file

@ -1,109 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005-2007 Miika Pekkarinen
* Copyright (C) 2007-2008 Nicolas Pennequin
* Copyright (C) 2011-2013 Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef AUDIO_THREAD_H
#define AUDIO_THREAD_H
/* Define one constant that includes recording related functionality */
#if defined(HAVE_RECORDING) && !defined(SIMULATOR)
#define AUDIO_HAVE_RECORDING
#endif
enum
{
Q_NULL = 0, /* reserved */
/* -> audio */
Q_AUDIO_PLAY,
Q_AUDIO_STOP,
Q_AUDIO_PAUSE,
Q_AUDIO_SKIP,
Q_AUDIO_PRE_FF_REWIND,
Q_AUDIO_FF_REWIND,
Q_AUDIO_FLUSH,
Q_AUDIO_DIR_SKIP,
/* pcmbuf -> audio */
Q_AUDIO_TRACK_CHANGED,
/* audio -> audio */
Q_AUDIO_FILL_BUFFER, /* continue buffering next track */
/* buffering -> audio */
Q_AUDIO_BUFFERING, /* some buffer event */
Q_AUDIO_FINISH_LOAD_TRACK, /* metadata is buffered */
Q_AUDIO_HANDLE_FINISHED, /* some other type is buffered */
/* codec -> audio (*) */
Q_AUDIO_CODEC_SEEK_COMPLETE,
Q_AUDIO_CODEC_COMPLETE,
/* audio -> codec */
Q_CODEC_LOAD,
Q_CODEC_RUN,
Q_CODEC_PAUSE,
Q_CODEC_SEEK,
Q_CODEC_STOP,
Q_CODEC_UNLOAD,
/* -> codec */
Q_CODEC_DO_CALLBACK,
/* -> recording */
#ifdef HAVE_RECORDING
Q_AUDIO_INIT_RECORDING,
Q_AUDIO_CLOSE_RECORDING,
Q_AUDIO_RECORDING_OPTIONS,
Q_AUDIO_RECORD,
Q_AUDIO_RECORD_STOP,
Q_AUDIO_RECORD_PAUSE,
Q_AUDIO_RECORD_RESUME,
Q_AUDIO_RECORD_FLUSH,
#endif
/*- settings -*/
#ifdef HAVE_DISK_STORAGE
/* -> audio */
Q_AUDIO_UPDATE_WATERMARK, /* buffering watermark needs updating */
#endif
/* -> audio */
Q_AUDIO_REMAKE_AUDIO_BUFFER, /* buffer needs to be reinitialized */
};
/* (*) If you change these, you must check audio_clear_track_notifications
in playback.c for correctness */
void audio_init(void);
void playback_init(void);
unsigned int playback_status(void);
void audio_playback_handler(struct queue_event *ev);
#ifdef AUDIO_HAVE_RECORDING
void audio_recording_handler(struct queue_event *ev);
#endif
/** --- audio_queue helpers --- **/
void audio_queue_post(long id, intptr_t data);
intptr_t audio_queue_send(long id, intptr_t data);
#endif /* AUDIO_THREAD_H */

View file

@ -1,103 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (c) 2011 Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "settings.h"
#include "pcm.h"
#include "pcm_mixer.h"
#include "misc.h"
#include "fixedpoint.h"
/** Beep generation, CPU optimized **/
#include "asm/beep.c"
static uint32_t beep_phase; /* Phase of square wave generator */
static uint32_t beep_step; /* Step of square wave generator on each sample */
#ifdef BEEP_GENERIC
static int16_t beep_amplitude; /* Amplitude of square wave generator */
#else
/* Optimized routines do XOR with phase sign bit in both channels at once */
static uint32_t beep_amplitude; /* Amplitude of square wave generator */
#endif
static int beep_count; /* Number of samples remaining to generate */
#define BEEP_COUNT(fs, duration) ((fs) / 1000 * (duration))
/* Reserve enough static space for keyclick to fit in worst case */
#define BEEP_BUF_COUNT BEEP_COUNT(PLAY_SAMPR_MAX, KEYCLICK_DURATION)
static int16_t beep_buf[BEEP_BUF_COUNT*2] IBSS_ATTR __attribute__((aligned(4)));
/* Callback to generate the beep frames - also don't want inlining of
call below in beep_play */
static void __attribute__((noinline))
beep_get_more(const void **start, size_t *size)
{
int count = beep_count;
if (count > 0)
{
count = MIN(count, BEEP_BUF_COUNT);
beep_count -= count;
*start = beep_buf;
*size = count * 2 * sizeof (int16_t);
beep_generate((void *)beep_buf, count, &beep_phase,
beep_step, beep_amplitude);
}
}
/* Generates a constant square wave sound with a given frequency in Hertz for
a duration in milliseconds */
void beep_play(unsigned int frequency, unsigned int duration,
unsigned int amplitude)
{
mixer_channel_stop(PCM_MIXER_CHAN_BEEP);
if (frequency == 0 || duration == 0 || amplitude == 0)
return;
if (amplitude > INT16_MAX)
amplitude = INT16_MAX;
/* Setup the parameters for the square wave generator */
uint32_t fout = mixer_get_frequency();
beep_phase = 0;
beep_step = fp_div(frequency, fout, 32);
beep_count = BEEP_COUNT(fout, duration);
#ifdef BEEP_GENERIC
beep_amplitude = amplitude;
#else
/* Optimized routines do XOR with phase sign bit in both channels at once */
beep_amplitude = amplitude | (amplitude << 16); /* Word:|AMP16|AMP16| */
#endif
/* If it fits - avoid cb overhead */
const void *start;
size_t size;
/* Generate first frame here */
beep_get_more(&start, &size);
mixer_channel_set_amplitude(PCM_MIXER_CHAN_BEEP, MIX_AMP_UNITY);
mixer_channel_play_data(PCM_MIXER_CHAN_BEEP,
beep_count ? beep_get_more : NULL,
start, size);
}

View file

@ -25,28 +25,27 @@ ifneq ($(strip $(BMP2RB_REMOTENATIVE)),)
BMP += $(call preprocess, $(BITMAPDIR)/remote_native/SOURCES)
endif
BMPOBJ = $(call full_path_subst,$(ROOTDIR)/%.bmp,$(BUILDDIR)/%.o,$(BMP))
BMPOBJ = $(BMP:$(ROOTDIR)/%.bmp=$(BUILDDIR)/%.o)
BMPHFILES = $(BMPINCDIR)/usblogo.h $(BMPINCDIR)/remote_usblogo.h \
$(BMPINCDIR)/default_icons.h $(BMPINCDIR)/remote_default_icons.h \
$(BMPINCDIR)/rockboxlogo.h $(BMPINCDIR)/remote_rockboxlogo.h \
$(BMPINCDIR)/rockboxicon.h $(BMPINCDIR)/toolsicon.h
$(BMPINCDIR)/rockboxlogo.h $(BMPINCDIR)/remote_rockboxlogo.h
$(BMPHFILES): $(BMPOBJ)
# pattern rules to create .c files from .bmp, one for each subdir:
$(BUILDDIR)/apps/bitmaps/mono/%.c: $(ROOTDIR)/apps/bitmaps/mono/%.bmp $(TOOLSDIR)/bmp2rb
$(SILENT)mkdir -p $(dir $@) $(BMPINCDIR)
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_MONO) -b -h $(BMPINCDIR) $< > $@
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_MONO) -h $(BMPINCDIR) $< > $@
$(BUILDDIR)/apps/bitmaps/native/%.c: $(ROOTDIR)/apps/bitmaps/native/%.bmp $(TOOLSDIR)/bmp2rb
$(SILENT)mkdir -p $(dir $@) $(BMPINCDIR)
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_NATIVE) -b -h $(BMPINCDIR) $< > $@
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_NATIVE) -h $(BMPINCDIR) $< > $@
$(BUILDDIR)/apps/bitmaps/remote_mono/%.c: $(ROOTDIR)/apps/bitmaps/remote_mono/%.bmp $(TOOLSDIR)/bmp2rb
$(SILENT)mkdir -p $(dir $@) $(BMPINCDIR)
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_REMOTEMONO) -b -h $(BMPINCDIR) $< > $@
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_REMOTEMONO) -h $(BMPINCDIR) $< > $@
$(BUILDDIR)/apps/bitmaps/remote_native/%.c: $(ROOTDIR)/apps/bitmaps/remote_native/%.bmp $(TOOLSDIR)/bmp2rb
$(SILENT)mkdir -p $(dir $@) $(BMPINCDIR)
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_REMOTENATIVE) -b -h $(BMPINCDIR) $< > $@
$(call PRINTS,BMP2RB $(<F))$(BMP2RB_REMOTENATIVE) -h $(BMPINCDIR) $< > $@

View file

@ -1,5 +1,3 @@
default_icons.bmp
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(__APPLE__)
osx_dummy.bmp
#endif

View file

@ -1,3 +1,5 @@
#ifdef HAVE_LCD_BITMAP
/* Rockbox logo */
#if (LCD_DEPTH == 1)
#if (LCD_WIDTH == 160)
@ -7,56 +9,34 @@ rockboxlogo.128x42x1.bmp
#else
rockboxlogo.112x30x1.bmp
#endif
#elif (LCD_WIDTH == 96) && (LCD_DEPTH >= 16)
rockboxlogo.96x30x16.bmp
#elif (LCD_WIDTH == 128) && (LCD_DEPTH == 2)
rockboxlogo.128x42x2.bmp
#elif (LCD_WIDTH == 128) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH == 128) && (LCD_DEPTH == 16)
rockboxlogo.128x40x16.bmp
#elif (LCD_WIDTH == 132) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH == 132) && (LCD_DEPTH == 16)
rockboxlogo.132x40x16.bmp
#elif (LCD_WIDTH == 138) && (LCD_DEPTH >= 2)
#elif (LCD_WIDTH == 138) && (LCD_DEPTH == 2)
rockboxlogo.138x46x2.bmp
#elif (LCD_WIDTH == 160) && (LCD_DEPTH == 2)
rockboxlogo.160x53x2.bmp
#elif (LCD_WIDTH == 320) && (LCD_DEPTH == 2)
rockboxlogo.160x53x2.bmp
#elif (LCD_WIDTH == 160) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH == 160) && (LCD_DEPTH == 16)
rockboxlogo.160x50x16.bmp
#elif (LCD_WIDTH == 176) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH == 176) && (LCD_DEPTH == 16)
rockboxlogo.176x54x16.bmp
#elif (LCD_WIDTH == 220) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH == 220) && (LCD_DEPTH == 16)
rockboxlogo.220x68x16.bmp
#elif (LCD_WIDTH == 240) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH == 240) && (LCD_DEPTH == 16)
rockboxlogo.240x74x16.bmp
#elif (LCD_WIDTH >= 320) && (LCD_WIDTH < 480) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH >= 320) && (LCD_WIDTH < 480) && (LCD_DEPTH == 16)
rockboxlogo.320x98x16.bmp
#elif (LCD_WIDTH >= 480) && (LCD_WIDTH < 640) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH >= 480) && (LCD_WIDTH < 640) && (LCD_DEPTH == 16)
rockboxlogo.480x149x16.bmp
#elif (LCD_WIDTH >= 640) && (LCD_DEPTH >= 16)
#elif (LCD_WIDTH >= 640) && (LCD_DEPTH == 16)
rockboxlogo.640x198x16.bmp
#endif
/* The Sony NWZ linux bootloader needs icons to display a menu */
#if defined(BOOTLOADER)
#if defined(SONY_NWZ_LINUX)
rockboxicon.130x130x16.bmp
toolsicon.130x130x16.bmp
#elif defined(AGPTEK_ROCKER)
hibyicon.70x70x16.bmp
rockboxicon.70x70x16.bmp
toolsicon.70x70x16.bmp
#elif (defined(XDUOO_X3II) || defined(XDUOO_X20) || defined(EROS_Q))
hibyicon.130x130x16.bmp
rockboxicon.130x130x16.bmp
toolsicon.130x130x16.bmp
#elif defined(FIIO_M3K_LINUX)
fiioicon.130x130x16.bmp
rockboxicon.130x130x16.bmp
toolsicon.130x130x16.bmp
#endif
#endif
#ifndef BOOTLOADER /* We don't need these for the bootloader */
/* USB logo */
@ -65,8 +45,6 @@ toolsicon.130x130x16.bmp
usblogo.176x48x16.bmp
#elif LCD_WIDTH >= 128
usblogo.128x37x16.bmp
#elif LCD_WIDTH >= 88
usblogo.88x24x16.bmp
#endif
#elif LCD_DEPTH > 1 /* greyscale */
#ifdef IPOD_1G2G /* use firewire logo */
@ -82,4 +60,15 @@ usblogo.104x27x1.bmp
#endif
#endif
/* List Icons */
#if LCD_DEPTH == 16
default_icons.6x8x16.bmp
#elif LCD_DEPTH > 1 /* greyscale */
default_icons.6x8x2.bmp
#else
default_icons.6x8x1.bmp
#endif
#endif /* BOOTLOADER */
#endif /* HAVE_LCD_BITMAP */

View file

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -1,5 +1,3 @@
remote_default_icons.bmp
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(__APPLE__)
osx_remote_dummy.bmp
#endif

View file

@ -5,9 +5,11 @@
#if (LCD_REMOTE_DEPTH == 1)
remote_rockboxlogo.128x42x1.bmp
remote_usblogo.104x27x1.bmp
remote_default_icons.6x8x1.bmp
#elif (LCD_REMOTE_DEPTH == 2)
remote_rockboxlogo.128x42x2.bmp
remote_usblogo.104x27x2.bmp
remote_default_icons.6x8x2.bmp
#endif
#endif /* BOOTLOADER */

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

File diff suppressed because it is too large Load diff

View file

@ -23,26 +23,13 @@
#include <stdbool.h>
enum {
BOOKMARK_FAIL = -1,
BOOKMARK_SUCCESS = 0,
BOOKMARK_USB_CONNECTED = 1
};
enum {
BOOKMARK_CANCEL,
BOOKMARK_DONT_RESUME,
BOOKMARK_DO_RESUME
};
int bookmark_load_menu(void);
bool bookmark_load_menu(void);
bool bookmark_autobookmark(bool prompt_ok);
bool bookmark_create_menu(void);
bool bookmark_mrb_load(void);
int bookmark_autoload(const char* file);
bool bookmark_autoload(const char* file);
bool bookmark_load(const char* file, bool autoload);
bool bookmark_exists(void);
bool bookmark_is_bookmarkable_state(void);
#endif /* __BOOKMARK_H__ */

File diff suppressed because it is too large Load diff

View file

@ -24,7 +24,6 @@
#include <sys/types.h>
#include <stdbool.h>
#include "config.h"
#include "appevents.h"
@ -36,7 +35,6 @@ enum data_type {
TYPE_ATOMIC_AUDIO,
TYPE_CUESHEET,
TYPE_BITMAP,
TYPE_RAW_ATOMIC,
};
/* Error return values */
@ -46,10 +44,10 @@ enum data_type {
#define ERR_FILE_ERROR -4
#define ERR_HANDLE_NOT_DONE -5
#define ERR_UNSUPPORTED_TYPE -6
#define ERR_BITMAP_TOO_LARGE -7
/* Initialise the buffering subsystem */
void buffering_init(void) INIT_ATTR;
void buffering_init(void);
/* Reset the buffering system */
bool buffering_reset(char *buf, size_t buflen);
@ -67,13 +65,17 @@ bool buffering_reset(char *buf, size_t buflen);
* bufftell : Return the handle's file read position
* bufread : Copy data from a handle to a buffer
* bufgetdata: Obtain a pointer for linear access to a "size" amount of data
* bufgettail: Out-of-band get the last size bytes of a handle.
* bufcuttail: Out-of-band remove the trailing 'size' bytes of a handle.
*
* NOTE: bufread and bufgetdata will block the caller until the requested
* amount of data is ready (unless EOF is reached).
* NOTE: Tail operations are only legal when the end of the file is buffered.
****************************************************************************/
int bufopen(const char *file, off_t offset, enum data_type type,
#define BUF_MAX_HANDLES 256
int bufopen(const char *file, size_t offset, enum data_type type,
void *user_data);
int bufalloc(const void *src, size_t size, enum data_type type);
bool bufclose(int handle_id);
@ -82,6 +84,8 @@ int bufadvance(int handle_id, off_t offset);
off_t bufftell(int handle_id);
ssize_t bufread(int handle_id, size_t size, void *dest);
ssize_t bufgetdata(int handle_id, size_t size, void **data);
ssize_t bufgettail(int handle_id, size_t size, void **data);
ssize_t bufcuttail(int handle_id, size_t size);
/***************************************************************************
* SECONDARY FUNCTIONS
@ -97,19 +101,24 @@ ssize_t bufgetdata(int handle_id, size_t size, void **data);
* buf_back_off_storage: tell buffering thread to take it easy
****************************************************************************/
enum data_type buf_handle_data_type(int handle_id);
ssize_t buf_handle_remaining(int handle_id);
bool buf_is_handle(int handle_id);
int buf_handle_data_type(int handle_id);
off_t buf_filesize(int handle_id);
off_t buf_handle_offset(int handle_id);
off_t buf_handle_remaining(int handle_id);
bool buf_pin_handle(int handle_id, bool pin);
bool buf_signal_handle(int handle_id, bool signal);
ssize_t buf_handle_offset(int handle_id);
void buf_set_base_handle(int handle_id);
size_t buf_length(void);
size_t buf_used(void);
bool buf_pin_handle(int handle_id, bool pin);
bool buf_signal_handle(int handle_id, bool signal);
#ifdef HAVE_IO_PRIORITY
void buf_back_off_storage(bool back_off);
#endif
/* Settings */
void buf_set_base_handle(int handle_id);
enum {
BUFFERING_SET_WATERMARK = 1,
BUFFERING_SET_CHUNKSIZE,
};
void buf_set_watermark(size_t bytes);
size_t buf_get_watermark(void);
@ -117,6 +126,7 @@ size_t buf_get_watermark(void);
struct buffering_debug {
int num_handles;
size_t buffered_data;
size_t wasted_space;
size_t data_rem;
size_t useful_data;
size_t watermark;

View file

@ -20,19 +20,16 @@
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "kernel.h"
#include "codecs.h"
#include "codec_thread.h"
#include "pcmbuf.h"
#include "audio_thread.h"
#include "playback.h"
#include "buffering.h"
#include "dsp_core.h"
#include "dsp.h"
#include "metadata.h"
#include "settings.h"
/* Define LOGF_ENABLE to enable logf output in this file */
/*#define LOGF_ENABLE*/
@ -80,26 +77,16 @@ struct codec_load_info
static int codec_type = AFMT_UNKNOWN; /* Codec type (C,A-) */
/* Private interfaces to main playback control */
extern void audio_codec_update_elapsed(unsigned long elapsed);
extern void audio_codec_update_offset(size_t offset);
extern void audio_codec_complete(int status);
extern void audio_codec_seek_complete(void);
extern void audio_codec_update_elapsed(unsigned long value);
extern void audio_codec_update_offset(size_t value);
extern void audio_queue_post(long id, intptr_t data);
extern struct codec_api ci; /* from codecs.c */
/* Codec thread */
static unsigned int codec_thread_id; /* For modifying thread priority later */
static struct event_queue codec_queue SHAREDBSS_ATTR;
static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR;
/* Workaround stack overflow in opus codec on highmem devices (see FS#13060). */
/* Fixed 2019-8-14 (see FS#13131) */
#if 0 /*!defined(CPU_COLDFIRE) && (MEMORYSIZE >= 8) && defined(IRAMSIZE) && IRAMSIZE > (32 * 1024)*/
#define WORKAROUND_FS13060 0x800
#else
#define WORKAROUND_FS13060 0
#endif
static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000 + WORKAROUND_FS13060)/sizeof(long)] IBSS_ATTR;
static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR;
static const char codec_thread_name[] = "codec";
static void unload_codec(void);
@ -134,13 +121,13 @@ static int codec_check_queue__have_msg(void)
switch (ev.id)
{
case Q_CODEC_SEEK:
LOGFQUEUE("codec - Q_CODEC_SEEK %ld", ev.id);
LOGFQUEUE("codec - Q_CODEC_SEEK", ev.id);
return -1;
case Q_CODEC_PAUSE:
LOGFQUEUE("codec - Q_CODEC_PAUSE %ld", ev.id);
LOGFQUEUE("codec - Q_CODEC_PAUSE", ev.id);
return -1;
case Q_CODEC_STOP:
LOGFQUEUE("codec - Q_CODEC_STOP %ld", ev.id);
LOGFQUEUE("codec - Q_CODEC_STOP", ev.id);
return -1;
}
@ -183,16 +170,14 @@ const char * get_codec_filename(int cod_spec)
/* Can choose decoder or encoder if one available */
int type = cod_spec & CODEC_TYPE_MASK;
int afmt = cod_spec & CODEC_AFMT_MASK;
int tmp_fmt = afmt;
if ((unsigned)afmt >= AFMT_NUM_CODECS)
{
type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
tmp_fmt = AFMT_UNKNOWN;
}
fname = (type == CODEC_TYPE_ENCODER) ?
audio_formats[tmp_fmt].codec_enc_root_fn :
audio_formats[tmp_fmt].codec_root_fn;
audio_formats[afmt].codec_enc_root_fn :
audio_formats[afmt].codec_root_fn;
logf("%s: %d - %s",
(type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
afmt, fname ? fname : "<unknown>");
@ -226,41 +211,49 @@ void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
static void codec_pcmbuf_insert_callback(
const void *ch1, const void *ch2, int count)
{
struct dsp_buffer src;
src.remcount = count;
src.pin[0] = ch1;
src.pin[1] = ch2;
src.proc_mask = 0;
const char *src[2] = { ch1, ch2 };
while (LIKELY(queue_empty(&codec_queue)) ||
codec_check_queue__have_msg() >= 0)
while (count > 0)
{
struct dsp_buffer dst;
dst.remcount = 0;
dst.bufcount = MAX(src.remcount, 1024); /* Arbitrary min request */
int out_count = dsp_output_count(ci.dsp, count);
int inp_count;
char *dest;
if ((dst.p16out = pcmbuf_request_buffer(&dst.bufcount)) == NULL)
while (1)
{
if ((dest = pcmbuf_request_buffer(&out_count)) != NULL)
break;
cancel_cpu_boost();
/* It may be awhile before space is available but we want
/* It will be awhile before space is available but we want
"instant" response to any message */
queue_wait_w_tmo(&codec_queue, NULL, HZ/20);
}
else
{
dsp_process(ci.dsp, &src, &dst);
if (dst.remcount > 0)
{
pcmbuf_write_complete(dst.remcount, ci.id3->elapsed,
ci.id3->offset);
}
else if (src.remcount <= 0)
{
return; /* No input remains and DSP purged */
}
if (!queue_empty(&codec_queue) &&
codec_check_queue__have_msg() < 0)
return;
}
/* Get the real input_size for output_size bytes, guarding
* against resampling buffer overflows. */
inp_count = dsp_input_count(ci.dsp, out_count);
if (inp_count <= 0)
return;
/* Input size has grown, no error, just don't write more than length */
if (inp_count > count)
inp_count = count;
out_count = dsp_process(ci.dsp, dest, src, inp_count);
if (out_count <= 0)
return;
pcmbuf_write_complete(out_count);
count -= inp_count;
}
}
@ -341,11 +334,9 @@ static void codec_seek_complete_callback(void)
/* Clear DSP */
dsp_configure(ci.dsp, DSP_FLUSH, 0);
/* Sync position */
audio_codec_update_offset(ci.curpos);
/* Post notification to audio thread */
audio_codec_seek_complete();
LOGFQUEUE("audio > Q_AUDIO_CODEC_SEEK_COMPLETE");
audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
/* Wait for urgent or go message */
do
@ -357,10 +348,14 @@ static void codec_seek_complete_callback(void)
static void codec_configure_callback(int setting, intptr_t value)
{
dsp_configure(ci.dsp, setting, value);
if (!dsp_configure(ci.dsp, setting, value))
{
logf("Illegal key: %d", setting);
}
}
static long codec_get_command_callback(intptr_t *param)
static enum codec_command_action
codec_get_command_callback(intptr_t *param)
{
yield();
@ -371,73 +366,58 @@ static long codec_get_command_callback(intptr_t *param)
be expected) */
while (1)
{
long action = CODEC_ACTION_NULL;
enum codec_command_action action = CODEC_ACTION_NULL;
struct queue_event ev;
queue_wait(&codec_queue, &ev);
queue_peek(&codec_queue, &ev); /* Find out what it is */
intptr_t id = ev.id;
switch (id)
switch (ev.id)
{
case Q_NULL:
LOGFQUEUE("codec < Q_NULL");
break;
case Q_CODEC_RUN: /* Already running */
LOGFQUEUE("codec < Q_CODEC_RUN");
break;
case Q_CODEC_PAUSE: /* Stay here and wait */
LOGFQUEUE("codec < Q_CODEC_PAUSE");
queue_wait(&codec_queue, &ev); /* Remove message */
codec_queue_ack(Q_CODEC_PAUSE);
queue_wait(&codec_queue, NULL); /* Wait for next (no remove) */
continue;
case Q_CODEC_SEEK: /* Audio wants codec to seek */
LOGFQUEUE("codec < Q_CODEC_SEEK %ld", ev.data);
*param = ev.data;
action = CODEC_ACTION_SEEK_TIME;
trigger_cpu_boost();
break;
case Q_CODEC_STOP: /* Must only return 0 in main loop */
LOGFQUEUE("codec < Q_CODEC_STOP: %ld", ev.data);
#ifdef HAVE_RECORDING
if (type_is_encoder(codec_type))
{
/* Stream finish request (soft stop)? */
if (ev.data && param)
{
/* ev.data is pointer to size */
*param = ev.data;
action = CODEC_ACTION_STREAM_FINISH;
break;
}
}
else
#endif /* HAVE_RECORDING */
{
dsp_configure(ci.dsp, DSP_FLUSH, 0); /* Discontinuity */
}
return CODEC_ACTION_HALT; /* Leave in queue */
LOGFQUEUE("codec < Q_CODEC_STOP");
action = CODEC_ACTION_HALT;
break;
default: /* This is in error in this context. */
ev.id = Q_NULL;
logf("codec bad req %ld (%s)", ev.id, __func__);
id = Q_NULL;
}
queue_wait(&codec_queue, &ev); /* Actually remove it */
codec_queue_ack(id);
codec_queue_ack(ev.id);
return action;
}
}
static bool codec_loop_track_callback(void)
/* Initialize codec API */
void codec_init_codec_api(void)
{
return global_settings.repeat_mode == REPEAT_ONE;
ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP,
CODEC_IDX_AUDIO);
ci.codec_get_buffer = codec_get_buffer_callback;
ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
ci.set_elapsed = audio_codec_update_elapsed;
ci.read_filebuf = codec_filebuf_callback;
ci.request_buffer = codec_request_buffer_callback;
ci.advance_buffer = codec_advance_buffer_callback;
ci.seek_buffer = codec_seek_buffer_callback;
ci.seek_complete = codec_seek_complete_callback;
ci.set_offset = audio_codec_update_offset;
ci.configure = codec_configure_callback;
ci.get_command = codec_get_command_callback;
}
@ -480,11 +460,18 @@ static void load_codec(const struct codec_load_info *ev_data)
/* Either not a valid handle or the buffer method failed */
const char *codec_fn = get_codec_filename(data.afmt);
if (codec_fn)
{
#ifdef HAVE_IO_PRIORITY
buf_back_off_storage(true);
#endif
status = codec_load_file(codec_fn, &ci);
#ifdef HAVE_IO_PRIORITY
buf_back_off_storage(false);
#endif
}
}
/* Types must agree */
if (status >= 0 && encoder == !!codec_get_enc_callback())
if (status >= 0)
{
codec_type = data.afmt;
codec_queue_ack(Q_CODEC_LOAD);
@ -510,7 +497,6 @@ static void run_codec(void)
codec_queue_ack(Q_CODEC_RUN);
trigger_cpu_boost();
dsp_configure(ci.dsp, DSP_SET_OUT_FREQUENCY, pcmbuf_get_frequency());
if (!encoder)
{
@ -535,7 +521,8 @@ static void run_codec(void)
/* Notify audio that we're done for better or worse - advise of the
status */
audio_codec_complete(status);
LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
}
}
@ -573,9 +560,9 @@ static void do_callback(void (* callback)(void))
if (callback)
{
commit_discard_idcache();
cpucache_commit_discard();
callback();
commit_dcache();
cpucache_commit();
}
}
@ -584,7 +571,7 @@ static void NORETURN_ATTR codec_thread(void)
{
struct queue_event ev;
while (1)
while (1)
{
cancel_cpu_boost();
@ -630,34 +617,31 @@ static void NORETURN_ATTR codec_thread(void)
/** --- Miscellaneous external interfaces -- **/
/* Initialize playback's codec interface */
void INIT_ATTR codec_thread_init(void)
/* Create the codec thread and init kernel objects */
void make_codec_thread(void)
{
/* Init API */
ci.dsp = dsp_get_config(CODEC_IDX_AUDIO);
ci.codec_get_buffer = codec_get_buffer_callback;
ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
ci.set_elapsed = audio_codec_update_elapsed;
ci.read_filebuf = codec_filebuf_callback;
ci.request_buffer = codec_request_buffer_callback;
ci.advance_buffer = codec_advance_buffer_callback;
ci.seek_buffer = codec_seek_buffer_callback;
ci.seek_complete = codec_seek_complete_callback;
ci.set_offset = audio_codec_update_offset;
ci.configure = codec_configure_callback;
ci.get_command = codec_get_command_callback;
ci.loop_track = codec_loop_track_callback;
/* Init threading */
queue_init(&codec_queue, false);
codec_thread_id = create_thread(
codec_thread, codec_stack, sizeof(codec_stack), 0,
codec_thread, codec_stack, sizeof(codec_stack),
CREATE_THREAD_FROZEN,
codec_thread_name IF_PRIO(, PRIORITY_PLAYBACK)
IF_COP(, CPU));
queue_enable_queue_send(&codec_queue, &codec_queue_sender_list,
codec_thread_id);
}
/* Unfreeze the codec thread */
void codec_thread_resume(void)
{
thread_thaw(codec_thread_id);
}
/* Is the current thread the codec thread? */
bool is_codec_thread(void)
{
return thread_self() == codec_thread_id;
}
#ifdef HAVE_PRIORITY_SCHEDULING
/* Obtain codec thread's current priority */
int codec_thread_get_priority(void)
@ -711,33 +695,10 @@ bool codec_pause(void)
void codec_stop(void)
{
/* Wait until it's in the main loop */
LOGFQUEUE("audio >| codec Q_CODEC_STOP: 0");
LOGFQUEUE("audio >| codec Q_CODEC_STOP");
while (codec_queue_send(Q_CODEC_STOP, 0) != Q_NULL);
}
#ifdef HAVE_RECORDING
/* Tells codec to take final encoding step and then exit -
Returns minimum buffer size required or 0 if complete */
size_t codec_finish_stream(void)
{
size_t size = 0;
LOGFQUEUE("audio >| codec Q_CODEC_STOP: &size");
if (codec_queue_send(Q_CODEC_STOP, (intptr_t)&size) != Q_NULL)
{
/* Sync to keep size in scope and get response */
LOGFQUEUE("audio >| codec Q_NULL");
codec_queue_send(Q_NULL, 0);
if (size == 0)
codec_stop(); /* Replied with 0 size */
}
/* else thread running in the main loop */
return size;
}
#endif /* HAVE_RECORDING */
/* Call the codec's exit routine and close all references */
void codec_unload(void)
{

View file

@ -23,18 +23,20 @@
#define _CODEC_THREAD_H
#include <stdbool.h>
#include "config.h"
/* codec identity */
const char *get_codec_filename(int cod_spec);
/* codec thread */
void codec_thread_init(void) INIT_ATTR;
/* Audio MUST be stopped before requesting callback! */
void codec_thread_do_callback(void (*fn)(void),
unsigned int *codec_thread_id);
void codec_init_codec_api(void);
void make_codec_thread(void);
void codec_thread_resume(void);
bool is_codec_thread(void);
#ifdef HAVE_PRIORITY_SCHEDULING
int codec_thread_get_priority(void);
int codec_thread_set_priority(int priority);
@ -46,9 +48,6 @@ void codec_go(void);
bool codec_pause(void);
void codec_seek(long time);
void codec_stop(void);
#ifdef HAVE_RECORDING
size_t codec_finish_stream(void);
#endif
void codec_unload(void);
int codec_loaded(void);

View file

@ -40,6 +40,7 @@
#include "lang.h"
#include "keyboard.h"
#include "buffering.h"
#include "mp3_playback.h"
#include "backlight.h"
#include "storage.h"
#include "talk.h"
@ -49,7 +50,6 @@
#include "sound.h"
#include "splash.h"
#include "general.h"
#include "rbpaths.h"
#define LOGF_ENABLE
#include "logf.h"
@ -70,6 +70,15 @@ extern unsigned char codecbuf[];
static size_t codec_size;
extern void* plugin_get_audio_buffer(size_t *buffer_size);
#if (CONFIG_PLATFORM & PLATFORM_NATIVE) && defined(HAVE_RECORDING)
#undef open
static int open(const char* pathname, int flags, ...)
{
return file_open(pathname, flags);
}
#endif
struct codec_api ci = {
0, /* filesize */
@ -88,8 +97,7 @@ struct codec_api ci = {
NULL, /* set_offset */
NULL, /* configure */
NULL, /* get_command */
NULL, /* loop_track */
/* kernel/ system */
#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE
__div0,
@ -106,9 +114,8 @@ struct codec_api ci = {
semaphore_release,
#endif
commit_dcache,
commit_discard_dcache,
commit_discard_idcache,
cpucache_flush,
cpucache_invalidate,
/* strings and memory */
strcpy,
@ -120,6 +127,7 @@ struct codec_api ci = {
memmove,
memcmp,
memchr,
strcasestr,
#if defined(DEBUG) || defined(SIMULATOR)
debugf,
#endif
@ -127,7 +135,8 @@ struct codec_api ci = {
logf,
#endif
(void *)qsort,
(qsort_func)qsort,
&global_settings,
#ifdef RB_PROFILE
profile_thread,
@ -137,19 +146,25 @@ struct codec_api ci = {
#endif
#ifdef HAVE_RECORDING
NULL, /* enc_pcmbuf_read */
NULL, /* enc_pcmbuf_advance */
NULL, /* enc_encbuf_get_buffer */
NULL, /* enc_encbuf_finish_buffer */
NULL, /* enc_stream_read */
NULL, /* enc_stream_lseek */
NULL, /* enc_stream_write */
enc_get_inputs,
enc_set_parameters,
enc_get_chunk,
enc_finish_chunk,
enc_get_pcm_data,
enc_unget_pcm_data,
/* file */
(open_func)PREFIX(open),
PREFIX(close),
(read_func)PREFIX(read),
PREFIX(lseek),
(write_func)PREFIX(write),
round_value_to_list32,
#endif /* HAVE_RECORDING */
/* new stuff at the end, sort into place next time
the API gets incompatible */
};
void codec_get_full_path(char *path, const char *codec_root_fn)
@ -203,9 +218,8 @@ static int codec_load_ram(struct codec_api *api)
return CODEC_ERROR;
}
if (hdr->api_version != CODEC_API_VERSION ||
c_hdr->api_size > sizeof(struct codec_api))
{
if (hdr->api_version > CODEC_API_VERSION
|| hdr->api_version < CODEC_MIN_API_VERSION) {
logf("codec api version error");
lc_close(curr_handle);
curr_handle = NULL;
@ -283,16 +297,3 @@ int codec_close(void)
return status;
}
#ifdef HAVE_RECORDING
enc_callback_t codec_get_enc_callback(void)
{
if (curr_handle == NULL ||
c_hdr->lc_hdr.magic != CODEC_ENC_MAGIC) {
logf("Codec: not an encoder");
return NULL;
}
return c_hdr->rec_extension[0];
}
#endif /* HAVE_RECORDING */

View file

@ -22,30 +22,33 @@
#define _CODECS_H_
/* instruct simulator code to not redefine any symbols when compiling codecs.
(the CODEC macro is defined in codecs.make) */
(the CODEC macro is defined in apps/codecs/Makefile) */
#ifdef CODEC
#define NO_REDEFINES_PLEASE
#endif
#include "rbcodecconfig.h"
#include <stdbool.h>
#include <stdlib.h>
#include "strlcpy.h"
#include "config.h"
#include "system.h"
#include "metadata.h"
#include "audio.h"
#ifdef RB_PROFILE
#include "profile.h"
#include "thread.h"
#endif
#if (CONFIG_CODEC == SWCODEC)
#ifdef HAVE_RECORDING
#include "enc_base.h"
#include "pcm_record.h"
#endif
#include "dsp_core.h"
#include "dsp_misc.h"
#include "dsp-util.h"
#include "dsp.h"
#endif
#include "settings.h"
#include "gcc_extensions.h"
#include "load_code.h"
#include <limits.h>
#ifdef CODEC
#if defined(DEBUG) || defined(SIMULATOR)
#undef DEBUGF
@ -71,12 +74,13 @@
/* magic for encoder codecs */
#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
/*
* Increment this whenever a change breaks the codec ABI,
* when this happens please take the opportunity to sort in
* any new functions "waiting" at the end of the list.
*/
#define CODEC_API_VERSION 50
/* increase this every time the api struct changes */
#define CODEC_API_VERSION 42
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
#define CODEC_MIN_API_VERSION 42
/* reasons for calling codec main entrypoint */
enum codec_entry_call_reason {
@ -95,11 +99,6 @@ enum codec_command_action {
CODEC_ACTION_HALT = -1,
CODEC_ACTION_NULL = 0,
CODEC_ACTION_SEEK_TIME = 1,
#ifdef HAVE_RECORDING
CODEC_ACTION_STREAM_FINISH = 2,
#endif
CODEC_ACTION_MIN = LONG_MIN,
CODEC_ACTION_MAX = LONG_MAX,
};
/* NOTE: To support backwards compatibility, only add new functions at
@ -111,13 +110,13 @@ enum codec_command_action {
struct codec_api {
off_t filesize; /* Total file length */
off_t curpos; /* Current buffer position */
struct mp3entry *id3; /* TAG metadata pointer */
int audio_hid; /* Current audio handle */
/* The dsp instance to be used for audio output */
struct dsp_config *dsp;
/* Returns buffer to malloc array. Only codeclib should need this. */
void* (*codec_get_buffer)(size_t *size);
/* Insert PCM data into audio buffer for playback. Playback will start
@ -125,7 +124,7 @@ struct codec_api {
void (*pcmbuf_insert)(const void *ch1, const void *ch2, int count);
/* Set song position in WPS (value in ms). */
void (*set_elapsed)(unsigned long value);
/* Read next <size> amount bytes from file buffer to <ptr>.
Will return number of bytes read or 0 if end of file. */
size_t (*read_filebuf)(void *ptr, size_t size);
@ -145,9 +144,7 @@ struct codec_api {
/* Configure different codec buffer parameters. */
void (*configure)(int setting, intptr_t value);
/* Obtain command action on what to do next */
long (*get_command)(intptr_t *param);
/* Determine whether the track should be looped, if applicable. */
bool (*loop_track)(void);
enum codec_command_action (*get_command)(intptr_t *param);
/* kernel/ system */
#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE
@ -170,9 +167,8 @@ struct codec_api {
void (*semaphore_release)(struct semaphore *s);
#endif /* NUM_CORES */
void (*commit_dcache)(void);
void (*commit_discard_dcache)(void);
void (*commit_discard_idcache)(void);
void (*cpucache_flush)(void);
void (*cpucache_invalidate)(void);
/* strings and memory */
char* (*strcpy)(char *dst, const char *src);
@ -184,6 +180,7 @@ struct codec_api {
void* (*memmove)(void *out, const void *in, size_t n);
int (*memcmp)(const void *s1, const void *s2, size_t n);
void *(*memchr)(const void *s1, int c, size_t n);
char *(*strcasestr) (const char* phaystack, const char* pneedle);
#if defined(DEBUG) || defined(SIMULATOR)
void (*debugf)(const char *fmt, ...) ATTRIBUTE_PRINTF(1, 2);
@ -196,26 +193,35 @@ struct codec_api {
void (*qsort)(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *));
/* The ADX codec accesses global_settings to test for REPEAT_ONE mode */
struct user_settings* global_settings;
#ifdef RB_PROFILE
void (*profile_thread)(void);
void (*profstop)(void);
void (*profile_func_enter)(void *this_fn, void *call_site);
void (*profile_func_exit)(void *this_fn, void *call_site);
#endif
#ifdef HAVE_RECORDING
int (*enc_pcmbuf_read)(void *buf, int count);
int (*enc_pcmbuf_advance)(int count);
struct enc_chunk_data * (*enc_encbuf_get_buffer)(size_t need);
void (*enc_encbuf_finish_buffer)(void);
ssize_t (*enc_stream_read)(void *buf, size_t count);
off_t (*enc_stream_lseek)(off_t offset, int whence);
ssize_t (*enc_stream_write)(const void *buf, size_t count);
void (*enc_get_inputs)(struct enc_inputs *inputs);
void (*enc_set_parameters)(struct enc_parameters *params);
struct enc_chunk_hdr * (*enc_get_chunk)(void);
void (*enc_finish_chunk)(void);
unsigned char * (*enc_get_pcm_data)(size_t size);
size_t (*enc_unget_pcm_data)(size_t size);
/* file */
int (*open)(const char* pathname, int flags, ...);
int (*close)(int fd);
ssize_t (*read)(int fd, void* buf, size_t count);
off_t (*lseek)(int fd, off_t offset, int whence);
ssize_t (*write)(int fd, const void* buf, size_t count);
int (*round_value_to_list32)(unsigned long value,
const unsigned long list[],
int count,
bool signd);
#endif /* HAVE_RECORDING */
#endif
/* new stuff at the end, sort into place next time
the API gets incompatible */
@ -227,8 +233,6 @@ struct codec_header {
enum codec_status(*entry_point)(enum codec_entry_call_reason reason);
enum codec_status(*run_proc)(void);
struct codec_api **api;
size_t api_size;
void * rec_extension[]; /* extension for encoders */
};
#ifdef CODEC
@ -241,16 +245,15 @@ extern unsigned char plugin_end_addr[];
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
{ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
plugin_start_addr, plugin_end_addr }, \
codec_start, codec_run, &ci, sizeof(struct codec_api) };
plugin_start_addr, plugin_end_addr }, codec_start, \
codec_run, &ci };
/* encoders */
#define CODEC_ENC_HEADER \
const struct codec_header __header \
__attribute__ ((section (".header")))= { \
{ CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
plugin_start_addr, plugin_end_addr }, \
codec_start, codec_run, &ci, sizeof(struct codec_api), \
{ enc_callback } };
plugin_start_addr, plugin_end_addr }, codec_start, \
codec_run, &ci };
#else /* def SIMULATOR */
/* decoders */
@ -258,14 +261,12 @@ extern unsigned char plugin_end_addr[];
const struct codec_header __header \
__attribute__((visibility("default"))) = { \
{ CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
codec_start, codec_run, &ci, sizeof(struct codec_api) };
codec_start, codec_run, &ci };
/* encoders */
#define CODEC_ENC_HEADER \
const struct codec_header __header \
__attribute__((visibility("default"))) = { \
const struct codec_header __header = { \
{ CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
codec_start, codec_run, &ci, sizeof(struct codec_api), \
{ enc_callback } };
codec_start, codec_run, &ci };
#endif /* SIMULATOR */
#endif /* CODEC */
@ -280,19 +281,11 @@ void *codec_get_buffer_callback(size_t *size);
int codec_load_buf(int hid, struct codec_api *api);
int codec_load_file(const char* codec, struct codec_api *api);
int codec_run_proc(void);
int codec_halt(void);
int codec_close(void);
#if defined(HAVE_RECORDING)
enc_callback_t codec_get_enc_callback(void);
#endif
/* defined by the codec */
enum codec_status codec_start(enum codec_entry_call_reason reason);
enum codec_status codec_main(enum codec_entry_call_reason reason);
enum codec_status codec_run(void);
#if defined(HAVE_RECORDING)
int enc_callback(enum enc_callback_reason reason, void *params);
#else
#define codec_get_enc_callback() NULL
#endif
#endif /* _CODECS_H_ */

46
apps/codecs/SOURCES Normal file
View file

@ -0,0 +1,46 @@
/* decoders */
vorbis.c
mpa.c
flac.c
wav.c
a52.c
wavpack.c
#ifndef RB_PROFILE
alac.c
#endif
cook.c
raac.c
a52_rm.c
atrac3_rm.c
atrac3_oma.c
mpc.c
wma.c
sid.c
ape.c
nsf.c
asap.c
aac.c
spc.c
mod.c
shorten.c
aiff.c
speex.c
adx.c
smaf.c
au.c
vox.c
wav64.c
tta.c
wmapro.c
#ifdef HAVE_RECORDING
/* encoders */
aiff_enc.c
mp3_enc.c
wav_enc.c
wavpack_enc.c
#endif /* HAVE_RECORDING */

190
apps/codecs/a52.c Normal file
View file

@ -0,0 +1,190 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Dave Chapman
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "codeclib.h"
#include <inttypes.h> /* Needed by a52.h */
#include <codecs/liba52/config-a52.h>
#include <codecs/liba52/a52.h>
CODEC_HEADER
#define BUFFER_SIZE 4096
#define A52_SAMPLESPERFRAME (6*256)
static a52_state_t *state;
static unsigned long samplesdone;
static unsigned long frequency;
/* used outside liba52 */
static uint8_t buf[3840] IBSS_ATTR;
static inline void output_audio(sample_t *samples)
{
ci->yield();
ci->pcmbuf_insert(&samples[0], &samples[256], 256);
}
static void a52_decode_data(uint8_t *start, uint8_t *end)
{
static uint8_t *bufptr = buf;
static uint8_t *bufpos = buf + 7;
/*
* sample_rate and flags are static because this routine could
* exit between the a52_syncinfo() and the ao_setup(), and we want
* to have the same values when we get back !
*/
static int sample_rate;
static int flags;
int bit_rate;
int len;
while (1) {
len = end - start;
if (!len)
break;
if (len > bufpos - bufptr)
len = bufpos - bufptr;
memcpy(bufptr, start, len);
bufptr += len;
start += len;
if (bufptr == bufpos) {
if (bufpos == buf + 7) {
int length;
length = a52_syncinfo(buf, &flags, &sample_rate, &bit_rate);
if (!length) {
//DEBUGF("skip\n");
for (bufptr = buf; bufptr < buf + 6; bufptr++)
bufptr[0] = bufptr[1];
continue;
}
bufpos = buf + length;
} else {
/* Unity gain is 1 << 26, and we want to end up on 28 bits
of precision instead of the default 30.
*/
level_t level = 1 << 24;
sample_t bias = 0;
int i;
/* This is the configuration for the downmixing: */
flags = A52_STEREO | A52_ADJUST_LEVEL;
if (a52_frame(state, buf, &flags, &level, bias))
goto error;
a52_dynrng(state, NULL, NULL);
frequency = sample_rate;
/* An A52 frame consists of 6 blocks of 256 samples
So we decode and output them one block at a time */
for (i = 0; i < 6; i++) {
if (a52_block(state))
goto error;
output_audio(a52_samples(state));
samplesdone += 256;
}
ci->set_elapsed(samplesdone/(frequency/1000));
bufptr = buf;
bufpos = buf + 7;
continue;
error:
//logf("Error decoding A52 stream\n");
bufptr = buf;
bufpos = buf + 7;
}
}
}
}
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
}
else if (reason == CODEC_UNLOAD) {
if (state)
a52_free(state);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
size_t n;
unsigned char *filebuf;
int sample_loc;
intptr_t param;
if (codec_init())
return CODEC_ERROR;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
codec_set_replaygain(ci->id3);
/* Intialise the A52 decoder and check for success */
state = a52_init(0);
/* The main decoding loop */
if (ci->id3->offset) {
if (ci->seek_buffer(ci->id3->offset)) {
samplesdone = (ci->id3->offset / ci->id3->bytesperframe) *
A52_SAMPLESPERFRAME;
ci->set_elapsed(samplesdone/(ci->id3->frequency / 1000));
}
}
else {
ci->seek_buffer(ci->id3->first_frame_offset);
samplesdone = 0;
}
while (1) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
sample_loc = param/1000 * ci->id3->frequency;
if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) {
samplesdone = sample_loc;
ci->set_elapsed(samplesdone/(ci->id3->frequency/1000));
}
ci->seek_complete();
}
filebuf = ci->request_buffer(&n, BUFFER_SIZE);
if (n == 0) /* End of Stream */
break;
a52_decode_data(filebuf, filebuf + n);
ci->advance_buffer(n);
}
return CODEC_OK;
}

224
apps/codecs/a52_rm.c Normal file
View file

@ -0,0 +1,224 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2009 Mohamed Tarek
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "codeclib.h"
#include <codecs/librm/rm.h>
#include <inttypes.h> /* Needed by a52.h */
#include <codecs/liba52/config-a52.h>
#include <codecs/liba52/a52.h>
CODEC_HEADER
#define BUFFER_SIZE 4096
#define A52_SAMPLESPERFRAME (6*256)
static a52_state_t *state;
static unsigned long samplesdone;
static unsigned long frequency;
static RMContext rmctx;
static RMPacket pkt;
static void init_rm(RMContext *rmctx)
{
memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext));
}
/* used outside liba52 */
static uint8_t buf[3840] IBSS_ATTR;
/* The following two functions, a52_decode_data and output_audio are taken from apps/codecs/a52.c */
static inline void output_audio(sample_t *samples)
{
ci->yield();
ci->pcmbuf_insert(&samples[0], &samples[256], 256);
}
static void a52_decode_data(uint8_t *start, uint8_t *end)
{
static uint8_t *bufptr = buf;
static uint8_t *bufpos = buf + 7;
/*
* sample_rate and flags are static because this routine could
* exit between the a52_syncinfo() and the ao_setup(), and we want
* to have the same values when we get back !
*/
static int sample_rate;
static int flags;
int bit_rate;
int len;
while (1) {
len = end - start;
if (!len)
break;
if (len > bufpos - bufptr)
len = bufpos - bufptr;
memcpy(bufptr, start, len);
bufptr += len;
start += len;
if (bufptr == bufpos) {
if (bufpos == buf + 7) {
int length;
length = a52_syncinfo(buf, &flags, &sample_rate, &bit_rate);
if (!length) {
//DEBUGF("skip\n");
for (bufptr = buf; bufptr < buf + 6; bufptr++)
bufptr[0] = bufptr[1];
continue;
}
bufpos = buf + length;
} else {
/* Unity gain is 1 << 26, and we want to end up on 28 bits
of precision instead of the default 30.
*/
level_t level = 1 << 24;
sample_t bias = 0;
int i;
/* This is the configuration for the downmixing: */
flags = A52_STEREO | A52_ADJUST_LEVEL;
if (a52_frame(state, buf, &flags, &level, bias))
goto error;
a52_dynrng(state, NULL, NULL);
frequency = sample_rate;
/* An A52 frame consists of 6 blocks of 256 samples
So we decode and output them one block at a time */
for (i = 0; i < 6; i++) {
if (a52_block(state))
goto error;
output_audio(a52_samples(state));
samplesdone += 256;
}
ci->set_elapsed(samplesdone/(frequency/1000));
bufptr = buf;
bufpos = buf + 7;
continue;
error:
//logf("Error decoding A52 stream\n");
bufptr = buf;
bufpos = buf + 7;
}
}
}
}
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
}
else if (reason == CODEC_UNLOAD) {
if (state)
a52_free(state);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
size_t n;
uint8_t *filebuf;
int consumed, packet_offset;
int playback_on = -1;
size_t resume_offset;
intptr_t param;
enum codec_command_action action = CODEC_ACTION_NULL;
if (codec_init()) {
return CODEC_ERROR;
}
resume_offset = ci->id3->offset;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
codec_set_replaygain(ci->id3);
ci->seek_buffer(ci->id3->first_frame_offset);
/* Intializations */
state = a52_init(0);
ci->memset(&rmctx,0,sizeof(RMContext));
ci->memset(&pkt,0,sizeof(RMPacket));
init_rm(&rmctx);
/* check for a mid-track resume and force a seek time accordingly */
if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) {
resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
/* put number of subpackets to skip in resume_offset */
resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
action = CODEC_ACTION_SEEK_TIME;
}
else {
/* Seek to the first packet */
ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
}
/* The main decoding loop */
while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) {
if (action == CODEC_ACTION_NULL)
action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
if (action == CODEC_ACTION_SEEK_TIME) {
packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate);
ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE +
packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE));
rmctx.audio_pkt_cnt = packet_offset;
samplesdone = (rmctx.sample_rate/1000 * param);
ci->set_elapsed(samplesdone/(frequency/1000));
ci->seek_complete();
}
action = CODEC_ACTION_NULL;
filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE);
consumed = rm_get_packet(&filebuf, &rmctx, &pkt);
if(consumed < 0 && playback_on != 0) {
if(playback_on == -1) {
/* Error only if packet-parsing failed and playback hadn't started */
DEBUGF("rm_get_packet failed\n");
return CODEC_ERROR;
}
else {
break;
}
}
playback_on = 1;
a52_decode_data(filebuf, filebuf + rmctx.block_align);
ci->advance_buffer(pkt.length);
}
return CODEC_OK;
}

295
apps/codecs/aac.c Normal file
View file

@ -0,0 +1,295 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 Dave Chapman
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "codeclib.h"
#include "libm4a/m4a.h"
#include "libfaad/common.h"
#include "libfaad/structs.h"
#include "libfaad/decoder.h"
CODEC_HEADER
/* The maximum buffer size handled by faad. 12 bytes are required by libfaad
* as headroom (see libfaad/bits.c). FAAD_BYTE_BUFFER_SIZE bytes are buffered
* for each frame. */
#define FAAD_BYTE_BUFFER_SIZE (2048-12)
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
/* Note that when dealing with QuickTime/MPEG4 files, terminology is
* a bit confusing. Files with sound are split up in chunks, where
* each chunk contains one or more samples. Each sample in turn
* contains a number of "sound samples" (the kind you refer to with
* the sampling frequency).
*/
size_t n;
demux_res_t demux_res;
stream_t input_stream;
uint32_t sound_samples_done;
uint32_t elapsed_time;
int file_offset;
int framelength;
int lead_trim = 0;
unsigned int frame_samples;
unsigned int i;
unsigned char* buffer;
NeAACDecFrameInfo frame_info;
NeAACDecHandle decoder;
int err;
uint32_t seek_idx = 0;
uint32_t s = 0;
uint32_t sbr_fac = 1;
unsigned char c = 0;
void *ret;
intptr_t param;
bool empty_first_frame = false;
/* Clean and initialize decoder structures */
memset(&demux_res , 0, sizeof(demux_res));
if (codec_init()) {
LOGF("FAAD: Codec init error\n");
return CODEC_ERROR;
}
file_offset = ci->id3->offset;
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
codec_set_replaygain(ci->id3);
stream_create(&input_stream,ci);
ci->seek_buffer(ci->id3->first_frame_offset);
/* if qtmovie_read returns successfully, the stream is up to
* the movie data, which can be used directly by the decoder */
if (!qtmovie_read(&input_stream, &demux_res)) {
LOGF("FAAD: File init error\n");
return CODEC_ERROR;
}
/* initialise the sound converter */
decoder = NeAACDecOpen();
if (!decoder) {
LOGF("FAAD: Decode open error\n");
return CODEC_ERROR;
}
NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
conf->outputFormat = FAAD_FMT_24BIT; /* irrelevant, we don't convert */
NeAACDecSetConfiguration(decoder, conf);
err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c);
if (err) {
LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type);
return CODEC_ERROR;
}
#ifdef SBR_DEC
/* Check for need of special handling for seek/resume and elapsed time. */
if (ci->id3->needs_upsampling_correction) {
sbr_fac = 2;
} else {
sbr_fac = 1;
}
#endif
i = 0;
if (file_offset > 0) {
/* Resume the desired (byte) position. Important: When resuming SBR
* upsampling files the resulting sound_samples_done must be expanded
* by a factor of 2. This is done via using sbr_fac. */
if (m4a_seek_raw(&demux_res, &input_stream, file_offset,
&sound_samples_done, (int*) &i)) {
sound_samples_done *= sbr_fac;
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
ci->set_elapsed(elapsed_time);
} else {
sound_samples_done = 0;
}
NeAACDecPostSeekReset(decoder, i);
} else {
sound_samples_done = 0;
}
if (i == 0)
{
lead_trim = ci->id3->lead_trim;
}
/* The main decoding loop */
while (i < demux_res.num_sample_byte_sizes) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
/* Deal with any pending seek requests */
if (action == CODEC_ACTION_SEEK_TIME) {
/* Seek to the desired time position. Important: When seeking in SBR
* upsampling files the seek_time must be divided by 2 when calling
* m4a_seek and the resulting sound_samples_done must be expanded
* by a factor 2. This is done via using sbr_fac. */
if (m4a_seek(&demux_res, &input_stream,
(param/10/sbr_fac)*(ci->id3->frequency/100),
&sound_samples_done, (int*) &i)) {
sound_samples_done *= sbr_fac;
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
ci->set_elapsed(elapsed_time);
seek_idx = 0;
if (i == 0)
{
lead_trim = ci->id3->lead_trim;
}
}
NeAACDecPostSeekReset(decoder, i);
ci->seek_complete();
}
/* There can be gaps between chunks, so skip ahead if needed. It
* doesn't seem to happen much, but it probably means that a
* "proper" file can have chunks out of order. Why one would want
* that an good question (but files with gaps do exist, so who
* knows?), so we don't support that - for now, at least.
*/
file_offset = m4a_check_sample_offset(&demux_res, i, &seek_idx);
if (file_offset > ci->curpos)
{
ci->advance_buffer(file_offset - ci->curpos);
}
else if (file_offset == 0)
{
LOGF("AAC: get_sample_offset error\n");
return CODEC_ERROR;
}
/* Request the required number of bytes from the input buffer */
buffer=ci->request_buffer(&n, FAAD_BYTE_BUFFER_SIZE);
/* Decode one block - returned samples will be host-endian */
ret = NeAACDecDecode(decoder, &frame_info, buffer, n);
/* NeAACDecDecode may sometimes return NULL without setting error. */
if (ret == NULL || frame_info.error > 0) {
LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
return CODEC_ERROR;
}
/* Advance codec buffer (no need to call set_offset because of this) */
ci->advance_buffer(frame_info.bytesconsumed);
/* Output the audio */
ci->yield();
frame_samples = frame_info.samples >> 1;
if (empty_first_frame)
{
/* Remove the first frame from lead_trim, under the assumption
* that it had the same size as this frame
*/
empty_first_frame = false;
lead_trim -= frame_samples;
if (lead_trim < 0)
{
lead_trim = 0;
}
}
/* Gather number of samples for the decoded frame. */
framelength = frame_samples - lead_trim;
if (i == demux_res.num_sample_byte_sizes - 1)
{
// Size of the last frame
const uint32_t sample_duration = (demux_res.num_time_to_samples > 0) ?
demux_res.time_to_sample[demux_res.num_time_to_samples - 1].sample_duration :
frame_samples;
/* Currently limited to at most one frame of tail_trim.
* Seems to be enough.
*/
if (ci->id3->tail_trim == 0 && sample_duration < frame_samples)
{
/* Subtract lead_trim just in case we decode a file with only
* one audio frame with actual data (lead_trim is usually zero
* here).
*/
framelength = sample_duration - lead_trim;
}
else
{
framelength -= ci->id3->tail_trim;
}
}
if (framelength > 0)
{
ci->pcmbuf_insert(&decoder->time_out[0][lead_trim],
&decoder->time_out[1][lead_trim],
framelength);
sound_samples_done += framelength;
/* Update the elapsed-time indicator */
elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
ci->set_elapsed(elapsed_time);
}
if (lead_trim > 0)
{
/* frame_info.samples can be 0 for frame 0. We still want to
* remove it from lead_trim, so do that during frame 1.
*/
if (0 == i && 0 == frame_info.samples)
{
empty_first_frame = true;
}
lead_trim -= frame_samples;
if (lead_trim < 0)
{
lead_trim = 0;
}
}
++i;
}
LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done);
return CODEC_OK;
}

393
apps/codecs/adx.c Normal file
View file

@ -0,0 +1,393 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2006-2008 Adam Gashlin (hcs)
* Copyright (C) 2006 Jens Arnold
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <limits.h>
#include "codeclib.h"
#include "inttypes.h"
#include "math.h"
#include "lib/fixedpoint.h"
CODEC_HEADER
/* Maximum number of bytes to process in one iteration */
#define WAV_CHUNK_SIZE (1024*2)
/* Number of times to loop looped tracks when repeat is disabled */
#define LOOP_TIMES 2
/* Length of fade-out for looped tracks (milliseconds) */
#define FADE_LENGTH 10000L
/* Default high pass filter cutoff frequency is 500 Hz.
* Others can be set, but the default is nearly always used,
* and there is no way to determine if another was used, anyway.
*/
static const long cutoff = 500;
static int16_t samples[WAV_CHUNK_SIZE] IBSS_ATTR;
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
/* we only render 16 bits */
ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
int channels;
int sampleswritten, i;
uint8_t *buf;
int32_t ch1_1, ch1_2, ch2_1, ch2_2; /* ADPCM history */
size_t n;
int endofstream; /* end of stream flag */
uint32_t avgbytespersec;
int looping; /* looping flag */
int loop_count; /* number of loops done so far */
int fade_count; /* countdown for fadeout */
int fade_frames; /* length of fade in frames */
off_t start_adr, end_adr; /* loop points */
off_t chanstart, bufoff;
/*long coef1=0x7298L,coef2=-0x3350L;*/
long coef1, coef2;
intptr_t param;
DEBUGF("ADX: next_track\n");
if (codec_init()) {
return CODEC_ERROR;
}
DEBUGF("ADX: after init\n");
/* init history */
ch1_1=ch1_2=ch2_1=ch2_2=0;
codec_set_replaygain(ci->id3);
/* Get header */
DEBUGF("ADX: request initial buffer\n");
ci->seek_buffer(0);
buf = ci->request_buffer(&n, 0x38);
if (!buf || n < 0x38) {
return CODEC_ERROR;
}
bufoff = 0;
DEBUGF("ADX: read size = %lx\n",(unsigned long)n);
/* Get file header for starting offset, channel count */
chanstart = ((buf[2] << 8) | buf[3]) + 4;
channels = buf[7];
/* useful for seeking and reporting current playback position */
avgbytespersec = ci->id3->frequency * 18 * channels / 32;
DEBUGF("avgbytespersec=%ld\n",(unsigned long)avgbytespersec);
/* calculate filter coefficients */
/**
* A simple table of these coefficients would be nice, but
* some very odd frequencies are used and if I'm going to
* interpolate I might as well just go all the way and
* calclate them precisely.
* Speed is not an issue as this only needs to be done once per file.
*/
{
const int64_t big28 = 0x10000000LL;
const int64_t big32 = 0x100000000LL;
int64_t frequency = ci->id3->frequency;
int64_t phasemultiple = cutoff*big32/frequency;
long z;
int64_t a;
const int64_t b = (M_SQRT2*big28)-big28;
int64_t c;
int64_t d;
fp_sincos((unsigned long)phasemultiple,&z);
a = (M_SQRT2*big28) - (z >> 3);
/**
* In the long passed to fsqrt there are only 4 nonfractional bits,
* which is sufficient here, but this is the only reason why I don't
* use 32 fractional bits everywhere.
*/
d = fp_sqrt((a+b)*(a-b)/big28,28);
c = (a-d)*big28/b;
coef1 = (c*8192) >> 28;
coef2 = (c*c/big28*-4096) >> 28;
DEBUGF("ADX: samprate=%ld ",(long)frequency);
DEBUGF("coef1 %04x ",(unsigned int)(coef1*4));
DEBUGF("coef2 %04x\n",(unsigned int)(coef2*-4));
}
/* Get loop data */
looping = 0; start_adr = 0; end_adr = 0;
if (!memcmp(buf+0x10,"\x01\xF4\x03\x00",4)) {
/* Soul Calibur 2 style (type 03) */
DEBUGF("ADX: type 03 found\n");
/* check if header is too small for loop data */
if (chanstart-6 < 0x2c) looping=0;
else {
looping = (buf[0x18]) ||
(buf[0x19]) ||
(buf[0x1a]) ||
(buf[0x1b]);
end_adr = (buf[0x28]<<24) |
(buf[0x29]<<16) |
(buf[0x2a]<<8) |
(buf[0x2b]);
start_adr = (
(buf[0x1c]<<24) |
(buf[0x1d]<<16) |
(buf[0x1e]<<8) |
(buf[0x1f])
)/32*channels*18+chanstart;
}
} else if (!memcmp(buf+0x10,"\x01\xF4\x04\x00",4)) {
/* Standard (type 04) */
DEBUGF("ADX: type 04 found\n");
/* check if header is too small for loop data */
if (chanstart-6 < 0x38) looping=0;
else {
looping = (buf[0x24]) ||
(buf[0x25]) ||
(buf[0x26]) ||
(buf[0x27]);
end_adr = (buf[0x34]<<24) |
(buf[0x35]<<16) |
(buf[0x36]<<8) |
buf[0x37];
start_adr = (
(buf[0x28]<<24) |
(buf[0x29]<<16) |
(buf[0x2a]<<8) |
(buf[0x2b])
)/32*channels*18+chanstart;
}
} else {
DEBUGF("ADX: error, couldn't determine ADX type\n");
return CODEC_ERROR;
}
if (looping) {
DEBUGF("ADX: looped, start: %lx end: %lx\n",start_adr,end_adr);
} else {
DEBUGF("ADX: not looped\n");
}
/* advance to first frame */
DEBUGF("ADX: first frame at %lx\n",chanstart);
bufoff = chanstart;
/* get in position */
ci->seek_buffer(bufoff);
/* setup pcm buffer format */
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
if (channels == 2) {
ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
} else if (channels == 1) {
ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
} else {
DEBUGF("ADX CODEC_ERROR: more than 2 channels\n");
return CODEC_ERROR;
}
endofstream = 0;
loop_count = 0;
fade_count = -1; /* disable fade */
fade_frames = 1;
/* The main decoder loop */
while (!endofstream) {
enum codec_command_action action = ci->get_command(&param);
if (action == CODEC_ACTION_HALT)
break;
/* do we need to loop? */
if (bufoff > end_adr-18*channels && looping) {
DEBUGF("ADX: loop!\n");
/* check for endless looping */
if (ci->global_settings->repeat_mode==REPEAT_ONE) {
loop_count=0;
fade_count = -1; /* disable fade */
} else {
/* otherwise start fade after LOOP_TIMES loops */
loop_count++;
if (loop_count >= LOOP_TIMES && fade_count < 0) {
/* frames to fade over */
fade_frames = FADE_LENGTH*ci->id3->frequency/32/1000;
/* volume relative to fade_frames */
fade_count = fade_frames;
DEBUGF("ADX: fade_frames = %d\n",fade_frames);
}
}
bufoff = start_adr;
ci->seek_buffer(bufoff);
}
/* do we need to seek? */
if (action == CODEC_ACTION_SEEK_TIME) {
uint32_t newpos;
DEBUGF("ADX: seek to %ldms\n", (long)param);
endofstream = 0;
loop_count = 0;
fade_count = -1; /* disable fade */
fade_frames = 1;
newpos = (((uint64_t)avgbytespersec*param)
/ (1000LL*18*channels))*(18*channels);
bufoff = chanstart + newpos;
while (bufoff > end_adr-18*channels) {
bufoff-=end_adr-start_adr;
loop_count++;
}
ci->seek_buffer(bufoff);
ci->seek_complete();
}
if (bufoff>ci->filesize-channels*18) break; /* End of stream */
sampleswritten=0;
while (
/* Is there data left in the file? */
(bufoff <= ci->filesize-(18*channels)) &&
/* Is there space in the output buffer? */
(sampleswritten <= WAV_CHUNK_SIZE-(32*channels)) &&
/* Should we be looping? */
((!looping) || bufoff <= end_adr-18*channels))
{
/* decode first/only channel */
int32_t scale;
int32_t ch1_0, d;
/* fetch a frame */
buf = ci->request_buffer(&n, 18);
if (!buf || n!=18) {
DEBUGF("ADX: couldn't get buffer at %lx\n",
bufoff);
return CODEC_ERROR;
}
scale = ((buf[0] << 8) | (buf[1])) +1;
for (i = 2; i < 18; i++)
{
d = (buf[i] >> 4) & 15;
if (d & 8) d-= 16;
ch1_0 = d*scale + ((coef1*ch1_1 + coef2*ch1_2) >> 12);
if (ch1_0 > 32767) ch1_0 = 32767;
else if (ch1_0 < -32768) ch1_0 = -32768;
samples[sampleswritten] = ch1_0;
sampleswritten+=channels;
ch1_2 = ch1_1; ch1_1 = ch1_0;
d = buf[i] & 15;
if (d & 8) d -= 16;
ch1_0 = d*scale + ((coef1*ch1_1 + coef2*ch1_2) >> 12);
if (ch1_0 > 32767) ch1_0 = 32767;
else if (ch1_0 < -32768) ch1_0 = -32768;
samples[sampleswritten] = ch1_0;
sampleswritten+=channels;
ch1_2 = ch1_1; ch1_1 = ch1_0;
}
bufoff+=18;
ci->advance_buffer(18);
if (channels == 2) {
/* decode second channel */
int32_t scale;
int32_t ch2_0, d;
buf = ci->request_buffer(&n, 18);
if (!buf || n!=18) {
DEBUGF("ADX: couldn't get buffer at %lx\n",
bufoff);
return CODEC_ERROR;
}
scale = ((buf[0] << 8)|(buf[1]))+1;
sampleswritten-=63;
for (i = 2; i < 18; i++)
{
d = (buf[i] >> 4) & 15;
if (d & 8) d-= 16;
ch2_0 = d*scale + ((coef1*ch2_1 + coef2*ch2_2) >> 12);
if (ch2_0 > 32767) ch2_0 = 32767;
else if (ch2_0 < -32768) ch2_0 = -32768;
samples[sampleswritten] = ch2_0;
sampleswritten+=2;
ch2_2 = ch2_1; ch2_1 = ch2_0;
d = buf[i] & 15;
if (d & 8) d -= 16;
ch2_0 = d*scale + ((coef1*ch2_1 + coef2*ch2_2) >> 12);
if (ch2_0 > 32767) ch2_0 = 32767;
else if (ch2_0 < -32768) ch2_0 = -32768;
samples[sampleswritten] = ch2_0;
sampleswritten+=2;
ch2_2 = ch2_1; ch2_1 = ch2_0;
}
bufoff+=18;
ci->advance_buffer(18);
sampleswritten--; /* go back to first channel's next sample */
}
if (fade_count>0) {
fade_count--;
for (i=0;i<(channels==1?32:64);i++) samples[sampleswritten-i-1]=
((int32_t)samples[sampleswritten-i-1])*fade_count/fade_frames;
if (fade_count==0) {endofstream=1; break;}
}
}
if (channels == 2)
sampleswritten >>= 1; /* make samples/channel */
ci->pcmbuf_insert(samples, NULL, sampleswritten);
ci->set_elapsed(
((end_adr-start_adr)*loop_count + bufoff-chanstart)*
1000LL/avgbytespersec);
}
return CODEC_OK;
}

348
apps/codecs/aiff.c Normal file
View file

@ -0,0 +1,348 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (c) 2005 Jvo Studer
* Copyright (c) 2009 Yoshihisa Uchida
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "codeclib.h"
#include "codecs/libpcm/support_formats.h"
CODEC_HEADER
#define FOURCC(c1, c2, c3, c4) \
((((uint32_t)c1)<<24)|(((uint32_t)c2)<<16)|(((uint32_t)c3)<<8)|((uint32_t)c4))
/* This codec supports the following AIFC compressionType formats */
enum {
AIFC_FORMAT_PCM = FOURCC('N', 'O', 'N', 'E'), /* AIFC PCM Format (big endian) */
AIFC_FORMAT_ALAW = FOURCC('a', 'l', 'a', 'w'), /* AIFC ALaw compressed */
AIFC_FORMAT_MULAW = FOURCC('u', 'l', 'a', 'w'), /* AIFC uLaw compressed */
AIFC_FORMAT_IEEE_FLOAT32 = FOURCC('f', 'l', '3', '2'), /* AIFC IEEE float 32 bit */
AIFC_FORMAT_IEEE_FLOAT64 = FOURCC('f', 'l', '6', '4'), /* AIFC IEEE float 64 bit */
AIFC_FORMAT_QT_IMA_ADPCM = FOURCC('i', 'm', 'a', '4'), /* AIFC QuickTime IMA ADPCM */
};
static const struct pcm_entry pcm_codecs[] = {
{ AIFC_FORMAT_PCM, get_linear_pcm_codec },
{ AIFC_FORMAT_ALAW, get_itut_g711_alaw_codec },
{ AIFC_FORMAT_MULAW, get_itut_g711_mulaw_codec },
{ AIFC_FORMAT_IEEE_FLOAT32, get_ieee_float_codec },
{ AIFC_FORMAT_IEEE_FLOAT64, get_ieee_float_codec },
{ AIFC_FORMAT_QT_IMA_ADPCM, get_qt_ima_adpcm_codec },
};
#define PCM_SAMPLE_SIZE (1024*2)
static int32_t samples[PCM_SAMPLE_SIZE] IBSS_ATTR;
static const struct pcm_codec *get_codec(uint32_t formattag)
{
unsigned i;
for (i = 0; i < sizeof(pcm_codecs)/sizeof(pcm_codecs[0]); i++)
if (pcm_codecs[i].format_tag == formattag)
return pcm_codecs[i].get_codec();
return NULL;
}
/* this is the codec entry point */
enum codec_status codec_main(enum codec_entry_call_reason reason)
{
if (reason == CODEC_LOAD) {
/* Generic codec initialisation */
ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
}
return CODEC_OK;
}
/* this is called for each file to process */
enum codec_status codec_run(void)
{
struct pcm_format format;
uint32_t bytesdone, decodedsamples;
/* rockbox: comment 'set but unused' variables
uint32_t num_sample_frames = 0;
*/
size_t n;
int bufcount;
int endofstream;
unsigned char *buf;
uint8_t *aifbuf;
uint32_t offset2snd = 0;
off_t firstblockposn; /* position of the first block in file */
bool is_aifc = false;
const struct pcm_codec *codec;
uint32_t size;
intptr_t param;
if (codec_init()) {
return CODEC_ERROR;
}
codec_set_replaygain(ci->id3);
/* Need to save offset for later use (cleared indirectly by advance_buffer) */
bytesdone = ci->id3->offset;
/* assume the AIFF header is less than 1024 bytes */
ci->seek_buffer(0);
buf = ci->request_buffer(&n, 1024);
if (n < 54) {
return CODEC_ERROR;
}
if (memcmp(buf, "FORM", 4) != 0)
{
DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[0]);
return CODEC_ERROR;
}
if (memcmp(&buf[8], "AIFF", 4) == 0)
is_aifc = false;
else if (memcmp(&buf[8], "AIFC", 4) == 0)
is_aifc = true;
else
{
DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[8]);
return CODEC_ERROR;
}
buf += 12;
n -= 12;
ci->memset(&format, 0, sizeof(struct pcm_format));
format.is_signed = true;
format.is_little_endian = false;
decodedsamples = 0;
codec = 0;
/* read until 'SSND' chunk, which typically is last */
while (format.numbytes == 0 && n >= 8)
{
/* chunkSize */
size = ((buf[4]<<24)|(buf[5]<<16)|(buf[6]<<8)|buf[7]);
if (memcmp(buf, "COMM", 4) == 0) {
if ((!is_aifc && size < 18) || (is_aifc && size < 22))
{
DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu < %d\n",
(unsigned long)size, (is_aifc)?22:18);
return CODEC_ERROR;
}
/* num_channels */
format.channels = ((buf[8]<<8)|buf[9]);
/* num_sample_frames */
/*
num_sample_frames = ((buf[10]<<24)|(buf[11]<<16)|(buf[12]<<8)
|buf[13]);
*/
/* sample_size */
format.bitspersample = ((buf[14]<<8)|buf[15]);
/* sample_rate (don't use last 4 bytes, only integer fs) */
if (buf[16] != 0x40) {
DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n");
return CODEC_ERROR;
}
format.samplespersec = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1;
format.samplespersec >>= (16 + 14 - buf[17]);
/* compressionType (AIFC only) */
if (is_aifc)
{
format.formattag = (buf[26]<<24)|(buf[27]<<16)|(buf[28]<<8)|buf[29];
/*
* aiff's sample_size is uncompressed sound data size.
* But format.bitspersample is compressed sound data size.
*/
if (format.formattag == AIFC_FORMAT_ALAW ||
format.formattag == AIFC_FORMAT_MULAW)
format.bitspersample = 8;
else if (format.formattag == AIFC_FORMAT_QT_IMA_ADPCM)
format.bitspersample = 4;
}
else
format.formattag = AIFC_FORMAT_PCM;
/* calc average bytes per second */
format.avgbytespersec = format.samplespersec*format.channels*format.bitspersample/8;
} else if (memcmp(buf, "SSND", 4)==0) {
if (format.bitspersample == 0) {
DEBUGF("CODEC_ERROR: unsupported chunk order\n");
return CODEC_ERROR;
}
/* offset2snd */
offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11];
/* block_size */
format.blockalign = ((buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15]) >> 3;
if (format.blockalign == 0)
format.blockalign = format.channels * format.bitspersample >> 3;
format.numbytes = size - 8 - offset2snd;
size = 8 + offset2snd; /* advance to the beginning of data */
} else if (is_aifc && (memcmp(buf, "FVER", 4)==0)) {
/* Format Version Chunk (AIFC only chunk) */
/* skip this chunk */
} else {
DEBUGF("unsupported AIFF chunk: '%c%c%c%c', size=%lu\n",
buf[0], buf[1], buf[2], buf[3], (unsigned long)size);
}