From 22cb23eedb2eae7c79dc8fcf395be08bfc666256 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 14 Aug 2004 20:25:32 +0000 Subject: implement proper refcounting in polyplib 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 --- Makefile.am | 5 +- configure.ac | 2 +- doxygen/Makefile.am | 11 + doxygen/doxygen.conf.in | 1153 ++++++++++++++++++++++++++++++ polyp/Makefile.am | 25 +- polyp/cdecl.h | 21 + polyp/glib-mainloop.h | 20 +- polyp/llist.h | 39 + polyp/mainloop-api.h | 44 +- polyp/mainloop.h | 5 + polyp/memblock.c | 42 +- polyp/memblock.h | 4 +- polyp/native-common.h | 18 +- polyp/pacat.c | 150 ++-- polyp/pactl.c | 146 ++-- polyp/polyplib-context.c | 1490 ++++++-------------------------------- polyp/polyplib-context.h | 182 ++--- polyp/polyplib-def.h | 17 +- polyp/polyplib-error.h | 12 +- polyp/polyplib-internal.h | 1528 ++------------------------------------- polyp/polyplib-introspect.c | 1651 +++++++------------------------------------ polyp/polyplib-introspect.h | 109 +-- polyp/polyplib-operation.c | 78 ++ polyp/polyplib-operation.h | 56 ++ polyp/polyplib-sample.c | 1550 ---------------------------------------- polyp/polyplib-sample.h | 178 ----- polyp/polyplib-scache.c | 1495 +-------------------------------------- polyp/polyplib-scache.h | 162 +---- polyp/polyplib-simple.c | 68 +- polyp/polyplib-simple.h | 33 +- polyp/polyplib-stream.c | 1594 +++++++---------------------------------- polyp/polyplib-stream.h | 178 ++--- polyp/polyplib-subscribe.c | 1514 +-------------------------------------- polyp/polyplib-subscribe.h | 158 +---- polyp/polyplib.c | 1550 ---------------------------------------- polyp/polyplib.h | 156 +--- polyp/sample-util.c | 7 - polyp/sample-util.h | 4 - polyp/sample.c | 8 + polyp/sample.h | 21 +- polyp/socket-client.c | 2 +- polyp/socket-client.h | 2 + polyp/tagstruct.h | 2 - polyp/xmalloc.c | 29 +- polyp/xmalloc.h | 2 + 45 files changed, 2787 insertions(+), 12734 deletions(-) create mode 100644 doxygen/Makefile.am create mode 100644 doxygen/doxygen.conf.in create mode 100644 polyp/cdecl.h create mode 100644 polyp/llist.h create mode 100644 polyp/polyplib-operation.c create mode 100644 polyp/polyplib-operation.h delete mode 100644 polyp/polyplib-sample.c delete mode 100644 polyp/polyplib-sample.h delete mode 100644 polyp/polyplib.c diff --git a/Makefile.am b/Makefile.am index a54fd606..3fc81b40 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,4 +41,7 @@ homepage: all dist distcleancheck: @: -.PHONY: homepage distcleancheck +doxygen: + $(MAKE) -C doxygen + +.PHONY: homepage distcleancheck doxygen diff --git a/configure.ac b/configure.ac index 3183d174..b7766e4a 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 00000000..d2f508c7 --- /dev/null +++ b/doxygen/Makefile.am @@ -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 index 00000000..78a43685 --- /dev/null +++ b/doxygen/doxygen.conf.in @@ -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 , where +# is the value of the INPUT_FILTER tag, and 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 diff --git a/polyp/Makefile.am b/polyp/Makefile.am index ce753da4..7f70ec9d 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -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 index 00000000..39880a47 --- /dev/null +++ b/polyp/cdecl.h @@ -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 diff --git a/polyp/glib-mainloop.h b/polyp/glib-mainloop.h index 7655108a..c67e72bd 100644 --- a/polyp/glib-mainloop.h +++ b/polyp/glib-mainloop.h @@ -4,20 +4,26 @@ #include #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 index 00000000..1f145de2 --- /dev/null +++ b/polyp/llist.h @@ -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 diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 1b9e2783..97ab6a68 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -22,26 +22,37 @@ USA. ***/ -#include #include +#include -#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 diff --git a/polyp/mainloop.h b/polyp/mainloop.h index 58448c3e..4a4c85df 100644 --- a/polyp/mainloop.h +++ b/polyp/mainloop.h @@ -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 diff --git a/polyp/memblock.c b/polyp/memblock.c index 0571f5da..a4452efa 100644 --- a/polyp/memblock.c +++ b/polyp/memblock.c @@ -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--; } diff --git a/polyp/memblock.h b/polyp/memblock.h index 4bb02977..6e79aa3e 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -25,18 +25,20 @@ #include #include -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); diff --git a/polyp/native-common.h b/polyp/native-common.h index 4d5ab53d..fa3213d0 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -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 { diff --git a/polyp/pacat.c b/polyp/pacat.c index 4d8605c7..5d29451a 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -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); diff --git a/polyp/pactl.c b/polyp/pactl.c index 2f3a4833..0ff2aa90 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -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; } diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 35001d3d..5f849e24 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -31,7 +31,8 @@ #include #include -#include "polyplib.h" +#include "polyplib-internal.h" +#include "polyplib-context.h" #include "native-common.h" #include "pdispatch.h" #include "pstream.h" @@ -42,128 +43,11 @@ #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); } diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index a0dd9f9c..6a1cc8bd 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibcontexthfoo +#define foopolyplibcontexthfoo /* $Id$ */ @@ -22,157 +22,71 @@ USA. ***/ -#include - #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 diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index d96c6899..fc19be69 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -23,14 +23,13 @@ ***/ #include - -#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 diff --git a/polyp/polyplib-error.h b/polyp/polyplib-error.h index d76ce6ff..d7519af4 100644 --- a/polyp/polyplib-error.h +++ b/polyp/polyplib-error.h @@ -23,15 +23,13 @@ ***/ #include +#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 diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 35001d3d..0b6b3887 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -1,3 +1,6 @@ +#ifndef foopolyplibinternalhfoo +#define foopolyplibinternalhfoo + /* $Id$ */ /*** @@ -19,28 +22,16 @@ USA. ***/ -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include -#include -#include -#include - -#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 @@ -52,68 +43,41 @@ #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 diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 35001d3d..345a9cd5 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -23,1528 +23,421 @@ #include #endif -#include #include -#include -#include -#include -#include -#include - -#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); } diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index a0dd9f9c..bca752e2 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibintrospecthfoo +#define foopolyplibintrospecthfoo /* $Id$ */ @@ -22,61 +22,13 @@ USA. ***/ -#include +#include -#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 index 00000000..994ac016 --- /dev/null +++ b/polyp/polyplib-operation.c @@ -0,0 +1,78 @@ +#include + +#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 index 00000000..7d0adc26 --- /dev/null +++ b/polyp/polyplib-operation.h @@ -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 index 35001d3d..00000000 --- a/polyp/polyplib-sample.c +++ /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 -#endif - -#include -#include -#include -#include -#include -#include -#include - -#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 index a0dd9f9c..00000000 --- a/polyp/polyplib-sample.h +++ /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 - -#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 diff --git a/polyp/polyplib-scache.c b/polyp/polyplib-scache.c index 35001d3d..8215eaec 100644 --- a/polyp/polyplib-scache.c +++ b/polyp/polyplib-scache.c @@ -23,1083 +23,73 @@ #include #endif -#include #include #include +#include #include -#include -#include -#include -#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); -} diff --git a/polyp/polyplib-scache.h b/polyp/polyplib-scache.h index a0dd9f9c..ce74bef0 100644 --- a/polyp/polyplib-scache.h +++ b/polyp/polyplib-scache.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibscachehfoo +#define foopolyplibscachehfoo /* $Id$ */ @@ -24,155 +24,27 @@ #include -#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 diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index 1f5ea553..66ee5995 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -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; } diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index 0544410c..ee2e27e3 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -26,24 +26,41 @@ #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 diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 35001d3d..362dbad1 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -23,576 +23,217 @@ #include #endif -#include #include -#include #include -#include -#include -#include - -#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 - 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); } diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index a0dd9f9c..41801c6c 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibstreamhfoo +#define foopolyplibstreamhfoo /* $Id$ */ @@ -26,153 +26,79 @@ #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 diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index 35001d3d..a14d0b06 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -23,1528 +23,52 @@ #include #endif -#include #include -#include -#include -#include -#include -#include -#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); -} diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index a0dd9f9c..56384915 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -1,5 +1,5 @@ -#ifndef foopolyplibhfoo -#define foopolyplibhfoo +#ifndef foopolyplibsubscribehfoo +#define foopolyplibsubscribehfoo /* $Id$ */ @@ -22,157 +22,17 @@ USA. ***/ -#include +#include -#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 index 35001d3d..00000000 --- a/polyp/polyplib.c +++ /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 -#endif - -#include -#include -#include -#include -#include -#include -#include - -#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.h b/polyp/polyplib.h index a0dd9f9c..b9e5637c 100644 --- a/polyp/polyplib.h +++ b/polyp/polyplib.h @@ -22,157 +22,13 @@ USA. ***/ -#include - +#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 diff --git a/polyp/sample-util.c b/polyp/sample-util.c index 5b1cd626..8f5558a4 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -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; -} diff --git a/polyp/sample-util.h b/polyp/sample-util.h index 73101ab4..66f40a16 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -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 diff --git a/polyp/sample.c b/polyp/sample.c index e4c4bd52..4f93f2b7 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -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; +} diff --git a/polyp/sample.h b/polyp/sample.h index 25027879..a7cde093 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -25,9 +25,9 @@ #include #include -#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 diff --git a/polyp/socket-client.c b/polyp/socket-client.c index e8cb2f92..dffbfe7d 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -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; } diff --git a/polyp/socket-client.h b/polyp/socket-client.h index 2a89210e..7b9e2a72 100644 --- a/polyp/socket-client.h +++ b/polyp/socket-client.h @@ -23,6 +23,8 @@ ***/ #include +#include + #include "mainloop-api.h" #include "iochannel.h" diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index aefd03c4..bcd7f456 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -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 diff --git a/polyp/xmalloc.c b/polyp/xmalloc.c index 8ff3054d..7d8b4821 100644 --- a/polyp/xmalloc.c +++ b/polyp/xmalloc.c @@ -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; } } + diff --git a/polyp/xmalloc.h b/polyp/xmalloc.h index 45209b05..eaf8f708 100644 --- a/polyp/xmalloc.h +++ b/polyp/xmalloc.h @@ -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 -- cgit