]> code.delx.au - pulseaudio/commitdiff
implement proper refcounting in polyplib
authorLennart Poettering <lennart@poettering.net>
Sat, 14 Aug 2004 20:25:32 +0000 (20:25 +0000)
committerLennart Poettering <lennart@poettering.net>
Sat, 14 Aug 2004 20:25:32 +0000 (20:25 +0000)
split polyplib to multiple modules
add some prelimenary documentation
add doxygen support

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@123 fefdeb5f-60dc-0310-8127-8f9354f1896f

45 files changed:
Makefile.am
configure.ac
doxygen/Makefile.am [new file with mode: 0644]
doxygen/doxygen.conf.in [new file with mode: 0644]
polyp/Makefile.am
polyp/cdecl.h [new file with mode: 0644]
polyp/glib-mainloop.h
polyp/llist.h [new file with mode: 0644]
polyp/mainloop-api.h
polyp/mainloop.h
polyp/memblock.c
polyp/memblock.h
polyp/native-common.h
polyp/pacat.c
polyp/pactl.c
polyp/polyplib-context.c
polyp/polyplib-context.h
polyp/polyplib-def.h
polyp/polyplib-error.h
polyp/polyplib-internal.h
polyp/polyplib-introspect.c
polyp/polyplib-introspect.h
polyp/polyplib-operation.c [new file with mode: 0644]
polyp/polyplib-operation.h [new file with mode: 0644]
polyp/polyplib-sample.c [deleted file]
polyp/polyplib-sample.h [deleted file]
polyp/polyplib-scache.c
polyp/polyplib-scache.h
polyp/polyplib-simple.c
polyp/polyplib-simple.h
polyp/polyplib-stream.c
polyp/polyplib-stream.h
polyp/polyplib-subscribe.c
polyp/polyplib-subscribe.h
polyp/polyplib.c [deleted file]
polyp/polyplib.h
polyp/sample-util.c
polyp/sample-util.h
polyp/sample.c
polyp/sample.h
polyp/socket-client.c
polyp/socket-client.h
polyp/tagstruct.h
polyp/xmalloc.c
polyp/xmalloc.h

index a54fd606a2021b7096fb1ec36ca9ae49f39a7df2..3fc81b40eed3175d814e6a8644ba8072b9fa4b50 100644 (file)
@@ -41,4 +41,7 @@ homepage: all dist
 distcleancheck:
        @:
 
-.PHONY: homepage distcleancheck
+doxygen:
+       $(MAKE) -C doxygen
+
+.PHONY: homepage distcleancheck doxygen
index 3183d1743e2f822974508bcef214aa5751d88214..b7766e4a62b40395af4e046ecf19480832792404 100644 (file)
@@ -84,5 +84,5 @@ AM_CONDITIONAL([USE_LYNX], [test "x$lynx" = xyes])
 
 AM_CONDITIONAL(BUILD_LIBPOLYPCORE, false)
 
-AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html])
+AC_CONFIG_FILES([Makefile polyp/Makefile polyplib.pc polyplib-simple.pc polyplib-mainloop.pc polyplib-error.pc doc/Makefile doc/README.html doc/cli.html doc/daemon.html doc/modules.html doxygen/Makefile doxygen/doxygen.conf])
 AC_OUTPUT
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
new file mode 100644 (file)
index 0000000..d2f508c
--- /dev/null
@@ -0,0 +1,11 @@
+# $Id$
+
+noinst_DATA=html
+
+html: doxygen.conf
+       doxygen $<
+
+clean-local:
+       rm -rf html
+
+.PHONY: all html
diff --git a/doxygen/doxygen.conf.in b/doxygen/doxygen.conf.in
new file mode 100644 (file)
index 0000000..78a4368
--- /dev/null
@@ -0,0 +1,1153 @@
+# Doxyfile 1.3.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = @PACKAGE_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = @PACKAGE_VERSION@
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = 
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
+# 4096 sub-directories (in 2 levels) under the output directory of each output 
+# format and will distribute the generated files over these directories. 
+# Enabling this option can be useful when feeding doxygen a huge amount of source 
+# files, where putting all generated files in the same directory would otherwise 
+# cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, 
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, 
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, 
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, 
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# This tag can be used to specify the encoding used in the generated output. 
+# The encoding is not always determined by the language that is chosen, 
+# but also whether or not the output is meant for Windows or non-Windows users. 
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES 
+# forces the Windows encoding (this is the default for the Windows binary), 
+# whereas setting the tag to NO uses a Unix-style encoding (the default for 
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING   = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator 
+# that is used to form the text in various listings. Each string 
+# in this list, if found as the leading text of the brief description, will be 
+# stripped from the text and the result after processing the whole list, is used 
+# as the annotated text. Otherwise, the brief description is used as-is. If left 
+# blank, the following values are used ("$name" is automatically replaced with the 
+# name of the entity): "The $name class" "The $name widget" "The $name file" 
+# "is" "provides" "specifies" "contains" "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       = 
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user-defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. The tag can be used to show relative paths in the file list. 
+# If left blank the directory from which doxygen is run is used as the 
+# path to strip.
+
+STRIP_FROM_PATH        = 
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
+# the path mentioned in the documentation of a class, which tells 
+# the reader which header file to include in order to use a class. 
+# If left blank only the name of the header file containing the class 
+# definition is used. Otherwise one should specify the include paths that 
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    = 
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments will behave just like the Qt-style comments (thus requiring an 
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user-defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance, some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance, namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
+# the same type (for instance a group of public functions) to be put as a 
+# subgroup of that type (e.g. under the Public Functions section). Set it to 
+# NO to prevent subgrouping. Alternatively, this can be done per class using 
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local 
+# methods, which are defined in the implementation section but not in 
+# the interface are included in the documentation. 
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these classes will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
+# documentation blocks found inside the body of a function. 
+# If set to NO (the default) these blocks will be appended to the 
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower-case letters. If set to YES upper-case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put a list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
+# brief documentation of file, namespace and class members alphabetically 
+# by member name. If set to NO (the default) the members will appear in 
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
+# sorted by fully-qualified names, including namespaces. If set to 
+# NO (the default), the class list will be sorted only by class name, 
+# not including the namespace part. 
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the 
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = NO
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = NO
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = NO
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting 
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= NO
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consists of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
+# potential errors in the documentation, such as not documenting some 
+# parameters in a documented function, or documenting parameters that 
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = ../polyp/polyplib-context.h ../polyp/polyplib-stream.h ../polyp/polyplib.h ../polyp/sample.h ../polyp/polyplib-def.h ../polyp/polyplib-subscribe.h ../polyp/polyplib-introspect.h ../polyp/polyplib-scache.h ../polyp/mainloop-api.h ../polyp/cdecl.h ../polyp/glib-mainloop.h ../polyp/mainloop.h ../polyp/mainloop-signal.h ../polyp/native-common.h ../polyp/polyplib-error.h ../polyp/polyplib-operation.h ../polyp/polyplib-simple.h
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS          = 
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = 
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
+# ignored.
+
+INPUT_FILTER           = 
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
+# basis.  Doxygen will compare the file name with each pattern and apply the 
+# filter if there is a match.  The filters are a list of the form: 
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
+# is applied to all files.
+
+FILTER_PATTERNS        = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources. 
+# Note: To get rid of all source code in the generated output, make sure also 
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet. Note that doxygen will try to copy 
+# the style sheet file to the HTML output directory, so don't put your own 
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output directory.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
+# include the index chapters (such as File Index, Compound Index, etc.) 
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimized for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assignments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
+# dump the program listings (including syntax highlighting 
+# and cross-referencing information) to the XML output. Note that 
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
+# generate a Perl module file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
+# nicely formatted so it can be parsed by a human reader.  This is useful 
+# if you want to understand what is going on.  On the other hand, if this 
+# tag is set to NO the size of the Perl module output will be much smaller 
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file 
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
+# This is useful so different doxyrules.make files included by the same 
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX = 
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = PA_C_DECL_BEGIN=,PA_C_DECL_END
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = PA_C_DECL_BEGIN, PA_C_DECL_END
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. 
+# Optionally an initial location of the external documentation 
+# can be added for each tagfile. The format of a tag file without 
+# this location is as follows: 
+#   TAGFILES = file1 file2 ... 
+# Adding location for the tag files is done as follows: 
+#   TAGFILES = file1=loc1 "file2 = loc2" ... 
+# where "loc1" and "loc2" can be relative or absolute paths or 
+# URLs. If a location is present for each tag, the installdox tool 
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen 
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superseded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
+# collaboration diagrams in a style similar to the OMG's Unified Modeling 
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will 
+# generate a call dependency graph for every global function or class method. 
+# Note that enabling this option will significantly increase the time of a run. 
+# So in most cases it will be better to enable call graphs for selected 
+# functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
+# graphs generated by dot. A depth value of 3 means that only nodes reachable 
+# from the root by following a path via at most 3 edges will be shown. Nodes that 
+# lay further from the root node will be omitted. Note that setting this option to 
+# 1 or 2 may greatly reduce the computation time needed for large code bases. Also 
+# note that a graph may be further truncated if the graph's image dimensions are 
+# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). 
+# If 0 is used for the depth value (the default), the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermediate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
index ce753da47459ebfc7a681df8538814223f8d8aef..7f70ec9d4d7a0bffaaf851e636d1f9f46ee3b1ca 100644 (file)
@@ -25,12 +25,19 @@ polypincludedir=$(includedir)/polyp
 
 EXTRA_DIST = polypaudio.pa depmod.py
 bin_PROGRAMS = polypaudio pacat pactl
-noinst_PROGRAMS = pacat-simple parec-simple mainloop-test mainloop-test-glib
+noinst_PROGRAMS = mainloop-test mainloop-test-glib pacat-simple parec-simple 
 
 polypinclude_HEADERS=polyplib.h \
                polyplib-def.h \
                polyplib-simple.h \
                polyplib-error.h \
+               polyplib-stream.h \
+               polyplib-context.h \
+               polyplib-introspect.h \
+               polyplib-subscribe.h \
+               polyplib-operation.h \
+               polyplib-scache.h \
+               cdecl.h \
                mainloop-api.h \
                mainloop.h \
                mainloop-signal.h \
@@ -72,10 +79,11 @@ pkglib_LTLIBRARIES=libiochannel.la \
                module-x11-bell.la
 
 lib_LTLIBRARIES=libpolyp.la \
-               libpolyp-simple.la \
                libpolyp-error.la \
                libpolyp-mainloop.la \
-               libpolyp-mainloop-glib.la
+               libpolyp-mainloop-glib.la \
+               libpolyp-simple.la
+
 
 polypaudio_SOURCES = idxset.c idxset.h \
                queue.c queue.h \
@@ -261,7 +269,7 @@ module_x11_bell_la_SOURCES = module-x11-bell.c
 module_x11_bell_la_LDFLAGS = -module -avoid-version
 module_x11_bell_la_LIBADD = $(AM_LIBADD) -lX11 -L/usr/X11R6/lib
 
-libpolyp_la_SOURCES = polyplib.c polyplib.h \
+libpolyp_la_SOURCES = polyplib.h \
                polyplib-def.h \
                tagstruct.c tagstruct.h \
                iochannel.c iochannel.h \
@@ -281,7 +289,14 @@ libpolyp_la_SOURCES = polyplib.c polyplib.h \
                socket-util.c socket-util.h \
                native-common.h \
                sample.c sample.h \
-               xmalloc.c xmalloc.h
+               xmalloc.c xmalloc.h \
+               polyplib-operation.c polyplib-operation.h \
+               polyplib-context.c polyplib-context.h \
+               polyplib-stream.c polyplib-stream.h \
+               polyplib-introspect.c polyplib-introspect.h \
+               polyplib-scache.c polyplib-scache.h \
+               polyplib-subscribe.c polyplib-subscribe.h \
+               cdecl.h
 libpolyp_la_CFLAGS = $(AM_CFLAGS)
 
 libpolyp_mainloop_la_SOURCES = mainloop-api.h mainloop-api.c \
diff --git a/polyp/cdecl.h b/polyp/cdecl.h
new file mode 100644 (file)
index 0000000..39880a4
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef foocdeclhfoo
+#define foocdeclhfoo
+
+/** \file
+ * C++ compatibility support */
+
+#ifdef __cplusplus
+/** If using C++ this macro enables C mode, otherwise does nothing */
+#define PA_C_DECL_BEGIN extern "C" {
+/** If using C++ this macros switches back to C++ mode, otherwise does nothing */
+#define PA_C_DECL_END }
+
+#else
+/** If using C++ this macro enables C mode, otherwise does nothing */
+#define PA_C_DECL_BEGIN
+/** If using C++ this macros switches back to C++ mode, otherwise does nothing */
+#define PA_C_DECL_END
+
+#endif
+
+#endif
index 7655108afaa34fbb6628c1e2ff571c4d797bf8c0..c67e72bd11b79710903a94ca28295b427a23a2b5 100644 (file)
@@ -4,20 +4,26 @@
 #include <glib.h>
 
 #include "mainloop-api.h"
+#include "cdecl.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+/** \file
+ * GLIB main loop support */
+
+PA_C_DECL_BEGIN
 
+/** \struct pa_glib_mainloop
+ * A GLIB main loop object */
 struct pa_glib_mainloop;
 
+/** Create a new GLIB main loop object for the specified GLIB main loop context. If c is NULL the default context is used. */
 struct pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c);
+
+/** Free the GLIB main loop object */
 void pa_glib_mainloop_free(struct pa_glib_mainloop* g);
+
+/** Return the abstract main loop API vtable for the GLIB main loop object */
 struct pa_mainloop_api* pa_glib_mainloop_get_api(struct pa_glib_mainloop *g);
 
-        
-#ifdef __cplusplus
-}
-#endif
+PA_C_DECL_BEGIN
 
 #endif
diff --git a/polyp/llist.h b/polyp/llist.h
new file mode 100644 (file)
index 0000000..1f145de
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef foollistfoo
+#define foollistfoo
+
+#define PA_LLIST_HEAD(t,name) t *name
+
+#define PA_LLIST_FIELDS(t) t *next, *prev;
+
+#define PA_LLIST_HEAD_INIT(t,item) do { (item) = NULL; } while(0)
+
+#define PA_LLIST_INIT(t,item) do { \
+                               t *_item = (item); \
+                               assert(_item); \
+                               _item->prev = _item->next = NULL; \
+                               } while(0)
+
+#define PA_LLIST_PREPEND(t,head,item) do { \
+                                        t **_head = &(head), *_item = (item); \
+                                        assert(_item); \
+                                        if ((_item->next = *_head)) \
+                                           _item->next->prev = _item; \
+                                        _item->prev = NULL; \
+                                        *_head = _item; \
+                                        } while (0)
+
+#define PA_LLIST_REMOVE(t,head,item) do { \
+                                    t **_head = &(head), *_item = (item); \
+                                    assert(_item); \
+                                    if (_item->next) \
+                                       _item->next->prev = _item->prev; \
+                                    if (_item->prev) \
+                                       _item->prev->next = _item->next; \
+                                    else {\
+                                       assert(*_head == _item); \
+                                       *_head = _item->next; \
+                                    } \
+                                    _item->next = _item->prev = NULL; \
+                                    } while(0)
+
+#endif
index 1b9e27836fe7a1064fb2b516fb89bc81cbcd4172..97ab6a68403c002ad4cd3bed485d24d65ca8c60a 100644 (file)
   USA.
 ***/
 
-#include <time.h>
 #include <sys/time.h>
+#include <time.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "cdecl.h"
 
+PA_C_DECL_BEGIN
+
+/** A bitmask for IO events */
 enum pa_io_event_flags {
-    PA_IO_EVENT_NULL = 0,
-    PA_IO_EVENT_INPUT = 1,
-    PA_IO_EVENT_OUTPUT = 2,
-    PA_IO_EVENT_HANGUP = 4,
-    PA_IO_EVENT_ERROR = 8,
+    PA_IO_EVENT_NULL = 0,     /**< No event */
+    PA_IO_EVENT_INPUT = 1,    /**< Input event */
+    PA_IO_EVENT_OUTPUT = 2,   /**< Output event */
+    PA_IO_EVENT_HANGUP = 4,   /**< Hangup event */
+    PA_IO_EVENT_ERROR = 8,    /**< Error event */
 };
 
+/** \struct pa_io_event
+ * An IO event source object */
 struct pa_io_event;
+
+/** \struct pa_defer_event
+ * A deferred event source object. Events of this type are triggered once in every main loop iteration */
 struct pa_defer_event;
+
+/** \struct pa_time_event
+ * A timer event source object */
 struct pa_time_event;
 
+/** An abstract mainloop API vtable */
 struct pa_mainloop_api {
+    /** A pointer to some private, arbitrary data of the main loop implementation */
     void *userdata;
 
     /* IO sources */
@@ -56,20 +67,25 @@ struct pa_mainloop_api {
     void (*time_free)(struct pa_time_event* e);
     void (*time_set_destroy)(struct pa_time_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_time_event *e, void *userdata));
 
-    /* Deferred sources */
+    /** Create a new deferred event source object */
     struct pa_defer_event* (*defer_new)(struct pa_mainloop_api*a, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event* e, void *userdata), void *userdata);
+
+    /** Enable or disable a deferred event source temporarily */
     void (*defer_enable)(struct pa_defer_event* e, int b);
+
+    /** Free a deferred event source object */
     void (*defer_free)(struct pa_defer_event* e);
+
+    /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */
     void (*defer_set_destroy)(struct pa_defer_event *e, void (*callback) (struct pa_mainloop_api*a, struct pa_defer_event *e, void *userdata));
 
-    /* Exit mainloop */
+    /** Exit the main loop and return the specfied retval*/
     void (*quit)(struct pa_mainloop_api*a, int retval);
 };
 
+/** Run the specified callback function once from the main loop using an anonymous defer event. */
 void pa_mainloop_api_once(struct pa_mainloop_api*m, void (*callback)(struct pa_mainloop_api*m, void *userdata), void *userdata);
 
-#ifdef __cplusplus
-}
-#endif
+PA_C_DECL_END
 
 #endif
index 58448c3eeafe15aba55e4b8b9c3431734f760d14..4a4c85dfac8b28b27b693fb0c0ef6034f488256d 100644 (file)
@@ -23,6 +23,9 @@
 ***/
 
 #include "mainloop-api.h"
+#include "cdecl.h"
+
+PA_C_DECL_BEGIN
 
 struct pa_mainloop;
 
@@ -34,4 +37,6 @@ int pa_mainloop_run(struct pa_mainloop *m, int *retval);
 
 struct pa_mainloop_api* pa_mainloop_get_api(struct pa_mainloop*m);
 
+PA_C_DECL_END
+
 #endif
index 0571f5dae87859137c18f6bb20cdbf764447a8f2..a4452efa4dabfc682ea01aa5f7f0d149dce8659f 100644 (file)
@@ -39,6 +39,7 @@ struct pa_memblock *pa_memblock_new(size_t length) {
     b->ref = 1;
     b->length = length;
     b->data = b+1;
+    b->free_cb = NULL;
     memblock_count++;
     memblock_total += length;
     return b;
@@ -50,6 +51,7 @@ struct pa_memblock *pa_memblock_new_fixed(void *d, size_t length) {
     b->ref = 1;
     b->length = length;
     b->data = d;
+    b->free_cb = NULL;
     memblock_count++;
     memblock_total += length;
     return b;
@@ -61,6 +63,21 @@ struct pa_memblock *pa_memblock_new_dynamic(void *d, size_t length) {
     b->ref = 1;
     b->length = length;
     b->data = d;
+    b->free_cb = NULL;
+    memblock_count++;
+    memblock_total += length;
+    return b;
+}
+
+struct pa_memblock *pa_memblock_new_user(void *d, size_t length, void (*free_cb)(void *p)) {
+    struct pa_memblock *b;
+    assert(d && length && free_cb);
+    b = pa_xmalloc(sizeof(struct pa_memblock));
+    b->type = PA_MEMBLOCK_USER;
+    b->ref = 1;
+    b->length = length;
+    b->data = d;
+    b->free_cb = free_cb;
     memblock_count++;
     memblock_total += length;
     return b;
@@ -74,31 +91,28 @@ struct pa_memblock* pa_memblock_ref(struct pa_memblock*b) {
 
 void pa_memblock_unref(struct pa_memblock*b) {
     assert(b && b->ref >= 1);
-    b->ref--;
-
-    if (b->ref == 0) {
-        if (b->type == PA_MEMBLOCK_DYNAMIC)
-            pa_xfree(b->data);
 
+    if ((--(b->ref)) == 0) {
         memblock_count--;
         memblock_total -= b->length;
 
+        if (b->type == PA_MEMBLOCK_USER) {
+            assert(b->free_cb);
+            b->free_cb(b->data);
+        } else if (b->type == PA_MEMBLOCK_DYNAMIC)
+            pa_xfree(b->data);
+
         pa_xfree(b);
     }
 }
 
 void pa_memblock_unref_fixed(struct pa_memblock *b) {
-    void *d;
-    
-    assert(b && b->ref >= 1);
+    assert(b && b->ref >= 1 && b->type == PA_MEMBLOCK_FIXED);
 
-    if (b->ref == 1) {
+    if (b->ref == 1)
         pa_memblock_unref(b);
-        return;
-    } else {
-        d = pa_xmalloc(b->length);
-        memcpy(d, b->data, b->length);
-        b->data = d;
+    else {
+        b->data = pa_xmemdup(b->data, b->length);
         b->type = PA_MEMBLOCK_DYNAMIC;
         b->ref--;
     }
index 4bb029774e3e7f4a0b35aec85cc5e570af53452e..6e79aa3ef4a21f9210ce1678a211249a4d4f0418 100644 (file)
 #include <sys/types.h>
 #include <inttypes.h>
 
-enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC };
+enum pa_memblock_type { PA_MEMBLOCK_FIXED, PA_MEMBLOCK_APPENDED, PA_MEMBLOCK_DYNAMIC, PA_MEMBLOCK_USER };
 
 struct pa_memblock {
     enum pa_memblock_type type;
     unsigned ref;
     size_t length;
     void *data;
+    void (*free_cb)(void *p);
 };
 
 struct pa_memblock *pa_memblock_new(size_t length);
 struct pa_memblock *pa_memblock_new_fixed(void *data, size_t length);
 struct pa_memblock *pa_memblock_new_dynamic(void *data, size_t length);
+struct pa_memblock *pa_memblock_new_user(void *data, size_t length, void (*free_cb)(void *p));
 
 void pa_memblock_unref(struct pa_memblock*b);
 struct pa_memblock* pa_memblock_ref(struct pa_memblock*b);
index 4d5ab53d75938a6e92af0a0603a1b70037575192..fa3213d0152c01907168357885841f3f9260c085 100644 (file)
@@ -64,6 +64,9 @@ enum {
 
     PA_COMMAND_SUBSCRIBE,
     PA_COMMAND_SUBSCRIBE_EVENT,
+
+    PA_COMMAND_SET_SINK_VOLUME,
+    PA_COMMAND_SET_SINK_INPUT_VOLUME,
     
     PA_COMMAND_MAX
 };
@@ -90,13 +93,14 @@ enum {
 #define PA_NATIVE_COOKIE_FILE ".polypaudio-cookie"
 
 enum pa_subscription_mask {
-    PA_SUBSCRIPTION_FACILITY_SINK = 1,
-    PA_SUBSCRIPTION_FACILITY_SOURCE = 2,
-    PA_SUBSCRIPTION_FACILITY_SINK_INPUT = 4,
-    PA_SUBSCRIPTION_FACILITY_SOURCE_OUTPUT = 8,
-    PA_SUBSCRIPTION_FACILITY_MODULE = 16,
-    PA_SUBSCRIPTION_FACILITY_CLIENT = 32,
-    PA_SUBSCRIPTION_FACILITY_SAMPLE_CACHE = 64,
+    PA_SUBSCRIPTION_MASK_NULL = 0,
+    PA_SUBSCRIPTION_MASK_SINK = 1,
+    PA_SUBSCRIPTION_MASK_SOURCE = 2,
+    PA_SUBSCRIPTION_MASK_SINK_INPUT = 4,
+    PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8,
+    PA_SUBSCRIPTION_MASK_MODULE = 16,
+    PA_SUBSCRIPTION_MASK_CLIENT = 32,
+    PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64,
 };
 
 enum pa_subscription_event_type {
index 4d8605c7a06e501dcc17a7ecb6abe798d13f3279..5d29451ae9a9d9a04401d79c67b670c7bef324e0 100644 (file)
@@ -52,18 +52,6 @@ static void quit(int ret) {
     mainloop_api->quit(mainloop_api, ret);
 }
 
-static void context_die_callback(struct pa_context *c, void *userdata) {
-    assert(c);
-    fprintf(stderr, "Connection to server shut down, exiting.\n");
-    quit(1);
-}
-
-static void stream_die_callback(struct pa_stream *s, void *userdata) {
-    assert(s);
-    fprintf(stderr, "Stream deleted, exiting.\n");
-    quit(1);
-}
-
 static void do_stream_write(size_t length) {
     size_t l;
     assert(length);
@@ -75,7 +63,7 @@ static void do_stream_write(size_t length) {
     if (l > buffer_length)
         l = buffer_length;
     
-    pa_stream_write(stream, buffer+buffer_index, l);
+    pa_stream_write(stream, buffer+buffer_index, l, NULL);
     buffer_length -= l;
     buffer_index += l;
     
@@ -115,63 +103,97 @@ static void stream_read_callback(struct pa_stream *s, const void*data, size_t le
     buffer_index = 0;
 }
 
-static void stream_complete_callback(struct pa_stream*s, int success, void *userdata) {
+static void stream_state_callback(struct pa_stream *s, void *userdata) {
     assert(s);
 
-    if (!success) {
-        fprintf(stderr, "Stream creation failed: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
-        quit(1);
-        return;
+    switch (pa_stream_get_state(s)) {
+        case PA_STREAM_CREATING:
+            break;
+
+        case PA_STREAM_READY:
+            fprintf(stderr, "Stream successfully created\n");
+            break;
+            
+        case PA_STREAM_TERMINATED:
+            quit(0);
+            break;
+            
+        case PA_STREAM_FAILED:
+        default:
+            fprintf(stderr, "Stream errror: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
+            quit(1);
     }
-
-    fprintf(stderr, "Stream created.\n");
 }
 
-static void context_complete_callback(struct pa_context *c, int success, void *userdata) {
+static void context_state_callback(struct pa_context *c, void *userdata) {
     static const struct pa_sample_spec ss = {
         .format = PA_SAMPLE_S16LE,
         .rate = 44100,
         .channels = 2
     };
-        
-    assert(c && !stream);
 
-    if (!success) {
-        fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c)));
-        goto fail;
-    }
+    assert(c);
 
-    fprintf(stderr, "Connection established.\n");
-    
-    if (!(stream = pa_stream_new(c, mode == PLAYBACK ? PA_STREAM_PLAYBACK : PA_STREAM_RECORD, NULL, "pacat", &ss, NULL, stream_complete_callback, NULL))) {
-        fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c)));
-        goto fail;
+    switch (pa_context_get_state(c)) {
+        case PA_CONTEXT_CONNECTING:
+        case PA_CONTEXT_AUTHORIZING:
+        case PA_CONTEXT_SETTING_NAME:
+            break;
+        
+        case PA_CONTEXT_READY:
+            
+            assert(c && !stream);
+            fprintf(stderr, "Connection established.\n");
+
+            stream = pa_stream_new(c, "pacat", &ss);
+            assert(stream);
+
+            pa_stream_set_state_callback(stream, stream_state_callback, NULL);
+            pa_stream_set_write_callback(stream, stream_write_callback, NULL);
+            pa_stream_set_read_callback(stream, stream_read_callback, NULL);
+
+            if (mode == PLAYBACK)
+                pa_stream_connect_playback(stream, NULL, NULL);
+            else
+                pa_stream_connect_record(stream, NULL, NULL);
+                
+            break;
+            
+        case PA_CONTEXT_TERMINATED:
+            quit(0);
+            break;
+
+        case PA_CONTEXT_FAILED:
+        default:
+            fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c)));
+            quit(1);
     }
-
-    pa_stream_set_die_callback(stream, stream_die_callback, NULL);
-    pa_stream_set_write_callback(stream, stream_write_callback, NULL);
-    pa_stream_set_read_callback(stream, stream_read_callback, NULL);
-    
-    return;
-    
-fail:
-    quit(1);
 }
 
 static void context_drain_complete(struct pa_context*c, void *userdata) {
-    quit(0);
+    pa_context_disconnect(c);
 }
 
-static void stream_drain_complete(struct pa_stream*s, void *userdata) {
+static void stream_drain_complete(struct pa_stream*s, int success, void *userdata) {
+    struct pa_operation *o;
+
+    if (!success) {
+        fprintf(stderr, "Failed to drain stream: %s\n", pa_strerror(pa_context_errno(context)));
+        quit(1);
+    }
+        
     fprintf(stderr, "Playback stream drained.\n");
 
-    pa_stream_free(stream);
+    pa_stream_disconnect(stream);
+    pa_stream_unref(stream);
     stream = NULL;
     
-    if (pa_context_drain(context, context_drain_complete, NULL) < 0)
-        quit(0);
-    else
+    if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
+        pa_context_disconnect(context);
+    else {
+        pa_operation_unref(o);
         fprintf(stderr, "Draining connection to server.\n");
+    }
 }
 
 static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) {
@@ -184,7 +206,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int
         return;
     }
 
-    if (!stream || !pa_stream_is_ready(stream) || !(l = w = pa_stream_writable_size(stream)))
+    if (!stream || pa_stream_get_state(stream) != PA_STREAM_READY || !(l = w = pa_stream_writable_size(stream)))
         l = 4096;
     
     buffer = malloc(l);
@@ -192,7 +214,7 @@ static void stdin_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int
     if ((r = read(fd, buffer, l)) <= 0) {
         if (r == 0) {
             fprintf(stderr, "Got EOF.\n");
-            pa_stream_drain(stream, stream_drain_complete, NULL);
+            pa_operation_unref(pa_stream_drain(stream, stream_drain_complete, NULL));
         } else {
             fprintf(stderr, "read() failed: %s\n", strerror(errno));
             quit(1);
@@ -259,10 +281,11 @@ static void stream_get_latency_callback(struct pa_stream *s, uint32_t latency, v
 }
 
 static void sigusr1_signal_callback(struct pa_mainloop_api*m, struct pa_signal_event *e, int sig, void *userdata) {
-    if (mode == PLAYBACK) {
-        fprintf(stderr, "Got SIGUSR1, requesting latency.\n");
-        pa_stream_get_latency(stream, stream_get_latency_callback, NULL);
-    }
+    if (mode != PLAYBACK)
+        return;
+    
+    fprintf(stderr, "Got SIGUSR1, requesting latency.\n");
+    pa_operation_unref(pa_stream_get_latency(stream, stream_get_latency_callback, NULL));
 }
 
 int main(int argc, char *argv[]) {
@@ -306,12 +329,9 @@ int main(int argc, char *argv[]) {
         goto quit;
     }
 
-    if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) {
-        fprintf(stderr, "pa_context_connext() failed.\n");
-        goto quit;
-    }
-        
-    pa_context_set_die_callback(context, context_die_callback, NULL);
+    pa_context_set_state_callback(context, context_state_callback, NULL);
+
+    pa_context_connect(context, NULL);
 
     if (pa_mainloop_run(m, &ret) < 0) {
         fprintf(stderr, "pa_mainloop_run() failed.\n");
@@ -320,15 +340,21 @@ int main(int argc, char *argv[]) {
     
 quit:
     if (stream)
-        pa_stream_free(stream);
+        pa_stream_unref(stream);
+
     if (context)
-        pa_context_free(context);
+        pa_context_unref(context);
 
+    if (stdio_event) {
+        assert(mainloop_api);
+        mainloop_api->io_free(stdio_event);
+    }
+    
     if (m) {
         pa_signal_done();
         pa_mainloop_free(m);
     }
-    
+
     if (buffer)
         free(buffer);
     
index 2f3a48331e2f2c9ecfa17237a8c07a590cd93bae..0ff2aa909d662afdf0d705a1b3eb1aae43b2f379 100644 (file)
@@ -68,31 +68,27 @@ static void quit(int ret) {
     mainloop_api->quit(mainloop_api, ret);
 }
 
-static void context_die_callback(struct pa_context *c, void *userdata) {
-    assert(c);
-    fprintf(stderr, "Connection to server shut down, exiting.\n");
-    quit(1);
-}
 
 static void context_drain_complete(struct pa_context *c, void *userdata) {
-    assert(c);
-    fprintf(stderr, "Connection to server shut down, exiting.\n");
-    quit(0);
+    pa_context_disconnect(c);
 }
 
 static void drain(void) {
-    if (pa_context_drain(context, context_drain_complete, NULL) < 0)
-        quit(0);
+    struct pa_operation *o;
+    if (!(o = pa_context_drain(context, context_drain_complete, NULL)))
+        pa_context_disconnect(context);
+    else
+        pa_operation_unref(o);
 }
 
-static void stat_callback(struct pa_context *c, uint32_t blocks, uint32_t total, void *userdata) {
-    if (blocks == (uint32_t) -1) {
+static void stat_callback(struct pa_context *c, const struct pa_stat_info *i, void *userdata) {
+    if (!i) {
         fprintf(stderr, "Failed to get statistics: %s\n", pa_strerror(pa_context_errno(c)));
         quit(1);
         return;
     }
     
-    fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", blocks, total);
+    fprintf(stderr, "Currently in use: %u blocks containing %u bytes total.\n", i->memblock_count, i->memblock_total);
     drain();
 }
 
@@ -116,22 +112,23 @@ static void remove_sample_callback(struct pa_context *c, int success, void *user
     drain();
 }
 
-static void stream_die_callback(struct pa_stream *s, void *userdata) {
-    assert(s);
-    fprintf(stderr, "Stream deleted, exiting.\n");
-    quit(1);
-}
-
-static void finish_sample_callback(struct pa_stream *s, int success, void *userdata) {
+static void stream_state_callback(struct pa_stream *s, void *userdata) {
     assert(s);
 
-    if (!success) {
-        fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context)));
-        quit(1);
-        return;
+    switch (pa_stream_get_state(s)) {
+        case PA_STREAM_CREATING:
+        case PA_STREAM_READY:
+            break;
+            
+        case PA_STREAM_TERMINATED:
+            drain();
+            break;
+            
+        case PA_STREAM_FAILED:
+        default:
+            fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
+            quit(1);
     }
-
-    drain();
 }
 
 static void stream_write_callback(struct pa_stream *s, size_t length, void *userdata) {
@@ -151,58 +148,55 @@ static void stream_write_callback(struct pa_stream *s, size_t length, void *user
         quit(1);
     }
     
-    pa_stream_write(s, d, length);
-    free(d);
+    pa_stream_write(s, d, length, free);
 
     sample_length -= length;
 
     if (sample_length  <= 0) {
         pa_stream_set_write_callback(sample_stream, NULL, NULL);
-        pa_stream_finish_sample(sample_stream, finish_sample_callback, NULL);
-    }
-}
-
-static void upload_callback(struct pa_stream *s, int success, void *userdata) {
-    if (!success) {
-        fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(context)));
-        quit(1);
+        pa_stream_finish_upload(sample_stream);
     }
 }
 
-static void context_complete_callback(struct pa_context *c, int success, void *userdata) {
+static void context_state_callback(struct pa_context *c, void *userdata) {
     assert(c);
+    switch (pa_context_get_state(c)) {
+        case PA_CONTEXT_CONNECTING:
+        case PA_CONTEXT_AUTHORIZING:
+        case PA_CONTEXT_SETTING_NAME:
+            break;
+
+        case PA_CONTEXT_READY:
+            if (action == STAT)
+                pa_operation_unref(pa_context_stat(c, stat_callback, NULL));
+            else if (action == PLAY_SAMPLE)
+                pa_operation_unref(pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL));
+            else if (action == REMOVE_SAMPLE)
+                pa_operation_unref(pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL));
+            else if (action == UPLOAD_SAMPLE) {
+
+                sample_stream = pa_stream_new(c, sample_name, &sample_spec);
+                assert(sample_stream);
+
+                pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);
+                pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
+                pa_stream_connect_upload(sample_stream, sample_length);
+            } else {
+                assert(action == EXIT);
+                pa_context_exit_daemon(c);
+                drain();
+            }
+            break;
 
-    if (!success) {
-        fprintf(stderr, "Connection failed: %s\n", pa_strerror(pa_context_errno(c)));
-        goto fail;
-    }
+        case PA_CONTEXT_TERMINATED:
+            quit(0);
+            break;
 
-    fprintf(stderr, "Connection established.\n");
-
-    if (action == STAT)
-        pa_context_stat(c, stat_callback, NULL);
-    else if (action == PLAY_SAMPLE)
-        pa_context_play_sample(c, process_argv[2], NULL, 0x100, play_sample_callback, NULL);
-    else if (action == REMOVE_SAMPLE)
-        pa_context_remove_sample(c, process_argv[2], remove_sample_callback, NULL);
-    else if (action == UPLOAD_SAMPLE) {
-        if (!(sample_stream = pa_context_upload_sample(c, sample_name, &sample_spec, sample_length, upload_callback, NULL))) {
-            fprintf(stderr, "Failed to upload sample: %s\n", pa_strerror(pa_context_errno(c)));
-            goto fail;
-        }
-        
-        pa_stream_set_die_callback(sample_stream, stream_die_callback, NULL);
-        pa_stream_set_write_callback(sample_stream, stream_write_callback, NULL);
-    } else {
-        assert(action == EXIT);
-        pa_context_exit(c);
-        drain();
+        case PA_CONTEXT_FAILED:
+        default:
+            fprintf(stderr, "Connection failure: %s\n", pa_strerror(pa_context_errno(c)));
+            quit(1);
     }
-    
-    return;
-    
-fail:
-    quit(1);
 }
 
 static void exit_signal_callback(struct pa_mainloop_api *m, struct pa_signal_event *e, int sig, void *userdata) {
@@ -234,12 +228,15 @@ int main(int argc, char *argv[]) {
                 sample_name = argv[3];
             else {
                 char *f = strrchr(argv[2], '/');
+                size_t n;
                 if (f)
                     f++;
                 else
                     f = argv[2];
 
-                strncpy(sample_name = tmp, f, strcspn(f, "."));
+                n = strcspn(f, ".");
+                strncpy(sample_name = tmp, f, n);
+                tmp[n] = 0; 
             }
             
             memset(&sfinfo, 0, sizeof(sfinfo));
@@ -292,12 +289,8 @@ int main(int argc, char *argv[]) {
         goto quit;
     }
 
-    if (pa_context_connect(context, NULL, context_complete_callback, NULL) < 0) {
-        fprintf(stderr, "pa_context_connext() failed.\n");
-        goto quit;
-    }
-        
-    pa_context_set_die_callback(context, context_die_callback, NULL);
+    pa_context_set_state_callback(context, context_state_callback, NULL);
+    pa_context_connect(context, NULL);
 
     if (pa_mainloop_run(m, &ret) < 0) {
         fprintf(stderr, "pa_mainloop_run() failed.\n");
@@ -305,8 +298,11 @@ int main(int argc, char *argv[]) {
     }
 
 quit:
+    if (sample_stream)
+        pa_stream_unref(sample_stream);
+
     if (context)
-        pa_context_free(context);
+        pa_context_unref(context);
 
     if (m) {
         pa_signal_done();
@@ -315,6 +311,6 @@ quit:
     
     if (sndfile)
         sf_close(sndfile);
-    
+
     return ret;
 }
index 35001d3d31d29d8445af21a8ffedcd32d8c5d3a0..5f849e24247fba93bad751de857c9923aaac6ecb 100644 (file)
@@ -31,7 +31,8 @@
 #include <sys/socket.h>
 #include <netdb.h>
 
-#include "polyplib.h"
+#include "polyplib-internal.h"
+#include "polyplib-context.h"
 #include "native-common.h"
 #include "pdispatch.h"
 #include "pstream.h"
 #include "util.h"
 #include "xmalloc.h"
 
-#define DEFAULT_MAXLENGTH 204800
-#define DEFAULT_TLENGTH 10240
-#define DEFAULT_PREBUF 4096
-#define DEFAULT_MINREQ 1024
-#define DEFAULT_FRAGSIZE 1024
-
-#define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
-#define DEFAULT_PORT "4713"
-
-struct pa_context {
-    char *name;
-    struct pa_mainloop_api* mainloop;
-    struct pa_socket_client *client;
-    struct pa_pstream *pstream;
-    struct pa_pdispatch *pdispatch;
-    struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
-    uint32_t ctag;
-    uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
-    
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
-
-    void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
-    void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-};
-
-struct pa_stream {
-    struct pa_context *context;
-    struct pa_stream *next, *previous;
-
-    char *name;
-    struct pa_buffer_attr buffer_attr;
-    struct pa_sample_spec sample_spec;
-    uint32_t channel;
-    int channel_valid;
-    uint32_t device_index;
-    enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
-    uint32_t requested_bytes;
-
-    void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
-    void *read_userdata;
-
-    void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
-    void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
-};
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-
 static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
+    [PA_COMMAND_REQUEST] = { pa_command_request },
+    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { pa_command_stream_killed },
+    [PA_COMMAND_RECORD_STREAM_KILLED] = { pa_command_stream_killed },
+    [PA_COMMAND_SUBSCRIBE_EVENT] = { pa_command_subscribe_event },
 };
 
 struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
@@ -171,65 +55,41 @@ struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *
     assert(mainloop && name);
     
     c = pa_xmalloc(sizeof(struct pa_context));
+    c->ref = 1;
     c->name = pa_xstrdup(name);
     c->mainloop = mainloop;
     c->client = NULL;
     c->pstream = NULL;
     c->pdispatch = NULL;
     c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
     c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
+    assert(c->playback_streams && c->record_streams);
+
+    PA_LLIST_HEAD_INIT(struct pa_stream, c->streams);
+    PA_LLIST_HEAD_INIT(struct pa_operation, c->operations);
+    
     c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
+    c->state = PA_CONTEXT_UNCONNECTED;
     c->ctag = 0;
 
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
-
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
-
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
-
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
+    c->state_callback = NULL;
+    c->state_userdata = NULL;
 
     c->subscribe_callback = NULL;
     c->subscribe_userdata = NULL;
 
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
     pa_check_for_sigpipe();
     return c;
 }
 
-void pa_context_free(struct pa_context *c) {
+static void context_free(struct pa_context *c) {
     assert(c);
 
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
+    while (c->operations)
+        pa_operation_cancel(c->operations);
+
+    while (c->streams)
+        pa_stream_set_state(c->streams, PA_STREAM_TERMINATED);
     
     if (c->client)
         pa_socket_client_free(c->client);
@@ -237,6 +97,7 @@ void pa_context_free(struct pa_context *c) {
         pa_pdispatch_free(c->pdispatch);
     if (c->pstream)
         pa_pstream_free(c->pstream);
+    
     if (c->record_streams)
         pa_dynarray_free(c->record_streams, NULL, NULL);
     if (c->playback_streams)
@@ -246,66 +107,82 @@ void pa_context_free(struct pa_context *c) {
     pa_xfree(c);
 }
 
-static void stream_dead(struct pa_stream *s) {
-    assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
+struct pa_context* pa_context_ref(struct pa_context *c) {
+    assert(c && c->ref >= 1);
+    c->ref++;
+    return c;
 }
 
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
+void pa_context_unref(struct pa_context *c) {
+    assert(c && c->ref >= 1);
+
+    if ((--(c->ref)) == 0)
+        context_free(c);
+}
+
+void pa_context_set_state(struct pa_context *c, enum pa_context_state st) {
     assert(c);
     
-    if (c->state == CONTEXT_DEAD)
+    if (c->state == st)
         return;
 
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
+    pa_context_ref(c);
+
+    if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) {
+        struct pa_stream *s;
+        
+        s = c->streams ? pa_stream_ref(c->streams) : NULL;
+        while (s) {
+            struct pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
+            pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
+            pa_stream_unref(s);
+            s = n;
+        }
+
+        if (c->pdispatch)
+            pa_pdispatch_free(c->pdispatch);
+        c->pdispatch = NULL;
     
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
+        if (c->pstream)
+            pa_pstream_free(c->pstream);
+        c->pstream = NULL;
     
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
+        if (c->client)
+            pa_socket_client_free(c->client);
+        c->client = NULL;
+    }
+
+    c->state = st;
+    if (c->state_callback)
+        c->state_callback(c, c->state_userdata);
+
+    pa_context_unref(c);
+}
+
+void pa_context_fail(struct pa_context *c, int error) {
+    assert(c);
+    c->error = error;
+    pa_context_set_state(c, PA_CONTEXT_FAILED);
 }
 
 static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
     struct pa_context *c = userdata;
     assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
+    pa_context_fail(c, PA_ERROR_CONNECTIONTERMINATED);
 }
 
 static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
     struct pa_context *c = userdata;
     assert(p && packet && c);
 
+    pa_context_ref(c);
+    
     if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
         fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
+        pa_context_fail(c, PA_ERROR_PROTOCOL);
     }
+
+    pa_context_unref(c);
 }
 
 static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
@@ -313,90 +190,100 @@ static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, in
     struct pa_stream *s;
     assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
 
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
+    pa_context_ref(c);
+    
+    if ((s = pa_dynarray_get(c->record_streams, channel))) {
+        if (s->read_callback)
+            s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
+    }
 
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
+    pa_context_unref(c);
 }
 
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
+int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
     assert(c && t);
-    
+
     if (command == PA_COMMAND_ERROR) {
         if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
+            pa_context_fail(c, PA_ERROR_PROTOCOL);
             return -1;
+                
         }
-
-        return 0;
+    } else if (command == PA_COMMAND_TIMEOUT)
+        c->error = PA_ERROR_TIMEOUT;
+    else {
+        pa_context_fail(c, PA_ERROR_PROTOCOL);
+        return -1;
     }
 
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
+    return 0;
 }
 
 static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
     struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
+    assert(pd && c && (c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME));
 
+    pa_context_ref(c);
+    
     if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
+        if (pa_context_handle_error(c, command, t) < 0)
+            pa_context_fail(c, PA_ERROR_PROTOCOL);
 
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
+        goto finish;
     }
 
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
+    switch(c->state) {
+        case PA_CONTEXT_AUTHORIZING: {
+            struct pa_tagstruct *t;
+            t = pa_tagstruct_new(NULL, 0);
+            assert(t);
+            pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
+            pa_tagstruct_putu32(t, tag = c->ctag++);
+            pa_tagstruct_puts(t, c->name);
+            pa_pstream_send_tagstruct(c->pstream, t);
+            pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
+
+            pa_context_set_state(c, PA_CONTEXT_SETTING_NAME);
+            break;
+        }
 
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
+        case PA_CONTEXT_SETTING_NAME :
+            pa_context_set_state(c, PA_CONTEXT_READY);
+            break;
+            
+        default:
+            assert(0);
     }
 
-    return;
+finish:
+    pa_context_unref(c);
 }
 
 static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
     struct pa_context *c = userdata;
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
+    assert(client && c && c->state == PA_CONTEXT_CONNECTING);
 
+    pa_context_ref(c);
+    
     pa_socket_client_free(client);
     c->client = NULL;
 
     if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
+        pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
+        goto finish;
     }
-    
+
+    assert(!c->pstream);
     c->pstream = pa_pstream_new(c->mainloop, io);
     assert(c->pstream);
+    
     pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
     pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
     pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
-    
+
+    assert(!c->pdispatch);
     c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
     assert(c->pdispatch);
 
@@ -407,7 +294,11 @@ static void on_connection(struct pa_socket_client *client, struct pa_iochannel*i
     pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
     pa_pstream_send_tagstruct(c->pstream, t);
     pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
+
+    pa_context_set_state(c, PA_CONTEXT_AUTHORIZING);
+
+finish:
+    pa_context_unref(c);
 }
 
 static struct sockaddr *resolve_server(const char *server, size_t *len) {
@@ -438,353 +329,89 @@ static struct sockaddr *resolve_server(const char *server, size_t *len) {
     return sa;
 }
 
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
+int pa_context_connect(struct pa_context *c, const char *server) {
+    int r = -1;
+    assert(c && c->ref >= 1 && c->state == PA_CONTEXT_UNCONNECTED);
 
+    pa_context_ref(c);
+    
     if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
+        pa_context_fail(c, PA_ERROR_AUTHKEY);
+        goto finish;
     }
 
     if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
+        if (!(server = getenv(ENV_DEFAULT_SERVER)))
             server = DEFAULT_SERVER;
 
     assert(!c->client);
     
     if (*server == '/') {
         if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
+            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
+            goto finish;
         }
     } else {
         struct sockaddr* sa;
         size_t sa_len;
 
         if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
+            pa_context_fail(c, PA_ERROR_INVALIDSERVER);
+            goto finish;
         }
 
         c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
         pa_xfree(sa);
 
         if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
+            pa_context_fail(c, PA_ERROR_CONNECTIONREFUSED);
+            goto finish;
         }
     }
 
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
     pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
+    pa_context_set_state(c, PA_CONTEXT_CONNECTING);
 
-    return 0;
+    r = 0;
+    
+finish:
+    pa_context_unref(c);
+    
+    return r;
 }
 
-int pa_context_is_dead(struct pa_context *c) {
+void pa_context_disconnect(struct pa_context *c) {
     assert(c);
-    return c->state == CONTEXT_DEAD;
+    pa_context_set_state(c, PA_CONTEXT_TERMINATED);
 }
 
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
+enum pa_context_state pa_context_get_state(struct pa_context *c) {
+    assert(c && c->ref >= 1);
+    return c->state;
 }
 
 int pa_context_errno(struct pa_context *c) {
-    assert(c);
+    assert(c && c->ref >= 1);
     return c->error;
 }
 
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
-}
-
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    uint32_t channel;
-    assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
-
-    c->error = PA_ERROR_KILLED;
-    stream_dead(s);
-}
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s;
-    struct pa_context *c = userdata;
-    uint32_t bytes, channel;
-    assert(pd && command == PA_COMMAND_REQUEST && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        pa_tagstruct_getu32(t, &bytes) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
-
-    if (s->state != STREAM_READY)
-        return;
-    
-    s->requested_bytes += bytes;
-
-    if (s->requested_bytes && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
-}
-
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
-        ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    s->channel_valid = 1;
-    pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
-}
-
-static void create_stream(struct pa_stream *s, const char *dev) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s);
-
-    s->state = STREAM_CREATING;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_puts(t, s->name);
-    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
-    if (s->direction == PA_STREAM_PLAYBACK) {
-        pa_tagstruct_putu32(t, s->buffer_attr.tlength);
-        pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
-        pa_tagstruct_putu32(t, s->buffer_attr.minreq);
-    } else
-        pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
-
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
-
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
-
-    create_stream(s, dev);
-    
-    return s;
-}
-
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
-    }
-    
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
-
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
-}
-
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
-}
-
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
-    struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
-
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
-    chunk.index = 0;
-    chunk.length = length;
-
-    pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
-    pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
-    
-    if (length < s->requested_bytes)
-        s->requested_bytes -= length;
-    else
-        s->requested_bytes = 0;
-}
-
-size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
-    return s->requested_bytes;
-}
-
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
-
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
-
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
+void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
+    assert(c && c->ref >= 1);
+    c->state_callback = cb;
+    c->state_userdata = userdata;
 }
 
 int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
+    assert(c && c->ref >= 1);
 
-    if (c->state != CONTEXT_READY)
+    if (c->state != PA_CONTEXT_READY)
         return 0;
 
+    assert(c->pstream && c->pdispatch);
     return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
 }
 
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
-}
-
-static void set_dispatch_callbacks(struct pa_context *c);
+static void set_dispatch_callbacks(struct pa_operation *o);
 
 static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
     set_dispatch_callbacks(userdata);
@@ -794,107 +421,59 @@ static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
     set_dispatch_callbacks(userdata);
 }
 
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
+static void set_dispatch_callbacks(struct pa_operation *o) {
+    int done = 1;
+    assert(o && o->context && o->context->ref >= 1 && o->ref >= 1 && o->context->state == PA_CONTEXT_READY);
 
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
+    pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL);
+    pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL);
     
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
-
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
+    if (pa_pdispatch_is_pending(o->context->pdispatch)) {
+        pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o);
+        done = 0;
     }
 
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
+    if (pa_pstream_is_pending(o->context->pstream)) {
+        pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o);
+        done = 0;
     }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
-
-    set_dispatch_callbacks(c);
-
-    return 0;
-}
 
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
+    if (!done)
+        pa_operation_ref(o);
+    else {
+        if (o->callback) {
+            void (*cb)(struct pa_context *c, void *userdata);
+            cb = (void*) o->callback;
+            cb(o->context, o->userdata);
         }
+        
+        pa_operation_done(o);
+    }   
 
-        stream_dead(s);
-        return;
-    }
-
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
+    pa_operation_unref(o);
 }
 
+struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata) {
+    struct pa_operation *o;
+    assert(c && c->ref >= 1 && c->state == PA_CONTEXT_READY);
 
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s && s->state == STREAM_READY);
+    if (!pa_context_is_pending(c))
+        return NULL;
 
-    if (!complete) {
-        s->drain_complete_callback = NULL;
-        return;
-    }
+    o = pa_operation_new(c, NULL);
+    assert(o);
+    o->callback = cb;
+    o->userdata = userdata;
 
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
+    set_dispatch_callbacks(pa_operation_ref(o));
 
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_putu32(t, s->channel);
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
+    return o;
 }
 
-void pa_context_exit(struct pa_context *c) {
+void pa_context_exit_daemon(struct pa_context *c) {
     struct pa_tagstruct *t;
+    assert(c && c->ref >= 1);
+    
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
     pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
@@ -902,649 +481,46 @@ void pa_context_exit(struct pa_context *c) {
     pa_pstream_send_tagstruct(c->pstream, t);
 }
 
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
+void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    int success = 1;
+    assert(pd && o && o->context && o->ref >= 1);
 
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
+        success = 0;
+    } else if (!pa_tagstruct_eof(t)) {
+        pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+        goto finish;
     }
 
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
+    if (o->callback) {
+        void (*cb)(struct pa_context *c, int success, void *userdata) = o->callback;
+        cb(o->context, success, o->userdata);
     }
 
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
+struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata) {
     struct pa_tagstruct *t;
+    struct pa_operation *o;
+    uint32_t tag;
+    assert(c && cb);
 
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
-    if (cb == NULL)
-        return;
-    
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
+    pa_tagstruct_putu32(t, command);
     pa_tagstruct_putu32(t, tag = c->ctag++);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_callback, o);
 
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
-}
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
-}
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-
-    return s;
-}
-
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
-
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
-}
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name && *name && (!dev || *dev));
-
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, volume);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
-}
-
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name);
-
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
-}
-
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
-}
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
-
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
-        
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
-    }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
-    }
-
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
-}
-
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
-
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    enum pa_subscription_event_type e;
-    uint32_t index;
-    assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
-
-    if (pa_tagstruct_getu32(t, &e) < 0 ||
-        pa_tagstruct_getu32(t, &index) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
-        c->subscribe_callback(c, e, index, c->subscribe_userdata);
-}
-
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
-
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
-}
-
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
-    }
-
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
-}
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
-
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
+    return pa_operation_ref(o);
 }
index a0dd9f9cba4bece1dd871c7636007701c309de74..6a1cc8bd8ddfee5b3e85a4ab42942fb3088be695 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef foopolyplibhfoo
-#define foopolyplibhfoo
+#ifndef foopolyplibcontexthfoo
+#define foopolyplibcontexthfoo
 
 /* $Id$ */
 
   USA.
 ***/
 
-#include <sys/types.h>
-
 #include "sample.h"
 #include "polyplib-def.h"
 #include "mainloop-api.h"
+#include "cdecl.h"
+#include "polyplib-operation.h"
+
+/** \file
+ * Connection contexts */
+
+PA_C_DECL_BEGIN
+
+/** The state of a connection context */
+enum pa_context_state {
+    PA_CONTEXT_UNCONNECTED,    /**< The context hasn't been connected yet */
+    PA_CONTEXT_CONNECTING,     /**< A connection is being established */
+    PA_CONTEXT_AUTHORIZING,    /**< The client is authorizing itself to the daemon */
+    PA_CONTEXT_SETTING_NAME,   /**< The client is passing its application name to the daemon */
+    PA_CONTEXT_READY,          /**< The connection is established, the context is ready to execute operations */
+    PA_CONTEXT_FAILED,         /**< The connection failed or was disconnected */
+    PA_CONTEXT_TERMINATED      /**< The connect was terminated cleanly */
+};
 
-#ifdef __cplusplus
-//extern "C" {
-#endif
-
+/** \struct pa_context
+ * A connection context to a daemon */
 struct pa_context;
-struct pa_stream;
 
+/** Instantiate a new connection context with an abstract mainloop API
+ * and an application name */
 struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name);
+
+/** Decrease the reference counter of the context by one */
 void pa_context_unref(struct pa_context *c);
+
+/** Increase the reference counter of the context by one */
 struct pa_context* pa_context_ref(struct pa_context *c);
 
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata);
-int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata);
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
+/** Set a callback function that is called whenever the context status changes */
+void pa_context_set_state_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
 
-int pa_context_is_dead(struct pa_context *c);
-int pa_context_is_ready(struct pa_context *c);
+/** Return the error number of the last failed operation */
 int pa_context_errno(struct pa_context *c);
 
+/** Return non-zero if some data is pending to be written to the connection */
 int pa_context_is_pending(struct pa_context *c);
 
-struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_unref(struct pa_stream *s);
-struct pa_stream *pa_stream_ref(struct pa_stream *s);
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata);
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
-
-void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
-void pa_stream_write(struct pa_stream *p, const void *data, size_t length);
-size_t pa_stream_writable_size(struct pa_stream *p);
+/** Return the current context status */
+enum pa_context_state pa_context_get_state(struct pa_context *c);
 
-void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
+/** Connect the context to the specified server. If server is NULL,
+connect to the default server. This routine may but will not always
+return synchronously on error. Use pa_context_set_state_callback() to
+be notified when the connection is established */
+int pa_context_connect(struct pa_context *c, const char *server);
 
-int pa_stream_is_dead(struct pa_stream *p);
-int pa_stream_is_ready(struct pa_stream*p);
+/** Terminate the context connection immediately */
+void pa_context_disconnect(struct pa_context *c);
 
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
+/** Drain the context. If there is nothing to drain, the function returns NULL */
+struct pa_operation* pa_context_drain(struct pa_context *c, void (*cb) (struct pa_context*c, void *userdata), void *userdata);
 
-struct pa_context* pa_stream_get_context(struct pa_stream *p);
+/** Tell the daemon to exit. No operation object is returned as the
+ * connection is terminated when the daemon quits, thus this operation
+ * would never complete. */
+void pa_context_exit_daemon(struct pa_context *c);
 
-uint32_t pa_stream_get_index(struct pa_stream *s);
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata);
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-struct pa_sink_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t volume;
-    uint32_t monitor_source;
-    const char *monitor_source_name;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t monitor_of_sink;
-    const char *monitor_of_sink_name;
-};
-
-void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_server_info {
-    const char *user_name;
-    const char *host_name;
-    const char *server_version;
-    const char *server_name;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
-
-struct pa_module_info {
-    uint32_t index;
-    const char*name, *argument;
-    uint32_t n_used, auto_unload;
-};
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_client_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    const char *protocol_name;
-};
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_sink_input_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t sink;
-    struct pa_sample_spec sample_spec;
-    uint32_t volume;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_output_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t source;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-
-void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-void pa_context_exit(struct pa_context *c);
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
-
-#ifdef __cplusplus
-}
-#endif
+PA_C_DECL_END
 
 #endif
index d96c68995436c4ac9da0a06ffff377b945cdb81f..fc19be6972abdfacc6744820878b43a1cdaf1f5c 100644 (file)
 ***/
 
 #include <inttypes.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #include "native-common.h"
+#include "cdecl.h"
+
+PA_C_DECL_BEGIN
 
 enum pa_stream_direction {
+    PA_STREAM_NODIRECTION,
     PA_STREAM_PLAYBACK,
     PA_STREAM_RECORD,
     PA_STREAM_UPLOAD
@@ -43,9 +42,9 @@ struct pa_buffer_attr {
     uint32_t minreq;
     uint32_t fragsize;
 };
-    
-#ifdef __cplusplus
-}
-#endif
+
+#define PA_INVALID_INDEX ((uint32_t) -1)
+
+PA_C_DECL_END
 
 #endif
index d76ce6ffa93c9a0e0e99c10839895a35785fbb3a..d7519af4af66fb7aee3ab54ced1e9a718c09328b 100644 (file)
 ***/
 
 #include <inttypes.h>
+#include "cdecl.h"
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+PA_C_DECL_BEGIN;
 
+/** Return a human readable error message for the specified numeric error code */
 const char* pa_strerror(uint32_t error);
 
-#ifdef __cplusplus
-}
-#endif
-    
+PA_C_DECL_END;
+
 #endif
index 35001d3d31d29d8445af21a8ffedcd32d8c5d3a0..0b6b3887cbace282dca90f8967f9ceb0ee8fba91 100644 (file)
@@ -1,3 +1,6 @@
+#ifndef foopolyplibinternalhfoo
+#define foopolyplibinternalhfoo
+
 /* $Id$ */
 
 /***
   USA.
 ***/
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include "polyplib.h"
-#include "native-common.h"
-#include "pdispatch.h"
+#include "mainloop-api.h"
+#include "socket-client.h"
 #include "pstream.h"
+#include "pdispatch.h"
 #include "dynarray.h"
-#include "socket-client.h"
-#include "pstream-util.h"
-#include "authkey.h"
-#include "util.h"
-#include "xmalloc.h"
+
+#include "polyplib-context.h"
+#include "polyplib-stream.h"
+#include "polyplib-operation.h"
+#include "llist.h"
 
 #define DEFAULT_MAXLENGTH 204800
 #define DEFAULT_TLENGTH 10240
 #define DEFAULT_SERVER "/tmp/polypaudio/native"
 #define DEFAULT_PORT "4713"
 
+#define ENV_DEFAULT_SINK "POLYP_SINK"
+#define ENV_DEFAULT_SOURCE "POLYP_SOURCE"
+#define ENV_DEFAULT_SERVER "POLYP_SERVER"
+
 struct pa_context {
+    int ref;
+    
     char *name;
     struct pa_mainloop_api* mainloop;
+
     struct pa_socket_client *client;
     struct pa_pstream *pstream;
     struct pa_pdispatch *pdispatch;
+
     struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
+    PA_LLIST_HEAD(struct pa_stream, streams);
+    PA_LLIST_HEAD(struct pa_operation, operations);
+    
     uint32_t ctag;
     uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
+    enum pa_context_state state;
     
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
+    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
     
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
+    void (*state_callback)(struct pa_context*c, void *userdata);
+    void *state_userdata;
 
     void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
     void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
 };
 
 struct pa_stream {
+    int ref;
     struct pa_context *context;
-    struct pa_stream *next, *previous;
+    PA_LLIST_FIELDS(struct pa_stream);
 
     char *name;
     struct pa_buffer_attr buffer_attr;
@@ -122,1429 +86,47 @@ struct pa_stream {
     int channel_valid;
     uint32_t device_index;
     enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
     uint32_t requested_bytes;
+    enum pa_stream_state state;
+
+    void (*state_callback)(struct pa_stream*c, void *userdata);
+    void *state_userdata;
 
     void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
     void *read_userdata;
 
     void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
     void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
 };
 
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+struct pa_operation {
+    int ref;
+    struct pa_context *context;
+    struct pa_stream *stream;
+    PA_LLIST_FIELDS(struct pa_operation);
 
-static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
+    enum pa_operation_state state;
+    void *userdata;
+    void (*callback)();
 };
 
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
-    struct pa_context *c;
-    assert(mainloop && name);
-    
-    c = pa_xmalloc(sizeof(struct pa_context));
-    c->name = pa_xstrdup(name);
-    c->mainloop = mainloop;
-    c->client = NULL;
-    c->pstream = NULL;
-    c->pdispatch = NULL;
-    c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
-    c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
-    c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
-    c->ctag = 0;
-
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
-
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
-
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
-
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
-
-    c->subscribe_callback = NULL;
-    c->subscribe_userdata = NULL;
-
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
-    pa_check_for_sigpipe();
-    return c;
-}
-
-void pa_context_free(struct pa_context *c) {
-    assert(c);
-
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    if (c->record_streams)
-        pa_dynarray_free(c->record_streams, NULL, NULL);
-    if (c->playback_streams)
-        pa_dynarray_free(c->playback_streams, NULL, NULL);
-        
-    pa_xfree(c->name);
-    pa_xfree(c);
-}
-
-static void stream_dead(struct pa_stream *s) {
-    assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
-}
-
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
-    assert(c);
-    
-    if (c->state == CONTEXT_DEAD)
-        return;
-
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
-    
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
-}
-
-static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
-}
-
-static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && packet && c);
-
-    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
-        fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-    }
-}
-
-static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
-
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
-
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
-}
-
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
-    assert(c && t);
-    
-    if (command == PA_COMMAND_ERROR) {
-        if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            return -1;
-        }
-
-        return 0;
-    }
-
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
-}
-
-static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
-
-    if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
-    }
-
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
-
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
-    }
-
-    return;
-}
-
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
+void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
 
-    pa_socket_client_free(client);
-    c->client = NULL;
+struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s);
+void pa_operation_done(struct pa_operation *o);
 
-    if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
-    }
-    
-    c->pstream = pa_pstream_new(c->mainloop, io);
-    assert(c->pstream);
-    pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
-    pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
-    pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
-    
-    c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
-}
-
-static struct sockaddr *resolve_server(const char *server, size_t *len) {
-    struct sockaddr *sa;
-    struct addrinfo hints, *result = NULL;
-    char *port;
-    assert(server && len);
-
-    if ((port = strrchr(server, ':')))
-        port++;
-    if (!port)
-        port = DEFAULT_PORT;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-
-    if (getaddrinfo(server, port, &hints, &result) != 0)
-        return NULL;
-    assert(result);
-    
-    sa = pa_xmalloc(*len = result->ai_addrlen);
-    memcpy(sa, result->ai_addr, *len);
-
-    freeaddrinfo(result);
-    
-    return sa;
-}
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
-
-    if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
-    }
-
-    if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
-            server = DEFAULT_SERVER;
-
-    assert(!c->client);
-    
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
-
-        if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
-        }
-
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
-
-        if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    }
-
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
-    pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
-
-    return 0;
-}
-
-int pa_context_is_dead(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_DEAD;
-}
-
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
-}
-
-int pa_context_errno(struct pa_context *c) {
-    assert(c);
-    return c->error;
-}
-
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
-}
-
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    uint32_t channel;
-    assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
-
-    c->error = PA_ERROR_KILLED;
-    stream_dead(s);
-}
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s;
-    struct pa_context *c = userdata;
-    uint32_t bytes, channel;
-    assert(pd && command == PA_COMMAND_REQUEST && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        pa_tagstruct_getu32(t, &bytes) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
-
-    if (s->state != STREAM_READY)
-        return;
-    
-    s->requested_bytes += bytes;
-
-    if (s->requested_bytes && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
-}
-
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
-        ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    s->channel_valid = 1;
-    pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
-}
-
-static void create_stream(struct pa_stream *s, const char *dev) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s);
-
-    s->state = STREAM_CREATING;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_puts(t, s->name);
-    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
-    if (s->direction == PA_STREAM_PLAYBACK) {
-        pa_tagstruct_putu32(t, s->buffer_attr.tlength);
-        pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
-        pa_tagstruct_putu32(t, s->buffer_attr.minreq);
-    } else
-        pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
-
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
-
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
-
-    create_stream(s, dev);
-    
-    return s;
-}
-
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
-    }
-    
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
-
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
-}
-
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
-}
-
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
-    struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
-
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
-    chunk.index = 0;
-    chunk.length = length;
-
-    pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
-    pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
-    
-    if (length < s->requested_bytes)
-        s->requested_bytes -= length;
-    else
-        s->requested_bytes = 0;
-}
+void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+void pa_context_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
+void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
 
-size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
-    return s->requested_bytes;
-}
+void pa_context_fail(struct pa_context *c, int error);
+void pa_context_set_state(struct pa_context *c, enum pa_context_state st);
+int pa_context_handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t);
+struct pa_operation* pa_context_send_simple_command(struct pa_context *c, uint32_t command, void (*internal_callback)(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata), void (*cb)(), void *userdata);
 
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
+void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st);
 
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
-
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
-}
-
-int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
-
-    if (c->state != CONTEXT_READY)
-        return 0;
-
-    return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
-}
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
-}
-
-static void set_dispatch_callbacks(struct pa_context *c);
-
-static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
-
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-    
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
-
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
-    }
-
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
-    }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
-
-    set_dispatch_callbacks(c);
-
-    return 0;
-}
-
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        return;
-    }
-
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
-}
-
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s && s->state == STREAM_READY);
-
-    if (!complete) {
-        s->drain_complete_callback = NULL;
-        return;
-    }
-
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_putu32(t, s->channel);
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
-}
-
-void pa_context_exit(struct pa_context *c) {
-    struct pa_tagstruct *t;
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
-}
-
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
-}
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
-}
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-
-    return s;
-}
-
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
-
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
-}
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name && *name && (!dev || *dev));
-
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, volume);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
-}
-
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name);
-
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
-}
-
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
-}
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
-
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
-        
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
-    }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
-    }
-
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
-}
-
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
-
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    enum pa_subscription_event_type e;
-    uint32_t index;
-    assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
-
-    if (pa_tagstruct_getu32(t, &e) < 0 ||
-        pa_tagstruct_getu32(t, &index) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
-        c->subscribe_callback(c, e, index, c->subscribe_userdata);
-}
-
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
-
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
-}
-
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
-    }
-
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
-}
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
-
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
+#endif
index 35001d3d31d29d8445af21a8ffedcd32d8c5d3a0..345a9cd5fbe497ed136aa76177ece1fe3113e0ee 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include "polyplib.h"
-#include "native-common.h"
-#include "pdispatch.h"
-#include "pstream.h"
-#include "dynarray.h"
-#include "socket-client.h"
-#include "pstream-util.h"
-#include "authkey.h"
-#include "util.h"
-#include "xmalloc.h"
-
-#define DEFAULT_MAXLENGTH 204800
-#define DEFAULT_TLENGTH 10240
-#define DEFAULT_PREBUF 4096
-#define DEFAULT_MINREQ 1024
-#define DEFAULT_FRAGSIZE 1024
-
-#define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
-#define DEFAULT_PORT "4713"
-
-struct pa_context {
-    char *name;
-    struct pa_mainloop_api* mainloop;
-    struct pa_socket_client *client;
-    struct pa_pstream *pstream;
-    struct pa_pdispatch *pdispatch;
-    struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
-    uint32_t ctag;
-    uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
-    
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
-
-    void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
-    void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-};
-
-struct pa_stream {
-    struct pa_context *context;
-    struct pa_stream *next, *previous;
-
-    char *name;
-    struct pa_buffer_attr buffer_attr;
-    struct pa_sample_spec sample_spec;
-    uint32_t channel;
-    int channel_valid;
-    uint32_t device_index;
-    enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
-    uint32_t requested_bytes;
-
-    void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
-    void *read_userdata;
-
-    void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
-    void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
-};
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-
-static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
-};
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
-    struct pa_context *c;
-    assert(mainloop && name);
-    
-    c = pa_xmalloc(sizeof(struct pa_context));
-    c->name = pa_xstrdup(name);
-    c->mainloop = mainloop;
-    c->client = NULL;
-    c->pstream = NULL;
-    c->pdispatch = NULL;
-    c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
-    c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
-    c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
-    c->ctag = 0;
-
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
-
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
 
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
-
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
-
-    c->subscribe_callback = NULL;
-    c->subscribe_userdata = NULL;
-
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
-    pa_check_for_sigpipe();
-    return c;
-}
-
-void pa_context_free(struct pa_context *c) {
-    assert(c);
-
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    if (c->record_streams)
-        pa_dynarray_free(c->record_streams, NULL, NULL);
-    if (c->playback_streams)
-        pa_dynarray_free(c->playback_streams, NULL, NULL);
-        
-    pa_xfree(c->name);
-    pa_xfree(c);
-}
-
-static void stream_dead(struct pa_stream *s) {
-    assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
-}
-
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
-    assert(c);
-    
-    if (c->state == CONTEXT_DEAD)
-        return;
-
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
-    
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
-}
-
-static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
-}
-
-static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && packet && c);
-
-    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
-        fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-    }
-}
-
-static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
-
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
-
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
-}
-
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
-    assert(c && t);
-    
-    if (command == PA_COMMAND_ERROR) {
-        if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            return -1;
-        }
+#include "polyplib-introspect.h"
+#include "polyplib-context.h"
+#include "polyplib-internal.h"
+#include "pstream-util.h"
 
-        return 0;
-    }
+/*** Statistics ***/
 
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
-}
-
-static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
+static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    struct pa_stat_info i, *p = &i;
+    assert(pd && o && o->context && o->ref >= 1);
 
     if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
+        p = NULL;
+    } else if (pa_tagstruct_getu32(t, &i.memblock_count) < 0 ||
+               pa_tagstruct_getu32(t, &i.memblock_total) < 0 ||
+               !pa_tagstruct_eof(t)) {
+        pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+        goto finish;
     }
 
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
-
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
+    if (o->callback) {
+        void (*cb)(struct pa_context *s, const struct pa_stat_info*i, void *userdata) = o->callback;
+        cb(o->context, p, o->userdata);
     }
 
-    return;
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
-
-    pa_socket_client_free(client);
-    c->client = NULL;
-
-    if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
-    }
-    
-    c->pstream = pa_pstream_new(c->mainloop, io);
-    assert(c->pstream);
-    pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
-    pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
-    pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
-    
-    c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
+struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info*i, void *userdata), void *userdata) {
+    return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, cb, userdata);
 }
 
-static struct sockaddr *resolve_server(const char *server, size_t *len) {
-    struct sockaddr *sa;
-    struct addrinfo hints, *result = NULL;
-    char *port;
-    assert(server && len);
-
-    if ((port = strrchr(server, ':')))
-        port++;
-    if (!port)
-        port = DEFAULT_PORT;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-
-    if (getaddrinfo(server, port, &hints, &result) != 0)
-        return NULL;
-    assert(result);
-    
-    sa = pa_xmalloc(*len = result->ai_addrlen);
-    memcpy(sa, result->ai_addr, *len);
+/*** Server Info ***/
 
-    freeaddrinfo(result);
-    
-    return sa;
-}
+static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    struct pa_server_info i, *p = &i;
+    assert(pd && o && o->context && o->ref >= 1);
 
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
+    if (command != PA_COMMAND_REPLY) {
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-    if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
+        p = NULL;
+    } else if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
+               pa_tagstruct_gets(t, &i.server_version) < 0 ||
+               pa_tagstruct_gets(t, &i.user_name) < 0 ||
+               pa_tagstruct_gets(t, &i.host_name) < 0 ||
+               pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
+               !pa_tagstruct_eof(t)) {
+        pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+        goto finish;
     }
-
-    if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
-            server = DEFAULT_SERVER;
-
-    assert(!c->client);
     
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
-
-        if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
-        }
-
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
-
-        if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
+    if (o->callback) {
+        void (*cb)(struct pa_context *s, const struct pa_server_info*i, void *userdata) = o->callback;
+        cb(o->context, p, o->userdata);
     }
 
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
-    pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
-
-    return 0;
-}
-
-int pa_context_is_dead(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_DEAD;
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
+struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
+    return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, cb, userdata);
 }
 
-int pa_context_errno(struct pa_context *c) {
-    assert(c);
-    return c->error;
-}
-
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
-}
-
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    uint32_t channel;
-    assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
+/*** Sink Info ***/
 
-    c->error = PA_ERROR_KILLED;
-    stream_dead(s);
-}
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s;
-    struct pa_context *c = userdata;
-    uint32_t bytes, channel;
-    assert(pd && command == PA_COMMAND_REQUEST && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        pa_tagstruct_getu32(t, &bytes) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
-
-    if (s->state != STREAM_READY)
-        return;
-    
-    s->requested_bytes += bytes;
-
-    if (s->requested_bytes && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
-}
-
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
+static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    int eof = 1;
+    assert(pd && o && o->context && o->ref >= 1);
 
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
-        ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    s->channel_valid = 1;
-    pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
-}
-
-static void create_stream(struct pa_stream *s, const char *dev) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s);
-
-    s->state = STREAM_CREATING;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_puts(t, s->name);
-    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
-    if (s->direction == PA_STREAM_PLAYBACK) {
-        pa_tagstruct_putu32(t, s->buffer_attr.tlength);
-        pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
-        pa_tagstruct_putu32(t, s->buffer_attr.minreq);
-    } else
-        pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
-
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
-
-    create_stream(s, dev);
-    
-    return s;
-}
-
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
+        eof = -1;
+    } else {
+        
+        while (!pa_tagstruct_eof(t)) {
+            struct pa_sink_info i;
+            
+            if (pa_tagstruct_getu32(t, &i.index) < 0 ||
+                pa_tagstruct_gets(t, &i.name) < 0 ||
+                pa_tagstruct_gets(t, &i.description) < 0 ||
+                pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
+                pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
+                pa_tagstruct_getu32(t, &i.volume) < 0 ||
+                pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
+                pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
+                pa_tagstruct_getu32(t, &i.latency) < 0) {
+                pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+                goto finish;
+            }
+
+            if (o->callback) {
+                void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback;
+                cb(o->context, &i, 0, o->userdata);
+            }
+        }
     }
     
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
-
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
-}
-
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
-}
-
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
-    struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
-
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
-    chunk.index = 0;
-    chunk.length = length;
-
-    pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
-    pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
-    
-    if (length < s->requested_bytes)
-        s->requested_bytes -= length;
-    else
-        s->requested_bytes = 0;
-}
-
-size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
-    return s->requested_bytes;
-}
-
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
-
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
-
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
-}
-
-int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
-
-    if (c->state != CONTEXT_READY)
-        return 0;
-
-    return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
-}
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
-}
-
-static void set_dispatch_callbacks(struct pa_context *c);
-
-static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
-
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-    
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
-
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
-    }
-
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
+    if (o->callback) {
+        void (*cb)(struct pa_context *s, const struct pa_sink_info*i, int eof, void *userdata) = o->callback;
+        cb(o->context, NULL, eof, o->userdata);
     }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
 
-    set_dispatch_callbacks(c);
-
-    return 0;
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        return;
-    }
-
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
+struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
+    return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, cb, userdata);
 }
 
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
+struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
     struct pa_tagstruct *t;
+    struct pa_operation *o;
     uint32_t tag;
-    assert(s && s->state == STREAM_READY);
-
-    if (!complete) {
-        s->drain_complete_callback = NULL;
-        return;
-    }
+    assert(c && cb);
 
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_putu32(t, s->channel);
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
-}
-
-void pa_context_exit(struct pa_context *c) {
-    struct pa_tagstruct *t;
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
-    pa_tagstruct_putu32(t, c->ctag++);
+    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
+    pa_tagstruct_putu32(t, tag = c->ctag++);
+    pa_tagstruct_putu32(t, index);
+    pa_tagstruct_puts(t, "");
     pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
-    }
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, o);
 
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
+    return pa_operation_ref(o);
 }
 
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
+/*** Source info ***/
 
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
+static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    int eof = 1;
+    assert(pd && o && o->context && o->ref >= 1);
 
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
+        eof = -1;
+    } else {
+        
+        while (!pa_tagstruct_eof(t)) {
+            struct pa_source_info i;
+            
+            if (pa_tagstruct_getu32(t, &i.index) < 0 ||
+                pa_tagstruct_gets(t, &i.name) < 0 ||
+                pa_tagstruct_gets(t, &i.description) < 0 ||
+                pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
+                pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
+                pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
+                pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
+                pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+                goto finish;
+            }
+
+            if (o->callback) {
+                void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback;
+                cb(o->context, &i, 0, o->userdata);
+            }
+        }
     }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
+    
+    if (o->callback) {
+        void (*cb)(struct pa_context *s, const struct pa_source_info*i, int eof, void *userdata) = o->callback;
+        cb(o->context, NULL, eof, o->userdata);
     }
 
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
+struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
+    return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, cb, userdata);
 }
 
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
+struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
     struct pa_tagstruct *t;
+    struct pa_operation *o;
     uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
+    assert(c && cb);
 
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
+    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
     pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
+    pa_tagstruct_putu32(t, index);
+    pa_tagstruct_puts(t, "");
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, o);
 
-    return s;
+    return pa_operation_ref(o);
 }
 
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
+/*** Client info ***/
 
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
+static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    int eof = 1;
+    assert(pd && o && o->context && o->ref >= 1);
 
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
+        eof = -1;
+    } else {
+        
+        while (!pa_tagstruct_eof(t)) {
+            struct pa_client_info i;
+            
+            if (pa_tagstruct_getu32(t, &i.index) < 0 ||
+                pa_tagstruct_gets(t, &i.name) < 0 ||
+                pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
+                pa_tagstruct_getu32(t, &i.owner_module) < 0) {
+                pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+                goto finish;
+            }
+
+            if (o->callback) {
+                void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback;
+                cb(o->context, &i, 0, o->userdata);
+            }
+        }
     }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
+    
+    if (o->callback) {
+        void (*cb)(struct pa_context *s, const struct pa_client_info*i, int eof, void *userdata) = o->callback;
+        cb(o->context, NULL, eof, o->userdata);
     }
 
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
     struct pa_tagstruct *t;
+    struct pa_operation *o;
     uint32_t tag;
-    assert(c && name && *name && (!dev || *dev));
+    assert(c && cb);
 
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
+    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
     pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, volume);
-    pa_tagstruct_puts(t, name);
+    pa_tagstruct_putu32(t, index);
+    pa_tagstruct_puts(t, "");
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
-}
-
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, o);
 
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
+    return pa_operation_ref(o);
 }
 
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
+struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
+    return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, cb, userdata);
 }
 
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
+/*** Module info ***/
 
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
+static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    int eof = 1;
+    assert(pd && o && o->context && o->ref >= 1);
 
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
+        eof = -1;
+    } else {
         
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
+        while (!pa_tagstruct_eof(t)) {
+            struct pa_module_info i;
+            
+            if (pa_tagstruct_getu32(t, &i.index) < 0 ||
+                pa_tagstruct_gets(t, &i.name) < 0 ||
+                pa_tagstruct_gets(t, &i.argument) < 0 ||
+                pa_tagstruct_getu32(t, &i.n_used) < 0 ||
+                pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
+                pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+                goto finish;
+            }
+
+            if (o->callback) {
+                void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback;
+                cb(o->context, &i, 0, o->userdata);
+            }
         }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
     }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
     
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
+    if (o->callback) {
+        void (*cb)(struct pa_context *s, const struct pa_module_info*i, int eof, void *userdata) = o->callback;
+        cb(o->context, NULL, eof, o->userdata);
     }
 
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
+struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
     struct pa_tagstruct *t;
+    struct pa_operation *o;
     uint32_t tag;
-    assert(c);
+    assert(c && cb);
 
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
-    if (!cb)
-        return;
-    
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
+    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
     pa_tagstruct_putu32(t, tag = c->ctag++);
+    pa_tagstruct_putu32(t, index);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, o);
 
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
+    return pa_operation_ref(o);
 }
 
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    enum pa_subscription_event_type e;
-    uint32_t index;
-    assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
-
-    if (pa_tagstruct_getu32(t, &e) < 0 ||
-        pa_tagstruct_getu32(t, &index) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
-        c->subscribe_callback(c, e, index, c->subscribe_userdata);
+struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
+    return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, cb, userdata);
 }
 
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
+/*** Volume manipulation ***/
 
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
+struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+    struct pa_operation *o;
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(c);
+    assert(c && index != PA_INVALID_INDEX);
 
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
-    if (!cb)
-        return;
-    
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
+    pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME);
     pa_tagstruct_putu32(t, tag = c->ctag++);
     pa_tagstruct_putu32(t, index);
     pa_tagstruct_puts(t, "");
+    pa_tagstruct_putu32(t, volume);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
 
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
-
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
+    return pa_operation_ref(o);
 }
 
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
+struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+    struct pa_operation *o;
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
+    assert(c && name);
 
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
-    if (!cb)
-        return;
-    
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
+    pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_VOLUME);
     pa_tagstruct_putu32(t, tag = c->ctag++);
+    pa_tagstruct_putu32(t, PA_INVALID_INDEX);
+    pa_tagstruct_puts(t, name);
+    pa_tagstruct_putu32(t, volume);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
-    }
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
 
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
-    }
-
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
+    return pa_operation_ref(o);
 }
 
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
+struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+    struct pa_operation *o;
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(c);
+    assert(c && index != PA_INVALID_INDEX);
 
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
-    if (!cb)
-        return;
-    
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
+    pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME);
     pa_tagstruct_putu32(t, tag = c->ctag++);
     pa_tagstruct_putu32(t, index);
+    pa_tagstruct_putu32(t, volume);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
 
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
+    return pa_operation_ref(o);
 }
index a0dd9f9cba4bece1dd871c7636007701c309de74..bca752e2b40991d42e1ea57b39e543afefbfaa1c 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef foopolyplibhfoo
-#define foopolyplibhfoo
+#ifndef foopolyplibintrospecthfoo
+#define foopolyplibintrospecthfoo
 
 /* $Id$ */
 
   USA.
 ***/
 
-#include <sys/types.h>
+#include <inttypes.h>
 
-#include "sample.h"
-#include "polyplib-def.h"
-#include "mainloop-api.h"
+#include "polyplib-operation.h"
+#include "polyplib-context.h"
+#include "cdecl.h"
 
-#ifdef __cplusplus
-//extern "C" {
-#endif
-
-struct pa_context;
-struct pa_stream;
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name);
-void pa_context_unref(struct pa_context *c);
-struct pa_context* pa_context_ref(struct pa_context *c);
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata);
-int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata);
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
-
-int pa_context_is_dead(struct pa_context *c);
-int pa_context_is_ready(struct pa_context *c);
-int pa_context_errno(struct pa_context *c);
-
-int pa_context_is_pending(struct pa_context *c);
-
-struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_unref(struct pa_stream *s);
-struct pa_stream *pa_stream_ref(struct pa_stream *s);
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata);
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
-
-void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
-void pa_stream_write(struct pa_stream *p, const void *data, size_t length);
-size_t pa_stream_writable_size(struct pa_stream *p);
-
-void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
-
-int pa_stream_is_dead(struct pa_stream *p);
-int pa_stream_is_ready(struct pa_stream*p);
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p);
-
-uint32_t pa_stream_get_index(struct pa_stream *s);
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata);
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+PA_C_DECL_BEGIN
 
 struct pa_sink_info {
     const char *name;
@@ -90,9 +42,9 @@ struct pa_sink_info {
     uint32_t latency;
 };
 
-void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
 
 struct pa_source_info {
     const char *name;
@@ -104,9 +56,9 @@ struct pa_source_info {
     const char *monitor_of_sink_name;
 };
 
-void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
 
 struct pa_server_info {
     const char *user_name;
@@ -116,7 +68,7 @@ struct pa_server_info {
     struct pa_sample_spec sample_spec;
 };
 
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
 
 struct pa_module_info {
     uint32_t index;
@@ -124,8 +76,8 @@ struct pa_module_info {
     uint32_t n_used, auto_unload;
 };
 
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
 
 struct pa_client_info {
     uint32_t index;
@@ -134,8 +86,8 @@ struct pa_client_info {
     const char *protocol_name;
 };
 
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
 
 struct pa_sink_input_info {
     uint32_t index;
@@ -148,8 +100,8 @@ struct pa_sink_input_info {
     uint32_t latency;
 };
 
-void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
 
 struct pa_source_output_info {
     uint32_t index;
@@ -160,19 +112,20 @@ struct pa_source_output_info {
     struct pa_sample_spec sample_spec;
 };
 
-void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
+struct pa_operation* pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
 
-void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+struct pa_operation* pa_context_set_sink_volume_by_index(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+struct pa_operation* pa_context_set_sink_volume_by_name(struct pa_context *c, const char *name, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+struct pa_operation* pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
 
-void pa_context_exit(struct pa_context *c);
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
+struct pa_stat_info {
+    uint32_t memblock_count;
+    uint32_t memblock_total;
+};
 
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
+struct pa_operation* pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_stat_info *i, void *userdata), void *userdata);
 
-#ifdef __cplusplus
-}
-#endif
+PA_C_DECL_END
 
 #endif
diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c
new file mode 100644 (file)
index 0000000..994ac01
--- /dev/null
@@ -0,0 +1,78 @@
+#include <assert.h>
+
+#include "xmalloc.h"
+#include "polyplib-internal.h"
+#include "polyplib-operation.h"
+
+struct pa_operation *pa_operation_new(struct pa_context *c, struct pa_stream *s) {
+    struct pa_operation *o;
+    assert(c);
+
+    o = pa_xmalloc(sizeof(struct pa_operation));
+    o->ref = 1;
+    o->context = pa_context_ref(c);
+    o->stream = s ? pa_stream_ref(s) : NULL;
+
+    o->state = PA_OPERATION_RUNNING;
+    o->userdata = NULL;
+    o->callback = NULL;
+
+    PA_LLIST_PREPEND(struct pa_operation, o->context->operations, o);
+    return pa_operation_ref(o);
+}
+
+struct pa_operation *pa_operation_ref(struct pa_operation *o) {
+    assert(o && o->ref >= 1);
+    o->ref++;
+    return o;
+}
+
+void pa_operation_unref(struct pa_operation *o) {
+    assert(o && o->ref >= 1);
+
+    if ((--(o->ref)) == 0) {
+        assert(!o->context);
+        assert(!o->stream);
+        free(o);
+    }
+}
+
+static void operation_set_state(struct pa_operation *o, enum pa_operation_state st) {
+    assert(o && o->ref >= 1);
+
+    if (st == o->state)
+        return;
+
+    if (!o->context)
+        return;
+
+    o->state = st;
+
+    if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) {
+        PA_LLIST_REMOVE(struct pa_operation, o->context->operations, o);
+        pa_context_unref(o->context);
+        if (o->stream)
+            pa_stream_unref(o->stream);
+        o->context = NULL;
+        o->stream = NULL;
+        o->callback = NULL;
+        o->userdata = NULL;
+
+        pa_operation_unref(o);
+    }
+}
+
+void pa_operation_cancel(struct pa_operation *o) {
+    assert(o && o->ref >= 1);
+    operation_set_state(o, PA_OPERATION_CANCELED);
+}
+
+void pa_operation_done(struct pa_operation *o) {
+    assert(o && o->ref >= 1);
+    operation_set_state(o, PA_OPERATION_DONE);
+}
+
+enum pa_operation_state pa_operation_get_state(struct pa_operation *o) {
+    assert(o && o->ref >= 1);
+    return o->state;
+}
diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h
new file mode 100644 (file)
index 0000000..7d0adc2
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef foopolypliboperationhfoo
+#define foopolypliboperationhfoo
+
+/* $Id$ */
+
+/***
+  This file is part of polypaudio.
+  polypaudio 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.
+  polypaudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+  You should have received a copy of the GNU General Public License
+  along with polypaudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include "cdecl.h"
+
+/** \file
+ * Asynchronous operations */
+
+PA_C_DECL_BEGIN
+
+enum pa_operation_state {
+    PA_OPERATION_RUNNING,      /**< The operation is still running */
+    PA_OPERATION_DONE,         /**< The operation has been completed */
+    PA_OPERATION_CANCELED,     /**< The operation has been canceled */
+};
+
+/** \struct pa_operation
+ * An asynchronous operation object */
+struct pa_operation;
+
+/** Increase the reference count by one */
+struct pa_operation *pa_operation_ref(struct pa_operation *o);
+
+/** Decrease the reference count by one */
+void pa_operation_unref(struct pa_operation *o);
+
+/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */
+void pa_operation_cancel(struct pa_operation *o);
+
+/** Return the current status of the operation */
+enum pa_operation_state pa_operation_get_state(struct pa_operation *o);
+
+PA_C_DECL_END
+
+#endif
diff --git a/polyp/polyplib-sample.c b/polyp/polyplib-sample.c
deleted file mode 100644 (file)
index 35001d3..0000000
+++ /dev/null
@@ -1,1550 +0,0 @@
-/* $Id$ */
-
-/***
-  This file is part of polypaudio.
-  polypaudio 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.
-  polypaudio is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-  You should have received a copy of the GNU General Public License
-  along with polypaudio; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-  USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include "polyplib.h"
-#include "native-common.h"
-#include "pdispatch.h"
-#include "pstream.h"
-#include "dynarray.h"
-#include "socket-client.h"
-#include "pstream-util.h"
-#include "authkey.h"
-#include "util.h"
-#include "xmalloc.h"
-
-#define DEFAULT_MAXLENGTH 204800
-#define DEFAULT_TLENGTH 10240
-#define DEFAULT_PREBUF 4096
-#define DEFAULT_MINREQ 1024
-#define DEFAULT_FRAGSIZE 1024
-
-#define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
-#define DEFAULT_PORT "4713"
-
-struct pa_context {
-    char *name;
-    struct pa_mainloop_api* mainloop;
-    struct pa_socket_client *client;
-    struct pa_pstream *pstream;
-    struct pa_pdispatch *pdispatch;
-    struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
-    uint32_t ctag;
-    uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
-    
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
-
-    void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
-    void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-};
-
-struct pa_stream {
-    struct pa_context *context;
-    struct pa_stream *next, *previous;
-
-    char *name;
-    struct pa_buffer_attr buffer_attr;
-    struct pa_sample_spec sample_spec;
-    uint32_t channel;
-    int channel_valid;
-    uint32_t device_index;
-    enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
-    uint32_t requested_bytes;
-
-    void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
-    void *read_userdata;
-
-    void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
-    void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
-};
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-
-static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
-};
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
-    struct pa_context *c;
-    assert(mainloop && name);
-    
-    c = pa_xmalloc(sizeof(struct pa_context));
-    c->name = pa_xstrdup(name);
-    c->mainloop = mainloop;
-    c->client = NULL;
-    c->pstream = NULL;
-    c->pdispatch = NULL;
-    c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
-    c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
-    c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
-    c->ctag = 0;
-
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
-
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
-
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
-
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
-
-    c->subscribe_callback = NULL;
-    c->subscribe_userdata = NULL;
-
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
-    pa_check_for_sigpipe();
-    return c;
-}
-
-void pa_context_free(struct pa_context *c) {
-    assert(c);
-
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    if (c->record_streams)
-        pa_dynarray_free(c->record_streams, NULL, NULL);
-    if (c->playback_streams)
-        pa_dynarray_free(c->playback_streams, NULL, NULL);
-        
-    pa_xfree(c->name);
-    pa_xfree(c);
-}
-
-static void stream_dead(struct pa_stream *s) {
-    assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
-}
-
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
-    assert(c);
-    
-    if (c->state == CONTEXT_DEAD)
-        return;
-
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
-    
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
-}
-
-static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
-}
-
-static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && packet && c);
-
-    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
-        fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-    }
-}
-
-static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
-
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
-
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
-}
-
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
-    assert(c && t);
-    
-    if (command == PA_COMMAND_ERROR) {
-        if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            return -1;
-        }
-
-        return 0;
-    }
-
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
-}
-
-static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
-
-    if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
-    }
-
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
-
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
-    }
-
-    return;
-}
-
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
-
-    pa_socket_client_free(client);
-    c->client = NULL;
-
-    if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
-    }
-    
-    c->pstream = pa_pstream_new(c->mainloop, io);
-    assert(c->pstream);
-    pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
-    pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
-    pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
-    
-    c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
-}
-
-static struct sockaddr *resolve_server(const char *server, size_t *len) {
-    struct sockaddr *sa;
-    struct addrinfo hints, *result = NULL;
-    char *port;
-    assert(server && len);
-
-    if ((port = strrchr(server, ':')))
-        port++;
-    if (!port)
-        port = DEFAULT_PORT;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-
-    if (getaddrinfo(server, port, &hints, &result) != 0)
-        return NULL;
-    assert(result);
-    
-    sa = pa_xmalloc(*len = result->ai_addrlen);
-    memcpy(sa, result->ai_addr, *len);
-
-    freeaddrinfo(result);
-    
-    return sa;
-}
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
-
-    if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
-    }
-
-    if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
-            server = DEFAULT_SERVER;
-
-    assert(!c->client);
-    
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
-
-        if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
-        }
-
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
-
-        if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    }
-
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
-    pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
-
-    return 0;
-}
-
-int pa_context_is_dead(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_DEAD;
-}
-
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
-}
-
-int pa_context_errno(struct pa_context *c) {
-    assert(c);
-    return c->error;
-}
-
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
-}
-
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    uint32_t channel;
-    assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
-
-    c->error = PA_ERROR_KILLED;
-    stream_dead(s);
-}
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s;
-    struct pa_context *c = userdata;
-    uint32_t bytes, channel;
-    assert(pd && command == PA_COMMAND_REQUEST && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        pa_tagstruct_getu32(t, &bytes) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
-
-    if (s->state != STREAM_READY)
-        return;
-    
-    s->requested_bytes += bytes;
-
-    if (s->requested_bytes && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
-}
-
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
-        ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    s->channel_valid = 1;
-    pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
-}
-
-static void create_stream(struct pa_stream *s, const char *dev) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s);
-
-    s->state = STREAM_CREATING;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_puts(t, s->name);
-    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
-    if (s->direction == PA_STREAM_PLAYBACK) {
-        pa_tagstruct_putu32(t, s->buffer_attr.tlength);
-        pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
-        pa_tagstruct_putu32(t, s->buffer_attr.minreq);
-    } else
-        pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
-
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
-
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
-
-    create_stream(s, dev);
-    
-    return s;
-}
-
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
-    }
-    
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
-
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
-}
-
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
-}
-
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
-    struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
-
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
-    chunk.index = 0;
-    chunk.length = length;
-
-    pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
-    pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
-    
-    if (length < s->requested_bytes)
-        s->requested_bytes -= length;
-    else
-        s->requested_bytes = 0;
-}
-
-size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
-    return s->requested_bytes;
-}
-
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
-
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
-
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
-}
-
-int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
-
-    if (c->state != CONTEXT_READY)
-        return 0;
-
-    return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
-}
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
-}
-
-static void set_dispatch_callbacks(struct pa_context *c);
-
-static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
-
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-    
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
-
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
-    }
-
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
-    }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
-
-    set_dispatch_callbacks(c);
-
-    return 0;
-}
-
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        return;
-    }
-
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
-}
-
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s && s->state == STREAM_READY);
-
-    if (!complete) {
-        s->drain_complete_callback = NULL;
-        return;
-    }
-
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_putu32(t, s->channel);
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
-}
-
-void pa_context_exit(struct pa_context *c) {
-    struct pa_tagstruct *t;
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
-}
-
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
-}
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
-}
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-
-    return s;
-}
-
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
-
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
-}
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name && *name && (!dev || *dev));
-
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, volume);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
-}
-
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name);
-
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
-}
-
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
-}
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
-
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
-        
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
-    }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
-    }
-
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
-}
-
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
-
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    enum pa_subscription_event_type e;
-    uint32_t index;
-    assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
-
-    if (pa_tagstruct_getu32(t, &e) < 0 ||
-        pa_tagstruct_getu32(t, &index) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
-        c->subscribe_callback(c, e, index, c->subscribe_userdata);
-}
-
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
-
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
-}
-
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
-    }
-
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
-}
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
-
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
diff --git a/polyp/polyplib-sample.h b/polyp/polyplib-sample.h
deleted file mode 100644 (file)
index a0dd9f9..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-#ifndef foopolyplibhfoo
-#define foopolyplibhfoo
-
-/* $Id$ */
-
-/***
-  This file is part of polypaudio.
-  polypaudio 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.
-  polypaudio is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-  You should have received a copy of the GNU General Public License
-  along with polypaudio; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-  USA.
-***/
-
-#include <sys/types.h>
-
-#include "sample.h"
-#include "polyplib-def.h"
-#include "mainloop-api.h"
-
-#ifdef __cplusplus
-//extern "C" {
-#endif
-
-struct pa_context;
-struct pa_stream;
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name);
-void pa_context_unref(struct pa_context *c);
-struct pa_context* pa_context_ref(struct pa_context *c);
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata);
-int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata);
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
-
-int pa_context_is_dead(struct pa_context *c);
-int pa_context_is_ready(struct pa_context *c);
-int pa_context_errno(struct pa_context *c);
-
-int pa_context_is_pending(struct pa_context *c);
-
-struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_unref(struct pa_stream *s);
-struct pa_stream *pa_stream_ref(struct pa_stream *s);
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata);
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
-
-void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
-void pa_stream_write(struct pa_stream *p, const void *data, size_t length);
-size_t pa_stream_writable_size(struct pa_stream *p);
-
-void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
-
-int pa_stream_is_dead(struct pa_stream *p);
-int pa_stream_is_ready(struct pa_stream*p);
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p);
-
-uint32_t pa_stream_get_index(struct pa_stream *s);
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata);
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-struct pa_sink_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t volume;
-    uint32_t monitor_source;
-    const char *monitor_source_name;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t monitor_of_sink;
-    const char *monitor_of_sink_name;
-};
-
-void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_server_info {
-    const char *user_name;
-    const char *host_name;
-    const char *server_version;
-    const char *server_name;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
-
-struct pa_module_info {
-    uint32_t index;
-    const char*name, *argument;
-    uint32_t n_used, auto_unload;
-};
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_client_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    const char *protocol_name;
-};
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_sink_input_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t sink;
-    struct pa_sample_spec sample_spec;
-    uint32_t volume;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_output_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t source;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-
-void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-void pa_context_exit(struct pa_context *c);
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
index 35001d3d31d29d8445af21a8ffedcd32d8c5d3a0..8215eaec1aef3ec90fc10cdd3b8ff6a9f1203083 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <assert.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
 
-#include "polyplib.h"
-#include "native-common.h"
-#include "pdispatch.h"
-#include "pstream.h"
-#include "dynarray.h"
-#include "socket-client.h"
+#include "polyplib-scache.h"
+#include "polyplib-internal.h"
 #include "pstream-util.h"
-#include "authkey.h"
-#include "util.h"
-#include "xmalloc.h"
-
-#define DEFAULT_MAXLENGTH 204800
-#define DEFAULT_TLENGTH 10240
-#define DEFAULT_PREBUF 4096
-#define DEFAULT_MINREQ 1024
-#define DEFAULT_FRAGSIZE 1024
-
-#define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
-#define DEFAULT_PORT "4713"
-
-struct pa_context {
-    char *name;
-    struct pa_mainloop_api* mainloop;
-    struct pa_socket_client *client;
-    struct pa_pstream *pstream;
-    struct pa_pdispatch *pdispatch;
-    struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
-    uint32_t ctag;
-    uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
-    
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
-
-    void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
-    void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-};
-
-struct pa_stream {
-    struct pa_context *context;
-    struct pa_stream *next, *previous;
-
-    char *name;
-    struct pa_buffer_attr buffer_attr;
-    struct pa_sample_spec sample_spec;
-    uint32_t channel;
-    int channel_valid;
-    uint32_t device_index;
-    enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
-    uint32_t requested_bytes;
-
-    void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
-    void *read_userdata;
-
-    void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
-    void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
-};
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-
-static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
-};
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
-    struct pa_context *c;
-    assert(mainloop && name);
-    
-    c = pa_xmalloc(sizeof(struct pa_context));
-    c->name = pa_xstrdup(name);
-    c->mainloop = mainloop;
-    c->client = NULL;
-    c->pstream = NULL;
-    c->pdispatch = NULL;
-    c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
-    c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
-    c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
-    c->ctag = 0;
 
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
-
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
-
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
-
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
-
-    c->subscribe_callback = NULL;
-    c->subscribe_userdata = NULL;
-
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
-    pa_check_for_sigpipe();
-    return c;
-}
-
-void pa_context_free(struct pa_context *c) {
-    assert(c);
-
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    if (c->record_streams)
-        pa_dynarray_free(c->record_streams, NULL, NULL);
-    if (c->playback_streams)
-        pa_dynarray_free(c->playback_streams, NULL, NULL);
-        
-    pa_xfree(c->name);
-    pa_xfree(c);
-}
-
-static void stream_dead(struct pa_stream *s) {
-    assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
-}
-
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
-    assert(c);
-    
-    if (c->state == CONTEXT_DEAD)
-        return;
-
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
-    
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
-}
-
-static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
-}
-
-static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && packet && c);
-
-    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
-        fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-    }
-}
-
-static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
-
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
-
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
-}
-
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
-    assert(c && t);
-    
-    if (command == PA_COMMAND_ERROR) {
-        if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            return -1;
-        }
-
-        return 0;
-    }
-
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
-}
-
-static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
-
-    if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
-    }
-
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
-
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
-    }
-
-    return;
-}
-
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
+void pa_stream_connect_upload(struct pa_stream *s, size_t length) {
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
-
-    pa_socket_client_free(client);
-    c->client = NULL;
-
-    if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
-    }
-    
-    c->pstream = pa_pstream_new(c->mainloop, io);
-    assert(c->pstream);
-    pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
-    pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
-    pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
     
-    c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
+    assert(s && length);
 
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
-}
-
-static struct sockaddr *resolve_server(const char *server, size_t *len) {
-    struct sockaddr *sa;
-    struct addrinfo hints, *result = NULL;
-    char *port;
-    assert(server && len);
-
-    if ((port = strrchr(server, ':')))
-        port++;
-    if (!port)
-        port = DEFAULT_PORT;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-
-    if (getaddrinfo(server, port, &hints, &result) != 0)
-        return NULL;
-    assert(result);
-    
-    sa = pa_xmalloc(*len = result->ai_addrlen);
-    memcpy(sa, result->ai_addr, *len);
-
-    freeaddrinfo(result);
-    
-    return sa;
-}
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
-
-    if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
-    }
-
-    if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
-            server = DEFAULT_SERVER;
-
-    assert(!c->client);
+    pa_stream_ref(s);
     
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
-
-        if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
-        }
-
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
-
-        if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    }
-
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
-    pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
-
-    return 0;
-}
-
-int pa_context_is_dead(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_DEAD;
-}
-
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
-}
-
-int pa_context_errno(struct pa_context *c) {
-    assert(c);
-    return c->error;
-}
-
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
-}
-
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    uint32_t channel;
-    assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
-
-    c->error = PA_ERROR_KILLED;
-    stream_dead(s);
-}
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s;
-    struct pa_context *c = userdata;
-    uint32_t bytes, channel;
-    assert(pd && command == PA_COMMAND_REQUEST && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        pa_tagstruct_getu32(t, &bytes) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
-
-    if (s->state != STREAM_READY)
-        return;
-    
-    s->requested_bytes += bytes;
-
-    if (s->requested_bytes && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
-}
-
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
-        ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    s->channel_valid = 1;
-    pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
-}
-
-static void create_stream(struct pa_stream *s, const char *dev) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s);
+    s->state = PA_STREAM_CREATING;
+    s->direction = PA_STREAM_UPLOAD;
 
-    s->state = STREAM_CREATING;
-    
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
+    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
     pa_tagstruct_putu32(t, tag = s->context->ctag++);
     pa_tagstruct_puts(t, s->name);
     pa_tagstruct_put_sample_spec(t, &s->sample_spec);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
-    if (s->direction == PA_STREAM_PLAYBACK) {
-        pa_tagstruct_putu32(t, s->buffer_attr.tlength);
-        pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
-        pa_tagstruct_putu32(t, s->buffer_attr.minreq);
-    } else
-        pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
-
+    pa_tagstruct_putu32(t, length);
     pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
-
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
-
-    create_stream(s, dev);
-    
-    return s;
-}
-
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
-    }
-    
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
+    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s);
 
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
-}
-
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
-}
-
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
-    struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
-
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
-    chunk.index = 0;
-    chunk.length = length;
-
-    pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
-    pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
-    
-    if (length < s->requested_bytes)
-        s->requested_bytes -= length;
-    else
-        s->requested_bytes = 0;
-}
-
-size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
-    return s->requested_bytes;
-}
-
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
-
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
-
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
-}
-
-int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
-
-    if (c->state != CONTEXT_READY)
-        return 0;
-
-    return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
+    pa_stream_unref(s);
 }
 
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
-}
-
-static void set_dispatch_callbacks(struct pa_context *c);
-
-static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
-
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-    
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
-
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
-    }
-
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
-    }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
-
-    set_dispatch_callbacks(c);
-
-    return 0;
-}
-
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        return;
-    }
-
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
-}
-
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
+void pa_stream_finish_upload(struct pa_stream *s) {
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(s && s->state == STREAM_READY);
+    assert(s);
 
-    if (!complete) {
-        s->drain_complete_callback = NULL;
+    if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY)
         return;
-    }
 
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
+    pa_stream_ref(s);
 
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
     
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
+    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
     pa_tagstruct_putu32(t, tag = s->context->ctag++);
     pa_tagstruct_putu32(t, s->channel);
     pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
-}
-
-void pa_context_exit(struct pa_context *c) {
-    struct pa_tagstruct *t;
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
-}
-
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
-}
+    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s);
 
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
+    pa_stream_unref(s);
 }
 
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-
-    return s;
-}
-
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
-
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
-}
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+struct pa_operation * pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+    struct pa_operation *o;
     struct pa_tagstruct *t;
     uint32_t tag;
     assert(c && name && *name && (!dev || *dev));
 
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
+    if (!dev)
+        dev = getenv(ENV_DEFAULT_SINK);
+    
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
     pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
@@ -1109,44 +99,20 @@ void pa_context_play_sample(struct pa_context *c, const char *name, const char *
     pa_tagstruct_putu32(t, volume);
     pa_tagstruct_puts(t, name);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
 
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
+    return pa_operation_ref(o);
 }
 
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+    struct pa_operation *o;
     struct pa_tagstruct *t;
     uint32_t tag;
     assert(c && name);
 
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
     
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
@@ -1154,397 +120,8 @@ void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)
     pa_tagstruct_putu32(t, tag = c->ctag++);
     pa_tagstruct_puts(t, name);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
-}
-
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
 
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
+    return pa_operation_ref(o);
 }
 
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
-
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
-        
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
-    }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
-    }
-
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
-}
-
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
-
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    enum pa_subscription_event_type e;
-    uint32_t index;
-    assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
-
-    if (pa_tagstruct_getu32(t, &e) < 0 ||
-        pa_tagstruct_getu32(t, &index) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
-        c->subscribe_callback(c, e, index, c->subscribe_userdata);
-}
-
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
-
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
-}
-
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
-    }
-
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
-}
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
-
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
index a0dd9f9cba4bece1dd871c7636007701c309de74..ce74bef0978164ae9f41d52e43dcf10903a89b17 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef foopolyplibhfoo
-#define foopolyplibhfoo
+#ifndef foopolyplibscachehfoo
+#define foopolyplibscachehfoo
 
 /* $Id$ */
 
 
 #include <sys/types.h>
 
-#include "sample.h"
-#include "polyplib-def.h"
-#include "mainloop-api.h"
+#include "polyplib-context.h"
+#include "polyplib-stream.h"
+#include "cdecl.h"
 
-#ifdef __cplusplus
-//extern "C" {
-#endif
-
-struct pa_context;
-struct pa_stream;
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name);
-void pa_context_unref(struct pa_context *c);
-struct pa_context* pa_context_ref(struct pa_context *c);
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata);
-int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata);
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
-
-int pa_context_is_dead(struct pa_context *c);
-int pa_context_is_ready(struct pa_context *c);
-int pa_context_errno(struct pa_context *c);
-
-int pa_context_is_pending(struct pa_context *c);
-
-struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_unref(struct pa_stream *s);
-struct pa_stream *pa_stream_ref(struct pa_stream *s);
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata);
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
-
-void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
-void pa_stream_write(struct pa_stream *p, const void *data, size_t length);
-size_t pa_stream_writable_size(struct pa_stream *p);
-
-void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
-
-int pa_stream_is_dead(struct pa_stream *p);
-int pa_stream_is_ready(struct pa_stream*p);
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p);
-
-uint32_t pa_stream_get_index(struct pa_stream *s);
+/** \file
+ * All sample cache related routines */
 
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata);
+PA_C_DECL_BEGIN
 
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+/** Make this stream a sample upload stream */
+void pa_stream_connect_upload(struct pa_stream *s, size_t length);
 
-struct pa_sink_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t volume;
-    uint32_t monitor_source;
-    const char *monitor_source_name;
-    uint32_t latency;
-};
+/** Finish the sample upload, the stream name will become the sample name. You cancel a sample upload by issuing pa_stream_disconnect() */
+void pa_stream_finish_upload(struct pa_stream *s);
 
-void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
+/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */
+struct pa_operation* pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
 
-struct pa_source_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t monitor_of_sink;
-    const char *monitor_of_sink_name;
-};
+/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */
+struct pa_operation* pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
 
-void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_server_info {
-    const char *user_name;
-    const char *host_name;
-    const char *server_version;
-    const char *server_name;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
-
-struct pa_module_info {
-    uint32_t index;
-    const char*name, *argument;
-    uint32_t n_used, auto_unload;
-};
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_client_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    const char *protocol_name;
-};
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_sink_input_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t sink;
-    struct pa_sample_spec sample_spec;
-    uint32_t volume;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_output_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t source;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-
-void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-void pa_context_exit(struct pa_context *c);
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
-
-#ifdef __cplusplus
-}
-#endif
+PA_C_DECL_END
 
 #endif
index 1f5ea55358a7cb29288ee06c8a6d91ccb3effc34..66ee5995faae6c5674f701729521bf882d7942ed 100644 (file)
@@ -49,15 +49,28 @@ struct pa_simple {
 static void read_callback(struct pa_stream *s, const void*data, size_t length, void *userdata);
 
 static int check_error(struct pa_simple *p, int *perror) {
+    enum pa_context_state cst;
+    enum pa_stream_state sst;
     assert(p);
     
-    if (pa_context_is_dead(p->context) || (p->stream && pa_stream_is_dead(p->stream))) {
-        if (perror)
-            *perror = pa_context_errno(p->context);
-        return -1;
-    }
+    if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED)
+        goto fail;
 
+    assert(cst != PA_CONTEXT_TERMINATED);
+
+    if (p->stream) {
+        if ((sst = pa_stream_get_state(p->stream)) == PA_STREAM_FAILED)
+            goto fail;
+        
+        assert(sst != PA_STREAM_TERMINATED);
+    }
+    
     return 0;
+    
+fail:
+    if (perror)
+        *perror = pa_context_errno(p->context);
+    return -1;
 }
 
 static int iterate(struct pa_simple *p, int block, int *perror) {
@@ -96,7 +109,7 @@ struct pa_simple* pa_simple_new(
     
     struct pa_simple *p;
     int error = PA_ERROR_INTERNAL;
-    assert(ss);
+    assert(ss && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
 
     p = pa_xmalloc(sizeof(struct pa_simple));
     p->context = NULL;
@@ -110,23 +123,25 @@ struct pa_simple* pa_simple_new(
 
     if (!(p->context = pa_context_new(pa_mainloop_get_api(p->mainloop), name)))
         goto fail;
-
-    if (pa_context_connect(p->context, server, NULL, NULL) < 0) {
-        error = pa_context_errno(p->context);
-        goto fail;
-    }
+    
+    pa_context_connect(p->context, server);
 
     /* Wait until the context is ready */
-    while (!pa_context_is_ready(p->context)) {
+    while (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
         if (iterate(p, 1, &error) < 0)
             goto fail;
     }
 
-    if (!(p->stream = pa_stream_new(p->context, dir, dev, stream_name, ss, attr, NULL, NULL)))
+    if (!(p->stream = pa_stream_new(p->context, stream_name, ss)))
         goto fail;
 
+    if (dir == PA_STREAM_PLAYBACK)
+        pa_stream_connect_playback(p->stream, dev, attr);
+    else
+        pa_stream_connect_record(p->stream, dev, attr);
+
     /* Wait until the stream is ready */
-    while (!pa_stream_is_ready(p->stream)) {
+    while (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
         if (iterate(p, 1, &error) < 0)
             goto fail;
     }
@@ -148,10 +163,10 @@ void pa_simple_free(struct pa_simple *s) {
     pa_xfree(s->read_data);
 
     if (s->stream)
-        pa_stream_free(s->stream);
+        pa_stream_unref(s->stream);
     
     if (s->context)
-        pa_context_free(s->context);
+        pa_context_unref(s->context);
 
     if (s->mainloop)
         pa_mainloop_free(s->mainloop);
@@ -172,7 +187,7 @@ int pa_simple_write(struct pa_simple *p, const void*data, size_t length, int *pe
         if (l > length)
             l = length;
 
-        pa_stream_write(p->stream, data, l);
+        pa_stream_write(p->stream, data, l, NULL);
         data += l;
         length -= l;
     }
@@ -193,8 +208,7 @@ static void read_callback(struct pa_stream *s, const void*data, size_t length, v
         pa_xfree(p->read_data);
     }
 
-    p->read_data = pa_xmalloc(p->read_length = length);
-    memcpy(p->read_data, data, length);
+    p->read_data = pa_xmemdup(data, p->read_length = length);
     p->read_index = 0;
 }
 
@@ -235,23 +249,31 @@ int pa_simple_read(struct pa_simple *p, void*data, size_t length, int *perror) {
     return 0;
 }
 
-static void drain_complete(struct pa_stream *s, void *userdata) {
+static void drain_complete(struct pa_stream *s, int success, void *userdata) {
     struct pa_simple *p = userdata;
     assert(s && p);
-    p->drained = 1;
+    p->drained = success ? 1 : -1;
 }
 
 int pa_simple_drain(struct pa_simple *p, int *perror) {
+    struct pa_operation *o;
+    
     assert(p && p->direction == PA_STREAM_PLAYBACK);
     p->drained = 0;
-    pa_stream_drain(p->stream, drain_complete, p);
+    o = pa_stream_drain(p->stream, drain_complete, p);
 
     while (!p->drained) {
         if (iterate(p, 1, perror) < 0) {
-            pa_stream_drain(p->stream, NULL, NULL);
+            pa_operation_cancel(o);
+            pa_operation_unref(o);
             return -1;
         }
     }
 
+    pa_operation_unref(o);
+
+    if (p->drained < 0 && perror)
+        *perror = pa_context_errno(p->context);
+
     return 0;
 }
index 0544410c050298abcd6ab3b8222e48dc2283cd4b..ee2e27e3f61ccc18696e503e83de607b87519afc 100644 (file)
 
 #include "sample.h"
 #include "polyplib-def.h"
+#include "cdecl.h"
 
+/** \file
+ * A simple but limited synchronous playback and recording API. */
+
+PA_C_DECL_BEGIN
+
+/** \struct pa_simple
+ * A simple connection object */
 struct pa_simple;
 
+/** Create a new connection to the server */
 struct pa_simple* pa_simple_new(
-    const char *server,
-    const char *name,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *stream_name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    int *error);
+    const char *server,                 /**< Server name, or NULL for default */
+    const char *name,                   /**< A descriptive name for this client (application name, ...) */
+    enum pa_stream_direction dir,       /**< Open this stream for recording or playback? */
+    const char *dev,                    /**< Sink (resp. source) name, or NULL for default */
+    const char *stream_name,            /**< A descriptive name for this client (application name, song title, ...) */
+    const struct pa_sample_spec *ss,    /**< The sample type to use */
+    const struct pa_buffer_attr *attr,  /**< Buffering attributes, or NULL for default */
+    int *error                        /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */
+    );
 
+/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */
 void pa_simple_free(struct pa_simple *s);
 
+/** Write some data to the server */
 int pa_simple_write(struct pa_simple *s, const void*data, size_t length, int *error);
+
+/** Wait until all data already written is played by the daemon */
 int pa_simple_drain(struct pa_simple *s, int *error);
 
+/** Read some data from the server */
 int pa_simple_read(struct pa_simple *s, void*data, size_t length, int *error);
 
+PA_C_DECL_END
+
 #endif
index 35001d3d31d29d8445af21a8ffedcd32d8c5d3a0..362dbad14b89d14835f977be703672cefd9f7c85 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <assert.h>
-#include <stdlib.h>
 #include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include "polyplib.h"
-#include "native-common.h"
-#include "pdispatch.h"
-#include "pstream.h"
-#include "dynarray.h"
-#include "socket-client.h"
-#include "pstream-util.h"
-#include "authkey.h"
-#include "util.h"
-#include "xmalloc.h"
-
-#define DEFAULT_MAXLENGTH 204800
-#define DEFAULT_TLENGTH 10240
-#define DEFAULT_PREBUF 4096
-#define DEFAULT_MINREQ 1024
-#define DEFAULT_FRAGSIZE 1024
-
-#define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
-#define DEFAULT_PORT "4713"
-
-struct pa_context {
-    char *name;
-    struct pa_mainloop_api* mainloop;
-    struct pa_socket_client *client;
-    struct pa_pstream *pstream;
-    struct pa_pdispatch *pdispatch;
-    struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
-    uint32_t ctag;
-    uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
-    
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
-
-    void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
-    void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-};
-
-struct pa_stream {
-    struct pa_context *context;
-    struct pa_stream *next, *previous;
-
-    char *name;
-    struct pa_buffer_attr buffer_attr;
-    struct pa_sample_spec sample_spec;
-    uint32_t channel;
-    int channel_valid;
-    uint32_t device_index;
-    enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
-    uint32_t requested_bytes;
-
-    void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
-    void *read_userdata;
-
-    void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
-    void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
-};
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-
-static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
-};
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
-    struct pa_context *c;
-    assert(mainloop && name);
-    
-    c = pa_xmalloc(sizeof(struct pa_context));
-    c->name = pa_xstrdup(name);
-    c->mainloop = mainloop;
-    c->client = NULL;
-    c->pstream = NULL;
-    c->pdispatch = NULL;
-    c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
-    c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
-    c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
-    c->ctag = 0;
-
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
+#include <stdio.h>
 
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
+#include "polyplib-internal.h"
+#include "xmalloc.h"
+#include "pstream-util.h"
 
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
+struct pa_stream *pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss) {
+    assert(c && ss);
+    struct pa_stream *s;
 
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
+    s = pa_xmalloc(sizeof(struct pa_stream));
+    s->ref = 1;
+    s->context = c;
 
-    c->subscribe_callback = NULL;
-    c->subscribe_userdata = NULL;
+    s->read_callback = NULL;
+    s->read_userdata = NULL;
+    s->write_callback = NULL;
+    s->write_userdata = NULL;
+    s->state_callback = NULL;
+    s->state_userdata = NULL;
 
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
-    pa_check_for_sigpipe();
-    return c;
-}
+    s->state = PA_STREAM_NODIRECTION;
+    s->name = pa_xstrdup(name);
+    s->sample_spec = *ss;
+    s->channel = 0;
+    s->channel_valid = 0;
+    s->device_index = PA_INVALID_INDEX;
+    s->requested_bytes = 0;
+    s->state = PA_STREAM_DISCONNECTED;
+    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
 
-void pa_context_free(struct pa_context *c) {
-    assert(c);
+    PA_LLIST_PREPEND(struct pa_stream, c->streams, s);
 
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    if (c->record_streams)
-        pa_dynarray_free(c->record_streams, NULL, NULL);
-    if (c->playback_streams)
-        pa_dynarray_free(c->playback_streams, NULL, NULL);
-        
-    pa_xfree(c->name);
-    pa_xfree(c);
+    return pa_stream_ref(s);
 }
 
-static void stream_dead(struct pa_stream *s) {
+static void stream_free(struct pa_stream *s) {
     assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
-}
-
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
-    assert(c);
-    
-    if (c->state == CONTEXT_DEAD)
-        return;
-
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
-    
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
-}
-
-static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
+    pa_xfree(s->name);
+    pa_xfree(s);
 }
 
-static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && packet && c);
+void pa_stream_unref(struct pa_stream *s) {
+    assert(s && s->ref >= 1);
 
-    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
-        fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-    }
+    if (--(s->ref) == 0)
+        stream_free(s);
 }
 
-static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
-
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
-
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
+struct pa_stream* pa_stream_ref(struct pa_stream *s) {
+    assert(s && s->ref >= 1);
+    s->ref++;
+    return s;
 }
 
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
-    assert(c && t);
-    
-    if (command == PA_COMMAND_ERROR) {
-        if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            return -1;
-        }
-
-        return 0;
-    }
-
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
+enum pa_stream_state pa_stream_get_state(struct pa_stream *s) {
+    assert(s && s->ref >= 1);
+    return s->state;
 }
 
-static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
-
-    if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
-    }
-
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
-
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
-    }
-
-    return;
+struct pa_context* pa_stream_get_context(struct pa_stream *s) {
+    assert(s && s->ref >= 1);
+    return s->context;
 }
 
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
-
-    pa_socket_client_free(client);
-    c->client = NULL;
-
-    if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
-    }
-    
-    c->pstream = pa_pstream_new(c->mainloop, io);
-    assert(c->pstream);
-    pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
-    pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
-    pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
-    
-    c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
+uint32_t pa_stream_get_index(struct pa_stream *s) {
+    assert(s && s->ref >= 1);
+    return s->device_index;
 }
-
-static struct sockaddr *resolve_server(const char *server, size_t *len) {
-    struct sockaddr *sa;
-    struct addrinfo hints, *result = NULL;
-    char *port;
-    assert(server && len);
-
-    if ((port = strrchr(server, ':')))
-        port++;
-    if (!port)
-        port = DEFAULT_PORT;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-
-    if (getaddrinfo(server, port, &hints, &result) != 0)
-        return NULL;
-    assert(result);
     
-    sa = pa_xmalloc(*len = result->ai_addrlen);
-    memcpy(sa, result->ai_addr, *len);
+void pa_stream_set_state(struct pa_stream *s, enum pa_stream_state st) {
+    assert(s && s->ref >= 1);
 
-    freeaddrinfo(result);
+    if (s->state == st)
+        return;
     
-    return sa;
-}
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
-
-    if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
-    }
-
-    if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
-            server = DEFAULT_SERVER;
+    pa_stream_ref(s);
 
-    assert(!c->client);
+    s->state = st;
     
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
-
-        if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
-        }
+    if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) {
+        if (s->channel_valid)
+            pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
 
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
-
-        if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
+        PA_LLIST_REMOVE(struct pa_stream, s->context->streams, s);
+        pa_stream_unref(s);
     }
 
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
-    pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
-
-    return 0;
-}
-
-int pa_context_is_dead(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_DEAD;
-}
-
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
-}
-
-int pa_context_errno(struct pa_context *c) {
-    assert(c);
-    return c->error;
-}
+    if (s->state_callback)
+        s->state_callback(s, s->state_userdata);
 
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
+    pa_stream_unref(s);
 }
 
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+void pa_command_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
     struct pa_context *c = userdata;
     struct pa_stream *s;
     uint32_t channel;
     assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
 
+    pa_context_ref(c);
+    
     if (pa_tagstruct_getu32(t, &channel) < 0 ||
         !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
+        pa_context_fail(c, PA_ERROR_PROTOCOL);
+        goto finish;
     }
     
     if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
+        goto finish;
 
     c->error = PA_ERROR_KILLED;
-    stream_dead(s);
+    pa_stream_set_state(s, PA_STREAM_FAILED);
+
+finish:
+    pa_context_unref(c);
 }
 
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+void pa_command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
     struct pa_stream *s;
     struct pa_context *c = userdata;
     uint32_t bytes, channel;
     assert(pd && command == PA_COMMAND_REQUEST && t && c);
 
+    pa_context_ref(c);
+    
     if (pa_tagstruct_getu32(t, &channel) < 0 ||
         pa_tagstruct_getu32(t, &bytes) < 0 ||
         !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
+        pa_context_fail(c, PA_ERROR_PROTOCOL);
+        goto finish;
     }
     
     if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
+        goto finish;
 
-    if (s->state != STREAM_READY)
-        return;
+    if (s->state != PA_STREAM_READY)
+        goto finish;
+
+    pa_stream_ref(s);
     
     s->requested_bytes += bytes;
 
     if (s->requested_bytes && s->write_callback)
         s->write_callback(s, s->requested_bytes, s->write_userdata);
+
+    pa_stream_unref(s);
+
+finish:
+    pa_context_unref(c);
 }
 
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+void pa_create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
     struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
+    assert(pd && s && s->state == PA_STREAM_CREATING);
 
+    pa_stream_ref(s);
+    
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
+        if (pa_context_handle_error(s->context, command, t) < 0)
+            goto finish;
+        
+        pa_stream_set_state(s, PA_STREAM_FAILED);
+        goto finish;
     }
 
     if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
         ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
         !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
+        pa_context_fail(s->context, PA_ERROR_PROTOCOL);
+        goto finish;
     }
 
     s->channel_valid = 1;
     pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
+    pa_stream_set_state(s, PA_STREAM_READY);
+
+finish:
+    pa_stream_unref(s);
 }
 
-static void create_stream(struct pa_stream *s, const char *dev) {
+static void create_stream(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) {
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(s);
+    assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED);
+
+    pa_stream_ref(s);
+    
+    if (attr)
+        s->buffer_attr = *attr;
+    else {
+        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
+        s->buffer_attr.tlength = DEFAULT_TLENGTH;
+        s->buffer_attr.prebuf = DEFAULT_PREBUF;
+        s->buffer_attr.minreq = DEFAULT_MINREQ;
+        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
+    }
 
-    s->state = STREAM_CREATING;
+    pa_stream_set_state(s, PA_STREAM_CREATING);
     
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
+
+    if (!dev) {
+        if (s->direction == PA_STREAM_PLAYBACK)
+            dev = getenv(ENV_DEFAULT_SINK);
+        else
+            dev = getenv(ENV_DEFAULT_SOURCE);
+    }
     
     pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
     pa_tagstruct_putu32(t, tag = s->context->ctag++);
@@ -609,135 +250,40 @@ static void create_stream(struct pa_stream *s, const char *dev) {
         pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
 
     pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
-
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
+    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s);
 
-    create_stream(s, dev);
-    
-    return s;
+    pa_stream_unref(s);
 }
 
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
-    }
-    
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
-
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
+void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) {
+    assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1);
+    s->direction = PA_STREAM_PLAYBACK;
+    create_stream(s, dev, attr);
 }
 
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
+void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr) {
+    assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1);
+    s->direction = PA_STREAM_RECORD;
+    create_stream(s, dev, attr);
 }
 
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
+void pa_stream_write(struct pa_stream *s, const void *data, size_t length, void (*free_cb)(void *p)) {
     struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
+    assert(s && s->context && data && length && s->state == PA_STREAM_READY && s->ref >= 1);
 
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
+    if (free_cb) {
+        chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb);
+        assert(chunk.memblock && chunk.memblock->data);
+    } else {
+        chunk.memblock = pa_memblock_new(length);
+        assert(chunk.memblock && chunk.memblock->data);
+        memcpy(chunk.memblock->data, data, length);
+    }
     chunk.index = 0;
     chunk.length = length;
 
     pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
     pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
     
     if (length < s->requested_bytes)
         s->requested_bytes -= length;
@@ -746,805 +292,163 @@ void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
 }
 
 size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
+    assert(s && s->state == PA_STREAM_READY && s->ref >= 1);
     return s->requested_bytes;
 }
 
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
+struct pa_operation * pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
+    struct pa_operation *o;
+    struct pa_tagstruct *t;
+    uint32_t tag;
+    assert(s && s->ref >= 1 && s->state == PA_STREAM_READY);
 
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
+    o = pa_operation_new(s->context, s);
+    assert(o);
+    o->callback = cb;
+    o->userdata = userdata;
 
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
+    t = pa_tagstruct_new(NULL, 0);
+    assert(t);
+    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
+    pa_tagstruct_putu32(t, tag = s->context->ctag++);
+    pa_tagstruct_putu32(t, s->channel);
+    pa_pstream_send_tagstruct(s->context->pstream, t);
+    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, o);
 
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
+    return pa_operation_ref(o);
 }
 
-int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
+static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    uint32_t latency;
+    assert(pd && o && o->stream && o->context);
 
-    if (c->state != CONTEXT_READY)
-        return 0;
+    if (command != PA_COMMAND_REPLY) {
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-    return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
-}
+        latency = (uint32_t) -1;
+    } else if (pa_tagstruct_getu32(t, &latency) < 0 || !pa_tagstruct_eof(t)) {
+        pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+        goto finish;
+    }
 
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
+    if (o->callback) {
+        void (*cb)(struct pa_stream *s, uint32_t latency, void *userdata) = o->callback;
+        cb(o->stream, latency, o->userdata);
+    }
+
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
 
-static void set_dispatch_callbacks(struct pa_context *c);
+struct pa_operation* pa_stream_get_latency(struct pa_stream *s, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
+    uint32_t tag;
+    struct pa_operation *o;
+    struct pa_tagstruct *t;
+
+    o = pa_operation_new(s->context, s);
+    assert(o);
+    o->callback = cb;
+    o->userdata = userdata;
 
-static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
+    t = pa_tagstruct_new(NULL, 0);
+    assert(t);
+    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
+    pa_tagstruct_putu32(t, tag = s->context->ctag++);
+    pa_tagstruct_putu32(t, s->channel);
+    pa_pstream_send_tagstruct(s->context->pstream, t);
+    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, o);
 
-static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
-    set_dispatch_callbacks(userdata);
+    return pa_operation_ref(o);
 }
 
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
+void pa_stream_disconnect_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_stream *s = userdata;
+    assert(pd && s && s->ref >= 1);
 
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-    
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
+    pa_stream_ref(s);
 
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
-    }
-
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
-    }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
-
-    set_dispatch_callbacks(c);
-
-    return 0;
-}
-
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
+        if (pa_context_handle_error(s->context, command, t) < 0)
+            goto finish;
 
-        stream_dead(s);
-        return;
+        pa_stream_set_state(s, PA_STREAM_FAILED);
+        goto finish;
+    } else if (!pa_tagstruct_eof(t)) {
+        pa_context_fail(s->context, PA_ERROR_PROTOCOL);
+        goto finish;
     }
 
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
+    pa_stream_set_state(s, PA_STREAM_TERMINATED);
 
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
+finish:
+    pa_stream_unref(s);
 }
 
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
+void pa_stream_disconnect(struct pa_stream *s) {
     struct pa_tagstruct *t;
     uint32_t tag;
-    assert(s && s->state == STREAM_READY);
-
-    if (!complete) {
-        s->drain_complete_callback = NULL;
+    assert(s && s->ref >= 1);
+    
+    if (!s->channel_valid || !s->context->state == PA_CONTEXT_READY)
         return;
-    }
 
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
+    pa_stream_ref(s);
 
     t = pa_tagstruct_new(NULL, 0);
     assert(t);
     
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
+    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
+                        (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
     pa_tagstruct_putu32(t, tag = s->context->ctag++);
     pa_tagstruct_putu32(t, s->channel);
     pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
-}
-
-void pa_context_exit(struct pa_context *c) {
-    struct pa_tagstruct *t;
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
-}
-
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
-}
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
-}
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-
-    return s;
-}
-
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
-
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
-}
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name && *name && (!dev || *dev));
-
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, volume);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
-}
-
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name);
-
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
-}
-
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
-}
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
-
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
-        
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
-    }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
-    }
-
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
-}
-
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
-
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    enum pa_subscription_event_type e;
-    uint32_t index;
-    assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
+    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s);
 
-    if (pa_tagstruct_getu32(t, &e) < 0 ||
-        pa_tagstruct_getu32(t, &index) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
-        c->subscribe_callback(c, e, index, c->subscribe_userdata);
-}
-
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
+    pa_stream_unref(s);
 }
 
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
-
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
+void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
+    assert(s && s->ref >= 1);
+    s->read_callback = cb;
+    s->read_userdata = userdata;
 }
 
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
+void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
+    assert(s && s->ref >= 1);
+    s->write_callback = cb;
+    s->write_userdata = userdata;
 }
 
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
+void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
+    assert(s && s->ref >= 1);
+    s->state_callback = cb;
+    s->state_userdata = userdata;
 }
 
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
+void pa_stream_simple_ack_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+    struct pa_operation *o = userdata;
+    int success = 1;
+    assert(pd && o && o->context && o->ref >= 1);
 
     if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
+        if (pa_context_handle_error(o->context, command, t) < 0)
+            goto finish;
 
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
+        success = 0;
+    } else if (!pa_tagstruct_eof(t)) {
+        pa_context_fail(o->context, PA_ERROR_PROTOCOL);
+        goto finish;
     }
 
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
+    if (o->callback) {
+        void (*cb)(struct pa_stream *s, int success, void *userdata) = o->callback;
+        cb(o->stream, success, o->userdata);
     }
 
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
-}
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
-
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
+finish:
+    pa_operation_done(o);
+    pa_operation_unref(o);
 }
index a0dd9f9cba4bece1dd871c7636007701c309de74..41801c6c4d1241dc4151fd1cc946fe00469c4584 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef foopolyplibhfoo
-#define foopolyplibhfoo
+#ifndef foopolyplibstreamhfoo
+#define foopolyplibstreamhfoo
 
 /* $Id$ */
 
 
 #include "sample.h"
 #include "polyplib-def.h"
-#include "mainloop-api.h"
+#include "cdecl.h"
+#include "polyplib-operation.h"
 
-#ifdef __cplusplus
-//extern "C" {
-#endif
-
-struct pa_context;
-struct pa_stream;
+/** \file
+ * Audio streams for input, output and sample upload */
 
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name);
-void pa_context_unref(struct pa_context *c);
-struct pa_context* pa_context_ref(struct pa_context *c);
+PA_C_DECL_BEGIN
 
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata);
-int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata);
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
+/** The state of a stream */
+enum pa_stream_state {
+    PA_STREAM_DISCONNECTED, /**< The stream is not yet connected to any sink or source */
+    PA_STREAM_CREATING,     /**< The stream is being created */
+    PA_STREAM_READY,        /**< The stream is established, you may pass audio data to it now */
+    PA_STREAM_FAILED,       /**< An error occured that made the stream invalid */
+    PA_STREAM_TERMINATED,   /**< The stream has been terminated cleanly */
+};
 
-int pa_context_is_dead(struct pa_context *c);
-int pa_context_is_ready(struct pa_context *c);
-int pa_context_errno(struct pa_context *c);
+/** \struct pa_stream
+ * A stream for playback or recording */
+struct pa_stream;
 
-int pa_context_is_pending(struct pa_context *c);
+/** Create a new, unconnected stream with the specified name and sample type */
+struct pa_stream* pa_stream_new(struct pa_context *c, const char *name, const struct pa_sample_spec *ss);
 
-struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata);
+/** Decrease the reference counter by one */
 void pa_stream_unref(struct pa_stream *s);
-struct pa_stream *pa_stream_ref(struct pa_stream *s);
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata);
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
 
-void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
-void pa_stream_write(struct pa_stream *p, const void *data, size_t length);
-size_t pa_stream_writable_size(struct pa_stream *p);
-
-void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
-
-int pa_stream_is_dead(struct pa_stream *p);
-int pa_stream_is_ready(struct pa_stream*p);
+/** Increase the reference counter by one */
+struct pa_stream *pa_stream_ref(struct pa_stream *s);
 
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
+/** Return the current state of the stream */
+enum pa_stream_state pa_stream_get_state(struct pa_stream *p);
 
+/** Return the context this stream is attached to */
 struct pa_context* pa_stream_get_context(struct pa_stream *p);
 
+/** Return the device (sink input or source output) index this stream is connected to */
 uint32_t pa_stream_get_index(struct pa_stream *s);
 
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata);
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-struct pa_sink_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t volume;
-    uint32_t monitor_source;
-    const char *monitor_source_name;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t monitor_of_sink;
-    const char *monitor_of_sink_name;
-};
-
-void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_server_info {
-    const char *user_name;
-    const char *host_name;
-    const char *server_version;
-    const char *server_name;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
+/** Connect the stream to a sink */
+void pa_stream_connect_playback(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr);
 
-struct pa_module_info {
-    uint32_t index;
-    const char*name, *argument;
-    uint32_t n_used, auto_unload;
-};
+/** Connect the stream to a source */
+void pa_stream_connect_record(struct pa_stream *s, const char *dev, const struct pa_buffer_attr *attr);
 
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
+/** Disconnect a stream from a source/sink */
+void pa_stream_disconnect(struct pa_stream *s);
 
-struct pa_client_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    const char *protocol_name;
-};
+/** Write some data to the server (for playback sinks), if free_cb is
+ * non-NULL this routine is called when all data has been written out
+ * and an internal reference to the specified data is kept, the data
+ * is not copied. If NULL, the data is copied into an internal
+ * buffer. */ 
+void pa_stream_write(struct pa_stream *p, const void *data, size_t length, void (*free_cb)(void *p));
 
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_sink_input_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t sink;
-    struct pa_sample_spec sample_spec;
-    uint32_t volume;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
+/** Return the amount of bytes that may be written using pa_stream_write() */
+size_t pa_stream_writable_size(struct pa_stream *p);
 
-struct pa_source_output_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t source;
-    struct pa_sample_spec sample_spec;
-};
+/** Drain a playback stream */
+struct pa_operation* pa_stream_drain(struct pa_stream *s, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
 
-void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
+/** Get the playback latency of a stream */
+struct pa_operation* pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
 
-void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+/** Set the callback function that is called whenever the state of the stream changes */
+void pa_stream_set_state_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
 
-void pa_context_exit(struct pa_context *c);
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
+/** Set the callback function that is called when new data may be written to the stream */
+void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
 
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
+/** Set the callback function that is called when new data is available from the stream */
+void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
 
-#ifdef __cplusplus
-}
-#endif
+PA_C_DECL_END
 
 #endif
index 35001d3d31d29d8445af21a8ffedcd32d8c5d3a0..a14d0b064a0574d333cfcf6e4c0a2a2e06d56596 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
 
-#include "polyplib.h"
-#include "native-common.h"
-#include "pdispatch.h"
-#include "pstream.h"
-#include "dynarray.h"
-#include "socket-client.h"
+#include "polyplib-subscribe.h"
+#include "polyplib-internal.h"
 #include "pstream-util.h"
-#include "authkey.h"
-#include "util.h"
-#include "xmalloc.h"
 
-#define DEFAULT_MAXLENGTH 204800
-#define DEFAULT_TLENGTH 10240
-#define DEFAULT_PREBUF 4096
-#define DEFAULT_MINREQ 1024
-#define DEFAULT_FRAGSIZE 1024
-
-#define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
-#define DEFAULT_PORT "4713"
-
-struct pa_context {
-    char *name;
-    struct pa_mainloop_api* mainloop;
-    struct pa_socket_client *client;
-    struct pa_pstream *pstream;
-    struct pa_pdispatch *pdispatch;
-    struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
-    uint32_t ctag;
-    uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
-    
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
-
-    void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
-    void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-};
-
-struct pa_stream {
-    struct pa_context *context;
-    struct pa_stream *next, *previous;
-
-    char *name;
-    struct pa_buffer_attr buffer_attr;
-    struct pa_sample_spec sample_spec;
-    uint32_t channel;
-    int channel_valid;
-    uint32_t device_index;
-    enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
-    uint32_t requested_bytes;
-
-    void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
-    void *read_userdata;
-
-    void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
-    void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
-};
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-
-static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
-};
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
-    struct pa_context *c;
-    assert(mainloop && name);
-    
-    c = pa_xmalloc(sizeof(struct pa_context));
-    c->name = pa_xstrdup(name);
-    c->mainloop = mainloop;
-    c->client = NULL;
-    c->pstream = NULL;
-    c->pdispatch = NULL;
-    c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
-    c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
-    c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
-    c->ctag = 0;
-
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
-
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
-
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
-
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
-
-    c->subscribe_callback = NULL;
-    c->subscribe_userdata = NULL;
-
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
-    pa_check_for_sigpipe();
-    return c;
-}
-
-void pa_context_free(struct pa_context *c) {
-    assert(c);
-
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    if (c->record_streams)
-        pa_dynarray_free(c->record_streams, NULL, NULL);
-    if (c->playback_streams)
-        pa_dynarray_free(c->playback_streams, NULL, NULL);
-        
-    pa_xfree(c->name);
-    pa_xfree(c);
-}
-
-static void stream_dead(struct pa_stream *s) {
-    assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
-}
-
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
-    assert(c);
-    
-    if (c->state == CONTEXT_DEAD)
-        return;
-
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
-    
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
-}
-
-static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
-}
-
-static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && packet && c);
-
-    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
-        fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-    }
-}
-
-static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
-
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
-
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
-}
-
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
-    assert(c && t);
-    
-    if (command == PA_COMMAND_ERROR) {
-        if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            return -1;
-        }
-
-        return 0;
-    }
-
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
-}
-
-static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
-
-    if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
-    }
-
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
-
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
-    }
-
-    return;
-}
-
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
-
-    pa_socket_client_free(client);
-    c->client = NULL;
-
-    if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
-    }
-    
-    c->pstream = pa_pstream_new(c->mainloop, io);
-    assert(c->pstream);
-    pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
-    pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
-    pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
-    
-    c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
-}
-
-static struct sockaddr *resolve_server(const char *server, size_t *len) {
-    struct sockaddr *sa;
-    struct addrinfo hints, *result = NULL;
-    char *port;
-    assert(server && len);
-
-    if ((port = strrchr(server, ':')))
-        port++;
-    if (!port)
-        port = DEFAULT_PORT;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-
-    if (getaddrinfo(server, port, &hints, &result) != 0)
-        return NULL;
-    assert(result);
-    
-    sa = pa_xmalloc(*len = result->ai_addrlen);
-    memcpy(sa, result->ai_addr, *len);
-
-    freeaddrinfo(result);
-    
-    return sa;
-}
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
-
-    if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
-    }
-
-    if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
-            server = DEFAULT_SERVER;
-
-    assert(!c->client);
-    
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
-
-        if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
-        }
-
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
-
-        if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    }
-
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
-    pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
-
-    return 0;
-}
-
-int pa_context_is_dead(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_DEAD;
-}
-
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
-}
-
-int pa_context_errno(struct pa_context *c) {
-    assert(c);
-    return c->error;
-}
-
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
-}
-
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    uint32_t channel;
-    assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
-
-    c->error = PA_ERROR_KILLED;
-    stream_dead(s);
-}
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s;
-    struct pa_context *c = userdata;
-    uint32_t bytes, channel;
-    assert(pd && command == PA_COMMAND_REQUEST && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        pa_tagstruct_getu32(t, &bytes) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
-
-    if (s->state != STREAM_READY)
-        return;
-    
-    s->requested_bytes += bytes;
-
-    if (s->requested_bytes && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
-}
-
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
-        ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    s->channel_valid = 1;
-    pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
-}
-
-static void create_stream(struct pa_stream *s, const char *dev) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s);
-
-    s->state = STREAM_CREATING;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_puts(t, s->name);
-    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
-    if (s->direction == PA_STREAM_PLAYBACK) {
-        pa_tagstruct_putu32(t, s->buffer_attr.tlength);
-        pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
-        pa_tagstruct_putu32(t, s->buffer_attr.minreq);
-    } else
-        pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
-
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
-
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
-
-    create_stream(s, dev);
-    
-    return s;
-}
-
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
-    }
-    
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
-
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
-}
-
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
-}
-
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
-    struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
-
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
-    chunk.index = 0;
-    chunk.length = length;
-
-    pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
-    pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
-    
-    if (length < s->requested_bytes)
-        s->requested_bytes -= length;
-    else
-        s->requested_bytes = 0;
-}
-
-size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
-    return s->requested_bytes;
-}
-
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
-
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
-
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
-}
-
-int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
-
-    if (c->state != CONTEXT_READY)
-        return 0;
-
-    return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
-}
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
-}
-
-static void set_dispatch_callbacks(struct pa_context *c);
-
-static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
-
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-    
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
-
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
-    }
-
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
-    }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
-
-    set_dispatch_callbacks(c);
-
-    return 0;
-}
-
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        return;
-    }
-
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
-}
-
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s && s->state == STREAM_READY);
-
-    if (!complete) {
-        s->drain_complete_callback = NULL;
-        return;
-    }
-
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_putu32(t, s->channel);
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
-}
-
-void pa_context_exit(struct pa_context *c) {
-    struct pa_tagstruct *t;
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
-}
-
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
-}
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
-}
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-
-    return s;
-}
-
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
-
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
-}
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name && *name && (!dev || *dev));
-
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, volume);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
-}
-
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name);
-
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
-}
-
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
-}
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
-
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
-        
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
-    }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
-    }
-
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
-}
-
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
-
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
+void pa_command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
     struct pa_context *c = userdata;
     enum pa_subscription_event_type e;
     uint32_t index;
     assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
 
+    pa_context_ref(c);
+
     if (pa_tagstruct_getu32(t, &e) < 0 ||
         pa_tagstruct_getu32(t, &index) < 0 ||
         !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
+        pa_context_fail(c, PA_ERROR_PROTOCOL);
+        goto finish;
     }
 
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
+    if (c->subscribe_callback)
         c->subscribe_callback(c, e, index, c->subscribe_userdata);
-}
-
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
 
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
+finish:
+    pa_context_unref(c);
 }
 
 
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
+struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
+    struct pa_operation *o;
     struct pa_tagstruct *t;
     uint32_t tag;
     assert(c);
 
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
+    o = pa_operation_new(c, NULL);
+    o->callback = cb;
+    o->userdata = userdata;
 
-    if (!cb)
-        return;
-    
     t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
+    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
     pa_tagstruct_putu32(t, tag = c->ctag++);
+    pa_tagstruct_putu32(t, cb ? m : 0);
     pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
+    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, o);
 
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
-    }
-
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
+    return pa_operation_ref(o);
 }
 
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
-
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
index a0dd9f9cba4bece1dd871c7636007701c309de74..56384915199d615354b941c7e709cd9b2e18aac0 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef foopolyplibhfoo
-#define foopolyplibhfoo
+#ifndef foopolyplibsubscribehfoo
+#define foopolyplibsubscribehfoo
 
 /* $Id$ */
 
   USA.
 ***/
 
-#include <sys/types.h>
+#include <inttypes.h>
 
-#include "sample.h"
 #include "polyplib-def.h"
-#include "mainloop-api.h"
+#include "polyplib-context.h"
+#include "cdecl.h"
 
-#ifdef __cplusplus
-//extern "C" {
-#endif
-
-struct pa_context;
-struct pa_stream;
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name);
-void pa_context_unref(struct pa_context *c);
-struct pa_context* pa_context_ref(struct pa_context *c);
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata);
-int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata);
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
-
-int pa_context_is_dead(struct pa_context *c);
-int pa_context_is_ready(struct pa_context *c);
-int pa_context_errno(struct pa_context *c);
-
-int pa_context_is_pending(struct pa_context *c);
-
-struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_unref(struct pa_stream *s);
-struct pa_stream *pa_stream_ref(struct pa_stream *s);
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata);
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
-
-void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
-void pa_stream_write(struct pa_stream *p, const void *data, size_t length);
-size_t pa_stream_writable_size(struct pa_stream *p);
-
-void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
-
-int pa_stream_is_dead(struct pa_stream *p);
-int pa_stream_is_ready(struct pa_stream*p);
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p);
-
-uint32_t pa_stream_get_index(struct pa_stream *s);
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata);
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+PA_C_DECL_BEGIN
 
-struct pa_sink_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t volume;
-    uint32_t monitor_source;
-    const char *monitor_source_name;
-    uint32_t latency;
-};
+struct pa_operation* pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
+void pa_context_set_subscribe_callback(struct pa_context *c, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
 
-void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t monitor_of_sink;
-    const char *monitor_of_sink_name;
-};
-
-void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_server_info {
-    const char *user_name;
-    const char *host_name;
-    const char *server_version;
-    const char *server_name;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
-
-struct pa_module_info {
-    uint32_t index;
-    const char*name, *argument;
-    uint32_t n_used, auto_unload;
-};
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_client_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    const char *protocol_name;
-};
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_sink_input_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t sink;
-    struct pa_sample_spec sample_spec;
-    uint32_t volume;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_output_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t source;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-
-void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-void pa_context_exit(struct pa_context *c);
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
-
-#ifdef __cplusplus
-}
-#endif
+PA_C_DECL_END
 
 #endif
diff --git a/polyp/polyplib.c b/polyp/polyplib.c
deleted file mode 100644 (file)
index 35001d3..0000000
+++ /dev/null
@@ -1,1550 +0,0 @@
-/* $Id$ */
-
-/***
-  This file is part of polypaudio.
-  polypaudio 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.
-  polypaudio is distributed in the hope that it will be useful, but
-  WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-  General Public License for more details.
-  You should have received a copy of the GNU General Public License
-  along with polypaudio; if not, write to the Free Software
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-  USA.
-***/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netdb.h>
-
-#include "polyplib.h"
-#include "native-common.h"
-#include "pdispatch.h"
-#include "pstream.h"
-#include "dynarray.h"
-#include "socket-client.h"
-#include "pstream-util.h"
-#include "authkey.h"
-#include "util.h"
-#include "xmalloc.h"
-
-#define DEFAULT_MAXLENGTH 204800
-#define DEFAULT_TLENGTH 10240
-#define DEFAULT_PREBUF 4096
-#define DEFAULT_MINREQ 1024
-#define DEFAULT_FRAGSIZE 1024
-
-#define DEFAULT_TIMEOUT (5*60)
-#define DEFAULT_SERVER "/tmp/polypaudio/native"
-#define DEFAULT_PORT "4713"
-
-struct pa_context {
-    char *name;
-    struct pa_mainloop_api* mainloop;
-    struct pa_socket_client *client;
-    struct pa_pstream *pstream;
-    struct pa_pdispatch *pdispatch;
-    struct pa_dynarray *record_streams, *playback_streams;
-    struct pa_stream *first_stream;
-    uint32_t ctag;
-    uint32_t error;
-    enum {
-        CONTEXT_UNCONNECTED,
-        CONTEXT_CONNECTING,
-        CONTEXT_AUTHORIZING,
-        CONTEXT_SETTING_NAME,
-        CONTEXT_READY,
-        CONTEXT_DEAD
-    } state;
-
-    void (*connect_complete_callback)(struct pa_context*c, int success, void *userdata);
-    void *connect_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_context*c, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_context*c, void *userdata);
-    void *die_userdata;
-
-    void (*stat_callback)(struct pa_context*c, uint32_t count, uint32_t total, void *userdata);
-    void *stat_userdata;
-
-    void (*play_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *play_sample_userdata;
-    
-    void (*remove_sample_callback)(struct pa_context*c, int success, void *userdata);
-    void *remove_sample_userdata;
-
-    void (*get_server_info_callback)(struct pa_context*c, const struct pa_server_info* i, void *userdata);
-    void *get_server_info_userdata;
-
-    void (*get_sink_info_callback)(struct pa_context*c, const struct pa_sink_info* i, int is_last, void *userdata);
-    void *get_sink_info_userdata;
-
-    void (*get_source_info_callback)(struct pa_context*c, const struct pa_source_info* i, int is_last, void *userdata);
-    void *get_source_info_userdata;
-
-    void (*subscribe_callback)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata);
-    void *subscribe_userdata;
-    enum pa_subscription_mask subscribe_mask;
-
-    void (*get_client_info_callback)(struct pa_context*c, const struct pa_client_info* i, int is_last, void *userdata);
-    void *get_client_info_userdata;
-
-    void (*get_module_info_callback)(struct pa_context*c, const struct pa_module_info* i, int is_last, void *userdata);
-    void *get_module_info_userdata;
-
-    uint8_t auth_cookie[PA_NATIVE_COOKIE_LENGTH];
-};
-
-struct pa_stream {
-    struct pa_context *context;
-    struct pa_stream *next, *previous;
-
-    char *name;
-    struct pa_buffer_attr buffer_attr;
-    struct pa_sample_spec sample_spec;
-    uint32_t channel;
-    int channel_valid;
-    uint32_t device_index;
-    enum pa_stream_direction direction;
-    
-    enum { STREAM_CREATING, STREAM_READY, STREAM_DEAD} state;
-    uint32_t requested_bytes;
-
-    void (*read_callback)(struct pa_stream *p, const void*data, size_t length, void *userdata);
-    void *read_userdata;
-
-    void (*write_callback)(struct pa_stream *p, size_t length, void *userdata);
-    void *write_userdata;
-    
-    void (*create_complete_callback)(struct pa_stream *s, int success, void *userdata);
-    void *create_complete_userdata;
-
-    void (*drain_complete_callback)(struct pa_stream *s, void *userdata);
-    void *drain_complete_userdata;
-    
-    void (*die_callback)(struct pa_stream*c, void *userdata);
-    void *die_userdata;
-
-    void (*get_latency_callback)(struct pa_stream*c, uint32_t latency, void *userdata);
-    void *get_latency_userdata;
-
-    void (*finish_sample_callback)(struct pa_stream*c, int success, void *userdata);
-    void *finish_sample_userdata;
-};
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata);
-
-static const struct pa_pdispatch_command command_table[PA_COMMAND_MAX] = {
-    [PA_COMMAND_ERROR] = { NULL },
-    [PA_COMMAND_REPLY] = { NULL },
-    [PA_COMMAND_CREATE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_PLAYBACK_STREAM] = { NULL },
-    [PA_COMMAND_CREATE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_DELETE_RECORD_STREAM] = { NULL },
-    [PA_COMMAND_EXIT] = { NULL },
-    [PA_COMMAND_REQUEST] = { command_request },
-    [PA_COMMAND_PLAYBACK_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_RECORD_STREAM_KILLED] = { command_playback_stream_killed },
-    [PA_COMMAND_SUBSCRIBE_EVENT] = { command_subscribe_event },
-};
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name) {
-    struct pa_context *c;
-    assert(mainloop && name);
-    
-    c = pa_xmalloc(sizeof(struct pa_context));
-    c->name = pa_xstrdup(name);
-    c->mainloop = mainloop;
-    c->client = NULL;
-    c->pstream = NULL;
-    c->pdispatch = NULL;
-    c->playback_streams = pa_dynarray_new();
-    assert(c->playback_streams);
-    c->record_streams = pa_dynarray_new();
-    assert(c->record_streams);
-    c->first_stream = NULL;
-    c->error = PA_ERROR_OK;
-    c->state = CONTEXT_UNCONNECTED;
-    c->ctag = 0;
-
-    c->connect_complete_callback = NULL;
-    c->connect_complete_userdata = NULL;
-
-    c->drain_complete_callback = NULL;
-    c->drain_complete_userdata = NULL;
-
-    c->die_callback = NULL;
-    c->die_userdata = NULL;
-
-    c->stat_callback = NULL;
-    c->stat_userdata = NULL;
-
-    c->play_sample_callback = NULL;
-    c->play_sample_userdata = NULL;
-
-    c->remove_sample_callback = NULL;
-    c->remove_sample_userdata = NULL;
-
-    c->get_server_info_callback = NULL;
-    c->get_server_info_userdata = NULL;
-
-    c->get_sink_info_callback = NULL;
-    c->get_sink_info_userdata = NULL;
-
-    c->get_source_info_callback = NULL;
-    c->get_source_info_userdata = NULL;
-
-    c->subscribe_callback = NULL;
-    c->subscribe_userdata = NULL;
-
-    c->get_client_info_callback = NULL;
-    c->get_client_info_userdata = NULL;
-    
-    c->get_module_info_callback = NULL;
-    c->get_module_info_userdata = NULL;
-    
-    pa_check_for_sigpipe();
-    return c;
-}
-
-void pa_context_free(struct pa_context *c) {
-    assert(c);
-
-    while (c->first_stream)
-        pa_stream_free(c->first_stream);
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    if (c->record_streams)
-        pa_dynarray_free(c->record_streams, NULL, NULL);
-    if (c->playback_streams)
-        pa_dynarray_free(c->playback_streams, NULL, NULL);
-        
-    pa_xfree(c->name);
-    pa_xfree(c);
-}
-
-static void stream_dead(struct pa_stream *s) {
-    assert(s);
-    
-    if (s->state == STREAM_DEAD)
-        return;
-    
-    if (s->state == STREAM_READY) {
-        s->state = STREAM_DEAD;
-        if (s->die_callback)
-            s->die_callback(s, s->die_userdata);
-    } else
-        s->state = STREAM_DEAD;
-}
-
-static void context_dead(struct pa_context *c) {
-    struct pa_stream *s;
-    assert(c);
-    
-    if (c->state == CONTEXT_DEAD)
-        return;
-
-    if (c->pdispatch)
-        pa_pdispatch_free(c->pdispatch);
-    c->pdispatch = NULL;
-    
-    if (c->pstream)
-        pa_pstream_free(c->pstream);
-    c->pstream = NULL;
-    
-    if (c->client)
-        pa_socket_client_free(c->client);
-    c->client = NULL;
-    
-    for (s = c->first_stream; s; s = s->next)
-        stream_dead(s);
-
-    if (c->state == CONTEXT_READY) {
-        c->state = CONTEXT_DEAD;
-        if (c->die_callback)
-            c->die_callback(c, c->die_userdata);
-    } else
-        c->state = CONTEXT_DEAD;
-}
-
-static void pstream_die_callback(struct pa_pstream *p, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && c);
-    c->error = PA_ERROR_CONNECTIONTERMINATED;
-    context_dead(c);
-}
-
-static void pstream_packet_callback(struct pa_pstream *p, struct pa_packet *packet, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(p && packet && c);
-
-    if (pa_pdispatch_run(c->pdispatch, packet, c) < 0) {
-        fprintf(stderr, "polyp.c: invalid packet.\n");
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-    }
-}
-
-static void pstream_memblock_callback(struct pa_pstream *p, uint32_t channel, int32_t delta, const struct pa_memchunk *chunk, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    assert(p && chunk && c && chunk->memblock && chunk->memblock->data);
-
-    if (!(s = pa_dynarray_get(c->record_streams, channel)))
-        return;
-
-    if (s->read_callback)
-        s->read_callback(s, chunk->memblock->data + chunk->index, chunk->length, s->read_userdata);
-}
-
-static int handle_error(struct pa_context *c, uint32_t command, struct pa_tagstruct *t) {
-    assert(c && t);
-    
-    if (command == PA_COMMAND_ERROR) {
-        if (pa_tagstruct_getu32(t, &c->error) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            return -1;
-        }
-
-        return 0;
-    }
-
-    c->error = (command == PA_COMMAND_TIMEOUT) ? PA_ERROR_TIMEOUT : PA_ERROR_INTERNAL;
-    return -1;
-}
-
-static void setup_complete_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c && (c->state == CONTEXT_AUTHORIZING || c->state == CONTEXT_SETTING_NAME));
-
-    if (command != PA_COMMAND_REPLY) {
-        handle_error(c, command, t);
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-        
-        return;
-    }
-
-    if (c->state == CONTEXT_AUTHORIZING) {
-        struct pa_tagstruct *t;
-        c->state = CONTEXT_SETTING_NAME;
-        t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-        pa_tagstruct_putu32(t, PA_COMMAND_SET_NAME);
-        pa_tagstruct_putu32(t, tag = c->ctag++);
-        pa_tagstruct_puts(t, c->name);
-        pa_pstream_send_tagstruct(c->pstream, t);
-        pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    } else {
-        assert(c->state == CONTEXT_SETTING_NAME);
-        
-        c->state = CONTEXT_READY;
-
-        if (c->connect_complete_callback) 
-            c->connect_complete_callback(c, 1, c->connect_complete_userdata);
-    }
-
-    return;
-}
-
-static void on_connection(struct pa_socket_client *client, struct pa_iochannel*io, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(client && c && c->state == CONTEXT_CONNECTING);
-
-    pa_socket_client_free(client);
-    c->client = NULL;
-
-    if (!io) {
-        c->error = PA_ERROR_CONNECTIONREFUSED;
-        context_dead(c);
-
-        if (c->connect_complete_callback)
-            c->connect_complete_callback(c, 0, c->connect_complete_userdata);
-
-        return;
-    }
-    
-    c->pstream = pa_pstream_new(c->mainloop, io);
-    assert(c->pstream);
-    pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c);
-    pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c);
-    pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c);
-    
-    c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
-    assert(c->pdispatch);
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_AUTH);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_put_arbitrary(t, c->auth_cookie, sizeof(c->auth_cookie));
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c);
-    c->state = CONTEXT_AUTHORIZING;
-}
-
-static struct sockaddr *resolve_server(const char *server, size_t *len) {
-    struct sockaddr *sa;
-    struct addrinfo hints, *result = NULL;
-    char *port;
-    assert(server && len);
-
-    if ((port = strrchr(server, ':')))
-        port++;
-    if (!port)
-        port = DEFAULT_PORT;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    hints.ai_protocol = 0;
-
-    if (getaddrinfo(server, port, &hints, &result) != 0)
-        return NULL;
-    assert(result);
-    
-    sa = pa_xmalloc(*len = result->ai_addrlen);
-    memcpy(sa, result->ai_addr, *len);
-
-    freeaddrinfo(result);
-    
-    return sa;
-}
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata) {
-    assert(c && c->state == CONTEXT_UNCONNECTED);
-
-    if (pa_authkey_load_from_home(PA_NATIVE_COOKIE_FILE, c->auth_cookie, sizeof(c->auth_cookie)) < 0) {
-        c->error = PA_ERROR_AUTHKEY;
-        return -1;
-    }
-
-    if (!server)
-        if (!(server = getenv("POLYP_SERVER")))
-            server = DEFAULT_SERVER;
-
-    assert(!c->client);
-    
-    if (*server == '/') {
-        if (!(c->client = pa_socket_client_new_unix(c->mainloop, server))) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    } else {
-        struct sockaddr* sa;
-        size_t sa_len;
-
-        if (!(sa = resolve_server(server, &sa_len))) {
-            c->error = PA_ERROR_INVALIDSERVER;
-            return -1;
-        }
-
-        c->client = pa_socket_client_new_sockaddr(c->mainloop, sa, sa_len);
-        pa_xfree(sa);
-
-        if (!c->client) {
-            c->error = PA_ERROR_CONNECTIONREFUSED;
-            return -1;
-        }
-    }
-
-    c->connect_complete_callback = complete;
-    c->connect_complete_userdata = userdata;
-    
-    pa_socket_client_set_callback(c->client, on_connection, c);
-    c->state = CONTEXT_CONNECTING;
-
-    return 0;
-}
-
-int pa_context_is_dead(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_DEAD;
-}
-
-int pa_context_is_ready(struct pa_context *c) {
-    assert(c);
-    return c->state == CONTEXT_READY;
-}
-
-int pa_context_errno(struct pa_context *c) {
-    assert(c);
-    return c->error;
-}
-
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata) {
-    assert(c);
-    c->die_callback = cb;
-    c->die_userdata = userdata;
-}
-
-static void command_playback_stream_killed(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_stream *s;
-    uint32_t channel;
-    assert(pd && (command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED) && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel)))
-        return;
-
-    c->error = PA_ERROR_KILLED;
-    stream_dead(s);
-}
-
-static void command_request(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s;
-    struct pa_context *c = userdata;
-    uint32_t bytes, channel;
-    assert(pd && command == PA_COMMAND_REQUEST && t && c);
-
-    if (pa_tagstruct_getu32(t, &channel) < 0 ||
-        pa_tagstruct_getu32(t, &bytes) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-    
-    if (!(s = pa_dynarray_get(c->playback_streams, channel)))
-        return;
-
-    if (s->state != STREAM_READY)
-        return;
-    
-    s->requested_bytes += bytes;
-
-    if (s->requested_bytes && s->write_callback)
-        s->write_callback(s, s->requested_bytes, s->write_userdata);
-}
-
-static void create_stream_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s && s->state == STREAM_CREATING);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        if (s->create_complete_callback)
-            s->create_complete_callback(s, 0, s->create_complete_userdata);
-
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &s->channel) < 0 ||
-        ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    s->channel_valid = 1;
-    pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s);
-    
-    s->state = STREAM_READY;
-    if (s->create_complete_callback)
-        s->create_complete_callback(s, 1, s->create_complete_userdata);
-}
-
-static void create_stream(struct pa_stream *s, const char *dev) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s);
-
-    s->state = STREAM_CREATING;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_puts(t, s->name);
-    pa_tagstruct_put_sample_spec(t, &s->sample_spec);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
-    if (s->direction == PA_STREAM_PLAYBACK) {
-        pa_tagstruct_putu32(t, s->buffer_attr.tlength);
-        pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
-        pa_tagstruct_putu32(t, s->buffer_attr.minreq);
-    } else
-        pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
-
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-}
-
-static struct pa_stream *internal_stream_new(struct pa_context *c) {
-    struct pa_stream *s;
-
-    s = pa_xmalloc(sizeof(struct pa_stream));
-    s->context = c;
-
-    s->read_callback = NULL;
-    s->read_userdata = NULL;
-    s->write_callback = NULL;
-    s->write_userdata = NULL;
-    s->die_callback = NULL;
-    s->die_userdata = NULL;
-    s->create_complete_callback = NULL;
-    s->create_complete_userdata = NULL;
-    s->get_latency_callback = NULL;
-    s->get_latency_userdata = NULL;
-    s->finish_sample_callback = NULL;
-    s->finish_sample_userdata = NULL;
-
-    s->name = NULL;
-    s->state = STREAM_CREATING;
-    s->requested_bytes = 0;
-    s->channel = 0;
-    s->channel_valid = 0;
-    s->device_index = (uint32_t) -1;
-
-    memset(&s->buffer_attr, 0, sizeof(s->buffer_attr));
-    
-    s->next = c->first_stream;
-    if (s->next)
-        s->next->previous = s;
-    s->previous = NULL;
-    c->first_stream = s;
-
-    return s;
-}
-
-struct pa_stream* pa_stream_new(
-    struct pa_context *c,
-    enum pa_stream_direction dir,
-    const char *dev,
-    const char *name,
-    const struct pa_sample_spec *ss,
-    const struct pa_buffer_attr *attr,
-    void (*complete) (struct pa_stream*s, int success, void *userdata),
-    void *userdata) {
-    
-    struct pa_stream *s;
-
-    assert(c && name && ss && c->state == CONTEXT_READY && (dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD));
-
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = complete;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = dir;
-    s->sample_spec = *ss;
-    if (attr)
-        s->buffer_attr = *attr;
-    else {
-        s->buffer_attr.maxlength = DEFAULT_MAXLENGTH;
-        s->buffer_attr.tlength = DEFAULT_TLENGTH;
-        s->buffer_attr.prebuf = DEFAULT_PREBUF;
-        s->buffer_attr.minreq = DEFAULT_MINREQ;
-        s->buffer_attr.fragsize = DEFAULT_FRAGSIZE;
-    }
-
-    create_stream(s, dev);
-    
-    return s;
-}
-
-void pa_stream_free(struct pa_stream *s) {
-    assert(s && s->context);
-
-    if (s->context->pdispatch) 
-        pa_pdispatch_unregister_reply(s->context->pdispatch, s);
-    
-    pa_xfree(s->name);
-
-    if (s->channel_valid && s->context->state == CONTEXT_READY) {
-        struct pa_tagstruct *t = pa_tagstruct_new(NULL, 0);
-        assert(t);
-    
-        pa_tagstruct_putu32(t, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM :
-                            (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM));
-        pa_tagstruct_putu32(t, s->context->ctag++);
-        pa_tagstruct_putu32(t, s->channel);
-        pa_pstream_send_tagstruct(s->context->pstream, t);
-    }
-    
-    if (s->channel_valid)
-        pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL);
-
-    if (s->next)
-        s->next->previous = s->previous;
-    if (s->previous)
-        s->previous->next = s->next;
-    else
-        s->context->first_stream = s->next;
-    
-    pa_xfree(s);
-}
-
-void pa_stream_set_write_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata) {
-    s->write_callback = cb;
-    s->write_userdata = userdata;
-}
-
-void pa_stream_write(struct pa_stream *s, const void *data, size_t length) {
-    struct pa_memchunk chunk;
-    assert(s && s->context && data && length && s->state == STREAM_READY);
-
-    chunk.memblock = pa_memblock_new(length);
-    assert(chunk.memblock && chunk.memblock->data);
-    memcpy(chunk.memblock->data, data, length);
-    chunk.index = 0;
-    chunk.length = length;
-
-    pa_pstream_send_memblock(s->context->pstream, s->channel, 0, &chunk);
-    pa_memblock_unref(chunk.memblock);
-
-    /*fprintf(stderr, "Sent %u bytes\n", length);*/
-    
-    if (length < s->requested_bytes)
-        s->requested_bytes -= length;
-    else
-        s->requested_bytes = 0;
-}
-
-size_t pa_stream_writable_size(struct pa_stream *s) {
-    assert(s && s->state == STREAM_READY);
-    return s->requested_bytes;
-}
-
-void pa_stream_set_read_callback(struct pa_stream *s, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata) {
-    assert(s && cb);
-    s->read_callback = cb;
-    s->read_userdata = userdata;
-}
-
-int pa_stream_is_dead(struct pa_stream *s) {
-    return s->state == STREAM_DEAD;
-}
-
-int pa_stream_is_ready(struct pa_stream*s) {
-    return s->state == STREAM_READY;
-}
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata) {
-    assert(s);
-    s->die_callback = cb;
-    s->die_userdata = userdata;
-}
-
-int pa_context_is_pending(struct pa_context *c) {
-    assert(c);
-
-    if (c->state != CONTEXT_READY)
-        return 0;
-
-    return pa_pstream_is_pending(c->pstream) || pa_pdispatch_is_pending(c->pdispatch);
-}
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p) {
-    assert(p);
-    return p->context;
-}
-
-static void set_dispatch_callbacks(struct pa_context *c);
-
-static void pdispatch_drain_callback(struct pa_pdispatch*pd, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void pstream_drain_callback(struct pa_pstream *s, void *userdata) {
-    set_dispatch_callbacks(userdata);
-}
-
-static void set_dispatch_callbacks(struct pa_context *c) {
-    assert(c && c->state == CONTEXT_READY);
-
-    pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-    pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-    
-    if (pa_pdispatch_is_pending(c->pdispatch)) {
-        pa_pdispatch_set_drain_callback(c->pdispatch, pdispatch_drain_callback, c);
-        return;
-    }
-
-    if (pa_pstream_is_pending(c->pstream)) {
-        pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c);
-        return;
-    }
-
-    assert(c->drain_complete_callback);
-    c->drain_complete_callback(c, c->drain_complete_userdata);
-}
-
-int pa_context_drain(
-    struct pa_context *c, 
-    void (*complete) (struct pa_context*c, void *userdata),
-    void *userdata) {
-
-    assert(c && c->state == CONTEXT_READY);
-
-    if (complete == NULL) {
-        c->drain_complete_callback = NULL;
-        pa_pstream_set_drain_callback(c->pstream, NULL, NULL);
-        pa_pdispatch_set_drain_callback(c->pdispatch, NULL, NULL);
-        return 0;
-    }
-    
-    if (!pa_context_is_pending(c))
-        return -1;
-    
-    c->drain_complete_callback = complete;
-    c->drain_complete_userdata = userdata;
-
-    set_dispatch_callbacks(c);
-
-    return 0;
-}
-
-static void stream_drain_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-    
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        stream_dead(s);
-        return;
-    }
-
-    if (s->state != STREAM_READY)
-        return;
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->drain_complete_callback) {
-        void (*temp) (struct pa_stream*s, void *userdata) = s->drain_complete_callback;
-        s->drain_complete_callback = NULL;
-        temp(s, s->drain_complete_userdata);
-    }
-}
-
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(s && s->state == STREAM_READY);
-
-    if (!complete) {
-        s->drain_complete_callback = NULL;
-        return;
-    }
-
-    s->drain_complete_callback = complete;
-    s->drain_complete_userdata = userdata;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    
-    pa_tagstruct_putu32(t, PA_COMMAND_DRAIN_PLAYBACK_STREAM);
-    pa_tagstruct_putu32(t, tag = s->context->ctag++);
-    pa_tagstruct_putu32(t, s->channel);
-    pa_pstream_send_tagstruct(s->context->pstream, t);
-    pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_drain_callback, s);
-}
-
-void pa_context_exit(struct pa_context *c) {
-    struct pa_tagstruct *t;
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_EXIT);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void context_stat_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    uint32_t total, count;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->stat_callback)
-            c->stat_callback(c, (uint32_t) -1, (uint32_t) -1, c->stat_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &count) < 0 ||
-        pa_tagstruct_getu32(t, &total) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->stat_callback)
-        c->stat_callback(c, count, total, c->stat_userdata);
-}
-
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    c->stat_callback = cb;
-    c->stat_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_STAT);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_stat_callback, c);
-}
-
-static void stream_get_latency_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    uint32_t latency;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->get_latency_callback)
-            s->get_latency_callback(s, (uint32_t) -1, s->get_latency_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_getu32(t, &latency) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->get_latency_callback)
-        s->get_latency_callback(s, latency, s->get_latency_userdata);
-}
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata) {
-    uint32_t tag;
-    struct pa_tagstruct *t;
-
-    p->get_latency_callback = cb;
-    p->get_latency_userdata = userdata;
-
-    if (cb == NULL)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, p);
-}
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_stream *s;
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    
-    s = internal_stream_new(c);
-    assert(s);
-
-    s->create_complete_callback = cb;
-    s->create_complete_userdata = userdata;
-    s->name = pa_xstrdup(name);
-    s->state = STREAM_CREATING;
-    s->direction = PA_STREAM_UPLOAD;
-    s->sample_spec = *ss;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_CREATE_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_tagstruct_put_sample_spec(t, ss);
-    pa_tagstruct_putu32(t, length);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, s);
-
-    return s;
-}
-
-static void stream_finish_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_stream *s = userdata;
-    assert(pd && s);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(s->context, command, t) < 0) {
-            context_dead(s->context);
-            return;
-        }
-
-        if (s->finish_sample_callback)
-            s->finish_sample_callback(s, 0, s->finish_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        s->context->error = PA_ERROR_PROTOCOL;
-        context_dead(s->context);
-        return;
-    }
-
-    if (s->finish_sample_callback)
-        s->finish_sample_callback(s, 1, s->finish_sample_userdata);
-}
-
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(p);
-
-    p->finish_sample_callback = cb;
-    p->finish_sample_userdata = userdata;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_FINISH_UPLOAD_STREAM);
-    pa_tagstruct_putu32(t, tag = p->context->ctag++);
-    pa_tagstruct_putu32(t, p->channel);
-    pa_pstream_send_tagstruct(p->context->pstream, t);
-    pa_pdispatch_register_reply(p->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_finish_sample_callback, p);
-}
-
-static void context_play_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->play_sample_callback)
-            c->play_sample_callback(c, 0, c->play_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->play_sample_callback)
-        c->play_sample_callback(c, 1, c->play_sample_userdata);
-}
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name && *name && (!dev || *dev));
-
-    c->play_sample_callback = cb;
-    c->play_sample_userdata = userdata;
-
-    if (!cb)
-        return;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_PLAY_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, (uint32_t) -1);
-    pa_tagstruct_puts(t, dev ? dev : "");
-    pa_tagstruct_putu32(t, volume);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_play_sample_callback, c);
-}
-
-static void context_remove_sample_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->remove_sample_callback)
-            c->remove_sample_callback(c, 0, c->remove_sample_userdata);
-        return;
-    }
-
-    if (!pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->remove_sample_callback)
-        c->remove_sample_callback(c, 1, c->remove_sample_userdata);
-}
-
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c && name);
-
-    c->remove_sample_callback = cb;
-    c->remove_sample_userdata = userdata;
-    
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_REMOVE_SAMPLE);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_puts(t, name);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_remove_sample_callback, c);
-}
-
-static void context_get_server_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    struct pa_server_info i;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_server_info_callback)
-            c->get_server_info_callback(c, NULL, c->get_server_info_userdata);
-        return;
-    }
-
-    if (pa_tagstruct_gets(t, &i.server_name) < 0 ||
-        pa_tagstruct_gets(t, &i.server_version) < 0 ||
-        pa_tagstruct_gets(t, &i.user_name) < 0 ||
-        pa_tagstruct_gets(t, &i.host_name) < 0 ||
-        pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (c->get_server_info_callback)
-        c->get_server_info_callback(c, &i, c->get_server_info_userdata);
-}
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_server_info_callback = cb;
-    c->get_server_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_server_info_callback, c);
-}
-
-static void context_get_sink_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, NULL, 0, c->get_sink_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_sink_info i;
-        
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.volume) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.latency) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_sink_info_callback)
-            c->get_sink_info_callback(c, &i, 0, c->get_sink_info_userdata);
-    }
-
-    if (c->get_sink_info_callback)
-        c->get_sink_info_callback(c, NULL, 1, c->get_sink_info_userdata);
-}
-
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-static void context_get_source_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, NULL, 0, c->get_source_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_source_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.description) < 0 ||
-            pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
-            pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
-            pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_source_info_callback)
-            c->get_source_info_callback(c, &i, 0, c->get_source_info_userdata);
-    }
-
-    if (c->get_source_info_callback)
-        c->get_source_info_callback(c, NULL, 1, c->get_source_info_userdata);
-}
-
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    assert(c);
-
-    c->subscribe_callback = cb;
-    c->subscribe_userdata = userdata;
-    c->subscribe_mask = m;
-
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE);
-    pa_tagstruct_putu32(t, c->ctag++);
-    pa_tagstruct_putu32(t, cb ? m : 0);
-    pa_pstream_send_tagstruct(c->pstream, t);
-}
-
-static void command_subscribe_event(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    enum pa_subscription_event_type e;
-    uint32_t index;
-    assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c);
-
-    if (pa_tagstruct_getu32(t, &e) < 0 ||
-        pa_tagstruct_getu32(t, &index) < 0 ||
-        !pa_tagstruct_eof(t)) {
-        c->error = PA_ERROR_PROTOCOL;
-        context_dead(c);
-        return;
-    }
-
-    if (pa_subscription_match_flags(c->subscribe_mask, e) && c->subscribe_callback)
-        c->subscribe_callback(c, e, index, c->subscribe_userdata);
-}
-
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_sink_info_callback = cb;
-    c->get_sink_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, c);
-}
-
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_source_info_callback = cb;
-    c->get_source_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_tagstruct_puts(t, "");
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, c);
-}
-
-static void context_get_client_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, NULL, 0, c->get_client_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_client_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.protocol_name) < 0 ||
-            pa_tagstruct_getu32(t, &i.owner_module) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_client_info_callback)
-            c->get_client_info_callback(c, &i, 0, c->get_client_info_userdata);
-    }
-
-    if (c->get_client_info_callback)
-        c->get_client_info_callback(c, NULL, 1, c->get_client_info_userdata);
-}
-
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_client_info_callback = cb;
-    c->get_client_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_CLIENT_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, c);
-}
-
-static void context_get_module_info_callback(struct pa_pdispatch *pd, uint32_t command, uint32_t tag, struct pa_tagstruct *t, void *userdata) {
-    struct pa_context *c = userdata;
-    assert(pd && c);
-
-    if (command != PA_COMMAND_REPLY) {
-        if (handle_error(c, command, t) < 0) {
-            context_dead(c);
-            return;
-        }
-
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, NULL, 0, c->get_module_info_userdata);
-        return;
-    }
-
-    while (!pa_tagstruct_eof(t)) {
-        struct pa_module_info i;
-
-        if (pa_tagstruct_getu32(t, &i.index) < 0 ||
-            pa_tagstruct_gets(t, &i.name) < 0 ||
-            pa_tagstruct_gets(t, &i.argument) < 0 ||
-            pa_tagstruct_getu32(t, &i.n_used) < 0 ||
-            pa_tagstruct_getu32(t, &i.auto_unload) < 0) {
-            c->error = PA_ERROR_PROTOCOL;
-            context_dead(c);
-            return;
-        }
-        
-        if (c->get_module_info_callback)
-            c->get_module_info_callback(c, &i, 0, c->get_module_info_userdata);
-    }
-
-    if (c->get_module_info_callback)
-        c->get_module_info_callback(c, NULL, 1, c->get_module_info_userdata);
-}
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_tagstruct_putu32(t, index);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
-
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata) {
-    struct pa_tagstruct *t;
-    uint32_t tag;
-    assert(c);
-
-    c->get_module_info_callback = cb;
-    c->get_module_info_userdata = userdata;
-
-    if (!cb)
-        return;
-    
-    t = pa_tagstruct_new(NULL, 0);
-    assert(t);
-    pa_tagstruct_putu32(t, PA_COMMAND_GET_MODULE_INFO_LIST);
-    pa_tagstruct_putu32(t, tag = c->ctag++);
-    pa_pstream_send_tagstruct(c->pstream, t);
-    pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, c);
-}
index a0dd9f9cba4bece1dd871c7636007701c309de74..b9e5637cefbd95d78ef38bc1b00678c1834742d0 100644 (file)
   USA.
 ***/
 
-#include <sys/types.h>
-
+#include "mainloop-api.h"
 #include "sample.h"
 #include "polyplib-def.h"
-#include "mainloop-api.h"
-
-#ifdef __cplusplus
-//extern "C" {
-#endif
-
-struct pa_context;
-struct pa_stream;
-
-struct pa_context *pa_context_new(struct pa_mainloop_api *mainloop, const char *name);
-void pa_context_unref(struct pa_context *c);
-struct pa_context* pa_context_ref(struct pa_context *c);
-
-int pa_context_connect(struct pa_context *c, const char *server, void (*complete) (struct pa_context*c, int success, void *userdata), void *userdata);
-int pa_context_drain(struct pa_context *c, void (*complete) (struct pa_context*c, void *userdata), void *userdata);
-void pa_context_set_die_callback(struct pa_context *c, void (*cb)(struct pa_context *c, void *userdata), void *userdata);
-
-int pa_context_is_dead(struct pa_context *c);
-int pa_context_is_ready(struct pa_context *c);
-int pa_context_errno(struct pa_context *c);
-
-int pa_context_is_pending(struct pa_context *c);
-
-struct pa_stream* pa_stream_new(struct pa_context *c, enum pa_stream_direction dir, const char *dev, const char *name, const struct pa_sample_spec *ss, const struct pa_buffer_attr *attr, void (*complete) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_unref(struct pa_stream *s);
-struct pa_stream *pa_stream_ref(struct pa_stream *s);
-
-void pa_stream_drain(struct pa_stream *s, void (*complete) (struct pa_stream*s, void *userdata), void *userdata);
-
-void pa_stream_set_die_callback(struct pa_stream *s, void (*cb)(struct pa_stream *s, void *userdata), void *userdata);
-
-void pa_stream_set_write_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, size_t length, void *userdata), void *userdata);
-void pa_stream_write(struct pa_stream *p, const void *data, size_t length);
-size_t pa_stream_writable_size(struct pa_stream *p);
-
-void pa_stream_set_read_callback(struct pa_stream *p, void (*cb)(struct pa_stream *p, const void*data, size_t length, void *userdata), void *userdata);
-
-int pa_stream_is_dead(struct pa_stream *p);
-int pa_stream_is_ready(struct pa_stream*p);
-
-void pa_stream_get_latency(struct pa_stream *p, void (*cb)(struct pa_stream *p, uint32_t latency, void *userdata), void *userdata);
-
-struct pa_context* pa_stream_get_context(struct pa_stream *p);
-
-uint32_t pa_stream_get_index(struct pa_stream *s);
-
-struct pa_stream* pa_context_upload_sample(struct pa_context *c, const char *name, const struct pa_sample_spec *ss, size_t length, void (*cb) (struct pa_stream*s, int success, void *userdata), void *userdata);
-void pa_stream_finish_sample(struct pa_stream *p, void (*cb)(struct pa_stream*s, int success, void *userdata), void *userdata);
-
-void pa_context_play_sample(struct pa_context *c, const char *name, const char *dev, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_remove_sample(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-struct pa_sink_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t volume;
-    uint32_t monitor_source;
-    const char *monitor_source_name;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_info {
-    const char *name;
-    uint32_t index;
-    const char *description;
-    struct pa_sample_spec sample_spec;
-    uint32_t owner_module;
-    uint32_t monitor_of_sink;
-    const char *monitor_of_sink_name;
-};
-
-void pa_context_get_source_info_by_name(struct pa_context *c, const char *name, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_by_index(struct pa_context *c, uint32_t id, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_info *i, int is_last, void *userdata), void *userdata);
-
-struct pa_server_info {
-    const char *user_name;
-    const char *host_name;
-    const char *server_version;
-    const char *server_name;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_server_info(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_server_info*i, void *userdata), void *userdata);
-
-struct pa_module_info {
-    uint32_t index;
-    const char*name, *argument;
-    uint32_t n_used, auto_unload;
-};
-
-void pa_context_get_module_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_module_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_module_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_client_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    const char *protocol_name;
-};
-
-void pa_context_get_client_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_client_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_client_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_sink_input_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t sink;
-    struct pa_sample_spec sample_spec;
-    uint32_t volume;
-    uint32_t latency;
-};
-
-void pa_context_get_sink_input_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_sink_input_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_sink_input_info*i, int is_last, void *userdata), void *userdata);
-
-struct pa_source_output_info {
-    uint32_t index;
-    const char *name;
-    uint32_t owner_module;
-    uint32_t owner_client;
-    uint32_t source;
-    struct pa_sample_spec sample_spec;
-};
-
-void pa_context_get_source_output_info(struct pa_context *c, uint32_t index, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-void pa_context_get_source_output_info_list(struct pa_context *c, void (*cb)(struct pa_context *c, const struct pa_source_output_info*i, int is_last, void *userdata), void *userdata);
-
-void pa_context_set_sink_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-void pa_context_set_sink_input_volume(struct pa_context *c, uint32_t index, uint32_t volume, void (*cb)(struct pa_context *c, int success, void *userdata), void *userdata);
-
-void pa_context_exit(struct pa_context *c);
-void pa_context_stat(struct pa_context *c, void (*cb)(struct pa_context *c, uint32_t count, uint32_t total, void *userdata), void *userdata);
-
-void pa_context_subscribe(struct pa_context *c, enum pa_subscription_mask m, void (*cb)(struct pa_context *c, enum pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata);
-
-#ifdef __cplusplus
-}
-#endif
+#include "polyplib-context.h"
+#include "polyplib-stream.h"
+#include "polyplib-introspect.h"
+#include "polyplib-subscribe.h"
+#include "polyplib-scache.h"
 
 #endif
index 5b1cd626473bbbf33469f1e802bbf3483816fd47..8f5558a4ab3de4d91bae1c30448d32dceb4ad471 100644 (file)
@@ -135,10 +135,3 @@ void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec,
     }
 }
 
-uint32_t pa_volume_multiply(uint32_t a, uint32_t b) {
-    uint64_t p = a;
-    p *= b;
-    p /= PA_VOLUME_NORM;
-
-    return (uint32_t) p;
-}
index 73101ab4b143565b3d5b4a3239514045f67ac60c..66f40a16a08b0588cb34dfe5f89ed77376c07b59 100644 (file)
@@ -26,8 +26,6 @@
 #include "memblock.h"
 #include "memchunk.h"
 
-#define PA_VOLUME_NORM (0x100)
-#define PA_VOLUME_MUTE (0)
 
 struct pa_memblock *pa_silence_memblock(struct pa_memblock* b, const struct pa_sample_spec *spec);
 void pa_silence_memchunk(struct pa_memchunk *c, const struct pa_sample_spec *spec);
@@ -43,6 +41,4 @@ size_t pa_mix(struct pa_mix_info channels[], unsigned nchannels, void *data, siz
 
 void pa_volume_memchunk(struct pa_memchunk*c, const struct pa_sample_spec *spec, uint32_t volume);
 
-uint32_t pa_volume_multiply(uint32_t a, uint32_t b);
-
 #endif
index e4c4bd52637ec512fa606945768919f1f9f19a9c..4f93f2b7ef45f212d921c1eae9d75b62629c8c3f 100644 (file)
@@ -96,3 +96,11 @@ void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec) {
     assert(pa_sample_spec_valid(spec));
     snprintf(s, l, "%s %uch %uHz", table[spec->format], spec->channels, spec->rate);
 }
+
+uint32_t pa_volume_multiply(uint32_t a, uint32_t b) {
+    uint64_t p = a;
+    p *= b;
+    p /= PA_VOLUME_NORM;
+
+    return (uint32_t) p;
+}
index 2502787989f084bbd879e71574f31c56f3f04d9e..a7cde093ac478ca34403efb3186751f2a414c8dd 100644 (file)
@@ -25,9 +25,9 @@
 #include <inttypes.h>
 #include <sys/types.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "cdecl.h"
+
+PA_C_DECL_BEGIN
 
 enum pa_sample_format {
     PA_SAMPLE_U8,
@@ -49,10 +49,11 @@ enum pa_sample_format {
 #endif
 #define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE
 
+/** A sample format and attribute specification */
 struct pa_sample_spec {
-    enum pa_sample_format format;
-    uint32_t rate;
-    uint8_t channels;
+    enum pa_sample_format format;  /**< The sample format */
+    uint32_t rate;                 /**< The sample rate. (e.g. 44100) */
+    uint8_t channels;              /**< Audio channels. (1 for mono, 2 for stereo, ...) */
 };
 
 size_t pa_bytes_per_second(const struct pa_sample_spec *spec);
@@ -64,8 +65,10 @@ int pa_sample_spec_equal(const struct pa_sample_spec*a, const struct pa_sample_s
 #define PA_SAMPLE_SNPRINT_MAX_LENGTH 32
 void pa_sample_snprint(char *s, size_t l, const struct pa_sample_spec *spec);
 
-#ifdef __cplusplus
-}
-#endif
+#define PA_VOLUME_NORM (0x100)
+#define PA_VOLUME_MUTE (0)
+uint32_t pa_volume_multiply(uint32_t a, uint32_t b);
+
+PA_C_DECL_END
 
 #endif
index e8cb2f92a8349db242d4c3715e51018cf254a05f..dffbfe7d9704d83c85dfb9d894ca582ffe48a24b 100644 (file)
@@ -120,7 +120,7 @@ static int do_connect(struct pa_socket_client *c, const struct sockaddr *sa, soc
     
     if ((r = connect(c->fd, sa, len)) < 0) {
         if (errno != EINPROGRESS) {
-            fprintf(stderr, "connect(): %s\n", strerror(errno));
+            /*fprintf(stderr, "connect(): %s\n", strerror(errno));*/
             return -1;
         }
 
index 2a89210e6be95e65cec69f3a1401eec6db0d47d3..7b9e2a7200d20bddeb0c22e810557d6751d71c63 100644 (file)
@@ -23,6 +23,8 @@
 ***/
 
 #include <inttypes.h>
+#include <sys/socket.h>
+
 #include "mainloop-api.h"
 #include "iochannel.h"
 
index aefd03c4aca43eaf91e298f8485e81fb66f5271f..bcd7f456ae8f3cd7780ed7caa4f7861f2ce81367 100644 (file)
@@ -48,6 +48,4 @@ int pa_tagstruct_get_arbitrary(struct pa_tagstruct *t, const void **p, size_t le
 int pa_tagstruct_eof(struct pa_tagstruct*t);
 const uint8_t* pa_tagstruct_data(struct pa_tagstruct*t, size_t *l);
 
-
-
 #endif
index 8ff3054daad5b181804ee7890b727e7032d287b0..7d8b4821e51f7884524de10a696daaa8f5e9ca35 100644 (file)
@@ -52,25 +52,36 @@ void *pa_xrealloc(void *ptr, size_t size) {
     return p;
 }
 
-char *pa_xstrdup(const char *s) {
-    if (!s)
+void* pa_xmemdup(const void *p, size_t l) {
+    if (!p)
         return NULL;
     else {
-        char *r = strdup(s);
-        if (!r)
-            oom();
-
+        char *r = pa_xmalloc(l);
+        memcpy(r, p, l);
         return r;
     }
 }
 
+char *pa_xstrdup(const char *s) {
+    if (!s)
+        return NULL;
+
+    return pa_xmemdup(s, strlen(s)+1);
+}
+
 char *pa_xstrndup(const char *s, size_t l) {
     if (!s)
         return NULL;
     else {
-        char *r = strndup(s, l);
-        if (!r)
-            oom();
+        char *r;
+        size_t t = strlen(s);
+
+        if (t > l)
+            t = l;
+        
+        r = pa_xmemdup(s, t+1);
+        r[t] = 0;
         return r;
     }
 }
+
index 45209b05efc01805af4072616f667b582b792c5a..eaf8f708bdf6a4505934fcda6d3c2330bf63e053 100644 (file)
@@ -12,4 +12,6 @@ void *pa_xrealloc(void *ptr, size_t size);
 char *pa_xstrdup(const char *s);
 char *pa_xstrndup(const char *s, size_t l);
 
+void* pa_xmemdup(const void *p, size_t l);
+
 #endif