| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 
 | /** \page decoder_api Decoder API
\section decoder_api_introduction Introduction
This document is intended to make it easier to add support for new file
formats to MOC.  It documents the requirements of decoder plugins and
some useful functions.  It also says how to start.
\section decoder_plugin_idea The idea
Each file format is supported by code in a plugin.  It's something similar to
plugins in popular audio players like XMMS with exception that there is no
separate library and dedicated header files to build such a plugin.  It means
that to create a plugin you need to add it to MOC's source directory.  It
will be built with the program and a file named like my_plugin.so will be
created and placed in the plugin directory during installation.
So why plugins?  The idea is to avoid the dependency of the mocp binary on
various libraries used just to support some exotic formats.  If a plugin
with an unresolved dependency is found at startup it's just not loaded.
\section decoder_plugin_how_to_add_source How to add the plugin code
Let's create a plugin named myplug.  First create a directory in the
decoder_plugins directory named myplug; you will place the sources there.
Let's have 2 source files: myplug1.c and myplug2.c in your plugin's directory.
Now you must create a Makefile.am file there that contains the following lines:
\code
lib_LTLIBRARIES = libmyplug_decoder.la
libdir = $(plugindir)/$(DECODER_PLUGIN_DIR)
libmyplug_decoder_la_LDFLAGS = @PLUGIN_LDFLAGS@
libmyplug_decoder_la_LIBADD = $(MYPLUG_LIBS)
libmyplug_decoder_la_CFLAGS = $(MYPLUG_CFLAGS) -I$(top_srcdir)
libmyplug_decoder_la_SOURCES = myplug1.c myplug2.c
\endcode
Next you have to tell the build system to include your newly created directory
by editting the file Makefile.am in the decoder_plugins directory.  You'll
see plenty of examples there, but your new entry will look like this:
\code
if BUILD_myplug
    SUBDIRS += myplug
endif
\endcode
Almost done, now the hard part.  As you may have already noticed,
the code in Makefile.am uses two useful variables: MYPLUG_CFLAGS and
MYPLUG_LIBS.  They contain additional compiler and linker flags used to
compile your plugin.  They are set by the configure script.  You must
include a configure script fragment (myplug.m4 in this case) in your
myplug directory and modify decoder_plugins/decoders.m4 to include it.
The fragment needs to detect libraries and compiler flags needed to
build the plugin, add myplug to the DECODER_PLUGINS variable and set
things up so the plugin can be built.  As an example, let's look at the
code detecting libFLAC which is using an autoconf macro provided by the
FLAC library and is very simple:
\code
AC_ARG_WITH(flac, AS_HELP_STRING([--without-flac],
                                 [Compile without FLAC support]))
if test "x$with_flac" != "xno"
then
    AM_PATH_LIBFLAC([AC_SUBST(LIBFLAC_LIBS)
                     AC_SUBST(LIBFLAC_CFLAGS)
                     $want_flac="yes"
                     DECODER_PLUGINS="$DECODER_PLUGINS flac"])
fi
AM_CONDITIONAL([BUILD_flac], [test "$want_flac"])
AC_CONFIG_FILES([decoder_plugins/flac/Makefile])
\endcode
If your decoder uses packages which don't have pkg-config configurations,
you can use something like this:
\code
AC_ARG_WITH(myplug, AS_HELP_STRING([--without-myplug],
                                   [Compile without MyPlug support]))
if test "x$with_myplug" != "xno"
then
    AC_CHECK_LIB(required_library, SomeFunction, [myplug_OK="yes"])
    if test "x$myplug_OK" = "xyes"
    then
        MYPLUG_LIBS='-lrequired_library'
        AC_SUBST(MYPLUG_LIBS)
        MYPLUG_CFLAGS='-I/usr/include/required_library_includes'
        AC_SUBST(MYPLUG_CFLAGS)
        $want_myplug="yes"
        DECODER_PLUGINS="$DECODER_PLUGINS myplug"
    fi
fi
AM_CONDITIONAL([BUILD_myplug], [test "$want_flac"])
AC_CONFIG_FILES([decoder_plugins/myplug/Makefile])
\endcode
In the absence of any library dependencies, this reduces to:
\code
AC_ARG_WITH(myplug, AS_HELP_STRING([--without-myplug],
                                   [Compile without MyPlug support]))
if test "x$with_myplug" != "xno"
then
    MYPLUG_LIBS='-lrequired_library'
    AC_SUBST(MYPLUG_LIBS)
    MYPLUG_CFLAGS='-I/usr/include/required_library_includes'
    AC_SUBST(MYPLUG_CFLAGS)
    $want_myplug="yes"
    DECODER_PLUGINS="$DECODER_PLUGINS myplug"
fi
AM_CONDITIONAL([BUILD_myplug], [test "$want_flac"])
AC_CONFIG_FILES([decoder_plugins/myplug/Makefile])
\endcode
Now you must recreate the configure script and all Makefile.in files:
run 'autoreconf [-i]' (it requires autoconf, automake and libtool -- the
newest versions of these tools are preferred; older versions may not work).
\section decoder_plugin_how_to_begin First code
The only public (not static) function that your plugin must contain is a
function named plugin_init.  It returns a structure (struct decoder) with
pointers to functions provided by the plugin.  Let's look at ogg's plugin
code:
\code
static struct decoder ogg_decoder = {
	DECODER_API_VERSION,
	ogg_open,
	ogg_open_stream,
	ogg_can_decode,
	ogg_close,
	ogg_decode,
	ogg_seek,
	ogg_info,
	ogg_get_bitrate,
	ogg_get_duration,
	ogg_get_error,
	ogg_our_format_ext,
	ogg_our_mime,
	ogg_get_name,
	ogg_current_tags,
	ogg_get_stream
};
struct decoder *plugin_init ()
{
	return &ogg_decoder;
}
\endcode
This is something that every plugin must have.
Also, the first lines of code in each C source file should be:
\code
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
\endcode
You may place comments above them (for example, containing copyright
information).
Includes you need are:
\verbatim
#include "main.h"     /* for xmalloc(), xstrdup() etc. */
#include "log.h"      /* for logit() and debug() */
#include "decoder.h"  /* required: provides decoder structure definition */
#include "io.h"       /* if you use io_*() functions to access files. */
#include "audio.h"    /* for sound_params structure */
\endverbatim
\section decoder_plugin_requirements Requirements
First thing you must remember is that your plugin is running in multi-thread
program.  When it is asked to open a file it must return a pointer to the
structure containing your private data.  This pointer will be passed to each
function associated with the stream.  You must not use any global or static
(in function) variables, because more than one file your plugin handles may
be open at a time (for example, when precaching).
When you operate on a file it is preferred (but not required) that you use
io_*() functions from io.h instead of standard open(), read(), write()
etc.  MOC's I/O functions provide sophisticated features: buffering in a
separate thread and reading from Internet streams.  They were made to
be used like standard UNIX input/output functions: they take similar
parameters and return similar values.
\section decoder_plugin_useful_api The API
Now it's time to read the documentation and find out what all that
functions must do and what functions you may use to achieve that.
\li \ref decoder
\li \ref decoder_error_funcs
For debugging purposes you may use two macros: debug() and logit() from log.h.
The first one does nothing if you don't define DEBUG before including log.h,
and works like logit() if you do.  logit() works like printf(), but it only
prints to the log file when the --debug command line option is used.
Also, logit() includes time and source file name of the
function name where it was invoked.  You don't need to add the end of line
character to make lines, each invocation of logit() makes a new line.
It is also preferred that you use xmalloc(), xrealloc(), xstrdup() functions
from common.h instead of those without x.  They check if allocation of memory
succeeds, so you don't need to do that.
\section decoder_plugin_useful_testing Testing and Debugging
There is a script in the 'tools' subdirectory which will help you to test
your decoder.  It checks that the samples which arrive at MOC's player
code are the same as those produced by the library the decoder is using.
It does this by having MOC compute the MD5 sum of the audio file as it is
playing it and writing the result to the server's log file.  The log file
is then read by the 'md5check.sh' tool and the MD5 sum checked against one
computed from the audio file using the library's native decoding program.
You will need to add a new function and case item to call it to the script
so it can recognise your new decoder's library.  It is important to use
the program associated with the decoder library if one exists because
other programs may not produce exactly the same samples, particularly
for lossy formats.  It is also possible that bugs in the library mean
the samples produced are not correct, but the tool is intended to test
the passage of the samples through the driver and not the fidelity of
the library used.
*/
 |