diff --git a/.gitignore b/.gitignore index cb613eefeb3240c0cdab593f7c9fd11bee34e806..503baa332de9a413450931f60e60305525a9e978 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ doc/*.html *x86_64-unknown-* sip_autoconf.h os-auto.mak +cc-auto.mak build.mak config.log config.status @@ -69,6 +70,13 @@ config_auto.h # Cscope/Ctags files cscope.* tags +TAGS.LST +ID # IDE stuffs nbproject + +# JNI generated files +*_wrap.cpp +*_wrap.h +*_loader.c diff --git a/astylerc b/astylerc index 5fe7ea2a692f3923a99b1d7502341a6f3ec5874e..7f14310574b90b9d41b3065853175a0edf06b0b6 100644 --- a/astylerc +++ b/astylerc @@ -13,6 +13,7 @@ break-blocks # Pad empty lines around header blocks (e.g. 'if', 'while'.. brackets=linux unpad-paren # Remove unwanted space around parentheses pad-header # Insert space padding after paren headers only (e.g. 'if', 'for', 'while'...) +pad-oper # Insert space padding around operator formatted # only display files that have changed recursive # recursively enter subdirs suffix=none # don't create backup files (that's what version control is for) diff --git a/daemon/.cproject b/daemon/.cproject deleted file mode 100644 index 2e2c63ac1528664da909fe2924f7590dab4705c2..0000000000000000000000000000000000000000 --- a/daemon/.cproject +++ /dev/null @@ -1,940 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?fileVersion 4.0.0?> - -<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> - <storageModule moduleId="org.eclipse.cdt.core.settings"> - <cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.1334434668"> - <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.1334434668" moduleId="org.eclipse.cdt.core.settings" name="Debug"> - <externalSettings/> - <extensions> - <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> - <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> - </extensions> - </storageModule> - <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactName="daemon" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.1334434668" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug"> - <folderInfo id="cdt.managedbuild.config.gnu.exe.debug.1334434668." name="/" resourcePath=""> - <toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.1440064034" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug"> - <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.1326164352" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/> - <builder buildPath="${workspace_loc:/daemon}" id="cdt.managedbuild.target.gnu.builder.exe.debug.943929430" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="-1" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/> - <tool id="cdt.managedbuild.tool.gnu.archiver.base.346381185" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> - <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.27143558" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug"> - <option id="gnu.cpp.compiler.exe.debug.option.optimization.level.921724511" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/> - <option id="gnu.cpp.compiler.exe.debug.option.debugging.level.1752614994" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/> - <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.548320150" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> - </tool> - <tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.8935091" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug"> - <option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.1442755176" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" valueType="enumerated"/> - <option id="gnu.c.compiler.exe.debug.option.debugging.level.768478086" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/> - <option id="gnu.c.compiler.option.include.paths.672698944" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath"/> - <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1769752022" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> - </tool> - <tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1740382896" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"/> - <tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.1001572120" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug"> - <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.2023620584" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> - <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> - <additionalInput kind="additionalinput" paths="$(LIBS)"/> - </inputType> - </tool> - <tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.1753020190" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug"> - <inputType id="cdt.managedbuild.tool.gnu.assembler.input.384585975" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> - </tool> - </toolChain> - </folderInfo> - <sourceEntries> - <entry flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/> - </sourceEntries> - </configuration> - </storageModule> - <storageModule moduleId="scannerConfiguration"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1334434668;cdt.managedbuild.config.gnu.exe.debug.1334434668.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.8935091;cdt.managedbuild.tool.gnu.c.compiler.input.1769752022"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.418162094;cdt.managedbuild.config.gnu.exe.release.418162094.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.1870258177;cdt.managedbuild.tool.gnu.c.compiler.input.186132729"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.418162094;cdt.managedbuild.config.gnu.exe.release.418162094.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.270168324;cdt.managedbuild.tool.gnu.cpp.compiler.input.758787020"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1334434668;cdt.managedbuild.config.gnu.exe.debug.1334434668.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.27143558;cdt.managedbuild.tool.gnu.cpp.compiler.input.548320150"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - </storageModule> - <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> - <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/> - <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> - <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> - </cconfiguration> - <cconfiguration id="cdt.managedbuild.config.gnu.exe.release.418162094"> - <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.release.418162094" moduleId="org.eclipse.cdt.core.settings" name="Release"> - <externalSettings/> - <extensions> - <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> - <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> - </extensions> - </storageModule> - <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactName="daemon" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.418162094" name="Release" parent="cdt.managedbuild.config.gnu.exe.release"> - <folderInfo id="cdt.managedbuild.config.gnu.exe.release.418162094." name="/" resourcePath=""> - <toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.1224261522" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release"> - <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.1551176649" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/> - <builder buildPath="${workspace_loc:/daemon}" id="cdt.managedbuild.target.gnu.builder.exe.release.821405347" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="-1" superClass="cdt.managedbuild.target.gnu.builder.exe.release"/> - <tool id="cdt.managedbuild.tool.gnu.archiver.base.808688542" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> - <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.270168324" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release"> - <option id="gnu.cpp.compiler.exe.release.option.optimization.level.324641683" name="Optimization Level" superClass="gnu.cpp.compiler.exe.release.option.optimization.level" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/> - <option id="gnu.cpp.compiler.exe.release.option.debugging.level.1322686559" name="Debug Level" superClass="gnu.cpp.compiler.exe.release.option.debugging.level" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/> - <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.758787020" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> - </tool> - <tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.1870258177" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release"> - <option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.exe.release.option.optimization.level.1967167078" name="Optimization Level" superClass="gnu.c.compiler.exe.release.option.optimization.level" valueType="enumerated"/> - <option id="gnu.c.compiler.exe.release.option.debugging.level.1326539031" name="Debug Level" superClass="gnu.c.compiler.exe.release.option.debugging.level" value="gnu.c.debugging.level.none" valueType="enumerated"/> - <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.186132729" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> - </tool> - <tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.1339934122" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release"/> - <tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.1247653269" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release"> - <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.2024163167" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> - <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> - <additionalInput kind="additionalinput" paths="$(LIBS)"/> - </inputType> - </tool> - <tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.779475213" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release"> - <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1675601061" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> - </tool> - </toolChain> - </folderInfo> - </configuration> - </storageModule> - <storageModule moduleId="scannerConfiguration"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1334434668;cdt.managedbuild.config.gnu.exe.debug.1334434668.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.8935091;cdt.managedbuild.tool.gnu.c.compiler.input.1769752022"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.418162094;cdt.managedbuild.config.gnu.exe.release.418162094.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.1870258177;cdt.managedbuild.tool.gnu.c.compiler.input.186132729"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.418162094;cdt.managedbuild.config.gnu.exe.release.418162094.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.270168324;cdt.managedbuild.tool.gnu.cpp.compiler.input.758787020"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1334434668;cdt.managedbuild.config.gnu.exe.debug.1334434668.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.27143558;cdt.managedbuild.tool.gnu.cpp.compiler.input.548320150"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/${specs_file}"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'g++ -E -P -v -dD "${plugin_state_location}/specs.cpp"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-c 'gcc -E -P -v -dD "${plugin_state_location}/specs.c"'" command="sh" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - </storageModule> - <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/> - <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> - <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> - <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> - </cconfiguration> - </storageModule> - <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <project id="daemon.cdt.managedbuild.target.gnu.exe.246189308" name="Executable" projectType="cdt.managedbuild.target.gnu.exe"/> - </storageModule> -</cproject> diff --git a/daemon/.gitignore b/daemon/.gitignore index f3ac37f26d20da7cd5004287d783a6895bc8c4d5..7c6793afafcff5ba58756c1737fbeb25708376a5 100644 --- a/daemon/.gitignore +++ b/daemon/.gitignore @@ -1,7 +1,8 @@ aclocal.m4 +build-aux configure -src/dbus/org.sflphone.SFLphone.service +src/client/dbus/org.sflphone.SFLphone.service src/sflphoned # Ignore sub-modules stuff diff --git a/daemon/.project b/daemon/.project deleted file mode 100644 index 8bfaab5ca3eeaed4fd1838c33d91c57c652511f7..0000000000000000000000000000000000000000 --- a/daemon/.project +++ /dev/null @@ -1,82 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>daemon</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - <buildCommand> - <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> - <triggers>clean,full,incremental,</triggers> - <arguments> - <dictionary> - <key>?name?</key> - <value></value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.append_environment</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.autoBuildTarget</key> - <value>all</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.buildArguments</key> - <value>-j</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.buildCommand</key> - <value>make</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.buildLocation</key> - <value>${workspace_loc:/daemon}</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.cleanBuildTarget</key> - <value>clean</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.contents</key> - <value>org.eclipse.cdt.make.core.activeConfigSettings</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.enableAutoBuild</key> - <value>false</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.enableCleanBuild</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.enableFullBuild</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.fullBuildTarget</key> - <value>all</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.stopOnError</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key> - <value>true</value> - </dictionary> - </arguments> - </buildCommand> - <buildCommand> - <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> - <arguments> - </arguments> - </buildCommand> - </buildSpec> - <natures> - <nature>org.eclipse.cdt.core.cnature</nature> - <nature>org.eclipse.cdt.core.ccnature</nature> - <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> - <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> - </natures> -</projectDescription> diff --git a/daemon/configure-android.sh b/daemon/configure-android.sh new file mode 100755 index 0000000000000000000000000000000000000000..b61a06ba54cc57b6166c49b263fc253e765d35d2 --- /dev/null +++ b/daemon/configure-android.sh @@ -0,0 +1 @@ +./configure --without-dbus --without-alsa --without-pulse --without-tls --without-iax2 --without-zrtp --without-sdes --without-speexdsp --without-speex diff --git a/daemon/configure.ac b/daemon/configure.ac index a16e9bdaf70b9b55ec7937de0e676355a05dd881..6ffd8c2ef185a0c4d5d02d7d546400b447563bff 100644 --- a/daemon/configure.ac +++ b/daemon/configure.ac @@ -35,6 +35,9 @@ LT_INIT dnl Define C++ as default language AC_LANG(C++) +dnl Check for C++11 support +AX_CXX_COMPILE_STDCXX_11 + dnl Check for header files AC_FUNC_ALLOCA AC_HEADER_STDC @@ -74,7 +77,16 @@ PKG_CHECK_MODULES(LIBCRYPTO, libcrypto >= ${LIBCRYPTO_MIN_VERSION}, HAVE_LIBCRYP dnl Check for alsa development package - name: libasound2-dev ALSA_MIN_VERSION=1.0 -PKG_CHECK_MODULES(ALSA, alsa >= ${ALSA_MIN_VERSION},, AC_MSG_ERROR([Missing alsa development package: libasound2-dev or alsa-lib-devel])) +AC_ARG_WITH([alsa], + [ AS_HELP_STRING([--without-alsa], [disable support for alsa]) ], + [], + [with_alsa=yes]) +AS_IF([test "x$with_alsa" = "xyes"], [ + PKG_CHECK_MODULES(ALSA, alsa >= ${ALSA_MIN_VERSION},, AC_MSG_ERROR([Missing alsa development files])) + ]); + +AC_DEFINE_UNQUOTED([HAVE_ALSA], `if test "x$with_alsa" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have alsa]) +AM_CONDITIONAL(BUILD_ALSA, test "x$with_alsa" = "xyes") dnl Check for pulseaudio development package - name: libpulse-dev @@ -85,15 +97,18 @@ AC_ARG_WITH([pulse], [with_pulse=yes]) AS_IF([test "x$with_pulse" = "xyes"], [ - PKG_CHECK_MODULES(PULSEAUDIO, libpulse >= ${LIBPULSE_MIN_VERSION},, AC_MSG_ERROR([Missing pulseaudio development package: libpulse-dev])) + PKG_CHECK_MODULES(PULSEAUDIO, libpulse >= ${LIBPULSE_MIN_VERSION},, AC_MSG_ERROR([Missing pulseaudio development files])) ]); AC_DEFINE_UNQUOTED([HAVE_PULSE], `if test "x$with_pulse" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have pulseaudio]) -AM_CONDITIONAL(BUILD_PULSE, test "x$with_pulse" = "xyes" ) +AM_CONDITIONAL(BUILD_PULSE, test "x$with_pulse" = "xyes") dnl Check for the samplerate development package - name: libsamplerate0-dev LIBSAMPLERATE_MIN_VERSION=0.1.2 -PKG_CHECK_MODULES(SAMPLERATE, samplerate >= ${LIBSAMPLERATE_MIN_VERSION},, AC_MSG_ERROR([Missing libsamplerate development package: libsamplerate0-dev])) +PKG_CHECK_MODULES(SAMPLERATE, samplerate >= ${LIBSAMPLERATE_MIN_VERSION},, AC_MSG_ERROR([Missing libsamplerate development files])) + +dnl Check for the sndfile development package - name: libsndfile-dev +PKG_CHECK_MODULES(SNDFILE, sndfile,, AC_MSG_ERROR([Missing sndfile development files])) dnl Coverage is default-disabled AC_ARG_ENABLE([coverage], AS_HELP_STRING([--enable-coverage], [Enable coverage])) @@ -112,22 +127,22 @@ AS_IF([test "x$enable_video" = "xyes"], dnl The libav versions correspond to the last libav release: 0.7 dnl Check for libavcodec development package - name: libavcodec-dev - PKG_CHECK_MODULES(LIBAVCODEC, libavcodec >= 53.5.0,, AC_MSG_ERROR([Missing libavcodec package: libavcodec-dev])) + PKG_CHECK_MODULES(LIBAVCODEC, libavcodec >= 53.5.0,, AC_MSG_ERROR([Missing libavcodec development files])) LIBAVCODEC_CFLAGS="${LIBAVCODEC_CFLAGS} -D__STDC_CONSTANT_MACROS" dnl Check for libavformat development package - name: libavformat-dev - PKG_CHECK_MODULES(LIBAVFORMAT, libavformat >= 53.2.0,, AC_MSG_ERROR([Missing libavformat package: libavformat-dev])) + PKG_CHECK_MODULES(LIBAVFORMAT, libavformat >= 53.2.0,, AC_MSG_ERROR([Missing libavformat development files])) dnl Check for libswscale development package - name: libswcale-dev - PKG_CHECK_MODULES(LIBSWSCALE, libswscale >= 1.1.0,, AC_MSG_ERROR([Missing libswscale package: libswscale-dev])) + PKG_CHECK_MODULES(LIBSWSCALE, libswscale >= 1.1.0,, AC_MSG_ERROR([Missing libswscale development files])) dnl Check for libavdevice development package - name: libavdevice-dev - PKG_CHECK_MODULES(LIBAVDEVICE, libavdevice >= 53.0.0,, AC_MSG_ERROR([Missing libavdevice package: libavdevice-dev])) + PKG_CHECK_MODULES(LIBAVDEVICE, libavdevice >= 53.0.0,, AC_MSG_ERROR([Missing libavdevice development files])) dnl Check for libavutil development package - name: libavutil-dev - PKG_CHECK_MODULES(LIBAVUTIL, libavutil >= 51.7.0,, AC_MSG_ERROR([Missing libavutil package: libavutil-dev])) + PKG_CHECK_MODULES(LIBAVUTIL, libavutil >= 51.7.0,, AC_MSG_ERROR([Missing libavutil development files])) - PKG_CHECK_MODULES(UDEV, libudev,, AC_MSG_ERROR([Missing libudev package: libudev-dev])) + PKG_CHECK_MODULES(UDEV, libudev,, AC_MSG_ERROR([Missing libudev development files])) ], [AM_CONDITIONAL(SFL_VIDEO, false)]); @@ -135,12 +150,12 @@ AS_IF([test "x$enable_video" = "xyes"], LIBCCGNU2_MIN_VERSION=1.3.1 PKG_CHECK_MODULES([CCGNU2], [commoncpp] >= ${LIBCCGNU2_MIN_VERSION}, AC_DEFINE_UNQUOTED([COMMONCPP_PREFIX], [1], [Use commoncpp include prefix]), [ PKG_CHECK_MODULES([CCGNU2], [libccgnu2] >= ${LIBCCGNU2_MIN_VERSION}, AC_DEFINE_UNQUOTED([CCPP_PREFIX], [1], [Use cc++ include prefix]), - AC_MSG_ERROR([Missing common cpp development package: libcommoncpp2-dev])) + AC_MSG_ERROR([Missing commoncpp development files])) ]) LIBCCRTP_MIN_VERSION=1.3.0 PKG_CHECK_MODULES([CCRTP], [libccrtp] >= ${LIBCCRTP_MIN_VERSION},, [ - PKG_CHECK_MODULES([CCRTP], [libccrtp1] >= ${LIBCCRTP_MIN_VERSION},, AC_MSG_ERROR([Missing ccrtp development package: libccrtp-dev])) + PKG_CHECK_MODULES([CCRTP], [libccrtp1] >= ${LIBCCRTP_MIN_VERSION},, AC_MSG_ERROR([Missing ccrtp development files])) ]) @@ -152,7 +167,7 @@ AC_ARG_WITH([tls], [], [with_tls=yes]) AS_IF([test "x$with_tls" = "xyes"], [ - PKG_CHECK_MODULES([libssl], libssl,, AC_MSG_ERROR([Missing ssl development package: libssl-dev])) + PKG_CHECK_MODULES([libssl], libssl,, AC_MSG_ERROR([Missing ssl development files])) ]); AC_DEFINE_UNQUOTED([HAVE_TLS], `if test "x$with_tls" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have tls support]) @@ -168,22 +183,23 @@ AC_ARG_WITH([zrtp], [], [with_zrtp=yes]) AS_IF([test "x$with_zrtp" = "xyes"], [ - PKG_CHECK_MODULES([ZRTPCPP], libzrtpcpp >= ${LIBZRTPCPP_MIN_VERSION},, AC_MSG_ERROR([Missing zrtp development package: libzrtpcpp-dev])) + PKG_CHECK_MODULES([ZRTPCPP], libzrtpcpp >= ${LIBZRTPCPP_MIN_VERSION},, AC_MSG_ERROR([Missing zrtp development files])) ]); AC_DEFINE_UNQUOTED([HAVE_ZRTP], `if test "x$with_zrtp" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have zrtp support]) AM_CONDITIONAL(BUILD_ZRTP, test "x$with_zrtp" = "xyes" ) +# DBUSCPP +dnl Check for dbuscpp, the C++ bindings for D-Bus +AC_ARG_WITH([dbus], + [AS_HELP_STRING([--without-dbus], [disable support for dbus])], + [], + [with_dbus=yes]) +AS_IF([test "x$with_dbus" = "xyes"], [ + PKG_CHECK_MODULES(DBUSCPP, dbus-c++-1,, AC_MSG_WARN([Missing dbus development files])) + ]); -# DBUS -# required dependency(ies): libdbus-c++ -dnl DBus-C++ detection -dnl pkg-config doesn't like 0.6.0-pre1 version number, it assumes that it is -dnl more recent than (unreleased) 0.6.0 -DBUS_CPP_REQUIRED_VERSION=0.6.0-pre1 -PKG_CHECK_MODULES(DBUSCPP, dbus-c++-1,, -AC_MSG_ERROR([You need the DBus-c++ libraries (version $DBUS_CPP_REQUIRED_VERSION or better)])) - +AC_DEFINE_UNQUOTED([HAVE_DBUS], `if test "x$with_dbus" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have dbus support]) # Instant Messaging # required dependency(ies): libxpat @@ -193,7 +209,7 @@ AC_ARG_WITH([instant_messaging], [with_instant_messaging=yes]) AS_IF([test "x$with_instant_messaging" = "xyes"], [ AX_LIB_EXPAT([1.95.0]) - AS_IF([test "$HAVE_EXPAT" != "yes"], [AC_MSG_ERROR([libexpat could not be found, which is required to build this package.])], []) + AS_IF([test "$HAVE_EXPAT" != "yes"], [AC_MSG_ERROR([Missing libexpat development files])], []) ]); AC_DEFINE_UNQUOTED([HAVE_INSTANT_MESSAGING], `if test "x$with_instant_messaging" = "xyes"; then echo 1; else echo 0; fi`, [Define if you have instant messaging support]) @@ -253,7 +269,7 @@ AC_ARG_WITH([speex], [with_speex=yes]) AS_IF([test "x$with_speex" != xno], - [AC_CHECK_HEADER([speex/speex.h], , AC_MSG_FAILURE([Unable to find the libspeex headers (you may need to install the dev package). You may use --without-speex to compile without speex codec support.]))] + [AC_CHECK_HEADER([speex/speex.h], , AC_MSG_FAILURE([Missing speex development files. You may use --without-speex to compile without speex codec support.]))] [AC_CHECK_LIB([speex], [speex_decode_int], [], [AC_MSG_FAILURE([libspeex link test failed. You may use --without-speex to compile without speex codec support.])]) @@ -273,7 +289,7 @@ AC_ARG_WITH([speexdsp], [with_speexdsp=yes]) AS_IF([test "x$with_speexdsp" != xno], - AC_CHECK_HEADER([speex/speex_preprocess.h], , AC_MSG_FAILURE([Unable to find the libspeexdsp headers (you may need to install the libspeexdsp-dev package) used for Noise Suppression and Automatic Gain Control.])) + AC_CHECK_HEADER([speex/speex_preprocess.h], , AC_MSG_FAILURE([Missing libspeexdsp development files used for Noise Suppression and Automatic Gain Control.])) AC_SEARCH_LIBS([speex_preprocess_run], [speexdsp], [], [AC_MSG_ERROR([Unable to find speexdsp development files])]) ) @@ -365,7 +381,8 @@ AC_CONFIG_FILES([Makefile \ src/audio/sound/Makefile \ src/audio/codecs/Makefile \ src/config/Makefile \ - src/dbus/Makefile \ + src/client/Makefile \ + src/client/dbus/Makefile \ src/hooks/Makefile \ src/history/Makefile \ src/video/Makefile \ diff --git a/daemon/globals.mak b/daemon/globals.mak index e291f920cf6ce08b2a1198932752316a0373cec8..05d413ee18244a0b5aa4117832510b23d73c8237 100644 --- a/daemon/globals.mak +++ b/daemon/globals.mak @@ -25,6 +25,12 @@ else SPEEXCODEC= endif +if BUILD_OPUS +OPUSCODEC=-DHAVE_OPUS +else +OPUSCODEC= +endif + if BUILD_GSM GSMCODEC=-DHAVE_GSM_CODEC else @@ -46,8 +52,9 @@ AM_CPPFLAGS = \ -DCODECS_DIR=\""$(sflcodecdir)"\" \ -DPLUGINS_DIR=\""$(sflplugindir)"\" \ -DENABLE_TRACE \ - $(SPEEXCODEC) \ - $(GSMCODEC) + $(SPEEXCODEC) \ + $(GSMCODEC) \ + $(OPUSCODEC) indent: diff --git a/daemon/libs/iax2/iax.c b/daemon/libs/iax2/iax.c index 013879ac725a4789e82621366c8669ec6be6cd90..41b2bc73bdf82090a2d1efa2a995fa32ffb1902b 100644 --- a/daemon/libs/iax2/iax.c +++ b/daemon/libs/iax2/iax.c @@ -564,7 +564,7 @@ static int calc_timestamp(struct iax_session *session, unsigned int ts, struct a special cases. */ if (ts) { - if ( f && session ) + if ( f ) session->lastsent = ts; return ts; } @@ -842,12 +842,14 @@ static int iax_reliable_xmit(struct iax_frame *f) if (!fc->data || !fc->datalen) { IAXERROR "No frame data?"); DEBU(G "No frame data?\n"); + free(fc); return -1; } else { fc->data = (char *)malloc(fc->datalen); if (!fc->data) { DEBU(G "Out of memory\n"); IAXERROR "Out of memory\n"); + free(fc); return -1; } memcpy(fc->data, f->data, f->datalen); @@ -876,7 +878,7 @@ int iax_init(int preferredportno) if (iax_recvfrom == (iax_recvfrom_t)recvfrom) { - struct sockaddr_in sin; + struct sockaddr_in sin = {}; socklen_t sinlen; int flags; int bufsize = 256 * 1024; @@ -1198,7 +1200,7 @@ static int iax_send(struct iax_session *pvt, struct ast_frame *f, unsigned int t res = iax_xmit_frame(fr); } } - if( !now && fr!=NULL ) + if( !now ) iax_frame_free( fr ); return res; } @@ -1989,6 +1991,7 @@ void iax_pref_codec_del(struct iax_session *session, unsigned int format) char remove = which_bit(format) + diff; strncpy(old, session->codec_order, sizeof(old)); + old[sizeof(old) - 1] = '\0'; session->codec_order_len = 0; for (x = 0; x < (int) strlen(old); x++) { @@ -2644,6 +2647,7 @@ static struct iax_event *iax_header_to_event(struct iax_session *session, struct strncpy(session->codec_order, e->ies.codec_prefs, sizeof(session->codec_order)); + session->codec_order[sizeof(session->codec_order) - 1] = '\0'; session->codec_order_len = (int)strlen(session->codec_order); } @@ -3128,7 +3132,7 @@ struct iax_event *iax_net_process(unsigned char *buf, int len, struct sockaddr_i static struct iax_sched *iax_get_sched(struct timeval tv) { - struct iax_sched *cur, *prev=NULL; + struct iax_sched *cur; cur = schedq; /* Check the event schedule first. */ while(cur) { @@ -3136,11 +3140,7 @@ static struct iax_sched *iax_get_sched(struct timeval tv) ((tv.tv_sec == cur->when.tv_sec) && (tv.tv_usec >= cur->when.tv_usec))) { /* Take it out of the event queue */ - if (prev) { - prev->next = cur->next; - } else { - schedq = cur->next; - } + schedq = cur->next; return cur; } cur = cur->next; diff --git a/daemon/libs/iax2/iax2-parser.c b/daemon/libs/iax2/iax2-parser.c index 958380a4094c650f41daa889f050535427c7111a..0f538d8dca2c4991ca583eeb81c4736d07546ae0 100644 --- a/daemon/libs/iax2/iax2-parser.c +++ b/daemon/libs/iax2/iax2-parser.c @@ -369,7 +369,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s /* Don't mess with mini-frames */ return; } - if (fh->type > (int)sizeof(frames)/(int)sizeof(char *)) { + if (fh->type >= (int)sizeof(frames)/(int)sizeof(char *)) { snprintf(class2, (int)sizeof(class2), "(%d?)", fh->type); clas = class2; } else { @@ -386,7 +386,7 @@ void iax_showframe(struct iax_frame *f, struct ast_iax2_full_hdr *fhi, int rx, s subclass = iaxs[(int)fh->csub]; } } else if (fh->type == AST_FRAME_CONTROL) { - if (fh->csub > (int)sizeof(cmds)/(int)sizeof(char *)) { + if (fh->csub >= (int)sizeof(cmds)/(int)sizeof(char *)) { snprintf(subclass2, (int)sizeof(subclass2), "(%d?)", fh->csub); subclass = subclass2; } else { diff --git a/daemon/libs/iax2/jitterbuf.c b/daemon/libs/iax2/jitterbuf.c index 0d450240c15e8db21ed4923743b6b9468de458c9..6e74c3fc40761724fc6c5e239a8fc965ed7a2146 100644 --- a/daemon/libs/iax2/jitterbuf.c +++ b/daemon/libs/iax2/jitterbuf.c @@ -237,8 +237,10 @@ static void history_calc_maxbuf(jitterbuf *jb) for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { /* found where it fits */ if (toins > jb->hist_maxbuf[j]) { - /* move over */ - memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0])); + /* move over if there's space */ + const size_t slide = (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0]); + if (j < (JB_HISTORY_MAXBUF_SZ - 1)) + memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, slide); /* insert */ jb->hist_maxbuf[j] = toins; @@ -254,8 +256,10 @@ static void history_calc_maxbuf(jitterbuf *jb) for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) { /* found where it fits */ if (toins < jb->hist_minbuf[j]) { - /* move over */ - memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0])); + /* move over if there's space */ + const size_t slide = (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0]); + if (j < (JB_HISTORY_MAXBUF_SZ - 1)) + memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, slide); /* insert */ jb->hist_minbuf[j] = toins; @@ -263,18 +267,6 @@ static void history_calc_maxbuf(jitterbuf *jb) } } } - - if (0) { - int k; - fprintf(stderr, "toins = %ld\n", toins); - fprintf(stderr, "maxbuf ="); - for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) - fprintf(stderr, "%ld ", jb->hist_maxbuf[k]); - fprintf(stderr, "\nminbuf ="); - for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++) - fprintf(stderr, "%ld ", jb->hist_minbuf[k]); - fprintf(stderr, "\n"); - } } jb->hist_maxbuf_valid = 1; diff --git a/daemon/libs/iax2/md5.c b/daemon/libs/iax2/md5.c index 656601f98b3094293a1b0c84f1015c41eea07301..3830a61fda83e0cd2bbb1e93f21e279896da1c50 100644 --- a/daemon/libs/iax2/md5.c +++ b/daemon/libs/iax2/md5.c @@ -116,7 +116,7 @@ void IAX_MD5Update(struct IAX_MD5Context *ctx, uint8_t const *buf, unsigned int } memcpy(p, buf, t); IAX_byteReverse(ctx->in, 16); - IAX_MD5Transform(ctx->buf, (uint32_t *) ctx->in); + IAX_MD5Transform(ctx->buf, ctx->in_32); buf += t; len -= t; } @@ -171,13 +171,13 @@ void IAX_MD5Final(uint8_t digest[16], struct IAX_MD5Context *ctx) IAX_byteReverse(ctx->in, 14); /* Append length in bits and transform */ - ((uint32_t *) ctx->in)[14] = ctx->bits[0]; - ((uint32_t *) ctx->in)[15] = ctx->bits[1]; + ctx->in_32[14] = ctx->bits[0]; + ctx->in_32[15] = ctx->bits[1]; - IAX_MD5Transform(ctx->buf, (uint32_t *) ctx->in); + IAX_MD5Transform(ctx->buf, ctx->in_32); IAX_byteReverse((uint8_t *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ } #ifndef ASM_MD5 diff --git a/daemon/libs/iax2/md5.h b/daemon/libs/iax2/md5.h index b3ad37a9b36532268cc9f3e62d909963c70e8e01..f54b68bfb27de352d4143230a5cbffddd175606b 100644 --- a/daemon/libs/iax2/md5.h +++ b/daemon/libs/iax2/md5.h @@ -11,7 +11,10 @@ typedef unsigned char uint8_t; struct IAX_MD5Context { uint32_t buf[4]; uint32_t bits[2]; - uint8_t in[64]; + union { + uint8_t in[64]; + uint32_t in_32[16]; + }; }; void IAX_MD5Init(struct IAX_MD5Context *context); diff --git a/daemon/m4/ax_cxx_compile_stdcxx_11.m4 b/daemon/m4/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 0000000000000000000000000000000000000000..af37acdb5ca2c9f76bffdc1a12edfb862282af56 --- /dev/null +++ b/daemon/m4/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,133 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++11 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX11 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> +# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> +# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ + template <typename T> + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check<check<bool>> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check<int> check_type; + check_type c; + check_type&& cr = static_cast<check_type&&>(c); + + auto d = a; +]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], + [$2], [optional], [ax_cxx_compile_cxx11_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11 -std=gnu++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=c++11 -std=c++0x; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + AC_MSG_NOTICE([No compiler with C++11 support was found]) + else + HAVE_CXX11=1 + AC_DEFINE(HAVE_CXX11,1, + [define if the compiler supports basic C++11 syntax]) + fi + + AC_SUBST(HAVE_CXX11) + fi +]) diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am index 83e3652fb4bc8c2930a3201edc8c35bcb94f3f76..656204f6f044b570363da84b9fc72661bdcc46ce 100644 --- a/daemon/src/Makefile.am +++ b/daemon/src/Makefile.am @@ -24,7 +24,7 @@ if USE_NETWORKMANAGER NETWORKMANAGER=-DUSE_NETWORKMANAGER endif -SUBDIRS = dbus audio config hooks history sip $(IAX_SUBDIR) $(INSTANT_MESSAGING_SUBDIR) $(SFL_VIDEO_SUBDIR) +SUBDIRS = client audio config hooks history sip $(IAX_SUBDIR) $(INSTANT_MESSAGING_SUBDIR) $(SFL_VIDEO_SUBDIR) sflphoned_SOURCES = main.cpp @@ -41,7 +41,7 @@ libsflphone_la_LIBADD = \ $(IAX_LIB) \ ./sip/libsiplink.la \ ./audio/libaudio.la \ - ./dbus/libdbus.la \ + ./client/dbus/libclient.la \ ./config/libconfig.la \ ./hooks/libhooks.la \ ./history/libhistory.la $(SFL_VIDEO_LIB) $(IM_LIB) @@ -55,6 +55,7 @@ libsflphone_la_LDFLAGS = \ @ALSA_LIBS@ \ @PULSEAUDIO_LIBS@ \ @SAMPLERATE_LIBS@ \ + @SNDFILE_LIBS@ \ @libssl_LIBS@ \ @UUID_LIBS@ \ @DBUSCPP_LIBS@ @@ -69,14 +70,14 @@ libsflphone_la_CFLAGS = \ @PULSEAUDIO_CFLAGS@ \ @SAMPLERATE_CFLAGS@ \ @libssl_CFLAGS@ \ - @UUID_CFLAGS@ + @UUID_CFLAGS@ \ + @DBUSCPP_CFLAGS@ libsflphone_la_SOURCES = conference.cpp \ voiplink.cpp \ preferences.cpp \ managerimpl.cpp \ manager.cpp \ - managerimpl_registration.cpp \ eventthread.cpp \ call.cpp \ account.cpp \ diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp index ce497ce18a134a5cff20ef6acd6ebfed92799a13..363d975e3ad4770ec6d137a23bdf018dc668fecb 100644 --- a/daemon/src/account.cpp +++ b/daemon/src/account.cpp @@ -42,7 +42,8 @@ #include "logger.h" #include "manager.h" -#include "dbus/configurationmanager.h" + +#include "client/configurationmanager.h" const char * const Account::AUDIO_CODECS_KEY = "audioCodecs"; // 0/9/110/111/112/ const char * const Account::VIDEO_CODECS_KEY = "videoCodecs"; @@ -63,6 +64,8 @@ const char * const Account::HOSTNAME_KEY = "hostname"; const char * const Account::ACCOUNT_ENABLE_KEY = "enable"; const char * const Account::ACCOUNT_AUTOANSWER_KEY = "autoAnswer"; const char * const Account::MAILBOX_KEY = "mailbox"; +const char * const Account::DEFAULT_USER_AGENT = "SFLphone/" PACKAGE_VERSION; +const char * const Account::USER_AGENT_KEY = "useragent"; using std::map; using std::string; @@ -83,7 +86,7 @@ Account::Account(const string &accountID) : , ringtonePath_("/usr/share/sflphone/ringtones/konga.ul") , ringtoneEnabled_(true) , displayName_("") - , userAgent_("SFLphone") + , userAgent_(DEFAULT_USER_AGENT) , mailBox_() { // Initialize the codec order, used when creating a new account @@ -97,9 +100,8 @@ void Account::setRegistrationState(const RegistrationState &state) { if (state != registrationState_) { registrationState_ = state; - // Notify the client - ConfigurationManager *c(Manager::instance().getDbusManager()->getConfigurationManager()); + ConfigurationManager *c(Manager::instance().getClient()->getConfigurationManager()); c->registrationStateChanged(accountID_, registrationState_); } } @@ -157,8 +159,8 @@ namespace { } // check that it's in the list of valid codecs and that it has all the required fields - for (vector<map<string, string> >::const_iterator i = defaults.begin(); i != defaults.end(); ++i) { - const map<string, string>::const_iterator defaultName = i->find(Account::VIDEO_CODEC_NAME); + for (const auto &i : defaults) { + const auto defaultName = i.find(Account::VIDEO_CODEC_NAME); if (defaultName->second == name->second) { return isFieldValid(codec, Account::VIDEO_CODEC_BITRATE, isPositiveInteger) and isFieldValid(codec, Account::VIDEO_CODEC_ENABLED, isBoolean); @@ -170,16 +172,15 @@ namespace { bool isCodecListValid(const vector<map<string, string> > &list) { - const vector<map<string, string> > defaults(libav_utils::getDefaultCodecs()); + const auto defaults(libav_utils::getDefaultCodecs()); if (list.size() != defaults.size()) { ERROR("New codec list has a different length than the list of supported codecs"); return false; } // make sure that all codecs are present - for (vector<map<string, string> >::const_iterator i = list.begin(); - i != list.end(); ++i) { - if (not isCodecValid(*i, defaults)) + for (const auto &i : list) { + if (not isCodecValid(i, defaults)) return false; } return true; @@ -235,8 +236,8 @@ void Account::setActiveAudioCodecs(const vector<string> &list) // list contains the ordered payload of active codecs picked by the user for this account // we used the codec vector to save the order. - for (vector<string>::const_iterator iter = list.begin(); iter != list.end(); ++iter) { - int payload = std::atoi(iter->c_str()); + for (const auto &item : list) { + int payload = std::atoi(item.c_str()); audioCodecList_.push_back(payload); } diff --git a/daemon/src/account.h b/daemon/src/account.h index b2aabf09c98aa22751ee53c39705dadffbe68c07..fc8877cda7295729a939d232c8d5c2628d1ed141 100644 --- a/daemon/src/account.h +++ b/daemon/src/account.h @@ -222,6 +222,8 @@ class Account : public Serializable { static const char * const ACCOUNT_ENABLE_KEY; static const char * const ACCOUNT_AUTOANSWER_KEY; static const char * const MAILBOX_KEY; + static const char * const USER_AGENT_KEY; + static const char * const DEFAULT_USER_AGENT; static std::string mapStateNumberToString(RegistrationState state); diff --git a/daemon/src/audio/Makefile.am b/daemon/src/audio/Makefile.am index d59969e1642150047251d94cc97c14f4541d9a49..d5b25ec8f08db40584eb292b84736e30126a3e8a 100644 --- a/daemon/src/audio/Makefile.am +++ b/daemon/src/audio/Makefile.am @@ -2,7 +2,11 @@ include $(top_srcdir)/globals.mak noinst_LTLIBRARIES = libaudio.la -SUBDIRS = codecs audiortp sound alsa +SUBDIRS = codecs audiortp sound + +if BUILD_ALSA +SUBDIRS += alsa +endif if BUILD_PULSE SUBDIRS += pulseaudio @@ -14,6 +18,7 @@ SFL_SPEEXDSP_HEAD=noisesuppress.h endif libaudio_la_SOURCES = \ + audiobuffer.cpp \ audioloop.cpp \ ringbuffer.cpp \ mainbuffer.cpp \ @@ -28,6 +33,7 @@ libaudio_la_SOURCES = \ dcblocker.cpp noinst_HEADERS = \ + audiobuffer.h \ audioloop.h \ ringbuffer.h \ mainbuffer.h \ @@ -44,9 +50,12 @@ noinst_HEADERS = \ libaudio_la_LIBADD = \ ./audiortp/libaudiortp.la \ ./codecs/libcodecdescriptor.la \ - ./alsa/libalsalayer.la \ ./sound/libsound.la if BUILD_PULSE libaudio_la_LIBADD += ./pulseaudio/libpulselayer.la endif + +if BUILD_ALSA +libaudio_la_LIBADD += ./alsa/libalsalayer.la +endif diff --git a/daemon/src/audio/alsa/Makefile.am b/daemon/src/audio/alsa/Makefile.am index 4ca799e54638c2e2bc293990e86e9a491a66641d..ce6f2ad100218ae5b055857f4c10810239bf42dc 100644 --- a/daemon/src/audio/alsa/Makefile.am +++ b/daemon/src/audio/alsa/Makefile.am @@ -1,8 +1,11 @@ include $(top_srcdir)/globals.mak +if BUILD_ALSA + noinst_LTLIBRARIES = libalsalayer.la libalsalayer_la_SOURCES = alsalayer.cpp noinst_HEADERS = alsalayer.h +endif diff --git a/daemon/src/audio/alsa/alsalayer.cpp b/daemon/src/audio/alsa/alsalayer.cpp index f34e72a9a65c03e2eee24ab526921d38a79ae7a2..4fb286fd7319c0d2e0e539786af998c139028612 100644 --- a/daemon/src/audio/alsa/alsalayer.cpp +++ b/daemon/src/audio/alsa/alsalayer.cpp @@ -37,12 +37,12 @@ #include "logger.h" #include "manager.h" #include "noncopyable.h" -#include "dbus/configurationmanager.h" +#include "client/configurationmanager.h" #include <ctime> #define SFL_ALSA_PERIOD_SIZE 160 #define SFL_ALSA_NB_PERIOD 8 -#define SFL_ALSA_BUFFER_SIZE SFL_ALSA_PERIOD_SIZE*SFL_ALSA_NB_PERIOD +#define SFL_ALSA_BUFFER_SIZE SFL_ALSA_PERIOD_SIZE * SFL_ALSA_NB_PERIOD class AlsaThread { public: @@ -74,6 +74,7 @@ bool AlsaThread::isRunning() const AlsaThread::~AlsaThread() { running_ = false; + if (thread_) pthread_join(thread_, NULL); } @@ -112,18 +113,18 @@ void AlsaThread::initAudioLayer(void) alsa_->is_capture_open_ = alsa_->openDevice(&alsa_->captureHandle_, pcmc, SND_PCM_STREAM_CAPTURE); if (not alsa_->is_capture_open_) - Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_CAPTURE_DEVICE); + Manager::instance().getClient()->getConfigurationManager()->errorAlert(ALSA_CAPTURE_DEVICE); } if (not alsa_->is_playback_open_) { alsa_->is_playback_open_ = alsa_->openDevice(&alsa_->playbackHandle_, pcmp, SND_PCM_STREAM_PLAYBACK); if (not alsa_->is_playback_open_) - Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE); + Manager::instance().getClient()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE); if (alsa_->getIndexPlayback() != alsa_->getIndexRingtone()) if (!alsa_->openDevice(&alsa_->ringtoneHandle_, pcmr, SND_PCM_STREAM_PLAYBACK)) - Manager::instance().getDbusManager()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE); + Manager::instance().getClient()->getConfigurationManager()->errorAlert(ALSA_PLAYBACK_DEVICE); } alsa_->prepareCaptureStream(); @@ -149,7 +150,6 @@ void AlsaThread::run() } } -// Constructor AlsaLayer::AlsaLayer(const AudioPreference &pref) : indexIn_(pref.getAlsaCardin()) , indexOut_(pref.getAlsaCardout()) @@ -172,7 +172,6 @@ AlsaLayer::AlsaLayer(const AudioPreference &pref) setPlaybackGain(pref.getVolumespkr()); } -// Destructor AlsaLayer::~AlsaLayer() { isStarted_ = false; @@ -198,7 +197,7 @@ bool AlsaLayer::openDevice(snd_pcm_t **pcm, const std::string &dev, snd_pcm_stre if (err < 0) { ERROR("Alsa: couldn't open device %s : %s", dev.c_str(), - snd_strerror(err)); + snd_strerror(err)); return false; } @@ -248,10 +247,6 @@ AlsaLayer::stopStream() flushMain(); } -////////////////////////////////////////////////////////////////////////////////////////////// -///////////////// ALSA PRIVATE FUNCTIONS //////////////////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////////////////// - /* * GCC extension : statement expression * @@ -388,11 +383,12 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle) ERROR("buffer to small, could not use"); return false; } + #undef HW DEBUG("%s using sampling rate %dHz", - (snd_pcm_stream(pcm_handle) == SND_PCM_STREAM_PLAYBACK) ? "playback" : "capture", - sampleRate_); + (snd_pcm_stream(pcm_handle) == SND_PCM_STREAM_PLAYBACK) ? "playback" : "capture", + sampleRate_); snd_pcm_sw_params_t *swparams = NULL; snd_pcm_sw_params_alloca(&swparams); @@ -408,13 +404,14 @@ bool AlsaLayer::alsa_set_params(snd_pcm_t *pcm_handle) #undef TRY } -//TODO first frame causes broken pipe (underrun) because not enough data are send --> make the handle wait to be ready +// TODO first frame causes broken pipe (underrun) because not enough data is sent +// we should wait until the handle is ready void AlsaLayer::write(void* buffer, int length, snd_pcm_t * handle) { - //Do not waste CPU cycle to handle void + // Skip empty buffers if (!length) - return; + return; snd_pcm_uframes_t frames = snd_pcm_bytes_to_frames(handle, length); watchdogTotalCount_++; @@ -454,12 +451,14 @@ AlsaLayer::write(void* buffer, int length, snd_pcm_t * handle) ERROR("Writing in state SND_PCM_STATE_SETUP, should be " "SND_PCM_STATE_PREPARED or SND_PCM_STATE_RUNNING"); int error = snd_pcm_prepare(handle); + if (error < 0) { ERROR("Failed to prepare handle: %s", snd_strerror(error)); stopPlaybackStream(); } } } + break; } @@ -469,8 +468,9 @@ AlsaLayer::write(void* buffer, int length, snd_pcm_t * handle) break; } - //Detect when something is going wrong. This can be caused by alsa bugs or faulty encoder on the other side - //TODO do something useful instead of just warning and flushing buffers + // Detect when something is going wrong. This can be caused by alsa bugs or + // faulty encoder on the other side + // TODO do something useful instead of just warning and flushing buffers if (watchdogTotalErr_ > 0 && watchdogTotalCount_ / watchdogTotalErr_ >=4 && watchdogTotalCount_ > 50) { ERROR("Alsa: too many errors (%d error on %d frame)",watchdogTotalErr_,watchdogTotalCount_); flushUrgent(); @@ -539,13 +539,16 @@ namespace { bool safeUpdate(snd_pcm_t *handle, int &samples) { samples = snd_pcm_avail_update(handle); + if (samples < 0) { samples = snd_pcm_recover(handle, samples, 0); + if (samples < 0) { ERROR("Got unrecoverable error from snd_pcm_avail_update: %s", snd_strerror(samples)); return false; } } + return true; } @@ -553,9 +556,10 @@ std::vector<std::string> getValues(const std::vector<HwIDPair> &deviceMap) { std::vector<std::string> audioDeviceList; - for (std::vector<HwIDPair>::const_iterator iter = deviceMap.begin(); - iter != deviceMap.end(); ++iter) - audioDeviceList.push_back(iter->second); + + for (const auto &dev : deviceMap) + audioDeviceList.push_back(dev.second); + return audioDeviceList; } } @@ -600,12 +604,11 @@ AlsaLayer::getAudioDeviceIndexMap(bool getCapture) const if (snd_ctl_pcm_info(handle ,pcminfo) < 0) { DEBUG(" Cannot get info"); - } - else { + } else { DEBUG("card %i : %s [%s]", - numCard, - snd_ctl_card_info_get_id(info), - snd_ctl_card_info_get_name(info)); + numCard, + snd_ctl_card_info_get_id(info), + snd_ctl_card_info_get_name(info)); std::string description = snd_ctl_card_info_get_name(info); description.append(" - "); description.append(snd_pcm_info_get_name(pcminfo)); @@ -635,6 +638,7 @@ AlsaLayer::soundCardIndexExists(int card, PCMType stream) name.append(ss.str()); snd_ctl_t* handle; + if (snd_ctl_open(&handle, name.c_str(), 0) != 0) return false; @@ -654,9 +658,9 @@ AlsaLayer::getAudioDeviceIndex(const std::string &description) const audioDeviceIndexMap.insert(audioDeviceIndexMap.end(), captureDevice.begin(), captureDevice.end()); audioDeviceIndexMap.insert(audioDeviceIndexMap.end(), playbackDevice.begin(), playbackDevice.end()); - for (std::vector<HwIDPair>::const_iterator iter = audioDeviceIndexMap.begin(); iter != audioDeviceIndexMap.end(); ++iter) - if (iter->second == description) - return iter->first; + for (const auto &dev : audioDeviceIndexMap) + if (dev.second == description) + return dev.first; // else return the default one return 0; @@ -672,8 +676,10 @@ AlsaLayer::getAudioDeviceName(int index, PCMType type) const case SFL_PCM_PLAYBACK: case SFL_PCM_RINGTONE: return getPlaybackDeviceList().at(index); + case SFL_PCM_CAPTURE: return getCaptureDeviceList().at(index); + default: ERROR("Unexpected type %d", type); return ""; @@ -696,31 +702,28 @@ void AlsaLayer::capture() const int framesPerBufferAlsa = 2048; toGetSamples = std::min(framesPerBufferAlsa, toGetSamples); - std::vector<SFLDataFormat> in(toGetSamples); - SFLDataFormat * const in_ptr = &(*in.begin()); + AudioBuffer in(toGetSamples, 1, sampleRate_); + + // TODO: handle ALSA multichannel capture + const int toGetBytes = in.samples() * sizeof(SFLAudioSample); + SFLAudioSample * const in_ptr = in.getChannel(0)->data(); - const int toGetBytes = in.size() * sizeof(in[0]); if (read(in_ptr, toGetBytes) != toGetBytes) { ERROR("ALSA MIC : Couldn't read!"); return; } - AudioLayer::applyGain(in_ptr, toGetSamples, getCaptureGain()); + in.applyGain(captureGain_); if (resample) { int outSamples = toGetSamples * (static_cast<double>(sampleRate_) / mainBufferSampleRate); - std::vector<SFLDataFormat> rsmpl_out(outSamples); - SFLDataFormat * const rsmpl_out_ptr = &(*rsmpl_out.begin()); - converter_.resample(in_ptr, rsmpl_out_ptr, - rsmpl_out.size(), mainBufferSampleRate, sampleRate_, - toGetSamples); - dcblocker_.process(rsmpl_out_ptr, rsmpl_out_ptr, outSamples); - Manager::instance().getMainBuffer().putData(rsmpl_out_ptr, - rsmpl_out.size() * sizeof(rsmpl_out[0]), MainBuffer::DEFAULT_ID); + AudioBuffer rsmpl_out(outSamples, 1, mainBufferSampleRate); + converter_.resample(in, rsmpl_out); + dcblocker_.process(rsmpl_out); + Manager::instance().getMainBuffer().putData(rsmpl_out, MainBuffer::DEFAULT_ID); } else { - dcblocker_.process(in_ptr, in_ptr, toGetSamples); - Manager::instance().getMainBuffer().putData(in_ptr, toGetBytes, - MainBuffer::DEFAULT_ID); + dcblocker_.process(in); + Manager::instance().getMainBuffer().putData(in, MainBuffer::DEFAULT_ID); } } @@ -728,7 +731,8 @@ void AlsaLayer::playback(int maxSamples) { size_t bytesToGet = Manager::instance().getMainBuffer().availableForGet(MainBuffer::DEFAULT_ID); - const size_t bytesToPut = maxSamples * sizeof(SFLDataFormat); + const size_t bytesToPut = maxSamples * sizeof(SFLAudioSample); + // no audio available, play tone or silence if (bytesToGet <= 0) { // FIXME: not thread safe! we only lock the mutex when we get the @@ -736,14 +740,14 @@ void AlsaLayer::playback(int maxSamples) AudioLoop *tone = Manager::instance().getTelephoneTone(); AudioLoop *file_tone = Manager::instance().getTelephoneFile(); - std::vector<SFLDataFormat> out(maxSamples, 0); - SFLDataFormat * const out_ptr = &(*out.begin()); + AudioBuffer out(maxSamples, 1, sampleRate_); + if (tone) - tone->getNext(out_ptr, out.size(), getPlaybackGain()); + tone->getNext(out, playbackGain_); else if (file_tone && !ringtoneHandle_) - file_tone->getNext(out_ptr, out.size(), getPlaybackGain()); + file_tone->getNext(out, playbackGain_); - write(out_ptr, bytesToPut, playbackHandle_); + write(out.getChannel(0)->data(), bytesToPut, playbackHandle_); } else { // play the regular sound samples @@ -752,6 +756,7 @@ void AlsaLayer::playback(int maxSamples) double resampleFactor = 1.0; size_t maxNbBytesToGet = bytesToPut; + if (resample) { resampleFactor = static_cast<double>(sampleRate_) / mainBufferSampleRate; maxNbBytesToGet = bytesToGet / resampleFactor; @@ -759,22 +764,21 @@ void AlsaLayer::playback(int maxSamples) bytesToGet = std::min(maxNbBytesToGet, bytesToGet); - const size_t samplesToGet = bytesToGet / sizeof(SFLDataFormat); - std::vector<SFLDataFormat> out(samplesToGet, 0); - SFLDataFormat * const out_ptr = &(*out.begin()); - Manager::instance().getMainBuffer().getData(out_ptr, bytesToGet, MainBuffer::DEFAULT_ID); - AudioLayer::applyGain(out_ptr, samplesToGet, getPlaybackGain()); + const size_t samplesToGet = bytesToGet / sizeof(SFLAudioSample); + //std::vector<SFLAudioSample> out(samplesToGet, 0); + AudioBuffer out(samplesToGet, 1, mainBufferSampleRate); + + Manager::instance().getMainBuffer().getData(out, MainBuffer::DEFAULT_ID); + out.applyGain(playbackGain_); if (resample) { const size_t outSamples = samplesToGet * resampleFactor; - const size_t outBytes = outSamples * sizeof(SFLDataFormat); - std::vector<SFLDataFormat> rsmpl_out(outSamples); - SFLDataFormat * const rsmpl_out_ptr = &(*rsmpl_out.begin()); - converter_.resample(out_ptr, rsmpl_out_ptr, rsmpl_out.size(), - mainBufferSampleRate, sampleRate_, samplesToGet); - write(rsmpl_out_ptr, outBytes, playbackHandle_); + const size_t outBytes = outSamples * sizeof(SFLAudioSample); + AudioBuffer rsmpl_out(outSamples, 1, sampleRate_); + converter_.resample(out, rsmpl_out); + write(rsmpl_out.getChannel(0)->data(), outBytes, playbackHandle_); } else { - write(out_ptr, bytesToGet, playbackHandle_); + write(out.getChannel(0)->data(), bytesToGet, playbackHandle_); } } } @@ -789,24 +793,22 @@ void AlsaLayer::audioCallback() snd_pcm_wait(playbackHandle_, 20); int playbackAvailSmpl = 0; + if (not safeUpdate(playbackHandle_, playbackAvailSmpl)) return; - const size_t playbackAvailBytes = playbackAvailSmpl * sizeof(SFLDataFormat); - size_t bytesToGet = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID); + unsigned samplesToGet = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID); - if (bytesToGet > 0) { + if (samplesToGet > 0) { // Urgent data (dtmf, incoming call signal) come first. - bytesToGet = std::min(bytesToGet, playbackAvailBytes); - const size_t samplesToGet = bytesToGet / sizeof(SFLDataFormat); - std::vector<SFLDataFormat> out(samplesToGet); - SFLDataFormat * const out_ptr = &(*out.begin()); - urgentRingBuffer_.get(out_ptr, bytesToGet, MainBuffer::DEFAULT_ID); - AudioLayer::applyGain(out_ptr, samplesToGet, getPlaybackGain()); - - write(out_ptr, bytesToGet, playbackHandle_); + samplesToGet = std::min(samplesToGet, (unsigned)playbackAvailSmpl); + AudioBuffer out(samplesToGet); + urgentRingBuffer_.get(out, MainBuffer::DEFAULT_ID); + out.applyGain(playbackGain_); + + write(out.getChannel(0)->data(), samplesToGet * sizeof(SFLAudioSample), playbackHandle_); // Consume the regular one as well (same amount of bytes) - Manager::instance().getMainBuffer().discard(bytesToGet, MainBuffer::DEFAULT_ID); + Manager::instance().getMainBuffer().discard(samplesToGet, MainBuffer::DEFAULT_ID); } else { // regular audio data playback(playbackAvailSmpl); @@ -815,20 +817,19 @@ void AlsaLayer::audioCallback() if (ringtoneHandle_) { AudioLoop *file_tone = Manager::instance().getTelephoneFile(); int ringtoneAvailSmpl = 0; + if (not safeUpdate(ringtoneHandle_, ringtoneAvailSmpl)) return; - int ringtoneAvailBytes = ringtoneAvailSmpl * sizeof(SFLDataFormat); + int ringtoneAvailBytes = ringtoneAvailSmpl * sizeof(SFLAudioSample); - std::vector<SFLDataFormat> out(ringtoneAvailSmpl, 0); - SFLDataFormat * const out_ptr = &(*out.begin()); + AudioBuffer out(ringtoneAvailSmpl); if (file_tone) { - DEBUG("playback gain %d", getPlaybackGain()); - file_tone->getNext(out_ptr, ringtoneAvailSmpl, - getPlaybackGain()); + DEBUG("playback gain %d", playbackGain_); + file_tone->getNext(out, playbackGain_); } - write(out_ptr, ringtoneAvailBytes, ringtoneHandle_); + write(out.getChannel(0)->data(), ringtoneAvailBytes, ringtoneHandle_); } // Additionally handle the mic's audio stream @@ -842,12 +843,15 @@ void AlsaLayer::updatePreference(AudioPreference &preference, int index, PCMType case SFL_PCM_PLAYBACK: preference.setAlsaCardout(index); break; + case AudioLayer::SFL_PCM_CAPTURE: preference.setAlsaCardin(index); break; + case AudioLayer::SFL_PCM_RINGTONE: preference.setAlsaCardring(index); break; + default: break; } diff --git a/daemon/src/audio/audiobuffer.cpp b/daemon/src/audio/audiobuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e19413aa97464e8c205c9b0070521279585798f --- /dev/null +++ b/daemon/src/audio/audiobuffer.cpp @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Author: Adrien Beraud <adrien.beraud@wisdomvibes.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include <iostream> +#include "audiobuffer.h" + +AudioBuffer::AudioBuffer(size_t sample_num /* = 0 */, unsigned channel_num /* = 1 */, int sample_rate /* = 8000 */) + : sampleRate_(sample_rate), + samples_(std::max(1U, channel_num), + std::vector<SFLAudioSample>(sample_num, 0)) +{ +} + +AudioBuffer::AudioBuffer(const SFLAudioSample* in, size_t sample_num, unsigned channel_num /* = 1 */, int sample_rate /* = 8000 */) + : sampleRate_(sample_rate), + samples_((std::max(1U, channel_num)), std::vector<SFLAudioSample>(sample_num, 0)) +{ + deinterleave(in, sample_num, channel_num); +} + +AudioBuffer::AudioBuffer(const AudioBuffer& other, bool copy_content /* = false */) + : sampleRate_(other.sampleRate_), + samples_(copy_content ? other.samples_ : + std::vector<std::vector<SFLAudioSample> >(other.samples_.size(), std::vector<SFLAudioSample>(other.samples_[0].size()))) +{} + +int AudioBuffer::getSampleRate() const +{ + return sampleRate_; +} + +void AudioBuffer::setSampleRate(int sr) +{ + sampleRate_ = sr; +} + +void AudioBuffer::setChannelNum(unsigned n, bool copy_content /* = false */) +{ + n = std::max(1U, n); + + if (n == samples_.size()) + return; + + size_t start_size = 0; + + if (not samples_.empty()) + start_size = samples_[0].size(); + + if (copy_content and not samples_.empty()) + samples_.resize(n, samples_[0]); + else + samples_.resize(n, std::vector<SFLAudioSample>(start_size, 0)); +} + +void AudioBuffer::resize(size_t sample_num) +{ + if (samples_[0].size() == sample_num) + return; + + for (unsigned i = 0; i < samples_.size(); i++) + samples_[i].resize(sample_num); +} + +void AudioBuffer::empty() +{ + for (unsigned i = 0; i < samples_.size(); i++) + samples_[i].clear(); +} + +std::vector<SFLAudioSample> * AudioBuffer::getChannel(unsigned chan /* = 0 */) +{ + if (chan < samples_.size()) + return &samples_[chan]; + + return NULL; +} + +void AudioBuffer::applyGain(unsigned int gain) +{ + if (gain != 100) + applyGain(gain * 0.01); +} + +void AudioBuffer::applyGain(double gain) +{ + if (gain == 1.0) return; + + for (unsigned i = 0; i < samples_.size(); i++) + for (unsigned j = 0; j < samples_[0].size(); j++) + samples_[i][j] *= gain; +} + +size_t AudioBuffer::interleave(SFLAudioSample* out) const +{ + for (unsigned i = 0; i < samples_[0].size(); i++) + for (unsigned j = 0; j < samples_.size(); j++) + *out++ = samples_[j][i]; + + return samples_[0].size() * samples_.size(); +} + +size_t AudioBuffer::interleaveFloat(float* out) const +{ + for (unsigned i = 0; i < samples_[0].size(); i++) + for (unsigned j = 0; j < samples_.size(); j++) + *out++ = (float) samples_[j][i] * .000030517578125f; + + return samples_[0].size() * samples_.size(); +} + +void AudioBuffer::deinterleave(const SFLAudioSample* in, size_t sample_num, unsigned channel_num) +{ + if (in == NULL) + return; + + // Resize buffer + setChannelNum(channel_num); + resize(sample_num); + + for (unsigned i = 0; i < samples_[0].size(); i++) + for (unsigned j = 0; j < samples_.size(); j++) + samples_[j][i] = *in++; +} + +size_t AudioBuffer::mix(const AudioBuffer& other, bool up /* = true */) +{ + const bool upmix = up && (other.samples_.size() < samples_.size()); + const size_t samp_num = std::min(samples_[0].size(), other.samples_[0].size()); + const unsigned chan_num = upmix ? samples_.size() : std::min(samples_.size(), other.samples_.size()); + + for (unsigned i = 0; i < chan_num; i++) { + unsigned src_chan = upmix ? std::min<unsigned>(i, other.samples_.size() - 1) : i; + + for (unsigned j = 0; j < samp_num; j++) + samples_[i][j] += other.samples_[src_chan][j]; + } + + return samp_num; +} + +size_t AudioBuffer::copy(AudioBuffer& in, int sample_num /* = -1 */, size_t pos_in /* = 0 */, size_t pos_out /* = 0 */, bool up /* = true */) +{ + if (sample_num == -1) + sample_num = in.samples(); + + int to_copy = std::min((int)in.samples() - (int)pos_in, sample_num); + + if (to_copy <= 0) return 0; + + const bool upmix = up && (in.samples_.size() < samples_.size()); + const size_t chan_num = upmix ? samples_.size() : std::min(in.samples_.size(), samples_.size()); + + if ((pos_out + to_copy) > samples_[0].size()) + resize(pos_out + to_copy); + + sampleRate_ = in.sampleRate_; + //setChannelNum(chan_num); + + for (unsigned i = 0; i < chan_num; i++) { + size_t src_chan = upmix ? std::min<size_t>(i, in.samples_.size() - 1U) : i; + std::copy(in.samples_[src_chan].begin() + pos_in, in.samples_[src_chan].begin() + pos_in + to_copy, samples_[i].begin() + pos_out); + } + + return to_copy; +} + +size_t AudioBuffer::copy(SFLAudioSample* in, size_t sample_num, size_t pos_out /* = 0 */) +{ + if (in == NULL) return 0; + + if ((pos_out + sample_num) > samples_[0].size()) + resize(pos_out + sample_num); + + const size_t chan_num = samples_.size(); + unsigned i; + + for (i = 0; i < chan_num; i++) { + std::copy(in, in + sample_num, samples_[i].begin() + pos_out); + } + + return sample_num; +} + +std::ostream& operator<<(std::ostream& os, const AudioBuffer& buf) +{ + for (unsigned i = 0; i < buf.samples_[0].size(); i++) { + for (unsigned j = 0; j < buf.samples_.size(); j++) + os << buf.samples_[j][i]; + } + + return os; +} + +std::istream& operator>>(std::istream& is, AudioBuffer& buf) +{ + for (unsigned i = 0; ; i++) { + for (unsigned j = 0; j < buf.samples_.size(); j++) { + if (is && is.good()) + is >> buf.samples_[j][i]; + else + break; + } + } +} diff --git a/daemon/src/audio/audiobuffer.h b/daemon/src/audio/audiobuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..2128f86dd6c1836aa02d3e9fe878847d0cf4826d --- /dev/null +++ b/daemon/src/audio/audiobuffer.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Author: Adrien Beraud <adrien.beraud@wisdomvibes.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef _AUDIO_BUFFER_H +#define _AUDIO_BUFFER_H + +#include <iostream> +#include <vector> +#include <cstddef> // for size_t + +#include "sfl_types.h" + +class AudioBuffer { + public: + /** + * Default constructor. + */ + AudioBuffer(size_t sample_num = 0, unsigned channel_num = 1, int sample_rate = 8000); + + /** + * Construtor from existing interleaved data (copied into the buffer). + */ + AudioBuffer(const SFLAudioSample* in, size_t sample_num, unsigned channel_num = 1, int sample_rate = 8000); + + /** + * Copy constructor that by default only copies the buffer parameters (channel number, sample rate and buffer size). + * If copy_content is set to true, the other buffer content is also copied. + */ + AudioBuffer(const AudioBuffer& other, bool copy_content = false); + + void reset() { + for (std::vector<std::vector<SFLAudioSample> >::iterator i = samples_.begin(); i != samples_.end(); ++i) + std::fill(i->begin(), i->end(), 0); + } + + /** + * Returns the sample rate (in samples/sec) associated to this buffer. + */ + int getSampleRate() const; + + /** + * Set the sample rate (in samples/sec) associated to this buffer. + */ + void setSampleRate(int sr); + + /** + * Returns the number of channels in this buffer. + */ + inline unsigned channels() const { + return samples_.size(); + } + + /** + * Set the number of channels of this buffer. + * + * @param n: the new number of channels. If n < channels(), channels are removed from the buffer, otherwise the behavior depends on copy_first. + * + * @param copy_first: if set to true and n > channels(), new channels are initialised as a copy of the first channel (channel 0). If set to false, new channels are initialised to 0. + */ + void setChannelNum(unsigned n, bool copy_first = false); + + /** + * Returns the number of (multichannel) samples in this buffer. + */ + inline size_t samples() const { + return samples_[0].size(); + } + + /** + * Return the total number of single samples in the buffer (same as samples()*channels()). + */ + inline size_t capacity() const { + return samples() * channels(); + } + + /** + * Resize the buffer to make it able to hold sample_num multichannel samples. + */ + void resize(size_t sample_num); + + /** + * Set all samples in this buffer to 0. Buffer size is not changed. + */ + void clear(); + + /** + * Resize the buffer to 0. All samples are lost but the number of channels and sample rate are kept. + */ + void empty(); + + /** + * Return the data (audio samples) for a given channel number. + * Channel data can be modified but size of individual channel vectors should not be changed manually. + */ + std::vector<SFLAudioSample> *getChannel(unsigned chan); + + /** + * Return a pointer to the raw data in this buffer. + */ + inline std::vector<std::vector<SFLAudioSample> > &getData() { + return samples_; + } + + /** + * Write interleaved multichannel data to the out buffer (fixed-point 16-bits). + * The out buffer must be at least large by capacity()*sizeof(SFLAudioSample) bytes. + * + * @returns Number of samples writen. + */ + size_t interleave(SFLAudioSample* out) const; + + /** + * Write interleaved multichannel data to the out buffer, while samples are converted to float. + * The buffer must be at least of size getChannelNum()*samples()*sizeof(float). + * + * @returns Number of samples writen. + */ + size_t interleaveFloat(float* out) const; + + /** + * Import interleaved multichannel data. Internal buffer is resized as needed. Function will read sample_num*channel_num elements of the in buffer. + */ + void deinterleave(const SFLAudioSample* in, size_t sample_num, unsigned channel_num = 1); + + /** + * In-place gain transformation with integer parameter. + * + * @param gain: 0 -> 100 scale + */ + void applyGain(unsigned int gain); + + /** + * In-place gain transformation. + * + * @param gain: 0.0 -> 1.0 scale + */ + void applyGain(double gain); + + /** + * Mix elements of the other buffer within this buffer (in-place simple addition). + * If other.channels() is higher than this.channels(), only the first this.channels() channels are imported. + * If other.channels() is lower than this.channels(), behavior depends on upmix. + * Sample rate is not considered by this function. + * + * TODO: some kind of check for overflow/saturation. + * + * @param other: the other buffer to mix in this one. + * @param upmix: if true, upmixing occurs when other.channels() < this.channels(). + * If false, only the first other.channels() channels are edited in this buffer. + * + * @returns Number of samples modified. + */ + size_t mix(const AudioBuffer& other, bool upmix = true); + + /** + * Copy sample_num samples from in (from sample pos_in) to this buffer (at sample pos_out). + * If sample_num is -1 (the default), the entire in buffer is copied. + * + * The number of channels is changed to match the in channel number. + * Buffer sample number is also increased if required to hold the new requested samples. + */ + size_t copy(AudioBuffer& in, int sample_num = -1, size_t pos_in = 0, size_t pos_out = 0, bool upmix = true); + + /** + * Copy sample_num samples from in to this buffer (at sample pos_out). + * Input data is treated as mono and samples are duplicated in the case of a multichannel buffer. + * + * Buffer sample number is increased if required to hold the new requested samples. + */ + size_t copy(SFLAudioSample* in, size_t sample_num, size_t pos_out = 0); + + /** + * Overloading << and >> to easily import/export a multichannel stream + */ + friend std::ostream& operator<<(std::ostream& os, const AudioBuffer& buf); + friend std::istream& operator>>(std::istream& is, AudioBuffer& buf); + + private: + int sampleRate_; + + // main buffers holding data for each channels + std::vector<std::vector<SFLAudioSample> > samples_; +}; + +#endif // _AUDIO_BUFFER_H diff --git a/daemon/src/audio/audiolayer.cpp b/daemon/src/audio/audiolayer.cpp index 33b7bbdcc4c93ca9e13f710b5552fec1e72efa2a..1b59a2b8778fbb15a39d332e3edb98b8fe37a4c5 100644 --- a/daemon/src/audio/audiolayer.cpp +++ b/daemon/src/audio/audiolayer.cpp @@ -35,11 +35,10 @@ #include "manager.h" #include "scoped_lock.h" -unsigned int AudioLayer::captureGain_ = 100; -unsigned int AudioLayer::playbackGain_ = 100; - AudioLayer::AudioLayer() - : isStarted_(false) + : captureGain_(100) + , playbackGain_(100) + , isStarted_(false) , playbackMode_(NONE) , urgentRingBuffer_(SIZEBUF, MainBuffer::DEFAULT_ID) , sampleRate_(Manager::instance().getMainBuffer().getInternalSamplingRate()) @@ -70,17 +69,10 @@ void AudioLayer::flushUrgent() urgentRingBuffer_.flushAll(); } -void AudioLayer::putUrgent(void* buffer, int toCopy) +void AudioLayer::putUrgent(AudioBuffer& buffer) { sfl::ScopedLock guard(mutex_); - urgentRingBuffer_.put(buffer, toCopy); -} - -void AudioLayer::applyGain(SFLDataFormat *src , int samples, int gain) -{ - if (gain != 100) - for (int i = 0 ; i < samples; i++) - src[i] = src[i] * gain* 0.01; + urgentRingBuffer_.put(buffer); } // Notify (with a beep) an incoming call when there is already a call in progress @@ -103,11 +95,10 @@ void AudioLayer::notifyIncomingCall() Tone tone("440/160", getSampleRate()); unsigned int nbSample = tone.getSize(); - SFLDataFormat buf[nbSample]; - tone.getNext(buf, nbSample); + AudioBuffer buf(nbSample); + tone.getNext(buf); /* Put the data in the urgent ring buffer */ flushUrgent(); - putUrgent(buf, sizeof buf); + putUrgent(buf); } - diff --git a/daemon/src/audio/audiolayer.h b/daemon/src/audio/audiolayer.h index 8c9ba4640b8244051048109009cf739c0ff3703e..8ec0c67c9df965c404b81842614ddcfa6db025d2 100644 --- a/daemon/src/audio/audiolayer.h +++ b/daemon/src/audio/audiolayer.h @@ -50,6 +50,9 @@ class MainBuffer; class AudioPreference; + +typedef std::vector<AudioBuffer> AudioBufferStack; + namespace ost { class Time; } @@ -121,9 +124,8 @@ class AudioLayer { * Send a chunk of data to the hardware buffer to start the playback * Copy data in the urgent buffer. * @param buffer The buffer containing the data to be played ( ringtones ) - * @param toCopy The size of the buffer */ - void putUrgent(void* buffer, int toCopy); + void putUrgent(AudioBuffer& buffer); /** * Flush main buffer @@ -135,11 +137,6 @@ class AudioLayer { */ void flushUrgent(); - /** - * Apply gain to audio frame - */ - static void applyGain(SFLDataFormat *src , int samples, int gain); - /** * Convert audio amplitude value from linear value to dB */ @@ -164,7 +161,7 @@ class AudioLayer { /** * Set capture stream gain (microphone) */ - unsigned int getCaptureGain(void) { + unsigned int getCaptureGain() const { return captureGain_; } @@ -178,7 +175,7 @@ class AudioLayer { /** * Get playback stream gain (speaker) */ - unsigned int getPlaybackGain(void) { + unsigned int getPlaybackGain() const { return playbackGain_; } @@ -196,19 +193,20 @@ class AudioLayer { */ void notifyIncomingCall(); + virtual void updatePreference(AudioPreference &pref, int index, PCMType type) = 0; + + protected: + /** * Gain applied to mic signal */ - static unsigned int captureGain_; + unsigned int captureGain_; /** * Gain applied to playback signal */ - static unsigned int playbackGain_; - - virtual void updatePreference(AudioPreference &pref, int index, PCMType type) = 0; + unsigned int playbackGain_; - protected: /** * Whether or not the audio layer stream is started */ @@ -243,6 +241,7 @@ class AudioLayer { SamplerateConverter converter_; private: + /** * Time of the last incoming call notification */ diff --git a/daemon/src/audio/audioloop.cpp b/daemon/src/audio/audioloop.cpp index dcd99204f66ebdc558a69b4bb93956688e927fa6..fad4d0d29f1f0bd5a26ea1f2f01488390e88d4b6 100644 --- a/daemon/src/audio/audioloop.cpp +++ b/daemon/src/audio/audioloop.cpp @@ -32,84 +32,72 @@ * as that of the covered work. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "audioloop.h" -#include "manager.h" -#include "dbus/callmanager.h" + #include <cmath> #include <numeric> #include <cstring> #include <cassert> #include "logger.h" -AudioLoop::AudioLoop(unsigned int sampleRate) : buffer_(0), size_(0), pos_(0), sampleRate_(sampleRate), isRecording_(false) -{} +AudioLoop::AudioLoop(unsigned int sampleRate) : buffer_(0), pos_(0) +{ + buffer_ = new AudioBuffer; + buffer_->setSampleRate(sampleRate); +} AudioLoop::~AudioLoop() { - delete [] buffer_; + delete buffer_; } void AudioLoop::seek(double relative_position) { - size_t new_pos = (size_t)((double)size_ * (relative_position * 0.01)); - - pos_ = new_pos; + pos_ = static_cast<double>(buffer_->samples() * relative_position * 0.01); } -static unsigned int updatePlaybackScale = 0; - void -AudioLoop::getNext(SFLDataFormat* output, size_t total_samples, short volume) +AudioLoop::getNext(AudioBuffer& output, unsigned int volume) { + if (!buffer_) { + ERROR("buffer is NULL"); + return; + } + + const size_t buf_samples = buffer_->samples(); size_t pos = pos_; + size_t total_samples = output.samples(); + size_t output_pos = 0; - if (size_ == 0) { + if (buf_samples == 0) { ERROR("Audio loop size is 0"); return; - } else if (pos >= size_) { + } else if (pos >= buf_samples) { ERROR("Invalid loop position %d", pos); return; } while (total_samples > 0) { - size_t samples = total_samples; + size_t samples = std::min(total_samples, buf_samples - pos); - if (samples > (size_ - pos)) - samples = size_ - pos; + output.copy(*buffer_, samples, pos, output_pos); - // short->char conversion - memcpy(output, buffer_ + pos, samples * sizeof(SFLDataFormat)); - - // Scaling needed - if (volume != 100) { - const double gain = volume * 0.01; - - for (size_t i = 0; i < samples; ++i, ++output) - *output *= gain; - } else - output += samples; // this is the destination... - - pos = (pos + samples) % size_; + output_pos += samples; + pos = (pos + samples) % buf_samples; total_samples -= samples; } - pos_ = pos; + output.applyGain(volume); // apply volume - // We want to send values in milisecond - int divisor = sampleRate_ / 1000; - if(divisor == 0) { - ERROR("Error cannot update playback slider, sampling rate is 0"); - return; - } + pos_ = pos; - if(isRecording_) { - if((updatePlaybackScale % 5) == 0) { - CallManager *cm = Manager::instance().getDbusManager()->getCallManager(); - cm->updatePlaybackScale(pos_ / divisor, size_ / divisor); - } - updatePlaybackScale++; - } + onBufferFinish(); } +void AudioLoop::onBufferFinish() {} diff --git a/daemon/src/audio/audioloop.h b/daemon/src/audio/audioloop.h index c8bc3372c8da20b99387a11af712467911de59e5..b401fde7a38a3e12b3a39d45cb779f8b9b884ce2 100644 --- a/daemon/src/audio/audioloop.h +++ b/daemon/src/audio/audioloop.h @@ -36,6 +36,7 @@ #include "sfl_types.h" #include <cstring> #include "noncopyable.h" +#include "audiobuffer.h" /** * @file audioloop.h @@ -55,7 +56,7 @@ class AudioLoop { * @param nb of int16 to send * @param volume The volume */ - void getNext(SFLDataFormat* output, size_t samples, short volume=100); + void getNext(AudioBuffer& output, unsigned int volume=100); void seek(double relative_position); @@ -70,36 +71,20 @@ class AudioLoop { * Accessor to the size of the buffer * @return unsigned int The size */ - size_t getSize() const { - return size_; + size_t getSize() { + return buffer_->samples(); } - /** - * This should be set to true for recording playback - */ - void setIsRecording(bool isRec) { - isRecording_ = isRec; - } - - protected: /** The data buffer */ - SFLDataFormat* buffer_; - - /** Number of samples inside the buffer */ - size_t size_; + AudioBuffer * buffer_; /** current position, set to 0, when initialize */ size_t pos_; - /** Sample rate */ - unsigned int sampleRate_; - - /** Is a playback recording */ - bool isRecording_; - private: NON_COPYABLE(AudioLoop); + virtual void onBufferFinish(); }; #endif // __AUDIOLOOP_H__ diff --git a/daemon/src/audio/audiorecord.cpp b/daemon/src/audio/audiorecord.cpp index 14b30ddf1afe857b72eb48b66e5da23d448781d9..7d0da92c140816c000306f2df1abafd93fb97e05 100644 --- a/daemon/src/audio/audiorecord.cpp +++ b/daemon/src/audio/audiorecord.cpp @@ -33,6 +33,7 @@ #endif #include "audiorecord.h" +#include <sndfile.hh> #include <unistd.h> #include <sstream> // for stringstream #include <algorithm> @@ -40,24 +41,6 @@ #include "logger.h" #include "fileutils.h" -// structure for the wave header - -struct wavhdr { - char riff[4]; // "RIFF" - SINT32 file_size; // in bytes - char wave[4]; // "WAVE" - char fmt[4]; // "fmt " - SINT32 chunk_size; // in bytes (16 for PCM) - SINT16 format_tag; // 1=PCM, 2=ADPCM, 3=IEEE float, 6=A-Law, 7=Mu-Law - SINT16 num_chans; // 1=mono, 2=stereo - SINT32 sample_rate; - SINT32 bytes_per_sec; - SINT16 bytes_per_samp; // 2=16-bit mono, 4=16-bit stereo - SINT16 bits_per_samp; - char data[4]; // "data" - SINT32 data_length; // in bytes -}; - namespace { std::string createFilename() @@ -106,29 +89,27 @@ createFilename() } -AudioRecord::AudioRecord() : fileHandle_(NULL) - , fileType_(FILE_INVALID) +AudioRecord::AudioRecord() : fileHandle_(0) , channels_(1) - , byteCounter_(0) , sndSmplRate_(8000) - , nbSamplesMic_(0) - , nbSamplesSpk_(0) , recordingEnabled_(false) - , mixBuffer_() - , micBuffer_() - , spkBuffer_() , filename_(createFilename()) , savePath_() { WARN("Generate filename for this call %s ", filename_.c_str()); } +AudioRecord::~AudioRecord() +{ + delete fileHandle_; +} + void AudioRecord::setSndSamplingRate(int smplRate) { sndSmplRate_ = smplRate; } -void AudioRecord::setRecordingOption(FILE_TYPE type, int sndSmplRate, const std::string &path) +void AudioRecord::setRecordingOptions(int sndSmplRate, const std::string &path) { std::string filePath; @@ -139,7 +120,6 @@ void AudioRecord::setRecordingOption(FILE_TYPE type, int sndSmplRate, const std: filePath = path; } - fileType_ = type; channels_ = 1; sndSmplRate_ = sndSmplRate; savePath_ = (*filePath.rbegin() == DIR_SEPARATOR_CH) ? filePath : filePath + DIR_SEPARATOR_STR; @@ -149,7 +129,7 @@ namespace { bool nonFilenameCharacter(char c) { - return not (std::isalnum(c) or c == '_' or c == '.'); + return not(std::isalnum(c) or c == '_' or c == '.'); } // Replace any character that is inappropriate for a filename with '_' @@ -166,16 +146,9 @@ void AudioRecord::initFilename(const std::string &peerNumber) std::string fName(filename_); fName.append("-" + sanitize(peerNumber) + "-" PACKAGE); - if (fileType_ == FILE_RAW) { - if (filename_.find(".raw") == std::string::npos) { - DEBUG("Concatenate .raw file extension: name : %s", filename_.c_str()); - fName.append(".raw"); - } - } else if (fileType_ == FILE_WAV) { - if (filename_.find(".wav") == std::string::npos) { - DEBUG("Concatenate .wav file extension: name : %s", filename_.c_str()); - fName.append(".wav"); - } + if (filename_.find(".wav") == std::string::npos) { + DEBUG("Concatenate .wav file extension: name : %s", filename_.c_str()); + fName.append(".wav"); } savePath_.append(fName); @@ -189,34 +162,30 @@ std::string AudioRecord::getFilename() const bool AudioRecord::openFile() { bool result = false; + delete fileHandle_; + const bool doAppend = fileExists(); + const int access = doAppend ? SFM_RDWR : SFM_WRITE; - if (not fileExists()) { - DEBUG("Filename does not exist, creating one"); - byteCounter_ = 0; + fileHandle_ = new SndfileHandle(savePath_.c_str(), access, SF_FORMAT_WAV | SF_FORMAT_PCM_16, channels_, sndSmplRate_); - if (fileType_ == FILE_RAW) - result = setRawFile(); - else if (fileType_ == FILE_WAV) - result = setWavFile(); - } else { - DEBUG("Filename already exists, opening it"); - if (fileType_ == FILE_RAW) - result = openExistingRawFile(); - else if (fileType_ == FILE_WAV) - result = openExistingWavFile(); + // check overloaded boolean operator + if (!*fileHandle_) { + WARN("Could not open WAV file!"); + delete fileHandle_; + fileHandle_ = 0; + return false; } + if (doAppend and fileHandle_->seek(0, SEEK_END) < 0) + WARN("Couldn't seek to the end of the file "); + return result; } void AudioRecord::closeFile() { - if (fileHandle_ == 0) return; - - if (fileType_ == FILE_RAW) - fclose(fileHandle_); - else if (fileType_ == FILE_WAV) - closeWavFile(); + delete fileHandle_; + fileHandle_ = 0; } bool AudioRecord::isOpenFile() const @@ -242,6 +211,7 @@ bool AudioRecord::toggleRecording() openFile(); recordingEnabled_ = true; } + return recordingEnabled_; } @@ -251,185 +221,22 @@ void AudioRecord::stopRecording() recordingEnabled_ = false; } -bool AudioRecord::setRawFile() -{ - fileHandle_ = fopen(savePath_.c_str(), "wb"); - - if (!fileHandle_) { - WARN("Could not create RAW file!"); - return false; - } - - DEBUG("created RAW file."); - - return true; -} - -namespace { - std::string header_to_string(const wavhdr &hdr) - { - std::stringstream ss; - ss << hdr.riff << "\0 " - << hdr.file_size << " " - << hdr.wave << "\0 " - << hdr.fmt << "\0 " - << hdr.chunk_size << " " - << hdr.format_tag << " " - << hdr.num_chans << " " - << hdr.sample_rate << " " - << hdr.bytes_per_sec << " " - << hdr.bytes_per_samp << " " - << hdr.bits_per_samp << " " - << hdr.data << "\0 " - << hdr.data_length; - return ss.str(); - } -} - -bool AudioRecord::setWavFile() -{ - DEBUG("Create new wave file %s, sampling rate: %d", savePath_.c_str(), sndSmplRate_); - - fileHandle_ = fopen(savePath_.c_str(), "wb"); - - if (!fileHandle_) { - WARN("Could not create WAV file."); - return false; - } - - /* The text fields are NOT supposed to be null terminated, so we have to - * write them as arrays since strings enclosed in quotes include a - * null character */ - wavhdr hdr = {{'R', 'I', 'F', 'F'}, - 44, - {'W', 'A', 'V', 'E'}, - {'f','m', 't', ' '}, - 16, - 1, - channels_, - sndSmplRate_, - -1, /* initialized below */ - -1, /* initialized below */ - 16, - {'d', 'a', 't', 'a'}, - 0}; - - hdr.bytes_per_samp = channels_ * hdr.bits_per_samp / 8; - hdr.bytes_per_sec = hdr.sample_rate * hdr.bytes_per_samp; - - if (fwrite(&hdr, 4, 11, fileHandle_) != 11) { - WARN("Could not write WAV header for file. "); - return false; - } - - DEBUG("Wrote wave header \"%s\"", header_to_string(hdr).c_str()); - return true; -} - -bool AudioRecord::openExistingRawFile() -{ - fileHandle_ = fopen(filename_.c_str(), "ab+"); - - if (!fileHandle_) { - WARN("could not create RAW file!"); - return false; - } - - return true; -} - -bool AudioRecord::openExistingWavFile() +void AudioRecord::recData(AudioBuffer& buffer) { - DEBUG("Opening %s", filename_.c_str()); - - fileHandle_ = fopen(filename_.c_str(), "rb+"); - - if (!fileHandle_) { - WARN("Could not open WAV file!"); - return false; - } - - if (fseek(fileHandle_, 40, SEEK_SET) != 0) // jump to data length - WARN("Couldn't seek offset 40 in the file "); - - if (fread(&byteCounter_, 4, 1, fileHandle_)) - WARN("bytecounter Read successfully "); - - if (fseek(fileHandle_, 0 , SEEK_END) != 0) - WARN("Couldn't seek at the en of the file "); - - - if (fclose(fileHandle_) != 0) - WARN("Can't close file r+ "); - - fileHandle_ = fopen(filename_.c_str(), "ab+"); - - if (!fileHandle_) { - WARN("Could not createopen WAV file ab+!"); - return false; - } - - if (fseek(fileHandle_, 4 , SEEK_END) != 0) - WARN("Couldn't seek at the en of the file "); - - return true; - -} + if (not recordingEnabled_) + return; -void AudioRecord::closeWavFile() -{ if (fileHandle_ == 0) { - DEBUG("Can't closeWavFile, a file has not yet been opened!"); + DEBUG("Can't record data, a file has not yet been opened!"); return; } - DEBUG("Close wave file"); - - SINT32 bytes = byteCounter_ * channels_; - - // jump to data length - if (fseek(fileHandle_, 40, SEEK_SET) != 0) - WARN("Could not seek in file"); - - if (ferror(fileHandle_)) - WARN("Can't reach offset 40 while closing"); - - fwrite(&bytes, sizeof(SINT32), 1, fileHandle_); - - if (ferror(fileHandle_)) - WARN("Can't write bytes for data length "); + const int nSamples = buffer.samples(); - bytes = byteCounter_ * channels_ + 44; // + 44 for the wave header - - // jump to file size - if (fseek(fileHandle_, 4, SEEK_SET) != 0) - WARN("Could not seek in file"); - - if (ferror(fileHandle_)) - WARN("Can't reach offset 4"); - - fwrite(&bytes, 4, 1, fileHandle_); - - if (ferror(fileHandle_)) - WARN("Can't reach offset 4"); - - if (fclose(fileHandle_) != 0) - WARN("Can't close file"); -} - -void AudioRecord::recData(SFLDataFormat* buffer, size_t nSamples) -{ - if (recordingEnabled_) { - if (fileHandle_ == 0) { - DEBUG("Can't record data, a file has not yet been opened!"); - return; - } - - if (fwrite(buffer, sizeof(SFLDataFormat), nSamples, fileHandle_) != nSamples) - WARN("Could not record data! "); - else { - fflush(fileHandle_); - byteCounter_ += nSamples * sizeof(SFLDataFormat); - } + // FIXME: mono only + if (fileHandle_->write(buffer.getChannel(0)->data(), nSamples) != nSamples) { + WARN("Could not record data!"); + } else { + fileHandle_->writeSync(); } } diff --git a/daemon/src/audio/audiorecord.h b/daemon/src/audio/audiorecord.h index 3fb91948e8c98edb1c13ac6b817b6203448f3481..6ebd35369afd7eca8e6148e1bf11c091bb6338e3 100644 --- a/daemon/src/audio/audiorecord.h +++ b/daemon/src/audio/audiorecord.h @@ -37,16 +37,18 @@ #include "sfl_types.h" #include "noncopyable.h" +#include "audiobuffer.h" + +class SndfileHandle; class AudioRecord { public: - enum FILE_TYPE { FILE_RAW, FILE_WAV, FILE_INVALID }; - AudioRecord(); + ~AudioRecord(); void setSndSamplingRate(int smplRate); - void setRecordingOption(FILE_TYPE type, int sndSmplRate, const std::string &path); + void setRecordingOptions(int sndSmplRate, const std::string &path); /** * Init recording file path @@ -102,20 +104,11 @@ class AudioRecord { * @param buffer The data chunk to be recorded * @param nSamples Number of samples (number of bytes) to be recorded */ - void recData(SFLDataFormat* buffer, size_t nSamples); + //void recData(SFLDataFormat* buffer, size_t nSamples); + void recData(AudioBuffer& buffer); protected: - /** - * Set the header for raw files - */ - bool setRawFile(); - - /** - * Set the header for wave files - */ - bool setWavFile(); - /** * Open an existing raw file, used when the call is set on hold */ @@ -135,38 +128,18 @@ class AudioRecord { /** * Pointer to the recorded file */ - FILE *fileHandle_; - - /** - * File format (RAW / WAVE) - */ - FILE_TYPE fileType_; + SndfileHandle *fileHandle_; /** * Number of channels */ - SINT16 channels_; - - /** - * Number of byte recorded - */ - unsigned long byteCounter_; + int16_t channels_; /** * Sampling rate */ int sndSmplRate_; - /** - * number of samples recorded for mic buffer - */ - int nbSamplesMic_; - - /** - * number of samples recorded for speaker buffer - */ - int nbSamplesSpk_; - /** * Maximum number of samples */ @@ -177,21 +150,6 @@ class AudioRecord { */ bool recordingEnabled_; - /** - * Buffer used for mixing two channels - */ - SFLDataFormat mixBuffer_[NB_SAMPLES_MAX]; - - /** - * Buffer used to copy mic info - */ - SFLDataFormat micBuffer_[NB_SAMPLES_MAX]; - - /** - * Buffer used to copy spkr info - */ - SFLDataFormat spkBuffer_[NB_SAMPLES_MAX]; - /** * Filename for this recording */ diff --git a/daemon/src/audio/audiorecorder.cpp b/daemon/src/audio/audiorecorder.cpp index 6b7fc65ff9d22d4e1464e243549290db853ae475..e1950226ad6b12adc12eb7057d23e30fe7eb691d 100644 --- a/daemon/src/audio/audiorecorder.cpp +++ b/daemon/src/audio/audiorecorder.cpp @@ -38,11 +38,9 @@ int AudioRecorder::count_ = 0; -AudioRecorder::AudioRecorder(AudioRecord *arec, MainBuffer *mb) : +AudioRecorder::AudioRecorder(AudioRecord *arec, MainBuffer &mb) : recorderId_(), mbuffer_(mb), arecord_(arec), running_(false), thread_(0) { - assert(mb); - ++count_; std::string id("processid_"); @@ -56,8 +54,10 @@ AudioRecorder::AudioRecorder(AudioRecord *arec, MainBuffer *mb) : recorderId_ = id.append(s); } -AudioRecorder::~AudioRecorder() { +AudioRecorder::~AudioRecorder() +{ running_ = false; + if (thread_) pthread_join(thread_, NULL); } @@ -81,16 +81,16 @@ AudioRecorder::runCallback(void *data) */ void AudioRecorder::run() { - const size_t BUFFER_LENGTH = 10000; - std::tr1::array<SFLDataFormat, BUFFER_LENGTH> buffer; - buffer.assign(0); + static const size_t BUFFER_LENGTH = 10000; + AudioBuffer buffer(BUFFER_LENGTH); while (running_) { - const size_t availableBytes = mbuffer_->availableForGet(recorderId_); - mbuffer_->getData(buffer.data(), std::min(availableBytes, buffer.size()), recorderId_); + const size_t availableSamples = mbuffer_.availableForGet(recorderId_); + buffer.resize(std::min(availableSamples, BUFFER_LENGTH)); + mbuffer_.getData(buffer, recorderId_); - if (availableBytes > 0) - arecord_->recData(buffer.data(), availableBytes / sizeof(SFLDataFormat)); + if (availableSamples > 0) + arecord_->recData(buffer); usleep(20000); // 20 ms } diff --git a/daemon/src/audio/audiorecorder.h b/daemon/src/audio/audiorecorder.h index 0a471e37f9b0144b2b91f2ce210f1cf6f4878609..00bff8679dfb010ca25c5968a1edd497e61ea6f5 100644 --- a/daemon/src/audio/audiorecorder.h +++ b/daemon/src/audio/audiorecorder.h @@ -41,7 +41,7 @@ class MainBuffer; class AudioRecorder { public: - AudioRecorder(AudioRecord *arec, MainBuffer *mb); + AudioRecorder(AudioRecord *arec, MainBuffer &mb); ~AudioRecorder(); std::string getRecorderID() const { return recorderId_; @@ -56,7 +56,7 @@ class AudioRecorder { static int count_; std::string recorderId_; - MainBuffer *mbuffer_; + MainBuffer &mbuffer_; AudioRecord *arecord_; bool running_; pthread_t thread_; diff --git a/daemon/src/audio/audiortp/audio_rtp_factory.cpp b/daemon/src/audio/audiortp/audio_rtp_factory.cpp index 07483788087a9f668b930ea0473d6164563212c6..a97c2d3ea689d62b20e647e20539b0ce08c8cd69 100644 --- a/daemon/src/audio/audiortp/audio_rtp_factory.cpp +++ b/daemon/src/audio/audiortp/audio_rtp_factory.cpp @@ -68,6 +68,7 @@ AudioRtpFactory::~AudioRtpFactory() void AudioRtpFactory::initConfig() { DEBUG("AudioRtpFactory: init config"); + if (rtpSession_ != NULL) stop(); @@ -78,18 +79,22 @@ void AudioRtpFactory::initConfig() if (account) { srtpEnabled_ = account->getSrtpEnabled(); std::string key(account->getSrtpKeyExchange()); + if (srtpEnabled_) { #if HAVE_ZRTP + if (key == "sdes") keyExchangeProtocol_ = SDES; else if (key == "zrtp") keyExchangeProtocol_ = ZRTP; + #else - keyExchangeProtocol_ = SDES; + keyExchangeProtocol_ = SDES; #endif } else { keyExchangeProtocol_ = NONE; } + helloHashEnabled_ = account->getZrtpHelloHash(); } else { srtpEnabled_ = false; @@ -107,14 +112,18 @@ void AudioRtpFactory::initSession() switch (keyExchangeProtocol_) { #if HAVE_ZRTP + case ZRTP: rtpSession_ = new AudioZrtpSession(*ca_, zidFilename); + // TODO: be careful with that. The hello hash is computed asynchronously. Maybe it's // not even available at that point. if (helloHashEnabled_) ca_->getLocalSDP()->setZrtpHash(static_cast<AudioZrtpSession *>(rtpSession_)->getHelloHash()); + break; #endif + case SDES: rtpSession_ = new AudioSrtpSession(*ca_); break; @@ -175,8 +184,10 @@ void AudioRtpFactory::updateSessionMedia(const std::vector<AudioCodec*> &audioCo void AudioRtpFactory::updateDestinationIpAddress() { - if (rtpSession_) - rtpSession_->updateDestinationIpAddress(); + if (rtpSession_ == NULL) + throw AudioRtpFactoryException("RTP session was null when trying to update IP address"); + + rtpSession_->updateDestinationIpAddress(); } #if HAVE_ZRTP @@ -192,6 +203,7 @@ AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession() void AudioRtpFactory::initLocalCryptoInfo() { DEBUG("AudioRtpFactory: Init local crypto info"); + if (rtpSession_ && keyExchangeProtocol_ == SDES) { AudioSrtpSession *srtp = static_cast<AudioSrtpSession*>(rtpSession_); // the context is invalidated and deleted by the call to initLocalCryptoInfo @@ -203,6 +215,7 @@ void AudioRtpFactory::initLocalCryptoInfo() void AudioRtpFactory::initLocalCryptoInfoOnOffHold() { DEBUG("AudioRtpFactory: Init local crypto info"); + if (rtpSession_ && keyExchangeProtocol_ == SDES) { AudioSrtpSession *srtp = static_cast<AudioSrtpSession*>(rtpSession_); // the context is invalidated and deleted by the call to initLocalCryptoInfo @@ -214,7 +227,7 @@ void AudioRtpFactory::initLocalCryptoInfoOnOffHold() void AudioRtpFactory::setRemoteCryptoInfo(SdesNegotiator& nego) { - if (rtpSession_ ) { + if (rtpSession_) { if (keyExchangeProtocol_ == SDES) { AudioSrtpSession *srtp = static_cast<AudioSrtpSession *>(rtpSession_); srtp->setRemoteCryptoInfo(nego); diff --git a/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp b/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp index 38949b5422273a62e88d48b7c1e9ce585dcc7856..f51a08d610f683cc23db5602c098095f44a2e14c 100644 --- a/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp +++ b/daemon/src/audio/audiortp/audio_rtp_record_handler.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author: Adrien Beraud <adrien.beraud@wisdomvibes.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,37 +44,41 @@ namespace sfl { #ifdef RECTODISK -std::ofstream rtpResampled ("testRtpOutputResampled.raw", std::ifstream::binary); +std::ofstream rtpResampled("testRtpOutputResampled.raw", std::ifstream::binary); std::ofstream rtpNotResampled("testRtpOutput.raw", std::ifstream::binary); #endif DTMFEvent::DTMFEvent(char digit) : payload(), newevent(true), length(1000) { -/* - From RFC2833: - - Event encoding (decimal) - _________________________ - 0--9 0--9 - * 10 - # 11 - A--D 12--15 - Flash 16 -*/ + /* + From RFC2833: + + Event encoding (decimal) + _________________________ + 0--9 0--9 + * 10 + # 11 + A--D 12--15 + Flash 16 + */ switch (digit) { case '*': digit = 10; break; + case '#': digit = 11; break; + case 'A' ... 'D': digit = digit - 'A' + 12; break; + case '0' ... '9': digit = digit - '0'; break; + default: ERROR("Unexpected DTMF %c", digit); } @@ -85,7 +90,7 @@ DTMFEvent::DTMFEvent(char digit) : payload(), newevent(true), length(1000) } AudioRtpRecord::AudioRtpRecord() : - callId_("") + callId_("") , codecSampleRate_(0) , dtmfQueue_() , audioCodecs_() @@ -93,7 +98,7 @@ AudioRtpRecord::AudioRtpRecord() : , encoderPayloadType_(0) , decoderPayloadType_(0) , hasDynamicPayloadType_(false) - , decData_() // std::tr1::arrays will be 0-initialized + , decData_(DEC_BUFFER_SIZE) // std::tr1::arrays will be 0-initialized , resampledData_() , encodedData_() , converterEncode_(0) @@ -133,14 +138,16 @@ AudioRtpRecord::getCurrentCodec() const ERROR("No codec found"); return 0; } + return audioCodecs_[currentCodecIndex_]; } void AudioRtpRecord::deleteCodecs() { - for (std::vector<AudioCodec *>::iterator i = audioCodecs_.begin(); i != audioCodecs_.end(); ++i) - delete *i; + for (auto &i : audioCodecs_) + delete i; + audioCodecs_.clear(); } @@ -164,9 +171,9 @@ bool AudioRtpRecord::tryToSwitchPayloadTypes(int newPt) AudioRtpRecord::~AudioRtpRecord() { dead_ = true; -#ifdef RECTODISK - rtpResampled.close(); - rtpNotResampled.close(); +#ifdef RTP_DECODE_RECTODISK + beforedecode.close(); + afterdecode.close(); #endif delete converterEncode_; @@ -193,7 +200,6 @@ AudioRtpRecord::~AudioRtpRecord() #endif } - AudioRtpRecordHandler::AudioRtpRecordHandler(SIPCall &call) : audioRtpRecord_(), id_(call.getCallId()), @@ -202,7 +208,9 @@ AudioRtpRecordHandler::AudioRtpRecordHandler(SIPCall &call) : {} -AudioRtpRecordHandler::~AudioRtpRecordHandler() {} +AudioRtpRecordHandler::~AudioRtpRecordHandler() +{ +} std::string AudioRtpRecordHandler::getCurrentAudioCodecNames() @@ -211,10 +219,11 @@ AudioRtpRecordHandler::getCurrentAudioCodecNames() ScopedLock lock(audioRtpRecord_.audioCodecMutex_); { std::string sep = ""; - for (std::vector<AudioCodec*>::const_iterator i = audioRtpRecord_.audioCodecs_.begin(); - i != audioRtpRecord_.audioCodecs_.end(); ++i) { - if (*i) - result += sep + (*i)->getMimeSubtype(); + + for (auto &i : audioRtpRecord_.audioCodecs_) { + if (i) + result += sep + i->getMimeSubtype(); + sep = " "; } } @@ -229,6 +238,7 @@ void AudioRtpRecordHandler::setRtpMedia(const std::vector<AudioCodec*> &audioCod audioRtpRecord_.deleteCodecs(); // Set various codec info to reduce indirection audioRtpRecord_.audioCodecs_ = audioCodecs; + if (audioCodecs.empty()) { ERROR("Audio codecs empty"); return; @@ -283,60 +293,62 @@ int AudioRtpRecordHandler::processDataEncode() double resampleFactor = (double) mainBufferSampleRate / codecSampleRate; - // compute nb of byte to get coresponding to 1 audio frame - int samplesToGet = resampleFactor * getCodecFrameSize(); - const size_t bytesToGet = samplesToGet * sizeof(SFLDataFormat); + // compute nb of byte to get corresponding to 1 audio frame + const size_t samplesToGet = resampleFactor * getCodecFrameSize(); - if (Manager::instance().getMainBuffer().availableForGet(id_) < bytesToGet) + if (Manager::instance().getMainBuffer().availableForGet(id_) < samplesToGet) return 0; - SFLDataFormat *micData = audioRtpRecord_.decData_.data(); - const size_t bytes = Manager::instance().getMainBuffer().getData(micData, bytesToGet, id_); + AudioBuffer& micData = audioRtpRecord_.decData_; + micData.resize(samplesToGet); + const size_t samps = Manager::instance().getMainBuffer().getData(micData, id_); #ifdef RECTODISK - rtpNotResampled.write((const char *)micData, bytes); + rtpNotResampled << micData; #endif - if (bytes != bytesToGet) { - ERROR("Asked for %d bytes from mainbuffer, got %d", bytesToGet, bytes); + if (samps != samplesToGet) { + ERROR("Asked for %d samples from mainbuffer, got %d", samplesToGet, samps); return 0; } - int samples = bytesToGet / sizeof(SFLDataFormat); - - audioRtpRecord_.fadeInDecodedData(samples); + audioRtpRecord_.fadeInDecodedData(); - SFLDataFormat *out = micData; + AudioBuffer *out = &micData; if (codecSampleRate != mainBufferSampleRate) { RETURN_IF_NULL(audioRtpRecord_.converterEncode_, 0, "Converter already destroyed"); - audioRtpRecord_.converterEncode_->resample(micData, - audioRtpRecord_.resampledData_.data(), - audioRtpRecord_.resampledData_.size(), - mainBufferSampleRate, codecSampleRate, - samplesToGet); + micData.setSampleRate(mainBufferSampleRate); + audioRtpRecord_.resampledData_.setSampleRate(codecSampleRate); + audioRtpRecord_.converterEncode_->resample(micData, audioRtpRecord_.resampledData_); #ifdef RECTODISK - rtpResampled.write((const char *)audioRtpRecord_.resampledData_.data(), samplesToGet*sizeof(SFLDataFormat)/2 ); + rtpResampled << audioRtpRecord_.resampledData_; #endif - out = audioRtpRecord_.resampledData_.data(); + out = &(audioRtpRecord_.resampledData_); } #if HAVE_SPEEXDSP + if (Manager::instance().audioPreference.getNoiseReduce()) { ScopedLock lock(audioRtpRecord_.audioProcessMutex_); RETURN_IF_NULL(audioRtpRecord_.noiseSuppressEncode_, 0, "Noise suppressor already destroyed"); audioRtpRecord_.noiseSuppressEncode_->process(micData, getCodecFrameSize()); } + +#endif + +#ifdef RTP_ENCODE_RECTODISK + beforesend.write((const char *)(micData), getCodecFrameSize() * 2); #endif { ScopedLock lock(audioRtpRecord_.audioCodecMutex_); RETURN_IF_NULL(audioRtpRecord_.getCurrentCodec(), 0, "Audio codec already destroyed"); unsigned char *micDataEncoded = audioRtpRecord_.encodedData_.data(); - return audioRtpRecord_.getCurrentCodec()->encode(micDataEncoded, out, getCodecFrameSize()); + return audioRtpRecord_.getCurrentCodec()->encode(micDataEncoded, out->getData(), getCodecFrameSize()); } } #undef RETURN_IF_NULL @@ -347,70 +359,74 @@ void AudioRtpRecordHandler::processDataDecode(unsigned char *spkrData, size_t si { if (audioRtpRecord_.isDead()) return; + if (audioRtpRecord_.decoderPayloadType_ != payloadType) { const bool switched = audioRtpRecord_.tryToSwitchPayloadTypes(payloadType); + if (not switched) { if (!warningInterval_) { warningInterval_ = 250; WARN("Invalid payload type %d, expected %d", payloadType, audioRtpRecord_.decoderPayloadType_); } + warningInterval_--; return; } } - int inSamples = 0; - size = std::min(size, audioRtpRecord_.decData_.size()); - SFLDataFormat *spkrDataDecoded = audioRtpRecord_.decData_.data(); + size = std::min(size, audioRtpRecord_.decData_.samples()); + { ScopedLock lock(audioRtpRecord_.audioCodecMutex_); RETURN_IF_NULL(audioRtpRecord_.getCurrentCodec(), "Audio codecs already destroyed"); // Return the size of data in samples - inSamples = audioRtpRecord_.getCurrentCodec()->decode(spkrDataDecoded, spkrData, size); + audioRtpRecord_.getCurrentCodec()->decode(audioRtpRecord_.decData_.getData(), spkrData, size); } +#ifdef RTP_DECODE_RECTODISK + afterdecode.write((const char *)spkrDataDecoded, inSamples * sizeof(SFLDataFormat)); +#endif +#undef RTP_DECODE_RECTODISK + #if HAVE_SPEEXDSP + if (Manager::instance().audioPreference.getNoiseReduce()) { ScopedLock lock(audioRtpRecord_.audioProcessMutex_); RETURN_IF_NULL(audioRtpRecord_.noiseSuppressDecode_, "Noise suppressor already destroyed"); - audioRtpRecord_.noiseSuppressDecode_->process(spkrDataDecoded, getCodecFrameSize()); + audioRtpRecord_.noiseSuppressDecode_->process(audioRtpRecord_.decData_, getCodecFrameSize()); } + #endif - audioRtpRecord_.fadeInDecodedData(inSamples); + audioRtpRecord_.fadeInDecodedData(); - // Normalize incomming signal - gainController_.process(spkrDataDecoded, inSamples); + // Normalize incoming signal + gainController_.process(audioRtpRecord_.decData_); - SFLDataFormat *out = spkrDataDecoded; - int outSamples = inSamples; + AudioBuffer *out = &(audioRtpRecord_.decData_); - int codecSampleRate = getCodecSampleRate(); + int codecSampleRate = out->getSampleRate(); int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate(); // test if resampling is required if (codecSampleRate != mainBufferSampleRate) { RETURN_IF_NULL(audioRtpRecord_.converterDecode_, "Converter already destroyed"); - out = audioRtpRecord_.resampledData_.data(); + out = &(audioRtpRecord_.resampledData_); // Do sample rate conversion - outSamples = ((float) inSamples * ((float) mainBufferSampleRate / (float) codecSampleRate)); - audioRtpRecord_.converterDecode_->resample(spkrDataDecoded, out, - audioRtpRecord_.resampledData_.size(), codecSampleRate, - mainBufferSampleRate, inSamples); + audioRtpRecord_.converterDecode_->resample(audioRtpRecord_.decData_, audioRtpRecord_.resampledData_); } - Manager::instance().getMainBuffer().putData(out, outSamples * sizeof(SFLDataFormat), id_); + Manager::instance().getMainBuffer().putData(*out, id_); } #undef RETURN_IF_NULL -void AudioRtpRecord::fadeInDecodedData(size_t size) +void AudioRtpRecord::fadeInDecodedData() { // if factor reaches 1, this function should have no effect - if (fadeFactor_ >= 1.0 or size > decData_.size()) + if (fadeFactor_ >= 1.0) return; - for (size_t i = 0; i < size; ++i) - decData_[i] *= fadeFactor_; + decData_.applyGain(fadeFactor_); // Factor used to increase volume in fade in const double FADEIN_STEP_SIZE = 4.0; @@ -421,17 +437,24 @@ bool AudioRtpRecordHandler::codecsDiffer(const std::vector<AudioCodec*> &codecs) const { const std::vector<AudioCodec*> ¤t = audioRtpRecord_.audioCodecs_; + if (codecs.size() != current.size()) return true; - for (std::vector<AudioCodec*>::const_iterator i = codecs.begin(); i != codecs.end(); ++i) { - if (*i) { - bool matched = false; - for (std::vector<AudioCodec*>::const_iterator j = current.begin(); !matched and j != current.end(); ++j) - matched = (*i)->getPayloadType() == (*j)->getPayloadType(); - if (not matched) - return true; - } + + for (const auto &i : codecs) { + if (!i) + continue; + + bool matched = false; + + for (const auto &j : current) + if ((matched = i->getPayloadType() == j->getPayloadType())) + break; + + if (not matched) + return true; } + return false; } diff --git a/daemon/src/audio/audiortp/audio_rtp_record_handler.h b/daemon/src/audio/audiortp/audio_rtp_record_handler.h index 18ec89ae9e393644b3be618ce8bc915782374d4f..af6232f70f2bd7e17742a5ebd342e6a5699b2528 100644 --- a/daemon/src/audio/audiortp/audio_rtp_record_handler.h +++ b/daemon/src/audio/audiortp/audio_rtp_record_handler.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author: Adrien Beraud <adrien.beraud@wisdomvibes.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -94,9 +95,8 @@ class AudioRtpRecord { int encoderPayloadType_; int decoderPayloadType_; bool hasDynamicPayloadType_; - std::tr1::array<SFLDataFormat, DEC_BUFFER_SIZE> decData_; -// FIXME: resampledData should be resized as needed - std::tr1::array<SFLDataFormat, DEC_BUFFER_SIZE * 4> resampledData_; + AudioBuffer decData_; + AudioBuffer resampledData_; std::tr1::array<unsigned char, DEC_BUFFER_SIZE> encodedData_; SamplerateConverter *converterEncode_; SamplerateConverter *converterDecode_; @@ -117,7 +117,7 @@ class AudioRtpRecord { /** * Ramp In audio data to avoid audio click from peer */ - void fadeInDecodedData(size_t size); + void fadeInDecodedData();//size_t size); NON_COPYABLE(AudioRtpRecord); #ifdef CCPP_PREFIX ost::AtomicCounter dead_; diff --git a/daemon/src/audio/audiortp/audio_rtp_session.cpp b/daemon/src/audio/audiortp/audio_rtp_session.cpp index ab0fff684a992b61f715ab4228fdfd6fcce6f697..04bce53c96e37413917de5e9bfe566a781dbe191 100644 --- a/daemon/src/audio/audiortp/audio_rtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_rtp_session.cpp @@ -71,11 +71,13 @@ void AudioRtpSession::updateSessionMedia(const std::vector<AudioCodec*> &audioCo Manager::instance().audioSamplingRateChanged(audioRtpRecord_.codecSampleRate_); #if HAVE_SPEEXDSP + if (lastSamplingRate != audioRtpRecord_.codecSampleRate_) { DEBUG("Update noise suppressor with sampling rate %d and frame size %d", getCodecSampleRate(), getCodecFrameSize()); initNoiseSuppress(); } + #endif } @@ -85,6 +87,7 @@ void AudioRtpSession::setSessionMedia(const std::vector<AudioCodec*> &audioCodec // G722 requires timestamp to be incremented at 8kHz const ost::PayloadType payloadType = getEncoderPayloadType(); + if (payloadType == ost::sptG722) { const int G722_RTP_TIME_INCREMENT = 160; timestampIncrement_ = G722_RTP_TIME_INCREMENT; @@ -93,7 +96,7 @@ void AudioRtpSession::setSessionMedia(const std::vector<AudioCodec*> &audioCodec if (payloadType == ost::sptG722) { const int G722_RTP_CLOCK_RATE = 8000; - queue_.setPayloadFormat(ost::DynamicPayloadFormat( payloadType, G722_RTP_CLOCK_RATE)); + queue_.setPayloadFormat(ost::DynamicPayloadFormat(payloadType, G722_RTP_CLOCK_RATE)); } else { if (getHasDynamicPayload()) queue_.setPayloadFormat(ost::DynamicPayloadFormat(payloadType, getCodecSampleRate())); @@ -125,7 +128,8 @@ void AudioRtpSession::sendDtmfEvent() // Set marker in case this is a new Event if (dtmf.newevent) queue_.setMark(true); - queue_.sendImmediate(timestamp_, (const unsigned char *) (& (dtmf.payload)), sizeof (ost::RTPPacket::RFC2833Payload)); + + queue_.sendImmediate(timestamp_, (const unsigned char *)(& (dtmf.payload)), sizeof(ost::RTPPacket::RFC2833Payload)); // This is no longer a new event if (dtmf.newevent) { @@ -140,9 +144,11 @@ void AudioRtpSession::sendDtmfEvent() // decrease length remaining to process for this event dtmf.length -= increment; dtmf.payload.duration++; + // next packet is going to be the last one if ((dtmf.length - increment) < increment) dtmf.payload.ebit = true; + if (dtmf.length < increment) audioRtpRecord_.dtmfQueue_.pop_front(); } @@ -200,7 +206,7 @@ void AudioRtpSession::setDestinationIpAddress() if (!remote_ip_) { WARN("Target IP address (%s) is not correct!", - call_.getLocalSDP()->getRemoteIP().data()); + call_.getLocalSDP()->getRemoteIP().data()); return; } @@ -276,6 +282,7 @@ AudioRtpSession::AudioRtpSendThread::AudioRtpSendThread(AudioRtpSession &session AudioRtpSession::AudioRtpSendThread::~AudioRtpSendThread() { running_ = false; + if (thread_) pthread_join(thread_, NULL); } diff --git a/daemon/src/audio/audiortp/audio_srtp_session.cpp b/daemon/src/audio/audiortp/audio_srtp_session.cpp index cdf219abd5d660cad1897e7ff4e14d3035e86f01..a7ad99e885d478802793e6d547951187a88d607e 100644 --- a/daemon/src/audio/audiortp/audio_srtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_srtp_session.cpp @@ -47,84 +47,84 @@ namespace sfl { namespace { - std::string - encodeBase64(unsigned char *input, int length) - { - // init decoder - BIO *b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); +std::string +encodeBase64(unsigned char *input, int length) +{ + // init decoder + BIO *b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - // init internal buffer - BIO *bmem = BIO_new(BIO_s_mem()); + // init internal buffer + BIO *bmem = BIO_new(BIO_s_mem()); - // create decoder chain - b64 = BIO_push(b64, bmem); + // create decoder chain + b64 = BIO_push(b64, bmem); - BIO_write(b64, input, length); - // BIO_flush (b64); + BIO_write(b64, input, length); + // BIO_flush (b64); - // get pointer to data - BUF_MEM *bptr = 0; - BIO_get_mem_ptr(b64, &bptr); + // get pointer to data + BUF_MEM *bptr = 0; + BIO_get_mem_ptr(b64, &bptr); - std::string output(bptr->data, bptr->length); + std::string output(bptr->data, bptr->length); - BIO_free_all(bmem); + BIO_free_all(bmem); - return output; - } + return output; +} - std::vector<char> decodeBase64(unsigned char *input, int length) - { - BIO *b64, *bmem; +std::vector<char> decodeBase64(unsigned char *input, int length) +{ + BIO *b64, *bmem; - // init decoder and read-only BIO buffer - b64 = BIO_new(BIO_f_base64()); - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + // init decoder and read-only BIO buffer + b64 = BIO_new(BIO_f_base64()); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - // init internal buffer - bmem = BIO_new_mem_buf(input, length); + // init internal buffer + bmem = BIO_new_mem_buf(input, length); - // create encoder chain - bmem = BIO_push(b64, bmem); + // create encoder chain + bmem = BIO_push(b64, bmem); - std::vector<char> buffer(length, 0); - BIO_read(bmem, &(*buffer.begin()), length); + std::vector<char> buffer(length, 0); + BIO_read(bmem, buffer.data(), length); - BIO_free_all(bmem); + BIO_free_all(bmem); - return buffer; - } + return buffer; +} - // Fills the array dest with length random bytes - void bufferFillMasterKey(std::vector<uint8>& dest) - { - DEBUG("Init local master key"); +// Fills the array dest with length random bytes +void bufferFillMasterKey(std::vector<uint8>& dest) +{ + DEBUG("Init local master key"); - // Allocate memory for key - std::vector<unsigned char> random_key(dest.size()); + // Allocate memory for key + std::vector<unsigned char> random_key(dest.size()); - // Generate ryptographically strong pseudo-random bytes - if (RAND_bytes(&(*random_key.begin()), dest.size()) != 1) - DEBUG("Error occured while generating cryptographically strong pseudo-random key"); + // Generate ryptographically strong pseudo-random bytes + if (RAND_bytes(random_key.data(), dest.size()) != 1) + DEBUG("Error occured while generating cryptographically strong pseudo-random key"); - std::copy(random_key.begin(), random_key.end(), dest.begin()); - } + std::copy(random_key.begin(), random_key.end(), dest.begin()); +} - // Fills the array dest with length random bytes - void bufferFillMasterSalt(std::vector<uint8>& dest) - { - DEBUG("Init local master key"); +// Fills the array dest with length random bytes +void bufferFillMasterSalt(std::vector<uint8>& dest) +{ + DEBUG("Init local master key"); - // Allocate memory for key - std::vector<unsigned char> random_key(dest.size()); + // Allocate memory for key + std::vector<unsigned char> random_key(dest.size()); - // Generate ryptographically strong pseudo-random bytes - if (RAND_bytes(&(*random_key.begin()), dest.size()) != 1) - DEBUG("Error occured while generating cryptographically strong pseudo-random key"); + // Generate ryptographically strong pseudo-random bytes + if (RAND_bytes(random_key.data(), dest.size()) != 1) + DEBUG("Error occured while generating cryptographically strong pseudo-random key"); - std::copy(random_key.begin(), random_key.end(), dest.begin()); - } + std::copy(random_key.begin(), random_key.end(), dest.begin()); +} } AudioSrtpSession::AudioSrtpSession(SIPCall &call) : @@ -213,6 +213,7 @@ void AudioSrtpSession::setRemoteCryptoInfo(const sfl::SdesNegotiator& nego) // init crypto content in Srtp session initializeRemoteCryptoContext(); + if (remoteCryptoCtx_) { setInQueueCryptoContext(remoteCryptoCtx_); } @@ -222,7 +223,7 @@ void AudioSrtpSession::setRemoteCryptoInfo(const sfl::SdesNegotiator& nego) } namespace { - static const size_t BITS_PER_BYTE = 8; +static const size_t BITS_PER_BYTE = 8; } void AudioSrtpSession::initializeLocalMasterKey() @@ -250,7 +251,7 @@ std::string AudioSrtpSession::getBase64ConcatenatedKeys() concatKeys.insert(concatKeys.end(), localMasterSalt_.begin(), localMasterSalt_.end()); // encode concatenated keys in base64 - return encodeBase64(&(*concatKeys.begin()), concatKeys.size()); + return encodeBase64(concatKeys.data(), concatKeys.size()); } void AudioSrtpSession::unBase64ConcatenatedKeys(std::string base64keys) @@ -277,18 +278,18 @@ void AudioSrtpSession::initializeRemoteCryptoContext() const CryptoSuiteDefinition &crypto = sfl::CryptoSuites[remoteCryptoSuite_]; remoteCryptoCtx_ = new ost::CryptoContext(0x0, - 0, // roc, - 0L, // keydr, - SrtpEncryptionAESCM, - SrtpAuthenticationSha1Hmac, - &(*remoteMasterKey_.begin()), - remoteMasterKey_.size(), - &(*remoteMasterSalt_.begin()), - remoteMasterSalt_.size(), - crypto.encryptionKeyLength / BITS_PER_BYTE, - crypto.srtpAuthKeyLength / BITS_PER_BYTE, - crypto.masterSaltLength / BITS_PER_BYTE, - crypto.srtpAuthTagLength / BITS_PER_BYTE); + 0, // roc, + 0L, // keydr, + SrtpEncryptionAESCM, + SrtpAuthenticationSha1Hmac, + remoteMasterKey_.data(), + remoteMasterKey_.size(), + remoteMasterSalt_.data(), + remoteMasterSalt_.size(), + crypto.encryptionKeyLength / BITS_PER_BYTE, + crypto.srtpAuthKeyLength / BITS_PER_BYTE, + crypto.masterSaltLength / BITS_PER_BYTE, + crypto.srtpAuthTagLength / BITS_PER_BYTE); } @@ -299,18 +300,18 @@ void AudioSrtpSession::initializeLocalCryptoContext() const CryptoSuiteDefinition &crypto = sfl::CryptoSuites[localCryptoSuite_]; localCryptoCtx_ = new ost::CryptoContext(OutgoingDataQueue::getLocalSSRC(), - 0, // roc, - 0L, // keydr, - SrtpEncryptionAESCM, - SrtpAuthenticationSha1Hmac, - &(*localMasterKey_.begin()), - localMasterKey_.size(), - &(*localMasterSalt_.begin()), - localMasterSalt_.size(), - crypto.encryptionKeyLength / BITS_PER_BYTE, - crypto.srtpAuthKeyLength / BITS_PER_BYTE, - crypto.masterSaltLength / BITS_PER_BYTE, - crypto.srtpAuthTagLength / BITS_PER_BYTE); + 0, // roc, + 0L, // keydr, + SrtpEncryptionAESCM, + SrtpAuthenticationSha1Hmac, + localMasterKey_.data(), + localMasterKey_.size(), + localMasterSalt_.data(), + localMasterSalt_.size(), + crypto.encryptionKeyLength / BITS_PER_BYTE, + crypto.srtpAuthKeyLength / BITS_PER_BYTE, + crypto.masterSaltLength / BITS_PER_BYTE, + crypto.srtpAuthTagLength / BITS_PER_BYTE); } void diff --git a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp index 31850866d4f0c2f923e967a5df59f355a8e179cb..48e8048e7f7dcc6d61735d6c2812843445bef6f8 100644 --- a/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp +++ b/daemon/src/audio/audiortp/audio_symmetric_rtp_session.cpp @@ -43,7 +43,7 @@ AudioSymmetricRtpSession::AudioSymmetricRtpSession(SIPCall &call) : , AudioRtpSession(call, *this) { DEBUG("Setting new RTP session with destination %s:%d", - call_.getLocalIp().c_str(), call_.getLocalAudioPort()); + call_.getLocalIp().c_str(), call_.getLocalAudioPort()); audioRtpRecord_.callId_ = call_.getCallId(); } diff --git a/daemon/src/audio/audiortp/zrtp_session_callback.cpp b/daemon/src/audio/audiortp/zrtp_session_callback.cpp index 3f26698d6d320147948988610f8afed8b3f66502..4106c7401d25c5935336d61a4ae20f45100b1614 100644 --- a/daemon/src/audio/audiortp/zrtp_session_callback.cpp +++ b/daemon/src/audio/audiortp/zrtp_session_callback.cpp @@ -30,8 +30,8 @@ #include "zrtp_session_callback.h" #include "logger.h" #include "sip/sipcall.h" -#include "dbus/dbusmanager.h" -#include "dbus/callmanager.h" +#include "client/client.h" +#include "client/callmanager.h" #include "manager.h" #include <cstdlib> @@ -104,28 +104,28 @@ void ZrtpSessionCallback::secureOn(std::string cipher) { DEBUG("Secure mode is on with cipher %s", cipher.c_str()); - Manager::instance().getDbusManager()->getCallManager()->secureZrtpOn(call_.getCallId(), cipher); + Manager::instance().getClient()->getCallManager()->secureZrtpOn(call_.getCallId(), cipher); } void ZrtpSessionCallback::secureOff() { DEBUG("Secure mode is off"); - Manager::instance().getDbusManager()->getCallManager()->secureZrtpOff(call_.getCallId()); + Manager::instance().getClient()->getCallManager()->secureZrtpOff(call_.getCallId()); } void ZrtpSessionCallback::showSAS(std::string sas, bool verified) { DEBUG("SAS is: %s", sas.c_str()); - Manager::instance().getDbusManager()->getCallManager()->showSAS(call_.getCallId(), sas, verified); + Manager::instance().getClient()->getCallManager()->showSAS(call_.getCallId(), sas, verified); } void ZrtpSessionCallback::zrtpNotSuppOther() { DEBUG("Callee does not support ZRTP"); - Manager::instance().getDbusManager()->getCallManager()->zrtpNotSuppOther(call_.getCallId()); + Manager::instance().getClient()->getCallManager()->zrtpNotSuppOther(call_.getCallId()); } void @@ -151,15 +151,17 @@ ZrtpSessionCallback::zrtpNegotiationFailed(MessageSeverity severity, int subCode DEBUG("Sent error packet: "); std::map<int32, std::string>::const_iterator iter = zrtpMap_.find(subCode); + if (iter != zrtpMap_.end()) { DEBUG("%s", iter->second.c_str()); - Manager::instance().getDbusManager()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "ZRTP"); + Manager::instance().getClient()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "ZRTP"); } } else { std::map<int32, std::string>::const_iterator iter = severeMap_.find(subCode); + if (iter != severeMap_.end()) { DEBUG("%s", iter->second.c_str()); - Manager::instance().getDbusManager()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "severe"); + Manager::instance().getClient()->getCallManager()->zrtpNegotiationFailed(call_.getCallId(), iter->second, "severe"); } } } @@ -168,7 +170,7 @@ void ZrtpSessionCallback::confirmGoClear() { DEBUG("Received go clear message. Until confirmation, ZRTP won't send any data"); - Manager::instance().getDbusManager()->getCallManager()->zrtpNotSuppOther(call_.getCallId()); + Manager::instance().getClient()->getCallManager()->zrtpNotSuppOther(call_.getCallId()); } std::map<int32, std::string> ZrtpSessionCallback::infoMap_; diff --git a/daemon/src/audio/codecs/alaw.cpp b/daemon/src/audio/codecs/alaw.cpp index 18ea89033aec8eed0f63bbac58e130d6cae476bc..55ea59d206af82c3627c546890195d3eae6f2c82 100644 --- a/daemon/src/audio/codecs/alaw.cpp +++ b/daemon/src/audio/codecs/alaw.cpp @@ -42,7 +42,7 @@ class Alaw : public sfl::AudioCodec { } private: - int decode(SFLDataFormat *dst, unsigned char *src, size_t buf_size) + int decode(SFLAudioSample *dst, unsigned char *src, size_t buf_size) { for (unsigned char* end = src + buf_size; src < end; ++src, ++dst) *dst = ALawDecode(*src); @@ -50,7 +50,7 @@ class Alaw : public sfl::AudioCodec { return buf_size; } - int encode(unsigned char *dst, SFLDataFormat *src, size_t buf_size) + int encode(unsigned char *dst, SFLAudioSample *src, size_t buf_size) { for (unsigned char *end = dst + buf_size; dst < end; ++src, ++dst) *dst = ALawEncode(*src); @@ -58,10 +58,9 @@ class Alaw : public sfl::AudioCodec { return buf_size; } - int ALawDecode(uint8 alaw) - { + int ALawDecode(uint8_t alaw) { alaw ^= 0x55; // A-law has alternate bits inverted for transmission - uint sign = alaw & 0x80; + uint8_t sign = alaw & 0x80; int linear = alaw & 0x1f; linear <<= 4; linear += 8; // Add a 'half' bit (0x08) to place PCM value in middle of range @@ -70,7 +69,7 @@ class Alaw : public sfl::AudioCodec { if (alaw >= 0x20) { linear |= 0x100; // Put in MSB - uint shift = (alaw >> 4) - 1; + uint8_t shift = (alaw >> 4) - 1; linear <<= shift; } @@ -80,10 +79,9 @@ class Alaw : public sfl::AudioCodec { return linear; } - uint8 ALawEncode(SFLDataFormat pcm16) - { + uint8_t ALawEncode(SFLAudioSample pcm16) { int p = pcm16; - uint a; // u-law value we are forming + uint8_t a; // u-law value we are forming if (p < 0) { p = ~p; diff --git a/daemon/src/audio/codecs/audiocodec.cpp b/daemon/src/audio/codecs/audiocodec.cpp index 94d7927052352551c70185c5d4983f31b6e57a6f..6bfaa963b66bfb6de0021de672dc0e6ffb793368 100644 --- a/daemon/src/audio/codecs/audiocodec.cpp +++ b/daemon/src/audio/codecs/audiocodec.cpp @@ -32,19 +32,17 @@ #include "audiocodec.h" using std::ptrdiff_t; -#include <ccrtp/rtp.h> namespace sfl { -AudioCodec::AudioCodec(uint8 payload, const std::string &codecName, - int clockRate, int frameSize, int channel) : +AudioCodec::AudioCodec(uint8_t payload, const std::string &codecName, + int clockRate, int frameSize, unsigned channels) : codecName_(codecName), clockRate_(clockRate), - channel_(channel), + channel_(channels), frameSize_(frameSize), bitrate_(0.0), payload_(payload), - payloadFormat_(payload, clockRate_), hasDynamicPayload_((payload_ >= 96 and payload_ <= 127) or payload_ == 9) {} @@ -55,16 +53,27 @@ AudioCodec::AudioCodec(const AudioCodec& c) : frameSize_(c.frameSize_), bitrate_(c.bitrate_), payload_(c.payload_), - payloadFormat_(c.payloadFormat_), hasDynamicPayload_(c.hasDynamicPayload_) {} +// Mono only, subclasses must implement multichannel support +int AudioCodec::decode(std::vector<std::vector<SFLAudioSample> > &dst, unsigned char *buf, size_t buffer_size) +{ + return decode(dst[0].data(), buf, buffer_size); +} + +// Mono only, subclasses must implement multichannel support +int AudioCodec::encode(unsigned char *dst, std::vector<std::vector<SFLAudioSample> > &src, size_t buffer_size) +{ + return encode(dst, src[0].data(), buffer_size); +} + std::string AudioCodec::getMimeSubtype() const { return codecName_; } -uint8 AudioCodec::getPayloadType() const +uint8_t AudioCodec::getPayloadType() const { return payload_; } @@ -74,7 +83,7 @@ bool AudioCodec::hasDynamicPayload() const return hasDynamicPayload_; } -uint32 AudioCodec::getClockRate() const +uint32_t AudioCodec::getClockRate() const { return clockRate_; } @@ -89,4 +98,9 @@ double AudioCodec::getBitRate() const return bitrate_; } +unsigned AudioCodec::getChannels() const +{ + return channel_; +} + } // end namespace sfl diff --git a/daemon/src/audio/codecs/audiocodec.h b/daemon/src/audio/codecs/audiocodec.h index 7ed273101a4ef069b262233e9bcc8bc348c3cee5..a45910a6543fb1f58e4a8b6e1fa139c4cf218ba8 100644 --- a/daemon/src/audio/codecs/audiocodec.h +++ b/daemon/src/audio/codecs/audiocodec.h @@ -33,8 +33,8 @@ #define __AUDIO_CODEC_H__ #include <string> -#include "cc_config.h" -#include <ccrtp/formats.h> // for ost::DynamicPayloadFormat +#include <vector> +#include "sfl_types.h" #define XSTR(s) STR(s) #define STR(s) #s @@ -52,8 +52,7 @@ namespace sfl { class AudioCodec { public: - AudioCodec(uint8 payload, const std::string &codecName, int clockRate, - int frameSize, int channel); + AudioCodec(uint8_t payload, const std::string &codecName, int clockRate, int frameSize, unsigned channels); /** * Copy constructor. @@ -69,18 +68,30 @@ class AudioCodec { * @param buffer_size : the size of the input buffer * @return the number of samples decoded */ - virtual int decode(short *dst, unsigned char *buf, size_t buffer_size) = 0; + virtual int decode(SFLAudioSample *dst, unsigned char *buf, size_t buffer_size) = 0; /** * Encode an input buffer and fill the output buffer with the encoded data * @param buffer_size : the maximum size of encoded data buffer (dst) * @return the number of bytes encoded */ - virtual int encode(unsigned char *dst, short *src, size_t buffer_size) = 0; + virtual int encode(unsigned char *dst, SFLAudioSample *src, size_t buffer_size) = 0; - uint8 getPayloadType() const; + /** + * Multichannel version of decode(). + * Default implementation decode(short *, unsigned char *, size_t) to the first channel (assume 1 channel). + */ + virtual int decode(std::vector<std::vector<SFLAudioSample> > &dst, unsigned char *buf, size_t buffer_size); + + /** + * Multichannel version of encode(). + * Default implementation calls encode() on the first channel (assume 1 channel). + */ + virtual int encode(unsigned char *dst, std::vector<std::vector<SFLAudioSample> > &src, size_t buffer_size); + + uint8_t getPayloadType() const; - void setPayloadType(uint8 pt) { + void setPayloadType(uint8_t pt) { payload_ = pt; } @@ -89,10 +100,12 @@ class AudioCodec { */ bool hasDynamicPayload() const; - uint32 getClockRate() const; + uint32_t getClockRate() const; double getBitRate() const; + unsigned getChannels() const; + /** * @return the framing size for this codec. */ @@ -103,10 +116,10 @@ class AudioCodec { std::string codecName_; // what we put inside sdp /** Clock rate or sample rate of the codec, in Hz */ - uint32 clockRate_; + uint32_t clockRate_; /** Number of channel 1 = mono, 2 = stereo */ - uint8 channel_; + uint8_t channel_; /** codec frame size in samples*/ unsigned frameSize_; @@ -116,9 +129,7 @@ class AudioCodec { private: AudioCodec& operator=(const AudioCodec&); - uint8 payload_; - - ost::DynamicPayloadFormat payloadFormat_; + uint8_t payload_; protected: bool hasDynamicPayload_; diff --git a/daemon/src/audio/codecs/audiocodecfactory.cpp b/daemon/src/audio/codecs/audiocodecfactory.cpp index fc1319db585ab73f2ece4d113a8a83dc05a4f9d7..5f753cbf7d10c9d704ae75bf1e5bb55d5e8889c2 100644 --- a/daemon/src/audio/codecs/audiocodecfactory.cpp +++ b/daemon/src/audio/codecs/audiocodecfactory.cpp @@ -56,10 +56,9 @@ AudioCodecFactory::AudioCodecFactory() : if (codecDynamicList.empty()) ERROR("No codecs available"); else { - for (AudioCodecVector::const_iterator iter = codecDynamicList.begin(); - iter != codecDynamicList.end() ; ++iter) { - codecsMap_[(int)(*iter)->getPayloadType()] = *iter; - DEBUG("Loaded codec %s" , (*iter)->getMimeSubtype().c_str()); + for (const auto &codec: codecDynamicList) { + codecsMap_[(int) codec->getPayloadType()] = codec; + DEBUG("Loaded codec %s" , codec->getMimeSubtype().c_str()); } } } @@ -68,8 +67,9 @@ void AudioCodecFactory::setDefaultOrder() { defaultCodecList_.clear(); - for (AudioCodecsMap::const_iterator i = codecsMap_.begin(); i != codecsMap_.end(); ++i) - defaultCodecList_.push_back(i->first); + + for (const auto &codec : codecsMap_) + defaultCodecList_.push_back(codec.first); } std::string @@ -87,9 +87,10 @@ std::vector<int32_t> AudioCodecFactory::getCodecList() const { std::vector<int32_t> list; - for (AudioCodecsMap::const_iterator iter = codecsMap_.begin(); iter != codecsMap_.end(); ++iter) - if (iter->second) - list.push_back((int32_t) iter->first); + + for (const auto &codec : codecsMap_) + if (codec.second) + list.push_back((int32_t) codec.first); return list; } @@ -130,6 +131,17 @@ AudioCodecFactory::getSampleRate(int payload) const return 0; } +unsigned +AudioCodecFactory::getChannels(int payload) const +{ + AudioCodecsMap::const_iterator iter = codecsMap_.find(payload); + + if (iter != codecsMap_.end()) + return iter->second->getChannels(); + else + return 0; +} + void AudioCodecFactory::saveActiveCodecs(const std::vector<std::string>& list) { @@ -137,8 +149,8 @@ AudioCodecFactory::saveActiveCodecs(const std::vector<std::string>& list) // list contains the ordered payload of active codecs picked by the user // we used the codec vector to save the order. - for (std::vector<std::string>::const_iterator iter = list.begin(); iter != list.end(); ++iter) { - int payload = std::atoi(iter->c_str()); + for (const auto &codec : list) { + int payload = std::atoi(codec.c_str()); if (isCodecLoaded(payload)) defaultCodecList_.push_back(static_cast<int>(payload)); @@ -148,9 +160,8 @@ AudioCodecFactory::saveActiveCodecs(const std::vector<std::string>& list) AudioCodecFactory::~AudioCodecFactory() { - for (std::vector<AudioCodecHandlePointer>::iterator iter = - codecInMemory_.begin(); iter != codecInMemory_.end(); ++iter) - unloadCodec(*iter); + for (auto &codec : codecInMemory_) + unloadCodec(codec); } std::vector<sfl::AudioCodec*> @@ -168,8 +179,13 @@ AudioCodecFactory::scanCodecDirectory() const char *progDir = fileutils::get_program_dir(); - if (progDir) + if (progDir) { +#ifdef __ANDROID__ + dirToScan.push_back(std::string(progDir) + DIR_SEPARATOR_STR + "lib/"); +#else dirToScan.push_back(std::string(progDir) + DIR_SEPARATOR_STR + "audio/codecs/"); +#endif + } for (size_t i = 0 ; i < dirToScan.size() ; i++) { std::string dirStr = dirToScan[i]; @@ -227,6 +243,7 @@ AudioCodecFactory::loadCodec(const std::string &path) } sfl::AudioCodec *a = static_cast<sfl::AudioCodec *>(createCodec()); + if (a) codecInMemory_.push_back(AudioCodecHandlePointer(a, codecHandle)); else @@ -240,6 +257,9 @@ void AudioCodecFactory::unloadCodec(AudioCodecHandlePointer &ptr) { destroy_t *destroyCodec = 0; + // flush last error + dlerror(); + if (ptr.second) destroyCodec = (destroy_t*) dlsym(ptr.second, "destroy"); @@ -260,19 +280,24 @@ AudioCodecFactory::unloadCodec(AudioCodecHandlePointer &ptr) sfl::AudioCodec* AudioCodecFactory::instantiateCodec(int payload) const { - std::vector<AudioCodecHandlePointer>::const_iterator iter; + // flush last error + dlerror(); sfl::AudioCodec *result = NULL; - for (iter = codecInMemory_.begin(); iter != codecInMemory_.end(); ++iter) { - if (iter->first->getPayloadType() == payload) { - create_t* createCodec = (create_t*) dlsym(iter->second , AUDIO_CODEC_ENTRY_SYMBOL); + + for (const auto &codec : codecInMemory_) { + if (codec.first->getPayloadType() == payload) { + + create_t* createCodec = (create_t*) dlsym(codec.second , AUDIO_CODEC_ENTRY_SYMBOL); const char *error = dlerror(); - if (error) + if (error) { ERROR("%s", error); - else + dlerror(); + } else { result = static_cast<sfl::AudioCodec *>(createCodec()); + } } } @@ -284,7 +309,6 @@ AudioCodecFactory::seemsValid(const std::string &lib) { // The name of the shared library seems valid <==> it looks like libcodec_xxx.so // We check this - static const std::string prefix("libcodec_"); static const std::string suffix(".so"); @@ -299,28 +323,31 @@ AudioCodecFactory::seemsValid(const std::string &lib) return false; static const std::string validCodecs[] = { - "ulaw", - "alaw", - "g722", - "g729", //G729 have to be loaded first, if it is valid or not is checked later - "opus", //Opus have to be loaded first, if it is valid or not is checked later + "ulaw", + "alaw", + "g722", + "g729", //G729 have to be loaded first, if it is valid or not is checked later + "opus", //Opus have to be loaded first, if it is valid or not is checked later + "opus_stereo", #ifdef HAVE_SPEEX_CODEC - "speex_nb", - "speex_wb", - "speex_ub", + "speex_nb", + "speex_wb", + "speex_ub", #endif #ifdef HAVE_GSM_CODEC - "gsm", + "gsm", #endif #ifdef BUILD_ILBC - "ilbc", + "ilbc", #endif - ""}; + "" + }; const std::string name(lib.substr(prefix.length(), len)); const std::string *end = validCodecs + ARRAYSIZE(validCodecs); + return find(validCodecs, end, name) != end; } @@ -333,10 +360,8 @@ AudioCodecFactory::alreadyInCache(const std::string &lib) bool AudioCodecFactory::isCodecLoaded(int payload) const { - AudioCodecsMap::const_iterator iter; - - for (iter = codecsMap_.begin(); iter != codecsMap_.end(); ++iter) - if (iter->first == payload) + for (const auto &codec : codecsMap_) + if (codec.first == payload) return true; return false; @@ -359,6 +384,11 @@ AudioCodecFactory::getCodecSpecifications(const int32_t& payload) const // Add the bit rate ss << getBitRate(static_cast<int>(payload)); v.push_back(ss.str()); + ss.str(""); + + // Add the channel number + ss << getChannels(static_cast<int>(payload)); + v.push_back(ss.str()); return v; } diff --git a/daemon/src/audio/codecs/audiocodecfactory.h b/daemon/src/audio/codecs/audiocodecfactory.h index 137b7c2497254966a62a602bdd341c192b8add13..f7f4199fff863168985bf467a529fd69171ec4ad 100644 --- a/daemon/src/audio/codecs/audiocodecfactory.h +++ b/daemon/src/audio/codecs/audiocodecfactory.h @@ -87,6 +87,13 @@ class AudioCodecFactory { */ int getSampleRate(int payload) const; + /** + * Get the number of channels of the specified codec + * @param payload The payload of the codec + * @return int The number of channels of the specified codec + */ + unsigned getChannels(int payload) const; + /** * Set the order of codecs by their payload * @param list The ordered list sent by DBus diff --git a/daemon/src/audio/codecs/g722.cpp b/daemon/src/audio/codecs/g722.cpp index 684766eb5bbc4aeb1bfa991a9061773a49bd21d8..8d25afde55ec54e3b265a7764f9e3564b34ae3cb 100644 --- a/daemon/src/audio/codecs/g722.cpp +++ b/daemon/src/audio/codecs/g722.cpp @@ -41,7 +41,7 @@ class G722 : public sfl::AudioCodec { public: G722() : sfl::AudioCodec(9, "G722", 16000, 320, 1), decode_state_(), - encode_state_() { + encode_state_() { bitrate_ = 64; hasDynamicPayload_ = false; @@ -50,19 +50,18 @@ class G722 : public sfl::AudioCodec { } private: - int decode(SFLDataFormat *dst, unsigned char *src, size_t buf_size) + int decode(SFLAudioSample *dst, unsigned char *src, size_t buf_size) { return g722_decode(dst, src, buf_size); } - int encode(unsigned char *dst, SFLDataFormat *src, size_t /*buf_size*/) + int encode(unsigned char *dst, SFLAudioSample *src, size_t /*buf_size*/) { int out = g722_encode(dst, src, frameSize_); return out; } - static void g722_state_init(g722_state_t &state) - { + static void g722_state_init(g722_state_t &state) { state.itu_test_mode = false; // 8 => 64 kbps; 7 => 56 kbps; 6 => 48 kbps @@ -86,12 +85,12 @@ class G722 : public sfl::AudioCodec { state.out_bits = 0; } - SFLDataFormat saturate(int32_t amp) + SFLAudioSample saturate(int32_t amp) { - SFLDataFormat amp16 = 0; + SFLAudioSample amp16 = 0; /* Hopefully this is optimised for the common case - not clipping */ - amp16 = (SFLDataFormat) amp; + amp16 = (SFLAudioSample) amp; if (amp == amp16) return amp16; @@ -102,8 +101,7 @@ class G722 : public sfl::AudioCodec { return INT16_MIN; } - void block4_encode(int band, int d) - { + void block4_encode(int band, int d) { int wd1 = 0; int wd2 = 0; int wd3 = 0; @@ -207,8 +205,7 @@ class G722 : public sfl::AudioCodec { } - void block4_decode(int band, int d) - { + void block4_decode(int band, int d) { int wd1 = 0; int wd2 = 0; int wd3 = 0; @@ -313,7 +310,7 @@ class G722 : public sfl::AudioCodec { decode_state_.band[band].s = saturate(decode_state_.band[band].sp + decode_state_.band[band].sz); } - int g722_decode(SFLDataFormat amp[], const uint8_t g722_data[], int len) + int g722_decode(SFLAudioSample amp[], const uint8_t g722_data[], int len) { static const int wl[8] = {-60, -30, 58, 172, 334, 538, 1198, 3042 }; static const int rl42[16] = {0, 7, 6, 5, 4, 3, 2, 1, 7, 6, 5, 4, 3, 2, 1, 0 }; @@ -508,11 +505,11 @@ class G722 : public sfl::AudioCodec { } if (decode_state_.itu_test_mode) { - amp[outlen++] = (SFLDataFormat)(rlow << 1); - amp[outlen++] = (SFLDataFormat)(rhigh << 1); + amp[outlen++] = (SFLAudioSample)(rlow << 1); + amp[outlen++] = (SFLAudioSample)(rhigh << 1); } else { if (decode_state_.eight_k) { - amp[outlen++] = (SFLDataFormat) rlow; + amp[outlen++] = (SFLAudioSample) rlow; } else { /* Apply the receive QMF */ for (i = 0; i < 22; i++) @@ -531,9 +528,9 @@ class G722 : public sfl::AudioCodec { xout1 += decode_state_.x[2*i + 1]*qmf_coeffs[11 - i]; } - amp[outlen++] = (SFLDataFormat)(xout1 >> 12); + amp[outlen++] = (SFLAudioSample)(xout1 >> 12); - amp[outlen++] = (SFLDataFormat)(xout2 >> 12); + amp[outlen++] = (SFLAudioSample)(xout2 >> 12); } } } @@ -541,7 +538,7 @@ class G722 : public sfl::AudioCodec { return outlen; } - int g722_encode(uint8_t g722_data[], const SFLDataFormat amp[], int len) + int g722_encode(uint8_t g722_data[], const SFLAudioSample amp[], int len) { static const int q6[32] = { 0, 35, 72, 110, 150, 190, 233, 276, diff --git a/daemon/src/audio/codecs/g729.cpp b/daemon/src/audio/codecs/g729.cpp index a263ceb1f38215d387e0cd0ca435b81f457ebc9c..217b21d6f964c5e1750154fbc41495297b57e03b 100644 --- a/daemon/src/audio/codecs/g729.cpp +++ b/daemon/src/audio/codecs/g729.cpp @@ -28,12 +28,13 @@ * as that of the covered work. */ #include "g729.h" +#include "sfl_types.h" #include <iostream> #include <dlfcn.h> #include <stdexcept> -#define G729_TYPE_ENCODER (void (*)(bcg729EncoderChannelContextStruct*, int16_t[], uint8_t[])) -#define G729_TYPE_DECODER (void (*)(bcg729DecoderChannelContextStruct*, uint8_t[], uint8_t, int16_t[])) +#define G729_TYPE_ENCODER (void (*)(bcg729EncoderChannelContextStruct*, SFLAudioSample[], uint8_t[])) +#define G729_TYPE_DECODER (void (*)(bcg729DecoderChannelContextStruct*, uint8_t[], uint8_t, SFLAudioSample[])) #define G729_TYPE_DECODER_INIT (bcg729DecoderChannelContextStruct*(*)()) #define G729_TYPE_ENCODER_INIT (bcg729EncoderChannelContextStruct*(*)()) @@ -47,22 +48,23 @@ G729::G729() : sfl::AudioCodec(G729_PAYLOAD_TYPE, "G729", 8000, 160, 1), encoder_(0), decoder_(0) { - handler_ = dlopen("libbcg729.so.0", RTLD_NOW); - if (!handler_) - throw std::runtime_error("g729: did not open shared lib"); + handler_ = dlopen("libbcg729.so.0", RTLD_NOW); - encoder_ = G729_TYPE_ENCODER dlsym(handler_, "bcg729Encoder"); - loadError(dlerror()); - decoder_ = G729_TYPE_DECODER dlsym(handler_, "bcg729Decoder"); - loadError(dlerror()); + if (!handler_) + throw std::runtime_error("g729: did not open shared lib"); - bcg729DecoderChannelContextStruct*(*decInit)() = G729_TYPE_DECODER_INIT dlsym(handler_, "initBcg729DecoderChannel"); - loadError(dlerror()); - bcg729EncoderChannelContextStruct*(*encInit)() = G729_TYPE_ENCODER_INIT dlsym(handler_, "initBcg729EncoderChannel"); - loadError(dlerror()); + encoder_ = G729_TYPE_ENCODER dlsym(handler_, "bcg729Encoder"); + loadError(dlerror()); + decoder_ = G729_TYPE_DECODER dlsym(handler_, "bcg729Decoder"); + loadError(dlerror()); - decoderContext_ = (*decInit)(); - encoderContext_ = (*encInit)(); + bcg729DecoderChannelContextStruct*(*decInit)() = G729_TYPE_DECODER_INIT dlsym(handler_, "initBcg729DecoderChannel"); + loadError(dlerror()); + bcg729EncoderChannelContextStruct*(*encInit)() = G729_TYPE_ENCODER_INIT dlsym(handler_, "initBcg729EncoderChannel"); + loadError(dlerror()); + + decoderContext_ = (*decInit)(); + encoderContext_ = (*encInit)(); } G729::~G729() @@ -71,24 +73,24 @@ G729::~G729() dlclose(handler_); } -int G729::decode(short *dst, unsigned char *buf, size_t buffer_size) +int G729::decode(SFLAudioSample *dst, unsigned char *buf, size_t buffer_size) { - decoder_(decoderContext_, buf, false, dst); - decoder_(decoderContext_, buf + (buffer_size / 2), false, dst + 80); - return 160; + decoder_(decoderContext_, buf, false, dst); + decoder_(decoderContext_, buf + (buffer_size / 2), false, dst + 80); + return 160; } -int G729::encode(unsigned char *dst, short *src, size_t buffer_size) +int G729::encode(unsigned char *dst, SFLAudioSample *src, size_t buffer_size) { - encoder_(encoderContext_, src, dst); - encoder_(encoderContext_, src + (buffer_size / 2), dst + 10); - return 20; + encoder_(encoderContext_, src, dst); + encoder_(encoderContext_, src + (buffer_size / 2), dst + 10); + return 20; } void G729::loadError(const char *error) { - if (error != NULL) - throw std::runtime_error("G729 failed to load"); + if (error != NULL) + throw std::runtime_error("G729 failed to load"); } // cppcheck-suppress unusedFunction diff --git a/daemon/src/audio/codecs/g729.h b/daemon/src/audio/codecs/g729.h index 11d83c0d8fe0b03b727732031f6594372b3ff03e..1c2671b7473a7ba6cabdc1d830d84fc836d0f1b5 100644 --- a/daemon/src/audio/codecs/g729.h +++ b/daemon/src/audio/codecs/g729.h @@ -31,6 +31,7 @@ #define G729_H_ #include <cstdlib> +#include "sfl_types.h" #include "noncopyable.h" #include "audiocodec.h" @@ -43,8 +44,8 @@ public: G729(); ~G729(); private: - virtual int decode(short *dst, unsigned char *buf, size_t buffer_size); - virtual int encode(unsigned char *dst, short *src, size_t buffer_size); + virtual int decode(SFLAudioSample *dst, unsigned char *buf, size_t buffer_size); + virtual int encode(unsigned char *dst, SFLAudioSample *src, size_t buffer_size); NON_COPYABLE(G729); //Attributes @@ -53,8 +54,8 @@ private: void* handler_; //Extern functions - void (*encoder_) (bcg729EncoderChannelContextStruct *encoderChannelContext, int16_t inputFrame[], uint8_t bitStream[]); - void (*decoder_) (bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, int16_t signal[]); + void (*encoder_) (bcg729EncoderChannelContextStruct *encoderChannelContext, SFLAudioSample inputFrame[], uint8_t bitStream[]); + void (*decoder_) (bcg729DecoderChannelContextStruct *decoderChannelContext, uint8_t bitStream[], uint8_t frameErasureFlag, SFLAudioSample signal[]); static void loadError(const char *error); }; diff --git a/daemon/src/audio/codecs/gsmcodec.cpp b/daemon/src/audio/codecs/gsmcodec.cpp index b367b156a8f15deb3af1bd550ac7fe7d49a1f59b..9f5735d59ade18d91ab2b611388dafcfc1c1dbe8 100644 --- a/daemon/src/audio/codecs/gsmcodec.cpp +++ b/daemon/src/audio/codecs/gsmcodec.cpp @@ -46,10 +46,10 @@ extern "C" { class Gsm : public sfl::AudioCodec { -public: + public: // _payload should be 3 Gsm() : sfl::AudioCodec(3, "GSM", 8000, 160, 1), - decode_gsmhandle_(NULL), encode_gsmhandle_(NULL) { + decode_gsmhandle_(NULL), encode_gsmhandle_(NULL) { bitrate_ = 13.3; hasDynamicPayload_ = false; @@ -60,13 +60,12 @@ public: throw std::runtime_error("ERROR: encode_gsm_create\n"); } - ~Gsm() - { + ~Gsm() { gsm_destroy(decode_gsmhandle_); gsm_destroy(encode_gsmhandle_); } private: - int decode(SFLDataFormat * dst, unsigned char * src, size_t /*buf_size*/) + int decode(SFLAudioSample * dst, unsigned char * src, size_t /*buf_size*/) { if (gsm_decode(decode_gsmhandle_, (gsm_byte*) src, (gsm_signal*) dst) < 0) throw std::runtime_error("ERROR: gsm_decode\n"); @@ -74,7 +73,7 @@ private: return frameSize_; } - int encode(unsigned char * dst, SFLDataFormat * src, size_t /*buf_size*/) + int encode(unsigned char * dst, SFLAudioSample * src, size_t /*buf_size*/) { gsm_encode(encode_gsmhandle_, (gsm_signal*) src, (gsm_byte*) dst); return sizeof(gsm_frame); diff --git a/daemon/src/audio/codecs/ilbc.cpp b/daemon/src/audio/codecs/ilbc.cpp index c822558eedebcba89671109eb4a10888bf242bfc..1fb5a2835ca40ca35c4b3247bb03c817ad1eede5 100644 --- a/daemon/src/audio/codecs/ilbc.cpp +++ b/daemon/src/audio/codecs/ilbc.cpp @@ -29,6 +29,7 @@ */ #include "audiocodec.h" +#include "sfl_types.h" #include <tr1/array> #include <algorithm> @@ -41,8 +42,7 @@ class Ilbc: public sfl::AudioCodec { Ilbc() : sfl::AudioCodec(ILBC_PAYLOAD, "iLBC", 8000, ILBC_FRAME_SIZE, 1), ilbc_dec_(), - ilbc_enc_() - { + ilbc_enc_() { bitrate_ = 13.3; initDecode(&ilbc_dec_, 20, 1); @@ -51,13 +51,13 @@ class Ilbc: public sfl::AudioCodec { private: // iLBC expects floating point data, so we have to convert - int decode(short *dst, unsigned char *src, size_t /*buf_size*/) { + int decode(SFLAudioSample *dst, unsigned char *src, size_t /*buf_size*/) { const int NORMAL_MODE = 1; iLBC_decode(dst, reinterpret_cast<WebRtc_UWord16*>(src), &ilbc_dec_, NORMAL_MODE); return frameSize_; } - int encode(unsigned char *dst, short* src, size_t /*buf_size*/) { + int encode(unsigned char *dst, SFLAudioSample * src, size_t /*buf_size*/) { iLBC_encode(reinterpret_cast<WebRtc_UWord16*>(dst), src, &ilbc_enc_); return frameSize_; } diff --git a/daemon/src/audio/codecs/opus.cpp b/daemon/src/audio/codecs/opus.cpp index 02b7df3f51e70e3a845e0a869c0199d0af47cbaa..a1583efb9205df18595df1606fdab6a35b108958 100644 --- a/daemon/src/audio/codecs/opus.cpp +++ b/daemon/src/audio/codecs/opus.cpp @@ -1,6 +1,7 @@ /* * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. * Author: Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com> + * Author: Adrien Beraud <adrien.beraud@wisdomvibes.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,45 +29,87 @@ * as that of the covered work. */ #include "opus.h" +#include "sfl_types.h" #include <stdexcept> #include <iostream> -static const int Opus_PAYLOAD_TYPE = 104; // dynamic payload type, out of range of video (96-99) -Opus::Opus() : sfl::AudioCodec(Opus_PAYLOAD_TYPE, "OPUS", CLOCK_RATE, FRAME_SIZE, CHANNELS), +Opus::Opus() : sfl::AudioCodec(PAYLOAD_TYPE, "Opus", CLOCK_RATE, FRAME_SIZE, CHANNELS), encoder_(0), - decoder_(0) + decoder_(0), + interleaved_() { - hasDynamicPayload_ = true; + hasDynamicPayload_ = true; - int err = 0; - encoder_ = opus_encoder_create(CLOCK_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &err); - if (err) - throw std::runtime_error("opus: could not create encoder"); + int err = 0; + encoder_ = opus_encoder_create(CLOCK_RATE, CHANNELS, OPUS_APPLICATION_VOIP, &err); - decoder_ = opus_decoder_create(CLOCK_RATE, CHANNELS, &err); - if (err) - throw std::runtime_error("opus: could not create decoder"); + if (err) + throw std::runtime_error("opus: could not create encoder"); + + decoder_ = opus_decoder_create(CLOCK_RATE, CHANNELS, &err); + + if (err) + throw std::runtime_error("opus: could not create decoder"); } Opus::~Opus() { if (encoder_) opus_encoder_destroy(encoder_); + if (decoder_) opus_decoder_destroy(decoder_); } -int Opus::decode(short *dst, unsigned char *buf, size_t buffer_size) +int Opus::decode(SFLAudioSample *dst, unsigned char *buf, size_t buffer_size) { - return opus_decode(decoder_, buf, buffer_size, dst, FRAME_SIZE, 0); + return opus_decode(decoder_, buf, buffer_size, dst, FRAME_SIZE, 0); } -int Opus::encode(unsigned char *dst, short *src, size_t buffer_size) +int Opus::encode(unsigned char *dst, SFLAudioSample *src, size_t buffer_size) { - return opus_encode(encoder_, src, FRAME_SIZE, dst, buffer_size * 2); + return opus_encode(encoder_, src, FRAME_SIZE, dst, buffer_size * 2); } +int Opus::decode(std::vector<std::vector<SFLAudioSample> > &dst, unsigned char *buf, size_t buffer_size) +{ + if (buf == NULL || dst.size() < 2) return 0; + + interleaved_.resize(4 * FRAME_SIZE); + unsigned samples = opus_decode(decoder_, buf, buffer_size, interleaved_.data(), 2 * FRAME_SIZE, 0); + + std::vector<SFLAudioSample>::iterator left_it = dst.at(0).begin(); + std::vector<SFLAudioSample>::iterator right_it = dst.at(1).begin(); + std::vector<opus_int16>::iterator it = interleaved_.begin(); + + // hard-coded 2-channels as it is the stereo version + for (unsigned i = 0; i < samples; i++) { + *left_it++ = *it++; + *right_it++ = *it++; + } + + return samples; +} + +int Opus::encode(unsigned char *dst, std::vector<std::vector<SFLAudioSample> > &src, size_t buffer_size) +{ + if (dst == NULL or src.size() < 2) return 0; + + const unsigned samples = src.at(0).size(); + interleaved_.resize(2 * samples); + std::vector<opus_int16>::iterator it = interleaved_.begin(); + + // hard-coded 2-channels as it is the stereo version + for (unsigned i = 0; i < samples; i++) { + *it++ = src.at(0)[i]; + *it++ = src.at(1)[i]; + } + + return opus_encode(encoder_, interleaved_.data(), FRAME_SIZE, dst, buffer_size * 2); +} + + // cppcheck-suppress unusedFunction extern "C" sfl::AudioCodec* AUDIO_CODEC_ENTRY() { diff --git a/daemon/src/audio/codecs/opus.h b/daemon/src/audio/codecs/opus.h index 160abc2fed491aad944405fee65eef3c8f6b8168..f1b5181c1d8fcc2667980ebd628169a49028d5a4 100644 --- a/daemon/src/audio/codecs/opus.h +++ b/daemon/src/audio/codecs/opus.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. * Author: Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com> + * Author: Adrien Beraud <adrien.beraud@wisdomvibes.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +32,7 @@ #define OPUS_H_ #include "noncopyable.h" +#include "sfl_types.h" #include "audiocodec.h" @@ -40,17 +42,26 @@ class Opus : public sfl::AudioCodec { public: Opus(); ~Opus(); + + static const uint8_t PAYLOAD_TYPE = 104; // dynamic payload type, out of range of video (96-99) + private: - virtual int decode(short *dst, unsigned char *buf, size_t buffer_size); - virtual int encode(unsigned char *dst, short *src, size_t buffer_size); + virtual int decode(SFLAudioSample *dst, unsigned char *buf, size_t buffer_size); + virtual int encode(unsigned char *dst, SFLAudioSample *src, size_t buffer_size); + + //multichannel version + virtual int decode(std::vector<std::vector<SFLAudioSample> > &dst, unsigned char *buf, size_t buffer_size); + virtual int encode(unsigned char *dst, std::vector<std::vector<SFLAudioSample> > &src, size_t buffer_size); NON_COPYABLE(Opus); //Attributes OpusEncoder *encoder_; OpusDecoder *decoder_; + std::vector<opus_int16> interleaved_; + static const int FRAME_SIZE = 160; static const int CLOCK_RATE = 16000; - static const int CHANNELS = 1; + static const int CHANNELS = 2; }; #endif diff --git a/daemon/src/audio/codecs/speexcodec.h b/daemon/src/audio/codecs/speexcodec.h index 20b1b66a04ab969a3eadfb23def98f1d1d7c99f4..adb38bde309fb2418fa6a3a21f8cf8531355a33d 100644 --- a/daemon/src/audio/codecs/speexcodec.h +++ b/daemon/src/audio/codecs/speexcodec.h @@ -30,6 +30,7 @@ */ #include "global.h" +#include "sfl_types.h" #include "audiocodec.h" #include "noncopyable.h" #include "array_size.h" @@ -83,13 +84,13 @@ private: NON_COPYABLE(Speex); - virtual int decode(short *dst, unsigned char *src, size_t buf_size) { + virtual int decode(SFLAudioSample *dst, unsigned char *src, size_t buf_size) { speex_bits_read_from(&speex_dec_bits_, (char*) src, buf_size); speex_decode_int(speex_dec_state_, &speex_dec_bits_, dst); return frameSize_; } - virtual int encode(unsigned char *dst, short *src, size_t buf_size) { + virtual int encode(unsigned char *dst, SFLAudioSample *src, size_t buf_size) { speex_bits_reset(&speex_enc_bits_); speex_encode_int(speex_enc_state_, src, &speex_enc_bits_); return speex_bits_write(&speex_enc_bits_, (char*) dst, buf_size); diff --git a/daemon/src/audio/codecs/ulaw.cpp b/daemon/src/audio/codecs/ulaw.cpp index 7a2a96b6c966288bf44123d07ab072cacdd4aba5..b0a152c11377f7bdeaefaeb21e15cc8c494b2599 100644 --- a/daemon/src/audio/codecs/ulaw.cpp +++ b/daemon/src/audio/codecs/ulaw.cpp @@ -41,28 +41,27 @@ class Ulaw : public sfl::AudioCodec { } private: - int decode(SFLDataFormat *dst, unsigned char *src, size_t buf_size) { + int decode(SFLAudioSample *dst, unsigned char *src, size_t buf_size) { for (unsigned char* end = src + buf_size; src < end; ++src, ++dst) *dst = ULawDecode(*src); return buf_size; } - int encode(unsigned char *dst, SFLDataFormat *src, size_t buf_size) { + int encode(unsigned char *dst, SFLAudioSample *src, size_t buf_size) { for (unsigned char * end = dst + buf_size; dst < end; ++src, ++dst) *dst = ULawEncode(*src); return buf_size; } - SFLDataFormat ULawDecode(uint8 ulaw) - { + SFLAudioSample ULawDecode(uint8_t ulaw) { ulaw ^= 0xff; // u-law has all bits inverted for transmission int linear = ulaw & 0x0f; linear <<= 3; linear |= 0x84; // Set MSB (0x80) and a 'half' bit (0x04) to place PCM value in middle of range - uint shift = ulaw >> 4; + uint8_t shift = ulaw >> 4; shift &= 7; linear <<= shift; linear -= 0x84; // Subract uLaw bias @@ -73,10 +72,9 @@ class Ulaw : public sfl::AudioCodec { return linear; } - uint8 ULawEncode(SFLDataFormat pcm16) - { + uint8_t ULawEncode(SFLAudioSample pcm16) { int p = pcm16; - uint u; // u-law value we are forming + uint8_t u; // u-law value we are forming if (p < 0) { p = ~p; diff --git a/daemon/src/audio/dcblocker.cpp b/daemon/src/audio/dcblocker.cpp index 0acbb63bc6ca17903ab3f6a8e39d03706496f8da..92e631ba532394a370146c098f6cc170a78708ef 100644 --- a/daemon/src/audio/dcblocker.cpp +++ b/daemon/src/audio/dcblocker.cpp @@ -30,27 +30,46 @@ #include "dcblocker.h" -DcBlocker::DcBlocker() : y_(0), x_(0), xm1_(0), ym1_(0) +DcBlocker::DcBlocker(unsigned channels /* = 1 */) + : states(channels, (struct StreamState){0, 0, 0, 0}) {} void DcBlocker::reset() { - y_ = 0; - x_ = 0; - xm1_ = 0; - ym1_ = 0; + states.assign(states.size(), (struct StreamState){0, 0, 0, 0}); } -void DcBlocker::process(SFLDataFormat *out, SFLDataFormat *in, int samples) +void DcBlocker::doProcess(SFLAudioSample *out, SFLAudioSample *in, unsigned samples, struct StreamState * state) { - for (int i = 0; i < samples; ++i) { - x_ = in[i]; + for (unsigned i = 0; i < samples; ++i) { + state->x_ = in[i]; - y_ = (SFLDataFormat) ((float) x_ - (float) xm1_ + 0.9999 * (float) y_); - xm1_ = x_; - ym1_ = y_; - out[i] = y_; + state->y_ = (SFLAudioSample) ((float) state->x_ - (float) state->xm1_ + 0.9999 * (float) state->y_); + state->xm1_ = state->x_; + state->ym1_ = state->y_; + + out[i] = state->y_; + } +} + +void DcBlocker::process(SFLAudioSample *out, SFLAudioSample *in, int samples) +{ + if(out == NULL or in == NULL or samples == 0) return; + doProcess(out, in, samples, &states[0]); +} + +void DcBlocker::process(AudioBuffer& buf) +{ + const size_t chans = buf.channels(); + const size_t samples = buf.samples(); + if(chans > states.size()) + states.resize(buf.channels(), (struct StreamState){0, 0, 0, 0}); + + unsigned i; + for(i=0; i<chans; i++) { + SFLAudioSample *chan = buf.getChannel(i)->data(); + doProcess(chan, chan, samples, &states[i]); } } diff --git a/daemon/src/audio/dcblocker.h b/daemon/src/audio/dcblocker.h index fd5674e82271f2db2d66dc1df06147292145eea9..878b6855a23d92784c412c4172419169177a9102 100644 --- a/daemon/src/audio/dcblocker.h +++ b/daemon/src/audio/dcblocker.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author: Adrien Beraud <adrien.beraud@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,16 +33,28 @@ #define DCBLOCKER_H #include "sfl_types.h" +#include "audiobuffer.h" class DcBlocker { public: - DcBlocker(); + DcBlocker(unsigned channels = 1); void reset(); - void process(SFLDataFormat *out, SFLDataFormat *in, int samples); + + void process(SFLAudioSample *out, SFLAudioSample *in, int samples); + + /** + * In-place processing of all samples in buf (each channel treated independently) + */ + void process(AudioBuffer& buf); private: + struct StreamState { + SFLAudioSample y_, x_, xm1_, ym1_; + }; + + void doProcess(SFLAudioSample *out, SFLAudioSample *in, unsigned samples, struct StreamState * state); - SFLDataFormat y_, x_, xm1_, ym1_; + std::vector<StreamState> states; }; #endif diff --git a/daemon/src/audio/delaydetection.cpp b/daemon/src/audio/delaydetection.cpp index 46bbdce131f7d623d90973c0ac84a21a8c3b312a..7dd8c56fc9330582d914cd9d434cd30a102f85ff 100644 --- a/daemon/src/audio/delaydetection.cpp +++ b/daemon/src/audio/delaydetection.cpp @@ -38,26 +38,26 @@ namespace { // decimation filter coefficient const float decimationCoefs[] = {-0.09870257, 0.07473655, 0.05616626, 0.04448337, 0.03630817, 0.02944626, - 0.02244098, 0.01463477, 0.00610982, -0.00266367, -0.01120109, -0.01873722, - -0.02373243, -0.02602213, -0.02437806, -0.01869834, -0.00875287, 0.00500204, - 0.02183252, 0.04065763, 0.06015944, 0.0788299, 0.09518543, 0.10799179, - 0.1160644, 0.12889288, 0.1160644, 0.10799179, 0.09518543, 0.0788299, - 0.06015944, 0.04065763, 0.02183252, 0.00500204, -0.00875287, -0.01869834, - -0.02437806, -0.02602213, -0.02373243, -0.01873722, -0.01120109, -0.00266367, - 0.00610982, 0.01463477, 0.02244098, 0.02944626, 0.03630817, 0.04448337, - 0.05616626, 0.07473655, -0.09870257 - }; + 0.02244098, 0.01463477, 0.00610982, -0.00266367, -0.01120109, -0.01873722, + -0.02373243, -0.02602213, -0.02437806, -0.01869834, -0.00875287, 0.00500204, + 0.02183252, 0.04065763, 0.06015944, 0.0788299, 0.09518543, 0.10799179, + 0.1160644, 0.12889288, 0.1160644, 0.10799179, 0.09518543, 0.0788299, + 0.06015944, 0.04065763, 0.02183252, 0.00500204, -0.00875287, -0.01869834, + -0.02437806, -0.02602213, -0.02373243, -0.01873722, -0.01120109, -0.00266367, + 0.00610982, 0.01463477, 0.02244098, 0.02944626, 0.03630817, 0.04448337, + 0.05616626, 0.07473655, -0.09870257 + }; std::vector<double> ird(decimationCoefs, decimationCoefs + sizeof(decimationCoefs) /sizeof(float)); // decimation filter coefficient const float bandpassCoefs[] = {0.06278034, -0.0758545, -0.02274943, -0.0084497, 0.0702427, 0.05986113, - 0.06436469, -0.02412049, -0.03433526, -0.07568665, -0.03214543, -0.07236507, - -0.06979052, -0.12446371, -0.05530828, 0.00947243, 0.15294699, 0.17735563, - 0.15294699, 0.00947243, -0.05530828, -0.12446371, -0.06979052, -0.07236507, - -0.03214543, -0.07568665, -0.03433526, -0.02412049, 0.06436469, 0.05986113, - 0.0702427, -0.0084497, -0.02274943, -0.0758545, 0.06278034 - }; + 0.06436469, -0.02412049, -0.03433526, -0.07568665, -0.03214543, -0.07236507, + -0.06979052, -0.12446371, -0.05530828, 0.00947243, 0.15294699, 0.17735563, + 0.15294699, 0.00947243, -0.05530828, -0.12446371, -0.06979052, -0.07236507, + -0.03214543, -0.07568665, -0.03433526, -0.02412049, 0.06436469, 0.05986113, + 0.0702427, -0.0084497, -0.02274943, -0.0758545, 0.06278034 + }; std::vector<double> irb(bandpassCoefs, bandpassCoefs + sizeof(bandpassCoefs) / sizeof(float)); } // end anonymous namespace @@ -116,7 +116,7 @@ DelayDetection::DelayDetection() : } -void DelayDetection::putData(SFLDataFormat *inputData, int nbSamples) +void DelayDetection::putData(SFLAudioSample *inputData, int nbSamples) { // Machine may already got a spkr and is waiting for mic or computing correlation if (nbSpkrSampleStored_ == WINDOW_SIZE) @@ -144,7 +144,7 @@ void DelayDetection::putData(SFLDataFormat *inputData, int nbSamples) internalState_ = WaitForMic; } -void DelayDetection::process(SFLDataFormat *inputData, int nbSamples) +void DelayDetection::process(SFLAudioSample *inputData, int nbSamples) { if (internalState_ != WaitForMic) @@ -233,7 +233,7 @@ double DelayDetection::correlate(float *sig1, float *sig2, short size) } -void DelayDetection::convertInt16ToFloat32(SFLDataFormat *input, float *output, int nbSamples) +void DelayDetection::convertInt16ToFloat32(SFLAudioSample *input, float *output, int nbSamples) { static const float S2F_FACTOR = .000030517578125f; int len = nbSamples; diff --git a/daemon/src/audio/delaydetection.h b/daemon/src/audio/delaydetection.h index 47f4a5c9961226c91e4942ccb6a195b22fa325b4..d82fd97f68d74efadf703bf3f8472ce89ea8dd15 100644 --- a/daemon/src/audio/delaydetection.h +++ b/daemon/src/audio/delaydetection.h @@ -84,9 +84,9 @@ class DelayDetection { ~DelayDetection(); - void putData(SFLDataFormat *inputData, int samples); + void putData(SFLAudioSample *inputData, int samples); - void process(SFLDataFormat *inputData, int samples); + void process(SFLAudioSample *inputData, int samples); private: @@ -107,7 +107,7 @@ class DelayDetection { */ double correlate(float *sig1, float *sig2, short size); - void convertInt16ToFloat32(SFLDataFormat *input, float *ouput, int nbSamples); + void convertInt16ToFloat32(SFLAudioSample *input, float *ouput, int nbSamples); void downsampleData(float *input, float *output, int nbSamples, int factor); diff --git a/daemon/src/audio/gaincontrol.cpp b/daemon/src/audio/gaincontrol.cpp index 7ae0c03461a15107aa076e2eeba956ca682c70d4..8e8bc07b2954049b3b269a766d762e8821282abe 100644 --- a/daemon/src/audio/gaincontrol.cpp +++ b/daemon/src/audio/gaincontrol.cpp @@ -56,7 +56,12 @@ GainControl::GainControl(double sr, double target) : averager_(sr, SFL_GAIN_ATTA DEBUG("Target gain %f dB (%f linear)", targetLeveldB_, targetLevelLinear_); } -void GainControl::process(SFLDataFormat *buf, int samples) +void GainControl::process(AudioBuffer& buf) +{ + process(buf.getChannel(0)->data(), buf.samples()); +} + +void GainControl::process(SFLAudioSample *buf, int samples) { double rms, rmsAvgLevel, in, out, diffRms, maxRms; @@ -64,7 +69,7 @@ void GainControl::process(SFLDataFormat *buf, int samples) for (int i = 0; i < samples; i++) { // linear conversion - in = (double)buf[i] / (double)SHRT_MAX; + in = (double) buf[i] / (double) SFL_DATA_FORMAT_MAX; out = currentGain_ * in; @@ -76,7 +81,7 @@ void GainControl::process(SFLDataFormat *buf, int samples) out = limiter_.limit(out); - buf[i] = (short)(out * (double)SHRT_MAX); + buf[i] = (SFLAudioSample) (out * (double) SFL_DATA_FORMAT_MAX); } diffRms = maxRms - targetLevelLinear_; @@ -106,6 +111,7 @@ double GainControl::DetectionAverage::getAverage(double in) previous_y_ = ((1.0 - g_a_) * in) + (g_a_ * previous_y_); else previous_y_ = ((1.0 - g_r_) * in) + (g_r_ * previous_y_); + return previous_y_; } @@ -115,7 +121,7 @@ GainControl::Limiter::Limiter(double r, double thresh) : ratio_(r), threshold_(t double GainControl::Limiter::limit(double in) const { double out = (in > threshold_ ? (ratio_ * (in - threshold_)) + threshold_ : - in < -threshold_ ? (ratio_ * (in + threshold_)) - threshold_ : in); + in < -threshold_ ? (ratio_ * (in + threshold_)) - threshold_ : in); return out; } diff --git a/daemon/src/audio/gaincontrol.h b/daemon/src/audio/gaincontrol.h index 4c36953a76c742f5cc7fdd52a01fc5160fbbdc62..2187c17f195231d7be27ce98ed15f7cd956e64f4 100644 --- a/daemon/src/audio/gaincontrol.h +++ b/daemon/src/audio/gaincontrol.h @@ -32,6 +32,7 @@ #define GAINCONTROL_H #include "global.h" +#include "audiobuffer.h" class GainControl { @@ -48,7 +49,8 @@ class GainControl { * /param Input audio buffer * /param Input samples */ - void process(SFLDataFormat *, int samples); + void process(SFLAudioSample *, int samples); + void process(AudioBuffer& buf); private: class DetectionAverage { diff --git a/daemon/src/audio/mainbuffer.cpp b/daemon/src/audio/mainbuffer.cpp index f98abd11de85717466123f363aa1b2bd6850b091..61d3f73ff8fe1c39da5711154ae5356545aeb1ef 100644 --- a/daemon/src/audio/mainbuffer.cpp +++ b/daemon/src/audio/mainbuffer.cpp @@ -47,8 +47,9 @@ MainBuffer::MainBuffer() : ringBufferMap_(), callIDMap_(), mutex_(), internalSam MainBuffer::~MainBuffer() { // delete any ring buffers that didn't get removed - for (RingBufferMap::iterator iter = ringBufferMap_.begin(); iter != ringBufferMap_.end(); ++iter) - delete iter->second; + for (auto &item : ringBufferMap_) + delete item.second; + pthread_mutex_destroy(&mutex_); } @@ -88,6 +89,7 @@ void MainBuffer::removeCallIDSet(const std::string &set_id) void MainBuffer::addCallIDtoSet(const std::string &set_id, const std::string &call_id) { CallIDSet* callid_set = getCallIDSet(set_id); + if (callid_set) callid_set->insert(call_id); else @@ -228,24 +230,23 @@ void MainBuffer::unBindAll(const std::string & call_id) CallIDSet temp_set(*callid_set); - for (CallIDSet::iterator iter_set = temp_set.begin(); - iter_set != temp_set.end(); ++iter_set) { - std::string call_id_in_set(*iter_set); - unBindCallID(call_id, call_id_in_set); - } + for (const auto &item_set : temp_set) + unBindCallID(call_id, item_set); } -void MainBuffer::putData(void *buffer, size_t toCopy, const std::string &call_id) +//void MainBuffer::putData(void *buffer, size_t toCopy, const std::string &call_id) +void MainBuffer::putData(AudioBuffer& buffer, const std::string &call_id) { sfl::ScopedLock guard(mutex_); RingBuffer* ring_buffer = getRingBuffer(call_id); if (ring_buffer) - ring_buffer->put(buffer, toCopy); + ring_buffer->put(buffer); } -size_t MainBuffer::getData(void *buffer, size_t toCopy, const std::string &call_id) +//size_t MainBuffer::getData(void *buffer, size_t toCopy, const std::string &call_id) +size_t MainBuffer::getData(AudioBuffer& buffer, const std::string &call_id) { sfl::ScopedLock guard(mutex_); @@ -259,25 +260,21 @@ size_t MainBuffer::getData(void *buffer, size_t toCopy, const std::string &call_ CallIDSet::iterator iter_id = callid_set->begin(); if (iter_id != callid_set->end()) - return getDataByID(buffer, toCopy, *iter_id, call_id); + return getDataByID(buffer, *iter_id, call_id); //return getDataByID(buffer, toCopy, *iter_id, call_id); else return 0; } else { - memset(buffer, 0, toCopy); + buffer.reset(); + buffer.setSampleRate(internalSamplingRate_); size_t size = 0; + AudioBuffer mixBuffer(buffer); - for (CallIDSet::iterator iter_id = callid_set->begin(); - iter_id != callid_set->end(); ++iter_id) { - size_t nbSmplToCopy = toCopy / sizeof(SFLDataFormat); - SFLDataFormat mixBuffer[nbSmplToCopy]; - memset(mixBuffer, 0, toCopy); - size = getDataByID(mixBuffer, toCopy, *iter_id, call_id); + for (const auto &item_id : *callid_set) { + size = getDataByID(mixBuffer, item_id, call_id); if (size > 0) { - SFLDataFormat *dest = static_cast<SFLDataFormat*>(buffer); - for (size_t k = 0; k < nbSmplToCopy; ++k) - dest[k] += mixBuffer[k]; + buffer.mix(mixBuffer); } } @@ -285,12 +282,18 @@ size_t MainBuffer::getData(void *buffer, size_t toCopy, const std::string &call_ } } -size_t MainBuffer::getDataByID(void *buffer, size_t toCopy, const std::string & call_id, const std::string & reader_id) +size_t MainBuffer::getDataByID(AudioBuffer& buffer, const std::string & call_id, const std::string & reader_id) { RingBuffer* ring_buffer = getRingBuffer(call_id); - return ring_buffer ? ring_buffer->get(buffer, toCopy, reader_id) : 0; + return ring_buffer ? ring_buffer->get(buffer, reader_id) : 0; } +/*size_t MainBuffer::getDataByID(void *buffer, size_t toCopy, const std::string & call_id, const std::string & reader_id) +{ + RingBuffer* ring_buffer = getRingBuffer(call_id); + return ring_buffer ? ring_buffer->get(buffer, toCopy, reader_id) : 0; +}*/ + size_t MainBuffer::availableForGet(const std::string &call_id) { sfl::ScopedLock guard(mutex_); @@ -310,20 +313,21 @@ size_t MainBuffer::availableForGet(const std::string &call_id) } else { - size_t availableBytes = INT_MAX; - for (CallIDSet::iterator i = callid_set->begin(); i != callid_set->end(); ++i) { - const size_t nbBytes = availableForGetByID(*i, call_id); + size_t availableSamples = INT_MAX; + + for (auto &i : *callid_set) { + const size_t nbSamples = availableForGetByID(i, call_id); - if (nbBytes != 0) - availableBytes = std::min(availableBytes, nbBytes); + if (nbSamples != 0) + availableSamples = std::min(availableSamples, nbSamples); } - return availableBytes != INT_MAX ? availableBytes : 0; + return availableSamples != INT_MAX ? availableSamples : 0; } } size_t MainBuffer::availableForGetByID(const std::string &call_id, - const std::string &reader_id) const + const std::string &reader_id) const { if (call_id != DEFAULT_ID and reader_id == call_id) ERROR("RingBuffer has a readpointer on itself"); @@ -347,8 +351,8 @@ size_t MainBuffer::discard(size_t toDiscard, const std::string &call_id) if (!callid_set or callid_set->empty()) return 0; - for (CallIDSet::iterator iter = callid_set->begin(); iter != callid_set->end(); ++iter) - discardByID(toDiscard, *iter, call_id); + for (auto &item : *callid_set) + discardByID(toDiscard, item, call_id); return toDiscard; } @@ -370,9 +374,8 @@ void MainBuffer::flush(const std::string & call_id) if (callid_set == NULL) return; - for (CallIDSet::iterator iter = callid_set->begin(); iter != callid_set->end(); ++iter) - flushByID(*iter, call_id); - + for (auto &item : *callid_set) + flushByID(item, call_id); } void MainBuffer::flushByID(const std::string & call_id, const std::string & reader_id) @@ -386,23 +389,24 @@ void MainBuffer::flushByID(const std::string & call_id, const std::string & read void MainBuffer::flushAllBuffers() { - for (RingBufferMap::iterator iter = ringBufferMap_.begin(); iter != ringBufferMap_.end(); ++iter) - iter->second->flushAll(); + for (auto &item : ringBufferMap_) + item.second->flushAll(); } void MainBuffer::dumpInfo() { sfl::ScopedLock guard(mutex_); + // print each call and bound call ids - for (CallIDMap::const_iterator iter_call = callIDMap_.begin(); iter_call != callIDMap_.end(); ++iter_call) { + for (const auto &item_call : callIDMap_) { std::string dbg_str(" Call: \t"); - dbg_str.append(iter_call->first); + dbg_str.append(item_call.first); dbg_str.append(" is bound to: \t"); - CallIDSet *call_id_set = iter_call->second; + CallIDSet *call_id_set = item_call.second; - for (CallIDSet::iterator iter = call_id_set->begin(); iter != call_id_set->end(); ++iter) { - dbg_str.append(*iter); + for (const auto &item : *call_id_set) { + dbg_str.append(item); dbg_str.append(", "); } @@ -410,23 +414,25 @@ void MainBuffer::dumpInfo() } // Print ringbuffers ids and readpointers - for (RingBufferMap::const_iterator iter_buffer = ringBufferMap_.begin(); iter_buffer != ringBufferMap_.end(); ++iter_buffer) { + for (const auto &item_buffer : ringBufferMap_) { std::string dbg_str(" Buffer: \t"); - dbg_str.append(iter_buffer->first); + dbg_str.append(item_buffer.first); dbg_str.append(" as read pointer: \t"); - RingBuffer* rbuffer = iter_buffer->second; + RingBuffer* rbuffer = item_buffer.second; + if (rbuffer) { ReadPointer* rpointer = rbuffer->getReadPointerList(); if (rpointer) { - for (ReadPointer::iterator iter = rpointer->begin(); iter != rpointer->end(); ++iter) { - dbg_str.append(iter->first); + for (const auto &item : *rpointer) { + dbg_str.append(item.first); dbg_str.append(", "); } } } + DEBUG("%s", dbg_str.c_str()); } } diff --git a/daemon/src/audio/mainbuffer.h b/daemon/src/audio/mainbuffer.h index 17e137b7314e345412337cc57ec47cb82ed3f97e..da03075e1d5870ff5ef26abcbded15fda9a69762 100644 --- a/daemon/src/audio/mainbuffer.h +++ b/daemon/src/audio/mainbuffer.h @@ -36,6 +36,8 @@ #include <string> #include <pthread.h> +#include "audiobuffer.h" + class RingBuffer; typedef std::set<std::string> CallIDSet; @@ -80,9 +82,11 @@ class MainBuffer { void unBindAll(const std::string &call_id); - void putData(void *buffer, size_t toCopy, const std::string &call_id); + //void putData(void *buffer, size_t toCopy, const std::string &call_id); + void putData(AudioBuffer& buffer, const std::string &call_id); - size_t getData(void *buffer, size_t toCopy, const std::string &call_id); + //size_t getData(void *buffer, size_t toCopy, const std::string &call_id); + size_t getData(AudioBuffer& buffer, const std::string &call_id); size_t availableForGet(const std::string &call_id); @@ -119,7 +123,8 @@ class MainBuffer { RingBuffer* getRingBuffer(const std::string &call_id); const RingBuffer* getRingBuffer(const std::string & call_id) const; - size_t getDataByID(void *buffer, size_t toCopy, const std::string &call_id, const std::string &reader_id); + //size_t getDataByID(void *buffer, size_t toCopy, const std::string &call_id, const std::string &reader_id); + size_t getDataByID(AudioBuffer& buffer, const std::string &call_id, const std::string &reader_id); size_t availableForGetByID(const std::string &call_id, const std::string &reader_id) const; diff --git a/daemon/src/audio/noisesuppress.cpp b/daemon/src/audio/noisesuppress.cpp index 96092f5fa31fe02fb0c0b1d5e246201c948f3881..961cb88215d841775f51cb44be8d02bb24471afd 100644 --- a/daemon/src/audio/noisesuppress.cpp +++ b/daemon/src/audio/noisesuppress.cpp @@ -62,8 +62,9 @@ NoiseSuppress::~NoiseSuppress() noiseState_ = 0; } -void NoiseSuppress::process(SFLDataFormat *data, int samples) +void NoiseSuppress::process(AudioBuffer& buff, int samples) { + SFLAudioSample* data = buff.getChannel(0)->data(); if (noiseState_) { assert(smplPerFrame_ == samples); speex_preprocess_run(noiseState_, data); diff --git a/daemon/src/audio/noisesuppress.h b/daemon/src/audio/noisesuppress.h index 86a4f7822e09b72a85bda03a806cf5c5be82d0bf..afc56a20eb578caeb82ea05e4b13d99b61ee79a4 100644 --- a/daemon/src/audio/noisesuppress.h +++ b/daemon/src/audio/noisesuppress.h @@ -32,14 +32,15 @@ #define NOISESUPPRESS_H #include <speex/speex_preprocess.h> -#include "sfl_types.h" #include "noncopyable.h" +#include "audiobuffer.h" class NoiseSuppress { public: NoiseSuppress(int smplPerFrame, int samplingRate); ~NoiseSuppress(); - void process(SFLDataFormat *data, int samples); + //void process(SFLAudioSample *data, int samples); + void process(AudioBuffer& buf, int samples); private: NON_COPYABLE(NoiseSuppress); diff --git a/daemon/src/audio/opensl/opensllayer.cpp b/daemon/src/audio/opensl/opensllayer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..76212e7e21a7ebe41cffbaebff4feb46a8fbc414 --- /dev/null +++ b/daemon/src/audio/opensl/opensllayer.cpp @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include <cstdio> +#include <cassert> + +#include "logger.h" +#include "array_size.h" +#include "manager.h" +#include "mainbuffer.h" + +#include "opensllayer.h" + +const int OpenSLLayer::NB_BUFFER_PLAYBACK_QUEUE = ANDROID_BUFFER_QUEUE_LENGTH; +const int OpenSLLayer::NB_BUFFER_CAPTURE_QUEUE = ANDROID_BUFFER_QUEUE_LENGTH; + +static long sawPtr = 0; +static void generateSawTooth(short *buffer, int length) +{ + assert(NULL != buffer); + assert(length > 0); + + unsigned int i; + + for (i = 0; i < length; ++i, ++sawPtr) { + buffer[i] = 32768 - ((sawPtr % 10) * 6600); + } +} + +class OpenSLThread { + public: + OpenSLThread(OpenSLLayer *opensl); + ~OpenSLThread(); + void initAudioLayer(); + void start(); + bool isRunning() const; + + private: + void run(); + static void *runCallback(void *context); + + NON_COPYABLE(OpenSLThread); + pthread_t thread_; + OpenSLLayer* opensl_; + bool running_; +}; + +OpenSLThread::OpenSLThread(OpenSLLayer *opensl) + : thread_(0), opensl_(opensl), running_(false) +{} + +OpenSLThread::~OpenSLThread() +{ + running_ = false; + opensl_->shutdownAudioEngine(); + + if (thread_) + pthread_join(thread_, NULL); +} + +void +OpenSLThread::start() +{ + running_ = true; + pthread_create(&thread_, NULL, &runCallback, this); +} + +void * +OpenSLThread::runCallback(void *data) +{ + OpenSLThread *context = static_cast<OpenSLThread*>(data); + context->run(); + return NULL; +} + +bool +OpenSLThread::isRunning() const +{ + return running_; +} + +void +OpenSLThread::initAudioLayer() +{ + opensl_->initAudioEngine(); + opensl_->initAudioPlayback(); + opensl_->initAudioCapture(); +} + +/** + * Reimplementation of run() + */ +void +OpenSLThread::run() +{ + initAudioLayer(); + + opensl_->startAudioPlayback(); + opensl_->startAudioCapture(); + + while (opensl_->isStarted_) + usleep(20000); // 20 ms +} + +// Constructor +OpenSLLayer::OpenSLLayer() + : indexIn_(0) + , indexOut_(0) + , indexRing_(0) + , audioThread_(0) + , isStarted_(false) + , engineObject_(0) + , engineInterface_(0) + , outputMixer_(0) + , playerObject_(0) + , recorderObject_(0) + , playerInterface_(0) + , recorderInterface_(0) + , playbackBufferQueue_(0) + , recorderBufferQueue_(0) + , playbackBufferIndex_(0) + , recordBufferIndex_(0) + , playbackBufferStack_(ANDROID_BUFFER_QUEUE_LENGTH) + , recordBufferStack_(ANDROID_BUFFER_QUEUE_LENGTH) +{ +} + +// Destructor +OpenSLLayer::~OpenSLLayer() +{ + stopStream(); +} + +//#define RECORD_AUDIO_TODISK +#ifdef RECORD_AUDIO_TODISK +#include <fstream> +std::ofstream opensl_outfile; +std::ofstream opensl_infile; +#endif + +void +OpenSLLayer::startStream() +{ + if (isStarted_) + return; + + DEBUG("Start OpenSL audio layer"); + + if (audioThread_ == NULL) { +#ifdef RECORD_AUDIO_TODISK + opensl_outfile.open("/data/data/com.savoirfairelinux.sflphone/opensl_playback.raw", std::ofstream::out | std::ofstream::binary); + opensl_infile.open("/data/data/com.savoirfairelinux.sflphone/opensl_record.raw", std::ofstream::out | std::ofstream::binary); +#endif + + audioThread_ = new OpenSLThread(this); + isStarted_ = true; + audioThread_->start(); + } + +} + +void +OpenSLLayer::stopStream() +{ + if (not isStarted_) + return; + + DEBUG("Stop OpenSL audio layer"); + + stopAudioPlayback(); + stopAudioCapture(); + + isStarted_ = false; + + delete audioThread_; + audioThread_ = NULL; +#ifdef RECORD_AUDIO_TODISK + opensl_outfile.close(); + opensl_infile.close(); +#endif +} + +void +OpenSLLayer::initAudioEngine() +{ + SLresult result; + + DEBUG("Create Audio Engine\n"); + result = slCreateEngine(&engineObject_, 0, NULL, 0, NULL, NULL); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Realize Audio Engine\n"); + result = (*engineObject_)->Realize(engineObject_, SL_BOOLEAN_FALSE); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Create Audio Engine Interface\n"); + result = (*engineObject_)->GetInterface(engineObject_, SL_IID_ENGINE, &engineInterface_); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Create Output Mixer\n"); + result = (*engineInterface_)->CreateOutputMix(engineInterface_, &outputMixer_, 0, NULL, NULL); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Realize Output Mixer\n"); + result = (*outputMixer_)->Realize(outputMixer_, SL_BOOLEAN_FALSE); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Audio Engine Initialization Done\n"); +} + +void +OpenSLLayer::shutdownAudioEngine() +{ + + // destroy buffer queue audio player object, and invalidate all associated interfaces + DEBUG("Shutdown audio player\n"); + + if (playerObject_ != NULL) { + (*playerObject_)->Destroy(playerObject_); + playerObject_ = NULL; + playerInterface_ = NULL; + playbackBufferQueue_ = NULL; + } + + // destroy output mix object, and invalidate all associated interfaces + DEBUG("Shutdown audio mixer\n"); + + if (outputMixer_ != NULL) { + (*outputMixer_)->Destroy(outputMixer_); + outputMixer_ = NULL; + } + + // destroy engine object, and invalidate all associated interfaces + DEBUG("Shutdown audio engine\n"); + + if (engineObject_ != NULL) { + (*engineObject_)->Destroy(engineObject_); + engineObject_ = NULL; + engineInterface_ = NULL; + } +} + +void +OpenSLLayer::initAudioPlayback() +{ + assert(NULL != engineObject_); + assert(NULL != engineInterface_); + assert(NULL != outputMixer_); + + SLresult result; + + // Initialize the location of the buffer queue + DEBUG("Create playback queue\n"); + SLDataLocator_AndroidSimpleBufferQueue bufferLocation = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, + NB_BUFFER_PLAYBACK_QUEUE + }; + + // Initnialize the audio format for this queue + DEBUG("Setting audio format\n"); + SLDataFormat_PCM audioFormat = {SL_DATAFORMAT_PCM, 1, + SL_SAMPLINGRATE_8, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_SPEAKER_FRONT_CENTER, + SL_BYTEORDER_LITTLEENDIAN + }; + + // Create the audio source + DEBUG("Set Audio Sources\n"); + SLDataSource audioSource = {&bufferLocation, &audioFormat}; + + // Cofiguration fo the audio sink as an output mixer + DEBUG("Set output mixer location\n"); + SLDataLocator_OutputMix mixerLocation = {SL_DATALOCATOR_OUTPUTMIX, outputMixer_}; + SLDataSink audioSink = {&mixerLocation, NULL}; + + const SLInterfaceID ids[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + SL_IID_VOLUME, SL_IID_ANDROIDCONFIGURATION + }; + const SLboolean req[] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE}; + + const unsigned nbInterface = ARRAYSIZE(ids); + + // create audio player + DEBUG("Create audio player\n"); + result = (*engineInterface_)->CreateAudioPlayer(engineInterface_, &playerObject_, &audioSource, &audioSink, nbInterface, ids, req); + assert(SL_RESULT_SUCCESS == result); + + SLAndroidConfigurationItf playerConfig; + SLint32 streamType = SL_ANDROID_STREAM_VOICE; + + result = (*playerObject_)->GetInterface(playerObject_, + SL_IID_ANDROIDCONFIGURATION, + &playerConfig); + + if (result == SL_RESULT_SUCCESS && playerConfig) { + result = (*playerConfig)->SetConfiguration( + playerConfig, SL_ANDROID_KEY_STREAM_TYPE, + &streamType, sizeof(SLint32)); + } + + if (result != SL_RESULT_SUCCESS) { + ERROR("Unable to set android player configuration"); + } + + DEBUG("Realize audio player\n"); + result = (*playerObject_)->Realize(playerObject_, SL_BOOLEAN_FALSE); + assert(SL_RESULT_SUCCESS == result); + + // create audio interface + DEBUG("Create audio player interface\n"); + result = (*playerObject_)->GetInterface(playerObject_, SL_IID_PLAY, &playerInterface_); + assert(SL_RESULT_SUCCESS == result); + + // create the buffer queue interface + DEBUG("Create buffer queue interface\n"); + result = (*playerObject_)->GetInterface(playerObject_, SL_IID_BUFFERQUEUE, &playbackBufferQueue_); + assert(SL_RESULT_SUCCESS == result); + + // register the buffer queue on the buffer object + DEBUG("Register audio callback\n"); + result = (*playbackBufferQueue_)->RegisterCallback(playbackBufferQueue_, audioPlaybackCallback, this); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Audio Playback Initialization Done\n"); +} + +void +OpenSLLayer::initAudioCapture() +{ + SLresult result; + + // configure audio source + DEBUG("Configure audio source\n"); + SLDataLocator_IODevice deviceLocator = {SL_DATALOCATOR_IODEVICE, + SL_IODEVICE_AUDIOINPUT, + SL_DEFAULTDEVICEID_AUDIOINPUT, + NULL + }; + + SLDataSource audioSource = {&deviceLocator, + NULL + }; + + // configure audio sink + DEBUG("Configure audio sink\n"); + + SLDataLocator_AndroidSimpleBufferQueue bufferLocator = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, + NB_BUFFER_CAPTURE_QUEUE + }; + + SLDataFormat_PCM audioFormat = {SL_DATAFORMAT_PCM, 1, + SL_SAMPLINGRATE_8, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_PCMSAMPLEFORMAT_FIXED_16, + SL_SPEAKER_FRONT_CENTER, + SL_BYTEORDER_LITTLEENDIAN + }; + + SLDataSink audioSink = {&bufferLocator, + &audioFormat + }; + + // create audio recorder + // (requires the RECORD_AUDIO permission) + DEBUG("Create audio recorder\n"); + const SLInterfaceID id[] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE}; + const SLboolean req[] = {SL_BOOLEAN_TRUE}; + + if (engineInterface_ != NULL) { + result = (*engineInterface_)->CreateAudioRecorder(engineInterface_, + &recorderObject_, &audioSource, &audioSink, 1, id, req); + } + + if (SL_RESULT_SUCCESS != result) { + DEBUG("Error: could not create audio recorder"); + return; + } + + // realize the audio recorder + DEBUG("Realize the audio recorder\n"); + result = (*recorderObject_)->Realize(recorderObject_, SL_BOOLEAN_FALSE); + + if (SL_RESULT_SUCCESS != result) { + DEBUG("Error: could not realize audio recorder"); + return; + } + + // get the record interface + DEBUG("Create the record interface\n"); + result = (*recorderObject_)->GetInterface(recorderObject_, SL_IID_RECORD, &recorderInterface_); + assert(SL_RESULT_SUCCESS == result); + + // get the buffer queue interface + DEBUG("Create the buffer queue interface\n"); + result = (*recorderObject_)->GetInterface(recorderObject_, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, + &recorderBufferQueue_); + assert(SL_RESULT_SUCCESS == result); + + // register callback on the buffer queue + DEBUG("Register the audio capture callback\n"); + result = (*recorderBufferQueue_)->RegisterCallback(recorderBufferQueue_, audioCaptureCallback, this); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Audio capture initialized\n"); +} + + +void +OpenSLLayer::startAudioPlayback() +{ + assert(NULL != playbackBufferQueue_); + + DEBUG("Start audio playback\n"); + + SLresult result; + + for (int i = 0; i < NB_BUFFER_PLAYBACK_QUEUE; i++) { + AudioBuffer &buffer = getNextPlaybackBuffer(); + incrementPlaybackIndex(); + + buffer.reset(); + + result = (*playbackBufferQueue_)->Enqueue(playbackBufferQueue_, buffer.data(), buffer.size()); + + if (SL_RESULT_SUCCESS != result) { + DEBUG("Error could not enqueue initial buffers\n"); + } + } + + result = (*playerInterface_)->SetPlayState(playerInterface_, SL_PLAYSTATE_PLAYING); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Audio playback started\n"); +} + +void +OpenSLLayer::startAudioCapture() +{ + assert(NULL != playbackBufferQueue_); + + DEBUG("Start audio capture\n"); + + SLresult result; + + + // in case already recording, stop recording and clear buffer queue + if (recorderInterface_ != NULL) { + result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_STOPPED); + assert(SL_RESULT_SUCCESS == result); + } + + DEBUG("Clearing recorderBufferQueue\n"); + result = (*recorderBufferQueue_)->Clear(recorderBufferQueue_); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("getting next record buffer\n"); + // enqueue an empty buffer to be filled by the recorder + // (for streaming recording, we enqueue at least 2 empty buffers to start things off) + AudioBuffer &buffer = getNextRecordBuffer(); + incrementRecordIndex(); + + buffer.reset(); + + DEBUG("Enqueue record buffer\n"); + result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.data(), buffer.size()); + + // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, + // which for this code example would indicate a programming error + if (SL_RESULT_SUCCESS != result) { + DEBUG("Error could not enqueue buffers in audio capture\n"); + return; + } + + // start recording + result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_RECORDING); + assert(SL_RESULT_SUCCESS == result); + + DEBUG("Audio capture started\n"); +} + +void +OpenSLLayer::stopAudioPlayback() +{ + DEBUG("Stop audio playback\n"); + + if (playerInterface_ != NULL) { + SLresult result; + result = (*playerInterface_)->SetPlayState(playerInterface_, SL_PLAYSTATE_STOPPED); + assert(SL_RESULT_SUCCESS == result); + } + + DEBUG("Audio playback stopped\n"); +} + +void +OpenSLLayer::stopAudioCapture() +{ + DEBUG("Stop audio capture\n"); + + if (recorderInterface_ != NULL) { + SLresult result; + result = (*recorderInterface_)->SetRecordState(recorderInterface_, SL_RECORDSTATE_STOPPED); + assert(SL_RESULT_SUCCESS == result); + } + + DEBUG("Audio capture stopped\n"); + +} + +std::vector<std::string> +OpenSLLayer::getCaptureDeviceList() const +{ + std::vector<std::string> captureDeviceList; + + return captureDeviceList; +} + +std::vector<std::string> +OpenSLLayer::getPlaybackDeviceList() const +{ + std::vector<std::string> playbackDeviceList; + + return playbackDeviceList; +} + +void +OpenSLLayer::playback(SLAndroidSimpleBufferQueueItf queue) +{ + assert(NULL != queue); + + usleep(20000); + + AudioBuffer &buffer = getNextPlaybackBuffer(); + + buffer.reset(); + + const bool bufferFilled = audioPlaybackFillBuffer(buffer); + + if (bufferFilled) { +#ifdef RECORD_AUDIO_TODISK + opensl_outfile.write((char const *)(buffer.data()), buffer.size()); +#endif + SLresult result = (*queue)->Enqueue(queue, buffer.data(), buffer.size()); + + if (SL_RESULT_SUCCESS != result) { + DEBUG("Error could not enqueue buffers in playback callback\n"); + } + + incrementPlaybackIndex(); + } +} + +void +OpenSLLayer::audioPlaybackCallback(SLAndroidSimpleBufferQueueItf queue, void *context) +{ + assert(NULL != context); + static_cast<OpenSLLayer*>(context)->playback(queue); +} + +void +OpenSLLayer::capture(SLAndroidSimpleBufferQueueItf queue) +{ + assert(NULL != queue); + + AudioBuffer &buffer = getNextRecordBuffer(); + incrementRecordIndex(); + + SLresult result; + + // enqueue an empty buffer to be filled by the recorder + // (for streaming recording, we enqueue at least 2 empty buffers to start things off) + result = (*recorderBufferQueue_)->Enqueue(recorderBufferQueue_, buffer.data(), buffer.size()); + // the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT, + // which for this code example would indicate a programming error + assert(SL_RESULT_SUCCESS == result); + + audioCaptureFillBuffer(buffer); +#ifdef RECORD_AUDIO_TODISK + opensl_infile.write((char const *)(buffer.data()), buffer.size()); +#endif +} + +void +OpenSLLayer::audioCaptureCallback(SLAndroidSimpleBufferQueueItf queue, void *context) +{ + assert(NULL != context); + static_cast<OpenSLLayer*>(context)->capture(queue); +} + + +void +OpenSLLayer::updatePreference(AudioPreference &preference, int index, PCMType type) +{ +#ifdef OUTSIDE_TESTING + + switch (type) { + case SFL_PCM_PLAYBACK: + break; + + case SFL_PCM_CAPTURE: + break; + + case SFL_PCM_RINGTONE: + break; + + default: + break; + } + +#endif +} + +bool OpenSLLayer::audioPlaybackFillBuffer(AudioBuffer &buffer) +{ + // Looks if there's any voice audio from rtp to be played + MainBuffer &mbuffer = Manager::instance().getMainBuffer(); + size_t bytesToGet = mbuffer.availableForGet(MainBuffer::DEFAULT_ID); + size_t urgentBytesToGet = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID); + + + PlaybackMode mode = getPlaybackMode(); + + bool bufferFilled = false; + + switch (mode) { + case NONE: + case TONE: + case RINGTONE: + case URGENT: { + if (urgentBytesToGet > 0) + bufferFilled = audioPlaybackFillWithUrgent(buffer, urgentBytesToGet); + else + bufferFilled = audioPlaybackFillWithToneOrRingtone(buffer); + } + break; + + case VOICE: { + if (bytesToGet > 0) + bufferFilled = audioPlaybackFillWithVoice(buffer, bytesToGet); + else { + buffer.reset(); + bufferFilled = true; + } + } + break; + + case ZEROS: + default: { + buffer.reset(); + bufferFilled = true; + } + } + + if (!bufferFilled) + printf("Error buffer not filled in audio playback\n"); + + return bufferFilled; +} + +// #define RECORD_TOMAIN_TODISK +#ifdef RECORD_TOMAIN_TODISK +#include <fstream> +std::ofstream opensl_tomainbuffer("/data/data/com.savoirfairelinux.sflphone/opensl_tomain.raw", std::ofstream::out | std::ofstream::binary); +#endif + +void OpenSLLayer::audioCaptureFillBuffer(AudioBuffer &buffer) +{ + MainBuffer &mbuffer = Manager::instance().getMainBuffer(); + + const unsigned mainBufferSampleRate = mbuffer.getInternalSamplingRate(); + const bool resample = mainBufferSampleRate != sampleRate_; + + buffer.applyGain(captureGain_); + + if (resample) { + AudioBuffer out(buffer); + out.setSampleRate(sampleRate_); + + converter_.resample(buffer, out); + dcblocker_.process(out); + mbuffer.putData(out, MainBuffer::DEFAULT_ID); + } else { + dcblocker_.process(buffer); +#ifdef RECORD_TOMAIN_TODISK + opensl_tomainbuffer.write((char const *)in_ptr, toGetBytes /); +#endif + mbuffer.putData(buffer, MainBuffer::DEFAULT_ID); + } +} + +bool OpenSLLayer::audioPlaybackFillWithToneOrRingtone(AudioBuffer &buffer) +{ + AudioLoop *tone = Manager::instance().getTelephoneTone(); + AudioLoop *file_tone = Manager::instance().getTelephoneFile(); + + // In case of a dtmf, the pointers will be set to NULL once the dtmf length is + // reached. For this reason we need to fill audio buffer with zeros if pointer is NULL + if (tone) { + tone->getNext(buffer, playbackGain_); + } else if (file_tone) { + file_tone->getNext(buffer, playbackGain_); + } else { + buffer.reset(); + } + + return true; +} + +bool OpenSLLayer::audioPlaybackFillWithUrgent(AudioBuffer &buffer, size_t bytesToGet) +{ + // Urgent data (dtmf, incoming call signal) come first. + bytesToGet = std::min(bytesToGet, buffer.capacity()); + urgentRingBuffer_.get(buffer, MainBuffer::DEFAULT_ID); + buffer.applyGain(playbackGain_); + + // Consume the regular one as well (same amount of bytes) + Manager::instance().getMainBuffer().discard(bytesToGet, MainBuffer::DEFAULT_ID); + + return true; +} + +bool OpenSLLayer::audioPlaybackFillWithVoice(AudioBuffer &buffer, size_t bytesAvail) +{ + const size_t bytesToCpy = buffer.capacity(); + + if (bytesAvail == 0) + return false; + + MainBuffer &mainBuffer = Manager::instance().getMainBuffer(); + + mainBuffer.getData(buffer, MainBuffer::DEFAULT_ID); + buffer.applyGain(getPlaybackGain()); + + if (sampleRate_ != mainBuffer.getInternalSamplingRate()) { + AudioBuffer out(buffer, false); + out.setSampleRate(sampleRate_); + converter_.resample(buffer, out); + buffer = out; + } + + return true; +} diff --git a/daemon/src/audio/opensl/opensllayer.h b/daemon/src/audio/opensl/opensllayer.h new file mode 100644 index 0000000000000000000000000000000000000000..889137503af884fabb107f0a662f4489a90904d4 --- /dev/null +++ b/daemon/src/audio/opensl/opensllayer.h @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef _OPENSL_LAYER_H +#define _OPENSL_LAYER_H + +#include <SLES/OpenSLES.h> +#include <SLES/OpenSLES_Android.h> +#include <vector> + +#include "../audiolayer.h" + + +enum PCMType { + SFL_PCM_BOTH = 0x0021, /** To open both playback and capture devices */ + SFL_PCM_PLAYBACK = 0x0022, /** To open playback device only */ + SFL_PCM_CAPTURE = 0x0023, /** To open capture device only */ + SFL_PCM_RINGTONE = 0x0024 /** To open the ringtone device only */ +}; + +class AudioPreference; + +#include "noncopyable.h" + +class OpenSLThread; + +#define ANDROID_BUFFER_QUEUE_LENGTH 2 + + +/** + * @file OpenSLLayer.h + * @brief Main sound class for android. Manages the data transfers between the application and the hardware. + */ + +class OpenSLLayer : public AudioLayer { + public: + /** + * Constructor + */ + OpenSLLayer(); + + /** + * Destructor + */ + ~OpenSLLayer(); + + /** + * Start the capture stream and prepare the playback stream. + * The playback starts accordingly to its threshold + */ + virtual void startStream(); + + /** + * Stop the playback and capture streams. + * Drops the pending frames and put the capture and playback handles to PREPARED state + */ + virtual void stopStream(); + + /** + * Scan the sound card available for capture on the system + * @return std::vector<std::string> The vector containing the string description of the card + */ + virtual std::vector<std::string> getCaptureDeviceList() const; + + /** + * Scan the sound card available for capture on the system + * @return std::vector<std::string> The vector containing the string description of the card + */ + virtual std::vector<std::string> getPlaybackDeviceList() const; + + void initAudioEngine(); + + void shutdownAudioEngine(); + + void initAudioPlayback(); + + void initAudioCapture(); + + void startAudioPlayback(); + + void startAudioCapture(); + + void stopAudioPlayback(); + + void stopAudioCapture(); + + virtual int getAudioDeviceIndex(const std::string&) const { + return 0; + } + + virtual std::string getAudioDeviceName(int, AudioLayer::PCMType) const { + return ""; + } + + private: + + bool audioBufferFillWithZeros(AudioBuffer &buffer); + + /** + * Here fill the input buffer with tone or ringtone samples + */ + bool audioPlaybackFillWithToneOrRingtone(AudioBuffer &buffer); + + bool audioPlaybackFillWithUrgent(AudioBuffer &buffer, size_t bytesAvail); + + bool audioPlaybackFillWithVoice(AudioBuffer &buffer, size_t bytesAvail); + + /** + * The main logic to determine what should be played is determined here + */ + bool audioPlaybackFillBuffer(AudioBuffer &buffer); + + void audioCaptureFillBuffer(AudioBuffer &buffer); + + + /** + * This is the main audio playabck callback called by the OpenSL layer + */ + static void audioPlaybackCallback(SLAndroidSimpleBufferQueueItf bq, void *context); + + /** + * This is the main audio capture callback called by the OpenSL layer + */ + static void audioCaptureCallback(SLAndroidSimpleBufferQueueItf bq, void *context); + + /** + * Get the index of the audio card for capture + * @return int The index of the card used for capture + * 0 for the first available card on the system, 1 ... + */ + virtual int getIndexCapture() const { + return indexIn_; + } + + /** + * Get the index of the audio card for playback + * @return int The index of the card used for playback + * 0 for the first available card on the system, 1 ... + */ + virtual int getIndexPlayback() const { + return indexOut_; + } + + /** + * Get the index of the audio card for ringtone (could be differnet from playback) + * @return int The index of the card used for ringtone + * 0 for the first available card on the system, 1 ... + */ + virtual int getIndexRingtone() const { + return indexRing_; + } + + AudioBuffer &getNextPlaybackBuffer(void) { + return playbackBufferStack_[playbackBufferIndex_]; + } + + AudioBuffer &getNextRecordBuffer(void) { + return recordBufferStack_[recordBufferIndex_]; + } + + void incrementPlaybackIndex(void) { + playbackBufferIndex_ = (playbackBufferIndex_ + 1) % NB_BUFFER_PLAYBACK_QUEUE; + } + + void incrementRecordIndex(void) { + recordBufferIndex_ = (recordBufferIndex_ + 1) % NB_BUFFER_CAPTURE_QUEUE; + } + + void playback(SLAndroidSimpleBufferQueueItf queue); + void capture(SLAndroidSimpleBufferQueueItf queue); + friend class OpenSLThread; + + static const int NB_BUFFER_PLAYBACK_QUEUE; + + static const int NB_BUFFER_CAPTURE_QUEUE; + + /** + * Number of audio cards on which capture stream has been opened + */ + int indexIn_; + + /** + * Number of audio cards on which playback stream has been opened + */ + int indexOut_; + + /** + * Number of audio cards on which ringtone stream has been opened + */ + int indexRing_; + + NON_COPYABLE(OpenSLLayer); + + virtual void updatePreference(AudioPreference &pref, int index, PCMType type); + + OpenSLThread *audioThread_; + + bool isStarted_; + + /** + * OpenSL standard object interface + */ + SLObjectItf engineObject_; + + /** + * OpenSL sound engine interface + */ + SLEngineItf engineInterface_; + + /** + * Output mix interface + */ + SLObjectItf outputMixer_; + + SLObjectItf playerObject_; + + SLObjectItf recorderObject_; + + /** + * + */ + SLPlayItf playerInterface_; + + SLRecordItf recorderInterface_; + + /** + * OpenSL playback buffer + */ + SLAndroidSimpleBufferQueueItf playbackBufferQueue_; + + SLAndroidSimpleBufferQueueItf recorderBufferQueue_; + + int playbackBufferIndex_; + + int recordBufferIndex_; + + AudioBufferStack playbackBufferStack_; + AudioBufferStack recordBufferStack_; +}; + +#endif // _OPENSL_LAYER_H_ diff --git a/daemon/src/audio/pulseaudio/audiostream.cpp b/daemon/src/audio/pulseaudio/audiostream.cpp index fe53f98409096387d655a6e0941f1ff6f4c8a2b9..97d7deef5929ff75a24216df43df0e321c8aa3ca 100644 --- a/daemon/src/audio/pulseaudio/audiostream.cpp +++ b/daemon/src/audio/pulseaudio/audiostream.cpp @@ -38,20 +38,19 @@ AudioStream::AudioStream(pa_context *c, const char *desc, int type, unsigned samplrate, - const std::string &deviceName) + const PaDeviceInfos* infos) : audiostream_(0), mainloop_(m) { - static const pa_channel_map channel_map = { - 1, - { PA_CHANNEL_POSITION_MONO }, - }; + const pa_channel_map channel_map = infos->channel_map; pa_sample_spec sample_spec = { PA_SAMPLE_S16LE, // PA_SAMPLE_FLOAT32LE, samplrate, - 1 + channel_map.channels }; + DEBUG("%s: trying to create stream with device %s (%dHz, %d channels)", desc, infos->name.c_str(), samplrate, channel_map.channels); + assert(pa_sample_spec_valid(&sample_spec)); assert(pa_channel_map_valid(&channel_map)); @@ -70,18 +69,17 @@ AudioStream::AudioStream(pa_context *c, attributes.minreq = (uint32_t) -1; pa_threaded_mainloop_lock(mainloop_); - const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(PA_STREAM_ADJUST_LATENCY | - PA_STREAM_AUTO_TIMING_UPDATE); + const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM) { pa_stream_connect_playback(audiostream_, - deviceName.empty() ? NULL : deviceName.c_str(), + infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags, NULL, NULL); } else if (type == CAPTURE_STREAM) { pa_stream_connect_record(audiostream_, - deviceName.empty() ? NULL : deviceName.c_str(), + infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags); } diff --git a/daemon/src/audio/pulseaudio/audiostream.h b/daemon/src/audio/pulseaudio/audiostream.h index ec782beb3f0282aa5fef6860109f774888446c1d..650a9bc20ca1e4cdd0465a7034cff62f204c0b2b 100644 --- a/daemon/src/audio/pulseaudio/audiostream.h +++ b/daemon/src/audio/pulseaudio/audiostream.h @@ -34,6 +34,7 @@ #include <pulse/pulseaudio.h> #include <string> #include "noncopyable.h" +#include "pulselayer.h" /** * This data structure contains the different king of audio streams available @@ -53,9 +54,9 @@ class AudioStream { * @param description * @param types * @param audio sampling rate - * @param device name + * @param pointer to pa_source_info or pa_sink_info (depending on type). */ - AudioStream(pa_context *, pa_threaded_mainloop *, const char *, int, unsigned, const std::string&); + AudioStream(pa_context *, pa_threaded_mainloop *, const char *, int, unsigned, const PaDeviceInfos*); ~AudioStream(); @@ -67,6 +68,18 @@ class AudioStream { return audiostream_; } + const pa_sample_spec *sampleSpec() { + return pa_stream_get_sample_spec(audiostream_); + } + + inline size_t sampleSize() { + return pa_sample_size(sampleSpec()); + } + + inline uint8_t channels() { + return sampleSpec()->channels; + } + bool isReady(); private: diff --git a/daemon/src/audio/pulseaudio/pulselayer.cpp b/daemon/src/audio/pulseaudio/pulselayer.cpp index 8c85d08bdfd2cf7419d4623898e70da1f4029e77..26f59c0b159e1546a90d43f883854f5f1142d6c7 100644 --- a/daemon/src/audio/pulseaudio/pulselayer.cpp +++ b/daemon/src/audio/pulseaudio/pulselayer.cpp @@ -3,6 +3,7 @@ * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * Author: Андрей Лухнов <aol.nnov@gmail.com> + * Author: Adrien Beraud <adrien.beraud@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +33,7 @@ #include <algorithm> // for std::find #include <stdexcept> + #include "audiostream.h" #include "pulselayer.h" #include "audio/samplerateconverter.h" @@ -39,6 +41,7 @@ #include "logger.h" #include "manager.h" +#include <unistd.h> #include <cstdlib> #include <fstream> @@ -67,7 +70,7 @@ void stream_moved_callback(pa_stream *s, void *userdata UNUSED) } // end anonymous namespace #ifdef RECTODISK -std::ofstream outfileResampled ("testMicOuputResampled.raw", std::ifstream::binary); +std::ofstream outfileResampled("testMicOuputResampled.raw", std::ifstream::binary); std::ofstream outfile("testMicOuput.raw", std::ifstream::binary); #endif @@ -77,20 +80,29 @@ PulseLayer::PulseLayer(AudioPreference &pref) , ringtone_(0) , sinkList_() , sourceList_() - , mic_buffer_(0) - , mic_buf_size_(0) + , mic_buffer_() , context_(0) , mainloop_(pa_threaded_mainloop_new()) , enumeratingSinks_(false) , enumeratingSources_(false) , preference_(pref) { - setenv("PULSE_PROP_media.role", "phone", 1); - if (!mainloop_) throw std::runtime_error("Couldn't create pulseaudio mainloop"); - context_ = pa_context_new(pa_threaded_mainloop_get_api(mainloop_) , "SFLphone"); +#if PA_CHECK_VERSION(1, 0, 0) + pa_proplist *pl = pa_proplist_new(); + pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "phone"); + + context_ = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mainloop_), "SFLphone", pl); + + if (pl) + pa_proplist_free(pl); + +#else + setenv("PULSE_PROP_media.role", "phone", 1); + context_ = pa_context_new(pa_threaded_mainloop_get_api(mainloop_), "SFLphone"); +#endif if (!context_) throw std::runtime_error("Couldn't create pulseaudio context"); @@ -134,8 +146,6 @@ PulseLayer::~PulseLayer() if (mainloop_) pa_threaded_mainloop_free(mainloop_); - - delete [] mic_buffer_; } void PulseLayer::context_state_callback(pa_context* c, void *user_data) @@ -143,7 +153,7 @@ void PulseLayer::context_state_callback(pa_context* c, void *user_data) PulseLayer *pulse = static_cast<PulseLayer*>(user_data); assert(c and pulse and pulse->mainloop_); const pa_subscription_mask_t mask = (pa_subscription_mask_t) - (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE); + (PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE); switch (pa_context_get_state(c)) { case PA_CONTEXT_CONNECTING: @@ -179,6 +189,7 @@ void PulseLayer::updateSinkList() sinkList_.clear(); enumeratingSinks_ = true; pa_operation *op = pa_context_get_sink_info_list(context_, sink_input_info_callback, this); + if (op != NULL) pa_operation_unref(op); } @@ -188,47 +199,72 @@ void PulseLayer::updateSourceList() sourceList_.clear(); enumeratingSources_ = true; pa_operation *op = pa_context_get_source_info_list(context_, source_input_info_callback, this); + if (op != NULL) pa_operation_unref(op); } -bool PulseLayer::inSinkList(const std::string &deviceName) const +bool PulseLayer::inSinkList(const std::string &deviceName) { - const bool found = std::find(sinkList_.begin(), sinkList_.end(), deviceName) != sinkList_.end(); + const bool found = std::find_if(sinkList_.begin(), sinkList_.end(), PaDeviceInfos::nameComparator(deviceName)) != sinkList_.end(); + DEBUG("seeking for %s in sinks. %s found", deviceName.c_str(), found ? "" : "NOT"); return found; } - -bool PulseLayer::inSourceList(const std::string &deviceName) const +bool PulseLayer::inSourceList(const std::string &deviceName) { - const bool found = std::find(sourceList_.begin(), sourceList_.end(), deviceName) != sourceList_.end(); + const bool found = std::find_if(sourceList_.begin(), sourceList_.end(), PaDeviceInfos::nameComparator(deviceName)) != sourceList_.end(); + DEBUG("seeking for %s in sources. %s found", deviceName.c_str(), found ? "" : "NOT"); return found; } std::vector<std::string> PulseLayer::getCaptureDeviceList() const { - return sourceList_; + const unsigned n = sourceList_.size(); + std::vector<std::string> names(n); + + for (unsigned i = 0; i < n; i++) + names[i] = sourceList_[i].name; + + return names; } std::vector<std::string> PulseLayer::getPlaybackDeviceList() const { - return sinkList_; + const unsigned n = sinkList_.size(); + std::vector<std::string> names(n); + + for (unsigned i = 0; i < n; i++) + names[i] = sinkList_[i].name; + + return names; } int PulseLayer::getAudioDeviceIndex(const std::string& name) const { - int index = std::distance(sourceList_.begin(), std::find(sourceList_.begin(), sourceList_.end(), name)); + int index = std::distance(sourceList_.begin(), std::find_if(sourceList_.begin(), sourceList_.end(), PaDeviceInfos::nameComparator(name))); + if (index == std::distance(sourceList_.begin(), sourceList_.end())) { - // not found in sources, search in sinks then - index = std::distance(sinkList_.begin(), std::find(sinkList_.begin(), sinkList_.end(), name)); + index = std::distance(sinkList_.begin(), std::find_if(sinkList_.begin(), sinkList_.end(), PaDeviceInfos::nameComparator(name))); } + return index; } +const PaDeviceInfos* PulseLayer::getDeviceInfos(const std::vector<PaDeviceInfos>& list, const std::string& name) const +{ + std::vector<PaDeviceInfos>::const_iterator dev_info = std::find_if(list.begin(), list.end(), PaDeviceInfos::nameComparator(name)); + + if (dev_info == list.end()) return NULL; + + return &(*dev_info); +} + std::string PulseLayer::getAudioDeviceName(int index, PCMType type) const { + switch (type) { case SFL_PCM_PLAYBACK: case SFL_PCM_RINGTONE: @@ -236,13 +272,17 @@ std::string PulseLayer::getAudioDeviceName(int index, PCMType type) const ERROR("Index %d out of range", index); return ""; } - return sinkList_[index]; + + return sinkList_[index].name; + case SFL_PCM_CAPTURE: if (index < 0 or static_cast<size_t>(index) >= sourceList_.size()) { ERROR("Index %d out of range", index); return ""; } - return sourceList_[index]; + + return sourceList_[index].name; + default: return ""; } @@ -258,23 +298,44 @@ void PulseLayer::createStreams(pa_context* c) std::string ringtoneDevice(preference_.getPulseDeviceRingtone()); std::string defaultDevice = ""; - DEBUG("Devices:\n playback: %s\n record: %s\n ringtone: %s", - playbackDevice.c_str(), captureDevice.c_str(), ringtoneDevice.c_str()); + DEBUG("Devices: playback: %s record: %s ringtone: %s", + playbackDevice.c_str(), captureDevice.c_str(), ringtoneDevice.c_str()); + + // Create playback stream + const PaDeviceInfos* dev_infos = getDeviceInfos(sinkList_, playbackDevice); - playback_ = new AudioStream(c, mainloop_, "SFLphone playback", PLAYBACK_STREAM, sampleRate_, - inSinkList(playbackDevice) ? playbackDevice : defaultDevice); + if (dev_infos == NULL) { + dev_infos = &sinkList_[0]; + DEBUG("Prefered playback device not found in device list, selecting %s instead.", dev_infos->name.c_str()); + } + + playback_ = new AudioStream(c, mainloop_, "SFLphone playback", PLAYBACK_STREAM, sampleRate_, dev_infos); pa_stream_set_write_callback(playback_->pulseStream(), playback_callback, this); pa_stream_set_moved_callback(playback_->pulseStream(), stream_moved_callback, this); - record_ = new AudioStream(c, mainloop_, "SFLphone capture", CAPTURE_STREAM, sampleRate_, - inSourceList(captureDevice) ? captureDevice : defaultDevice); + // Create capture stream + dev_infos = getDeviceInfos(sourceList_, captureDevice); + + if (dev_infos == NULL) { + dev_infos = &sourceList_[0]; + DEBUG("Prefered capture device not found in device list, selecting %s instead.", dev_infos->name.c_str()); + } + + record_ = new AudioStream(c, mainloop_, "SFLphone capture", CAPTURE_STREAM, sampleRate_, dev_infos); pa_stream_set_read_callback(record_->pulseStream() , capture_callback, this); pa_stream_set_moved_callback(record_->pulseStream(), stream_moved_callback, this); - ringtone_ = new AudioStream(c, mainloop_, "SFLphone ringtone", RINGTONE_STREAM, sampleRate_, - inSinkList(ringtoneDevice) ? ringtoneDevice : defaultDevice); + // Create ringtone stream + dev_infos = getDeviceInfos(sinkList_, ringtoneDevice); + + if (dev_infos == NULL) { + dev_infos = &sinkList_[0]; + DEBUG("Prefered ringtone device not found in device list, selecting %s instead.", dev_infos->name.c_str()); + } + + ringtone_ = new AudioStream(c, mainloop_, "SFLphone ringtone", RINGTONE_STREAM, sampleRate_, dev_infos); pa_stream_set_write_callback(ringtone_->pulseStream(), ringtone_callback, this); pa_stream_set_moved_callback(ringtone_->pulseStream(), stream_moved_callback, this); @@ -286,13 +347,13 @@ void PulseLayer::createStreams(pa_context* c) } namespace { - // Delete stream and zero out its pointer - void - cleanupStream(AudioStream *&stream) - { - delete stream; - stream = 0; - } +// Delete stream and zero out its pointer +void +cleanupStream(AudioStream *&stream) +{ + delete stream; + stream = 0; +} } @@ -338,6 +399,9 @@ void PulseLayer::writeToSpeaker() return; pa_stream *s = playback_->pulseStream(); + const pa_sample_spec* sample_spec = pa_stream_get_sample_spec(s); + size_t sample_size = pa_frame_size(sample_spec); + const unsigned n_channels = sample_spec->channels; // available bytes to be written in pulseaudio internal buffer int ret = pa_stream_writable_size(s); @@ -349,22 +413,29 @@ void PulseLayer::writeToSpeaker() return; size_t writableBytes = ret; + const size_t writableSamples = writableBytes / sample_size; notifyIncomingCall(); - size_t urgentBytes = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID); + size_t urgentSamples = urgentRingBuffer_.availableForGet(MainBuffer::DEFAULT_ID); + size_t urgentBytes = urgentSamples * sample_size; - if (urgentBytes > writableBytes) - urgentBytes = writableBytes; + if (urgentSamples > writableSamples) { + urgentSamples = writableSamples; + urgentBytes = urgentSamples * sample_size; + } + + SFLAudioSample *data = 0; - void *data = 0; if (urgentBytes) { - pa_stream_begin_write(s, &data, &urgentBytes); - urgentRingBuffer_.get(data, urgentBytes, MainBuffer::DEFAULT_ID); - applyGain(static_cast<SFLDataFormat *>(data), urgentBytes / sizeof(SFLDataFormat), getPlaybackGain()); + AudioBuffer linearbuff(urgentSamples, n_channels); + pa_stream_begin_write(s, (void**)&data, &urgentBytes); + urgentRingBuffer_.get(linearbuff, MainBuffer::DEFAULT_ID); // retrive only the first sample_spec->channels channels + linearbuff.applyGain(playbackGain_); + linearbuff.interleave(data); pa_stream_write(s, data, urgentBytes, NULL, 0, PA_SEEK_RELATIVE); - // Consume the regular one as well (same amount of bytes) - Manager::instance().getMainBuffer().discard(urgentBytes, MainBuffer::DEFAULT_ID); + // Consume the regular one as well (same amount of samples) + Manager::instance().getMainBuffer().discard(urgentSamples, MainBuffer::DEFAULT_ID); return; } @@ -374,9 +445,10 @@ void PulseLayer::writeToSpeaker() if (toneToPlay) { if (playback_->isReady()) { - pa_stream_begin_write(s, &data, &writableBytes); - toneToPlay->getNext((SFLDataFormat*)data, writableBytes / sizeof(SFLDataFormat), 100); - applyGain(static_cast<SFLDataFormat *>(data), writableBytes / sizeof(SFLDataFormat), getPlaybackGain()); + pa_stream_begin_write(s, (void**)&data, &writableBytes); + AudioBuffer linearbuff(writableSamples, n_channels); + toneToPlay->getNext(linearbuff, playbackGain_); // retrive only n_channels + linearbuff.interleave(data); pa_stream_write(s, data, writableBytes, NULL, 0, PA_SEEK_RELATIVE); } @@ -385,18 +457,15 @@ void PulseLayer::writeToSpeaker() flushUrgent(); // flush remaining samples in _urgentRingBuffer - size_t availSamples = Manager::instance().getMainBuffer().availableForGet(MainBuffer::DEFAULT_ID) / sizeof(SFLDataFormat); + size_t availSamples = Manager::instance().getMainBuffer().availableForGet(MainBuffer::DEFAULT_ID); if (availSamples == 0) { - pa_stream_begin_write(s, &data, &writableBytes); + pa_stream_begin_write(s, (void**)&data, &writableBytes); memset(data, 0, writableBytes); pa_stream_write(s, data, writableBytes, NULL, 0, PA_SEEK_RELATIVE); return; } - // how many samples we can write to the output - size_t writableSamples = writableBytes / sizeof(SFLDataFormat); - // how many samples we want to read from the buffer size_t readableSamples = writableSamples; @@ -404,30 +473,31 @@ void PulseLayer::writeToSpeaker() unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate(); bool resample = sampleRate_ != mainBufferSampleRate; + if (resample) { resampleFactor = (double) sampleRate_ / mainBufferSampleRate; readableSamples = (double) readableSamples / resampleFactor; } - if (readableSamples > availSamples) - readableSamples = availSamples; + readableSamples = std::min(readableSamples, availSamples); + size_t nResampled = (double) readableSamples * resampleFactor; + size_t resampledBytes = nResampled * sample_size; + + pa_stream_begin_write(s, (void**)&data, &resampledBytes); - size_t readableBytes = readableSamples * sizeof(SFLDataFormat); - pa_stream_begin_write(s, &data, &readableBytes); - Manager::instance().getMainBuffer().getData(data, readableBytes, MainBuffer::DEFAULT_ID); + AudioBuffer linearbuff(readableSamples, n_channels); + Manager::instance().getMainBuffer().getData(linearbuff, MainBuffer::DEFAULT_ID); if (resample) { - const size_t nResampled = (double) readableSamples * resampleFactor; - size_t resampledBytes = nResampled * sizeof(SFLDataFormat); - SFLDataFormat* rsmpl_out = (SFLDataFormat*) pa_xmalloc(resampledBytes); - converter_.resample((SFLDataFormat*)data, rsmpl_out, nResampled, - mainBufferSampleRate, sampleRate_, readableSamples); - applyGain(rsmpl_out, nResampled, getPlaybackGain()); - pa_stream_write(s, rsmpl_out, resampledBytes, NULL, 0, PA_SEEK_RELATIVE); - pa_xfree(rsmpl_out); + AudioBuffer rsmpl_out(nResampled, 1, sampleRate_); + converter_.resample(linearbuff, rsmpl_out); + rsmpl_out.applyGain(playbackGain_); + rsmpl_out.interleave(data); + pa_stream_write(s, data, resampledBytes, NULL, 0, PA_SEEK_RELATIVE); } else { - applyGain(static_cast<SFLDataFormat *>(data), readableSamples, getPlaybackGain()); - pa_stream_write(s, data, readableBytes, NULL, 0, PA_SEEK_RELATIVE); + linearbuff.applyGain(playbackGain_); + linearbuff.interleave(data); + pa_stream_write(s, data, resampledBytes, NULL, 0, PA_SEEK_RELATIVE); } } @@ -439,37 +509,50 @@ void PulseLayer::readFromMic() const char *data = NULL; size_t bytes; + size_t sample_size = record_->sampleSize(); + uint8_t channels = record_->channels(); + if (pa_stream_peek(record_->pulseStream() , (const void**) &data , &bytes) < 0 or !data) return; +#ifdef RECTODISK + outfile.write((const char *)data, bytes); +#endif + + size_t samples = bytes / sample_size; + + AudioBuffer in(samples, channels, sampleRate_); + in.deinterleave((SFLAudioSample*)data, samples, channels); + unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate(); bool resample = sampleRate_ != mainBufferSampleRate; - if (resample) { + /*if (resample) { double resampleFactor = (double) sampleRate_ / mainBufferSampleRate; - bytes = (double) bytes * resampleFactor; - } - - size_t samples = bytes / sizeof(SFLDataFormat); + //bytes = (double) bytes * resampleFactor; + }*/ - if (bytes > mic_buf_size_) { + /*if (bytes > mic_buf_size_) { mic_buf_size_ = bytes; delete [] mic_buffer_; - mic_buffer_ = new SFLDataFormat[samples]; - } + mic_buffer_ = new SFLAudioSample[samples]; + }*/ + + AudioBuffer * out = ∈ -#ifdef RECTODISK - outfile.write((const char *)data, bytes); -#endif if (resample) { - converter_.resample((SFLDataFormat*)data, mic_buffer_, samples, mainBufferSampleRate, sampleRate_, samples); + mic_buffer_.setSampleRate(mainBufferSampleRate); + //converter_.resample((SFLAudioSample*)data, mic_buffer_, samples, mainBufferSampleRate, sampleRate_, samples); + converter_.resample(in, mic_buffer_); + out = &mic_buffer_; } - dcblocker_.process(mic_buffer_, (SFLDataFormat*)data, samples); - applyGain(mic_buffer_, bytes / sizeof(SFLDataFormat), getCaptureGain()); - Manager::instance().getMainBuffer().putData(mic_buffer_, bytes, MainBuffer::DEFAULT_ID); + dcblocker_.process(*out); + out->applyGain(playbackGain_); + Manager::instance().getMainBuffer().putData(*out, MainBuffer::DEFAULT_ID); + #ifdef RECTODISK - outfileResampled.write((const char *)mic_buffer_, bytes); + outfileResampled.write((const char *)out->getChannel(0), out->samples() * sizeof(SFLAudioSample)); #endif if (pa_stream_drop(record_->pulseStream()) < 0) @@ -483,6 +566,7 @@ void PulseLayer::ringtoneToSpeaker() return; pa_stream *s = ringtone_->pulseStream(); + size_t sample_size = ringtone_->sampleSize(); int writable = pa_stream_writable_size(s); @@ -499,11 +583,13 @@ void PulseLayer::ringtoneToSpeaker() AudioLoop *fileToPlay = Manager::instance().getTelephoneFile(); if (fileToPlay) { - fileToPlay->getNext((SFLDataFormat *) data, bytes / sizeof(SFLDataFormat), 100); - applyGain(static_cast<SFLDataFormat *>(data), bytes / sizeof(SFLDataFormat), getPlaybackGain()); - } - else + const unsigned samples = (bytes / sample_size) / ringtone_->channels(); + AudioBuffer tmp(samples, ringtone_->channels()); + fileToPlay->getNext(tmp, playbackGain_); + tmp.interleave((SFLAudioSample*) data); + } else { memset(data, 0, bytes); + } pa_stream_write(s, data, bytes, NULL, 0, PA_SEEK_RELATIVE); } @@ -514,8 +600,9 @@ PulseLayer::context_changed_callback(pa_context* c, uint32_t idx UNUSED, void *userdata) { PulseLayer *context = static_cast<PulseLayer*>(userdata); + switch (type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) { - pa_operation *op; + pa_operation *op; case PA_SUBSCRIPTION_EVENT_SINK: switch (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) { @@ -524,11 +611,14 @@ PulseLayer::context_changed_callback(pa_context* c, DEBUG("Updating sink list"); context->sinkList_.clear(); op = pa_context_get_sink_info_list(c, sink_input_info_callback, userdata); + if (op != NULL) pa_operation_unref(op); + default: break; } + break; case PA_SUBSCRIPTION_EVENT_SOURCE: @@ -538,12 +628,16 @@ PulseLayer::context_changed_callback(pa_context* c, DEBUG("Updating source list"); context->sourceList_.clear(); op = pa_context_get_source_info_list(c, source_input_info_callback, userdata); + if (op != NULL) pa_operation_unref(op); + default: break; } + break; + default: DEBUG("Unhandled event type 0x%x", type); break; @@ -562,32 +656,34 @@ void PulseLayer::source_input_info_callback(pa_context *c UNUSED, const pa_sourc } DEBUG("Source %u\n" - " Name: %s\n" - " Driver: %s\n" - " Description: %s\n" - " Sample Specification: %s\n" - " Channel Map: %s\n" - " Owner Module: %u\n" - " Volume: %s\n" - " Monitor if Sink: %u\n" - " Latency: %0.0f usec\n" - " Flags: %s%s%s\n", - i->index, - i->name, - i->driver, - i->description, - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), - pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), - i->owner_module, - i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume), - i->monitor_of_sink, - (double) i->latency, - i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", - i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", - i->flags & PA_SOURCE_HARDWARE ? "HARDWARE" : ""); - - if (not context->inSourceList(i->name)) - context->sourceList_.push_back(i->name); + " Name: %s\n" + " Driver: %s\n" + " Description: %s\n" + " Sample Specification: %s\n" + " Channel Map: %s\n" + " Owner Module: %u\n" + " Volume: %s\n" + " Monitor if Sink: %u\n" + " Latency: %0.0f usec\n" + " Flags: %s%s%s\n", + i->index, + i->name, + i->driver, + i->description, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + i->owner_module, + i->mute ? "muted" : pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + i->monitor_of_sink, + (double) i->latency, + i->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "", + i->flags & PA_SOURCE_LATENCY ? "LATENCY " : "", + i->flags & PA_SOURCE_HARDWARE ? "HARDWARE" : ""); + + if (not context->inSourceList(i->name)) { + PaDeviceInfos ep_infos(i->index, i->name, i->sample_spec, i->channel_map); + context->sourceList_.push_back(ep_infos); + } } void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_info *i, int eol, void *userdata) @@ -625,26 +721,32 @@ void PulseLayer::sink_input_info_callback(pa_context *c UNUSED, const pa_sink_in i->flags & PA_SINK_LATENCY ? "LATENCY " : "", i->flags & PA_SINK_HARDWARE ? "HARDWARE" : ""); - if (not context->inSinkList(i->name)) - context->sinkList_.push_back(i->name); + if (not context->inSinkList(i->name)) { + PaDeviceInfos ep_infos(i->index, i->name, i->sample_spec, i->channel_map); + context->sinkList_.push_back(ep_infos); + } } void PulseLayer::updatePreference(AudioPreference &preference, int index, PCMType type) { const std::string devName(getAudioDeviceName(index, type)); + switch (type) { case SFL_PCM_PLAYBACK: DEBUG("setting %s for playback", devName.c_str()); preference.setPulseDevicePlayback(devName); break; + case SFL_PCM_CAPTURE: DEBUG("setting %s for capture", devName.c_str()); preference.setPulseDeviceRecord(devName); break; + case SFL_PCM_RINGTONE: DEBUG("setting %s for ringer", devName.c_str()); preference.setPulseDeviceRingtone(devName); break; + default: break; } diff --git a/daemon/src/audio/pulseaudio/pulselayer.h b/daemon/src/audio/pulseaudio/pulselayer.h index ddba192f3759cd93178395b3010b2a9fc976783f..cb6fa6e481a17f17f466ec54aac39bb7c598a512 100644 --- a/daemon/src/audio/pulseaudio/pulselayer.h +++ b/daemon/src/audio/pulseaudio/pulselayer.h @@ -3,6 +3,7 @@ * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * Author: Андрей Лухнов <aol.nnov@gmail.com> + * Author: Adrien Beraud <adrien.beraud@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,10 +40,38 @@ #include <pulse/stream.h> #include "audio/audiolayer.h" #include "noncopyable.h" +#include "logger.h" class AudioPreference; class AudioStream; +/** + * Convenience structure to hold PulseAudio device propreties such as supported channel number etc. + */ +typedef struct PaDeviceInfos { + uint32_t index; + std::string name; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + + PaDeviceInfos(unsigned idx, const char* ep_name, const pa_sample_spec &samp_spec, const pa_channel_map &chan_map) + : index(idx), name(ep_name), sample_spec(samp_spec), channel_map(chan_map) {} + virtual ~PaDeviceInfos() {} + + /** + * Unary function to search for a device by name in a list using std functions. + */ + class nameComparator { + public: + explicit nameComparator(const std::string &ref) : baseline(ref) {} + bool operator()(const PaDeviceInfos &arg) { + return arg.name == baseline; + } + private: + const std::string &baseline; + }; +} PaDeviceInfos; + class PulseLayer : public AudioLayer { public: PulseLayer(AudioPreference &pref); @@ -60,13 +89,14 @@ class PulseLayer : public AudioLayer { void updateSourceList(); - bool inSinkList(const std::string &deviceName) const; + bool inSinkList(const std::string &deviceName); - bool inSourceList(const std::string &deviceName) const; + bool inSourceList(const std::string &deviceName); virtual std::vector<std::string> getCaptureDeviceList() const; virtual std::vector<std::string> getPlaybackDeviceList() const; int getAudioDeviceIndex(const std::string& name) const; + std::string getAudioDeviceName(int index, PCMType type) const; virtual void startStream(); @@ -122,18 +152,22 @@ class PulseLayer : public AudioLayer { /** * Contain the list of playback devices */ - std::vector<std::string> sinkList_; + std::vector<PaDeviceInfos> sinkList_; /** * Contain the list of capture devices */ - std::vector<std::string> sourceList_; + std::vector<PaDeviceInfos> sourceList_; + + /** + * Returns a pointer to the PaEndpointInfos with the given name in sourceList_, or NULL if not found. + */ + const PaDeviceInfos* getDeviceInfos(const std::vector<PaDeviceInfos>&, const std::string& name) const; /* * Buffers used to avoid doing malloc/free in the audio thread */ - SFLDataFormat *mic_buffer_; - size_t mic_buf_size_; + AudioBuffer mic_buffer_; /** PulseAudio context and asynchronous loop */ pa_context* context_; diff --git a/daemon/src/audio/recordable.cpp b/daemon/src/audio/recordable.cpp index ebf30ee24da732c4dabf7030a679ab23a272f1d5..4696c8de4fb11756e4e2b70a175372ba0d50d727 100644 --- a/daemon/src/audio/recordable.cpp +++ b/daemon/src/audio/recordable.cpp @@ -31,10 +31,10 @@ #include "manager.h" #include "logger.h" -Recordable::Recordable() : recAudio_(), recorder_(&recAudio_, &Manager::instance().getMainBuffer()) +Recordable::Recordable() : recAudio_(), recorder_(&recAudio_, Manager::instance().getMainBuffer()) { DEBUG("Set recording options: %s", Manager::instance().audioPreference.getRecordPath().c_str()); - recAudio_.setRecordingOption(AudioRecord::FILE_WAV, 8000, Manager::instance().audioPreference.getRecordPath()); + recAudio_.setRecordingOptions(8000, Manager::instance().audioPreference.getRecordPath()); } Recordable::~Recordable() diff --git a/daemon/src/audio/ringbuffer.cpp b/daemon/src/audio/ringbuffer.cpp index a37e3ecce67a9e93ec21f5bc20d723b55ce19b7a..e054affba4785ff61ded42995750dffe0fabaee0 100644 --- a/daemon/src/audio/ringbuffer.cpp +++ b/daemon/src/audio/ringbuffer.cpp @@ -3,6 +3,7 @@ * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author: Adrien Beraud <adrien.beraud@gmail.com> * * Portions (c) Dominic Mazzoni (Audacity) * @@ -40,18 +41,18 @@ #include "ringbuffer.h" namespace { - // corresponds to 106 ms (about 5 rtp packets) - const size_t MIN_BUFFER_SIZE = 1280; +// corresponds to 160 ms (about 5 rtp packets) +const size_t MIN_BUFFER_SIZE = 1280; } // Create a ring buffer with 'size' bytes RingBuffer::RingBuffer(size_t size, const std::string &call_id) : - endPos_(0) - , bufferSize_(size > MIN_BUFFER_SIZE ? size : MIN_BUFFER_SIZE) - , buffer_(bufferSize_) + endPos_(0) + , buffer_(std::max(size, MIN_BUFFER_SIZE), 1) , readpointers_() , buffer_id_(call_id) -{} +{ +} void RingBuffer::flush(const std::string &call_id) @@ -72,19 +73,21 @@ RingBuffer::flushAll() size_t RingBuffer::putLength() const { + const size_t buffer_size = buffer_.samples(); const size_t startPos = (not readpointers_.empty()) ? getSmallestReadPointer() : 0; - return (endPos_ + bufferSize_ - startPos) % bufferSize_; + return (endPos_ + buffer_size - startPos) % buffer_size; } size_t RingBuffer::getLength(const std::string &call_id) const { - return (endPos_ + bufferSize_ - getReadPointer(call_id)) % bufferSize_; + const size_t buffer_size = buffer_.samples(); + return (endPos_ + buffer_size - getReadPointer(call_id)) % buffer_size; } void RingBuffer::debug() { - DEBUG("Start=%d; End=%d; BufferSize=%d", getSmallestReadPointer(), endPos_, bufferSize_); + DEBUG("Start=%d; End=%d; BufferSize=%d", getSmallestReadPointer(), endPos_, buffer_.samples()); } size_t RingBuffer::getReadPointer(const std::string &call_id) const @@ -102,7 +105,7 @@ RingBuffer::getSmallestReadPointer() const if (hasNoReadPointers()) return 0; - size_t smallest = bufferSize_; + size_t smallest = buffer_.samples(); ReadPointer::const_iterator iter; @@ -160,29 +163,35 @@ bool RingBuffer::hasNoReadPointers() const // // This one puts some data inside the ring buffer. -void -RingBuffer::put(void* buffer, size_t toCopy) +void RingBuffer::put(AudioBuffer& buf) { const size_t len = putLength(); + const size_t sample_num = buf.samples(); + const size_t buffer_size = buffer_.samples(); + size_t toCopy = sample_num; - if (toCopy > bufferSize_ - len) - toCopy = bufferSize_ - len; + // Add more channels if the input buffer holds more channels than the ring. + if (buffer_.channels() < buf.channels()) + buffer_.setChannelNum(buf.channels()); - unsigned char *src = static_cast<unsigned char *>(buffer); + if (toCopy > buffer_size - len) + toCopy = buffer_size - len; + size_t in_pos = 0; size_t pos = endPos_; while (toCopy) { size_t block = toCopy; - if (block > bufferSize_ - pos) // Wrap block around ring ? - block = bufferSize_ - pos; // Fill in to the end of the buffer + if (block > buffer_size - pos) // Wrap block around ring ? + block = buffer_size - pos; // Fill in to the end of the buffer - memcpy(&(*buffer_.begin()) + pos, src, block); - src += block; - pos = (pos + block) % bufferSize_; + buffer_.copy(buf, block, in_pos, pos); + in_pos += block; + pos = (pos + block) % buffer_size; toCopy -= block; } + endPos_ = pos; } @@ -198,8 +207,7 @@ RingBuffer::availableForGet(const std::string &call_id) const } // Get will move 'toCopy' bytes from the internal FIFO to 'buffer' -size_t -RingBuffer::get(void *buffer, size_t toCopy, const std::string &call_id) +size_t RingBuffer::get(AudioBuffer& buf, const std::string &call_id) { if (hasNoReadPointers()) return 0; @@ -208,24 +216,25 @@ RingBuffer::get(void *buffer, size_t toCopy, const std::string &call_id) return 0; const size_t len = getLength(call_id); - - if (toCopy > len) - toCopy = len; + const size_t sample_num = buf.samples(); + const size_t buffer_size = buffer_.samples(); + size_t toCopy = std::min(sample_num, len); const size_t copied = toCopy; - unsigned char *dest = (unsigned char *) buffer; + size_t dest = 0; size_t startPos = getReadPointer(call_id); while (toCopy > 0) { size_t block = toCopy; - if (block > bufferSize_ - startPos) - block = bufferSize_ - startPos; + if (block > buffer_size - startPos) + block = buffer_size - startPos; + + buf.copy(buffer_, block, startPos, dest); - memcpy(dest, &(*buffer_.begin()) + startPos, block); dest += block; - startPos = (startPos + block) % bufferSize_; + startPos = (startPos + block) % buffer_size; toCopy -= block; } @@ -241,7 +250,8 @@ RingBuffer::discard(size_t toDiscard, const std::string &call_id) if (toDiscard > len) toDiscard = len; - size_t startPos = (getReadPointer(call_id) + toDiscard) % bufferSize_; + size_t buffer_size = buffer_.samples(); + size_t startPos = (getReadPointer(call_id) + toDiscard) % buffer_size; storeReadPointer(startPos, call_id); diff --git a/daemon/src/audio/ringbuffer.h b/daemon/src/audio/ringbuffer.h index b4c4b3a4922bd459a3496e321b461afc7a571241..9977e8978508ff1ea0a0444aa34bcbf287b54d27 100644 --- a/daemon/src/audio/ringbuffer.h +++ b/daemon/src/audio/ringbuffer.h @@ -3,6 +3,7 @@ * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author: Adrien Beraud <adrien.beraud@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,10 +26,15 @@ #include <fstream> #include <vector> #include <map> + #include "noncopyable.h" +#include "audiobuffer.h" typedef std::map<std::string, size_t> ReadPointer; +/** + * A ring buffer for mutichannel audio samples + */ class RingBuffer { public: /** @@ -92,11 +98,11 @@ class RingBuffer { * @param buffer Data to copied * @param toCopy Number of bytes to copy */ - void put(void* buffer, size_t toCopy); + void put(AudioBuffer& buf); /** - * To get how much space is available in the buffer to read in - * @return int The available size + * To get how much samples are available in the buffer to read in + * @return int The available (multichannel) samples number */ size_t availableForGet(const std::string &call_id) const; @@ -106,12 +112,12 @@ class RingBuffer { * @param toCopy Number of bytes to copy * @return size_t Number of bytes copied */ - size_t get(void* buffer, size_t toCopy, const std::string &call_id); + size_t get(AudioBuffer& buf, const std::string &call_id); /** * Discard data from the buffer - * @param toDiscard Number of bytes to discard - * @return size_t Number of bytes discarded + * @param toDiscard Number of samples to discard + * @return size_t Number of samples discarded */ size_t discard(size_t toDiscard, const std::string &call_id); @@ -129,14 +135,13 @@ class RingBuffer { void debug(); private: + /* POULET! */ NON_COPYABLE(RingBuffer); /** Pointer on the last data */ size_t endPos_; - /** Buffer size */ - size_t bufferSize_; /** Data */ - std::vector<unsigned char> buffer_; + AudioBuffer buffer_; ReadPointer readpointers_; std::string buffer_id_; diff --git a/daemon/src/audio/samplerateconverter.cpp b/daemon/src/audio/samplerateconverter.cpp index 8397f1a9e79381888ca68b2df3cf59d6e2634fb9..337e0df4f654b4c88b87bbeebcc57931434c22e4 100644 --- a/daemon/src/audio/samplerateconverter.cpp +++ b/daemon/src/audio/samplerateconverter.cpp @@ -29,76 +29,81 @@ */ #include "samplerateconverter.h" -#include "manager.h" -#include <cassert> -#include "logger.h" +#include "sfl_types.h" -SamplerateConverter::SamplerateConverter(int freq) : floatBufferIn_(0), - floatBufferOut_(0), samples_(0), maxFreq_(freq), src_state_(0) +SamplerateConverter::SamplerateConverter(int freq, size_t channels /* = 1 */) : floatBufferIn_(), + floatBufferOut_(), samples_(0), channels_(channels), maxFreq_(freq), src_state_(0) { int err; - src_state_ = src_new(SRC_LINEAR, 1, &err); + src_state_ = src_new(SRC_LINEAR, channels_, &err); samples_ = (freq * 20) / 1000; // start with 20 ms buffers - floatBufferIn_ = new float[samples_]; - floatBufferOut_ = new float[samples_]; + floatBufferIn_.resize(samples_); + floatBufferOut_.resize(samples_); } SamplerateConverter::~SamplerateConverter() { - delete [] floatBufferIn_; - delete [] floatBufferOut_; - src_delete(src_state_); } void -SamplerateConverter::Short2FloatArray(const short *in, float *out, int len) +SamplerateConverter::Short2FloatArray(const SFLAudioSample *in, float *out, int len) { // factor is 1/(2^15), used to rescale the short int range to the // [-1.0 - 1.0] float range. + static const float FACTOR = 1.0f / (1 << 15); while (len--) - out[len] = (float) in[len] * .000030517578125f; + out[len] = (float) in[len] * FACTOR; } -void SamplerateConverter::resample(SFLDataFormat *dataIn, - SFLDataFormat *dataOut, - size_t dataOutSize, int inputFreq, - int outputFreq, size_t nbSamples) +void SamplerateConverter::resample(const AudioBuffer &dataIn, AudioBuffer &dataOut) { - double sampleFactor = (double) outputFreq / inputFreq; + const double inputFreq = dataIn.getSampleRate(); + const double outputFreq = dataOut.getSampleRate(); + const double sampleFactor = outputFreq / inputFreq; if (sampleFactor == 1.0) return; - size_t outSamples = nbSamples * sampleFactor; - const unsigned int maxSamples = std::max(outSamples, nbSamples); + const size_t nbFrames = dataIn.samples(); + const size_t nbChans = dataIn.channels(); - if (maxSamples > samples_) { - /* grow buffer if needed */ - samples_ = maxSamples; - delete [] floatBufferIn_; - delete [] floatBufferOut_; - floatBufferIn_ = new float[samples_]; - floatBufferOut_ = new float[samples_]; + if (nbChans != channels_) { + // change channel num if needed + int err; + src_delete(src_state_); + src_state_ = src_new(SRC_LINEAR, nbChans, &err); + channels_ = nbChans; } + size_t inSamples = nbChans * nbFrames; + size_t outSamples = inSamples * sampleFactor; + + // grow buffer if needed + samples_ = std::max(inSamples, outSamples); + floatBufferIn_.resize(inSamples); + floatBufferOut_.resize(outSamples); + SRC_DATA src_data; - src_data.data_in = floatBufferIn_; - src_data.data_out = floatBufferOut_; - src_data.input_frames = nbSamples; - src_data.output_frames = outSamples; + src_data.data_in = floatBufferIn_.data(); + src_data.data_out = floatBufferOut_.data(); + src_data.input_frames = nbFrames; + src_data.output_frames = nbFrames * sampleFactor; src_data.src_ratio = sampleFactor; src_data.end_of_input = 0; // More data will come - Short2FloatArray(dataIn, floatBufferIn_, nbSamples); + dataIn.interleaveFloat(floatBufferIn_.data()); + src_process(src_state_, &src_data); - if (outSamples > dataOutSize) { - ERROR("Outsamples exceeds output buffer size, clamping to %u", dataOutSize); - outSamples = dataOutSize; - } - src_float_to_short_array(floatBufferOut_, dataOut, outSamples); + /* + TODO: one-shot deinterleave and float-to-short conversion + currently using floatBufferIn_ as scratch + */ + SFLAudioSample *scratch_buff = reinterpret_cast<SFLAudioSample *>(floatBufferIn_.data()); + src_float_to_short_array(floatBufferOut_.data(), scratch_buff, outSamples); + dataOut.deinterleave(scratch_buff, src_data.output_frames, nbChans); } diff --git a/daemon/src/audio/samplerateconverter.h b/daemon/src/audio/samplerateconverter.h index bb2c52aacb67a58ae7f2aa6d0e5c6ec800000596..2b533e208347e6359eaf78a511532118659b30e2 100644 --- a/daemon/src/audio/samplerateconverter.h +++ b/daemon/src/audio/samplerateconverter.h @@ -35,6 +35,7 @@ #include <cmath> #include <cstring> +#include "audiobuffer.h" #include "sfl_types.h" #include "noncopyable.h" @@ -47,7 +48,7 @@ class SamplerateConverter { * internal buffer size. Converter must be reinitialized * every time these parameters change */ - SamplerateConverter(int freq); + SamplerateConverter(int freq, size_t channels = 1); /** Destructor */ ~SamplerateConverter(); @@ -59,7 +60,8 @@ class SamplerateConverter { * @param SamplerateConverter2 The desired sample rate * @param nbSamples The number of samples to process */ - void resample(SFLDataFormat* dataIn, SFLDataFormat* dataOut, size_t dataOutSize, int oldrate, int newrate, size_t nbSamples); + //void resample(SFLAudioSample* dataIn, SFLAudioSample* dataOut, size_t dataOutSize, int oldrate, int newrate, size_t nbSamples); + void resample(const AudioBuffer& dataIn, AudioBuffer& dataOut); /** * Convert short table to floats for audio processing @@ -67,16 +69,18 @@ class SamplerateConverter { * @param out The resulting (float) array * @param len The number of elements in both tables */ - void Short2FloatArray(const short *in, float *out, int len); + void Short2FloatArray(const SFLAudioSample *in, float *out, int len); private: NON_COPYABLE(SamplerateConverter); /* temporary buffers */ - float * floatBufferIn_; - float * floatBufferOut_; + std::vector<float> floatBufferIn_; + std::vector<float> floatBufferOut_; + size_t samples_; // size in samples of temporary buffers + size_t channels_; // number of channels configured int maxFreq_; // maximal output frequency SRC_STATE* src_state_; diff --git a/daemon/src/audio/sound/audiofile.cpp b/daemon/src/audio/sound/audiofile.cpp index 227f1bad04dd02040bd0586e6b28c6dea7be64c2..3cfedd333e582e1dbfe5451b2ae916d432bf1be8 100644 --- a/daemon/src/audio/sound/audiofile.cpp +++ b/daemon/src/audio/sound/audiofile.cpp @@ -36,178 +36,99 @@ #include <cstring> #include <vector> #include <climits> +#include <sndfile.hh> #include "audiofile.h" -#include "audio/codecs/audiocodec.h" #include "audio/samplerateconverter.h" +#include "client/callmanager.h" +#include "manager.h" + #include "logger.h" -RawFile::RawFile(const std::string& name, sfl::AudioCodec *codec, unsigned int sampleRate) - : AudioFile(name, sampleRate), audioCodec_(codec) +void +AudioFile::onBufferFinish() { - if (filepath_.empty()) - throw AudioFileException("Unable to open audio file: filename is empty"); - - std::fstream file; - file.open(filepath_.c_str(), std::fstream::in); - - if (!file.is_open()) - throw AudioFileException("Unable to open audio file"); - - file.seekg(0, std::ios::end); - size_t length = file.tellg(); - file.seekg(0, std::ios::beg); - - std::vector<char> fileBuffer(length); - file.read(&fileBuffer[0], length); - file.close(); - - const unsigned int frameSize = audioCodec_->getFrameSize(); - const unsigned int bitrate = audioCodec_->getBitRate() * 1000 / 8; - const unsigned int audioRate = audioCodec_->getClockRate(); - const unsigned int encFrameSize = frameSize * bitrate / audioRate; - const unsigned int decodedSize = length * (frameSize / encFrameSize); - - SFLDataFormat *monoBuffer = new SFLDataFormat[decodedSize]; - SFLDataFormat *bufpos = monoBuffer; - unsigned char *filepos = reinterpret_cast<unsigned char *>(&fileBuffer[0]); - size_ = decodedSize; - - while (length >= encFrameSize) { - bufpos += audioCodec_->decode(bufpos, filepos, encFrameSize); - filepos += encFrameSize; - length -= encFrameSize; + // We want to send values in milisecond + const int divisor = buffer_->getSampleRate() / 1000; + + if (divisor == 0) { + ERROR("Error cannot update playback slider, sampling rate is 0"); + return; } - if (sampleRate == audioRate) - buffer_ = monoBuffer; - else { - double factord = (double) sampleRate / audioRate; - float* floatBufferIn = new float[size_]; - int sizeOut = ceil(factord * size_); - src_short_to_float_array(monoBuffer, floatBufferIn, size_); - delete [] monoBuffer; - delete [] buffer_; - buffer_ = new SFLDataFormat[sizeOut]; - - SRC_DATA src_data; - src_data.data_in = floatBufferIn; - src_data.input_frames = size_; - src_data.output_frames = sizeOut; - src_data.src_ratio = factord; - - float* floatBufferOut = new float[sizeOut]; - src_data.data_out = floatBufferOut; - - src_simple(&src_data, SRC_SINC_BEST_QUALITY, 1); - src_float_to_short_array(floatBufferOut, buffer_, src_data.output_frames_gen); - - delete [] floatBufferOut; - delete [] floatBufferIn; - size_ = src_data.output_frames_gen; + if ((updatePlaybackScale_ % 5) == 0) { + CallManager *cm = Manager::instance().getClient()->getCallManager(); + cm->updatePlaybackScale(filepath_, pos_ / divisor, buffer_->samples() / divisor); } -} + updatePlaybackScale_++; +} -WaveFile::WaveFile(const std::string &fileName, unsigned int sampleRate) : AudioFile(fileName, sampleRate) +AudioFile::AudioFile(const std::string &fileName, unsigned int sampleRate) : + AudioLoop(sampleRate), filepath_(fileName), updatePlaybackScale_(0) { - const std::fstream fs(fileName.c_str(), std::ios_base::in); - - if (!fs) - throw AudioFileException("File " + fileName + " doesn't exist"); - - std::fstream fileStream; - fileStream.open(fileName.c_str(), std::ios::in | std::ios::binary); - - char riff[4] = { 0, 0, 0, 0 }; - fileStream.read(riff, sizeof riff / sizeof *riff); - - if (strncmp("RIFF", riff, sizeof riff / sizeof *riff) != 0) - throw AudioFileException("File is not of RIFF format"); - - char fmt[4] = { 0, 0, 0, 0 }; - int maxIteration = 10; - - while (maxIteration-- and strncmp("fmt ", fmt, sizeof fmt / sizeof *fmt)) - fileStream.read(fmt, sizeof fmt / sizeof *fmt); - - if (maxIteration == 0) - throw AudioFileException("Could not find \"fmt \" chunk"); - - SINT32 chunkSize; // fmt chunk size - fileStream.read(reinterpret_cast<char *>(&chunkSize), sizeof chunkSize); // Read fmt chunk size. - unsigned short formatTag; // data compression tag - fileStream.read(reinterpret_cast<char *>(&formatTag), sizeof formatTag); - - if (formatTag != 1) // PCM = 1, FLOAT = 3 - throw AudioFileException("File contains an unsupported data format type"); - - // Get number of channels from the header. - SINT16 chan; - fileStream.read(reinterpret_cast<char *>(&chan), sizeof chan); - - if (chan > 2) - throw AudioFileException("WaveFile: unsupported number of channels"); - - // Get file sample rate from the header. - SINT32 fileRate; - fileStream.read(reinterpret_cast<char *>(&fileRate), sizeof fileRate); - - SINT32 avgb; - fileStream.read(reinterpret_cast<char *>(&avgb), sizeof avgb); - - SINT16 blockal; - fileStream.read(reinterpret_cast<char *>(&blockal), sizeof blockal); + int format; + bool hasHeader = true; + + if (filepath_.find(".wav") != std::string::npos) { + format = SF_FORMAT_WAV; + } else if (filepath_.find(".ul") != std::string::npos) { + format = SF_FORMAT_RAW | SF_FORMAT_ULAW; + hasHeader = false; + } else if (filepath_.find(".al") != std::string::npos) { + format = SF_FORMAT_RAW | SF_FORMAT_ALAW; + hasHeader = false; + } else if (filepath_.find(".au") != std::string::npos) { + format = SF_FORMAT_AU; + } else if (filepath_.find(".flac") != std::string::npos) { + format = SF_FORMAT_FLAC; + } else if (filepath_.find(".ogg") != std::string::npos) { + format = SF_FORMAT_OGG; + } else { + WARN("No file extension, guessing WAV"); + format = SF_FORMAT_WAV; + } - // Determine the data type - SINT16 dt; - fileStream.read(reinterpret_cast<char *>(&dt), sizeof dt); + SndfileHandle fileHandle(fileName.c_str(), SFM_READ, format, hasHeader ? 0 : 1, + hasHeader ? 0 : 8000); - if (dt != 8 && dt != 16 && dt != 32) - throw AudioFileException("File's bits per sample with is not supported"); + if (!fileHandle) + throw AudioFileException("File " + fileName + " doesn't exist"); - // Find the "data" chunk - char data[4] = { 0, 0, 0, 0 }; - maxIteration = 10; + switch (fileHandle.channels()) { + case 1: + case 2: + break; + default: + throw AudioFileException("Unsupported number of channels"); + } - while (maxIteration-- && strncmp("data", data, sizeof data / sizeof *data)) - fileStream.read(data, sizeof data / sizeof *data); + // get # of bytes in file + const size_t fileSize = fileHandle.seek(0, SEEK_END); + fileHandle.seek(0, SEEK_SET); - // Samplerate converter initialized with 88200 sample long - const int rate = static_cast<SINT32>(sampleRate_); - SamplerateConverter converter(std::max(fileRate, rate)); + const sf_count_t nbFrames = hasHeader ? fileHandle.frames() : fileSize / fileHandle.channels(); - // Get length of data from the header. - SINT32 bytes; - fileStream.read(reinterpret_cast<char *>(&bytes), sizeof bytes); - - // sample frames, should not be longer than a minute - int nbSamples = std::min(60 * fileRate, 8 * bytes / dt / chan); + SFLAudioSample * interleaved = new SFLAudioSample[nbFrames * fileHandle.channels()]; - DEBUG("Frame size %ld, data size %d align %d rate %d avgbyte %d " - "chunk size %d dt %d", nbSamples, bytes, blockal, fileRate, avgb, - chunkSize, dt); + // get n "items", aka samples (not frames) + fileHandle.read(interleaved, nbFrames * fileHandle.channels()); - size_ = nbSamples; - SFLDataFormat *tempBuffer = new SFLDataFormat[size_]; + AudioBuffer * buffer = new AudioBuffer(nbFrames, fileHandle.channels(), fileHandle.samplerate()); + buffer->deinterleave(interleaved, nbFrames, fileHandle.channels()); + delete [] interleaved; - fileStream.read(reinterpret_cast<char *>(tempBuffer), - nbSamples * sizeof(SFLDataFormat)); + const int rate = static_cast<int32_t>(sampleRate); - // mix two channels together if stereo - if (chan == 2) { - for (int i = 0, j = 0; i < nbSamples - 1; i += 2, ++j) - tempBuffer[j] = (tempBuffer[i] + tempBuffer[i + 1]) * 0.5; - nbSamples *= 0.5; + if (fileHandle.samplerate() != rate) { + SamplerateConverter converter(std::max(fileHandle.samplerate(), rate), fileHandle.channels()); + AudioBuffer * resampled = new AudioBuffer(nbFrames, fileHandle.channels(), rate); + converter.resample(*buffer, *resampled); + delete buffer; + delete buffer_; + buffer_ = resampled; + } else { + delete buffer_; + buffer_ = buffer; } - - if (fileRate != rate) { - const float ratio = sampleRate_ / (float) fileRate; - const int outSamples = ceil(nbSamples * ratio); - size_ = outSamples; - buffer_ = new SFLDataFormat[size_]; - converter.resample(tempBuffer, buffer_, size_, fileRate, sampleRate_, nbSamples); - delete [] tempBuffer; - } else - buffer_ = tempBuffer; } diff --git a/daemon/src/audio/sound/audiofile.h b/daemon/src/audio/sound/audiofile.h index 621e038a67b441c0cd65aab4e45c59f0ba0b43ba..ff3530b5e34de57559ca2b87e2d7a84d14741a03 100644 --- a/daemon/src/audio/sound/audiofile.h +++ b/daemon/src/audio/sound/audiofile.h @@ -37,10 +37,6 @@ #include <stdexcept> #include "audio/audioloop.h" -namespace sfl { -class AudioCodec; -} - class AudioFileException : public std::runtime_error { public: AudioFileException(const std::string &str) : @@ -52,8 +48,7 @@ class AudioFileException : public std::runtime_error { */ class AudioFile : public AudioLoop { public: - AudioFile(const std::string &filepath, unsigned int sampleRate) : AudioLoop(sampleRate), filepath_(filepath) - {} + AudioFile(const std::string &filepath, unsigned int sampleRate); std::string getFilePath() const { return filepath_; @@ -62,30 +57,11 @@ class AudioFile : public AudioLoop { protected: /** The absolute path to the sound file */ std::string filepath_; -}; - -class RawFile : public AudioFile { - public: - /** - * Constructor - */ - RawFile(const std::string& name, sfl::AudioCodec* codec, unsigned int sampleRate = 8000); private: - NON_COPYABLE(RawFile); - - /** Your preferred codec */ - sfl::AudioCodec* audioCodec_; -}; - -class WaveFile : public AudioFile { - public: - /** - * Load a sound file in memory - * @param filename The absolute path to the file - * @param sampleRate The sample rate to read it - */ - WaveFile(const std::string&, unsigned int sampleRate); + // override + void onBufferFinish(); + unsigned updatePlaybackScale_; }; #endif // __AUDIOFILE_H__ diff --git a/daemon/src/audio/sound/dtmf.cpp b/daemon/src/audio/sound/dtmf.cpp index afddf9beac09825bd883d6be782508045bc56e8c..5a70553909c8c521ac218a43b333127991f72436 100644 --- a/daemon/src/audio/sound/dtmf.cpp +++ b/daemon/src/audio/sound/dtmf.cpp @@ -45,7 +45,7 @@ void DTMF::startTone(char code) using std::vector; -bool DTMF::generateDTMF(vector<SFLDataFormat> &buffer) +bool DTMF::generateDTMF(vector<SFLAudioSample> &buffer) { try { if (currentTone_ != 0) { @@ -71,8 +71,7 @@ bool DTMF::generateDTMF(vector<SFLDataFormat> &buffer) dtmfgenerator_.getSamples(buffer, newTone_); currentTone_ = newTone_; return true; - } - else + } else return false; } } catch (const DTMFException &e) { diff --git a/daemon/src/audio/sound/dtmf.h b/daemon/src/audio/sound/dtmf.h index 7b1ebc5d4659146f7c05a5df7ace297144f01897..f53c36671bf3dcbd68a140443dd20593e0047a7d 100644 --- a/daemon/src/audio/sound/dtmf.h +++ b/daemon/src/audio/sound/dtmf.h @@ -58,9 +58,9 @@ class DTMF { /** * Copy the sound inside the sampling* buffer - * @param buffer : a vector of SFLDataFormat + * @param buffer : a vector of SFLAudioSample */ - bool generateDTMF(std::vector<SFLDataFormat> &buffer); + bool generateDTMF(std::vector<SFLAudioSample> &buffer); private: char currentTone_; diff --git a/daemon/src/audio/sound/dtmfgenerator.cpp b/daemon/src/audio/sound/dtmfgenerator.cpp index ecf986d8a3c88cd1814402791f72aa128b668f5f..d7a32aac3e893c8709af3de8fc661d3a80f6f215 100644 --- a/daemon/src/audio/sound/dtmfgenerator.cpp +++ b/daemon/src/audio/sound/dtmfgenerator.cpp @@ -85,7 +85,7 @@ using std::vector; /* * Get n samples of the signal of code code */ -void DTMFGenerator::getSamples(vector<SFLDataFormat> &buffer, unsigned char code) +void DTMFGenerator::getSamples(vector<SFLAudioSample> &buffer, unsigned char code) { code = toupper(code); @@ -111,6 +111,7 @@ void DTMFGenerator::getSamples(vector<SFLDataFormat> &buffer, unsigned char code size_t i; const size_t n = buffer.size(); + for (i = 0; i < n; ++i) buffer[i] = state.sample[i % sampleRate_]; @@ -121,23 +122,24 @@ void DTMFGenerator::getSamples(vector<SFLDataFormat> &buffer, unsigned char code * Get next n samples (continues where previous call to * genSample or genNextSamples stopped */ -void DTMFGenerator::getNextSamples(vector<SFLDataFormat> &buffer) +void DTMFGenerator::getNextSamples(vector<SFLAudioSample> &buffer) { if (state.sample == 0) throw DTMFException("DTMF generator not initialized"); size_t i; const size_t n = buffer.size(); + for (i = 0; i < n; i++) buffer[i] = state.sample[(state.offset + i) % sampleRate_]; state.offset = (state.offset + i) % sampleRate_; } -SFLDataFormat* DTMFGenerator::fillToneBuffer(int index) +SFLAudioSample* DTMFGenerator::fillToneBuffer(int index) { assert(index >= 0 and index < NUM_TONES); - SFLDataFormat* ptr = new SFLDataFormat[sampleRate_]; - tone_.genSin(ptr, tones_[index].higher, tones_[index].lower, sampleRate_); + SFLAudioSample* ptr = new SFLAudioSample[sampleRate_]; + tone_.genSin(ptr, tones_[index].higher, tones_[index].lower, sampleRate_); return ptr; } diff --git a/daemon/src/audio/sound/dtmfgenerator.h b/daemon/src/audio/sound/dtmfgenerator.h index 742d88607083108d290bf9baa52ceaf7d0234c6a..a9f600d792e76699f8e60a2ee58195e5df29388b 100644 --- a/daemon/src/audio/sound/dtmfgenerator.h +++ b/daemon/src/audio/sound/dtmfgenerator.h @@ -69,7 +69,7 @@ class DTMFGenerator { /** State of the DTMF generator */ struct DTMFState { unsigned int offset; /** Offset in the sample currently being played */ - SFLDataFormat* sample; /** Currently generated code */ + SFLAudioSample* sample; /** Currently generated code */ }; /** State of the DTMF generator */ @@ -79,7 +79,7 @@ class DTMFGenerator { static const DTMFTone tones_[NUM_TONES]; /** Generated samples for each tone */ - SFLDataFormat* toneBuffers_[NUM_TONES]; + SFLAudioSample* toneBuffers_[NUM_TONES]; /** Sampling rate of generated dtmf */ int sampleRate_; @@ -101,26 +101,26 @@ class DTMFGenerator { /* * Get n samples of the signal of code code - * @param buffer a SFLDataFormat vector + * @param buffer a SFLAudioSample vector * @param code dtmf code to get sound */ - void getSamples(std::vector<SFLDataFormat> &buffer, unsigned char code); + void getSamples(std::vector<SFLAudioSample> &buffer, unsigned char code); /* * Get next n samples (continues where previous call to * genSample or genNextSamples stopped - * @param buffer a SFLDataFormat vector + * @param buffer a SFLAudioSample vector */ - void getNextSamples(std::vector<SFLDataFormat> &buffer); + void getNextSamples(std::vector<SFLAudioSample> &buffer); private: /** * Fill tone buffer for a given index of the array of tones. * @param index of the tone in the array tones_ - * @return SFLDataFormat* The generated data + * @return SFLAudioSample* The generated data */ - SFLDataFormat* fillToneBuffer(int index); + SFLAudioSample* fillToneBuffer(int index); }; #endif // DTMFGENERATOR_H diff --git a/daemon/src/audio/sound/tone.cpp b/daemon/src/audio/sound/tone.cpp index 64d793f2d77ebf03faba81323e09e9c614711f87..d8af35c64cabe9a1922bf39ad0880072cbac2d85 100644 --- a/daemon/src/audio/sound/tone.cpp +++ b/daemon/src/audio/sound/tone.cpp @@ -47,6 +47,9 @@ Tone::Tone(const std::string& definition, unsigned int sampleRate) : AudioLoop(sampleRate), xhigher_(0.0), xlower_(0.0) { fillWavetable(); + delete buffer_; + buffer_ = new AudioBuffer(); + buffer_->setSampleRate(sampleRate); genBuffer(definition); // allocate memory with definition parameter } @@ -56,10 +59,11 @@ Tone::genBuffer(const std::string& definition) if (definition.empty()) return; - size_ = 0; + size_t size = 0; + const int sampleRate = buffer_->getSampleRate(); - std::vector<SFLDataFormat> buffer(SIZEBUF); // 1kb - SFLDataFormat* bufferPos = &(*buffer.begin()); + std::vector<SFLAudioSample> buffer(SIZEBUF); // 1kb + SFLAudioSample* bufferPos = buffer.data(); // Number of format sections std::string::size_type posStart = 0; // position of precedent comma @@ -80,7 +84,7 @@ Tone::genBuffer(const std::string& definition) { // Sample string: "350+440" or "350+440/2000,244+655/2000" int freq1, freq2, time; - s = definition.substr(posStart, posEnd-posStart); + s = definition.substr(posStart, posEnd - posStart); // The 1st frequency is before the first + or the / size_t pos_plus = s.find('+'); @@ -107,25 +111,22 @@ Tone::genBuffer(const std::string& definition) // If there is time or if it's unlimited if (time == 0) - count = sampleRate_; + count = sampleRate; else - count = (sampleRate_ * time) / 1000; + count = (sampleRate * time) / 1000; // Generate SAMPLING_RATE samples of sinus, buffer is the result genSin(bufferPos, freq1, freq2, count); // To concatenate the different buffers for each section. - size_ += count; + size += count; bufferPos += count; } /* end scope */ posStart = posEnd + 1; } while (posStart < deflen); - assert(!buffer_); - buffer_ = new SFLDataFormat[size_]; - - memcpy(buffer_, &(*buffer.begin()), size_ * sizeof(SFLDataFormat)); // copy char, not SFLDataFormat. + buffer_->copy(buffer.data(), size); // fill the buffer } void @@ -154,13 +155,13 @@ Tone::interpolate(double x) const } void -Tone::genSin(SFLDataFormat* buffer, int frequency1, int frequency2, int nb) +Tone::genSin(SFLAudioSample* buffer, int frequency1, int frequency2, int nb) { xhigher_ = 0.0; xlower_ = 0.0; - double sr = sampleRate_; - double tableSize = TABLE_LENGTH; + const double sr = (double)buffer_->getSampleRate(); + static const double tableSize = TABLE_LENGTH; double N_h = sr / frequency1; double N_l = sr / frequency2; diff --git a/daemon/src/audio/sound/tone.h b/daemon/src/audio/sound/tone.h index 4c9bab9c9f61bd3e5e4d192a007e7ac679102f9d..586c61f5a215d943d0712d5893b2bb2f5944aa94 100644 --- a/daemon/src/audio/sound/tone.h +++ b/daemon/src/audio/sound/tone.h @@ -66,7 +66,7 @@ class Tone : public AudioLoop { * @param nb are the number of int16 (mono) to generate * by example nb=5 generate 10 int16, 5 for the left, 5 for the right */ - void genSin(SFLDataFormat* buffer, int frequency1, int frequency2, int nb); + void genSin(SFLAudioSample* buffer, int frequency1, int frequency2, int nb); /** * diff --git a/daemon/src/client/Makefile.am b/daemon/src/client/Makefile.am new file mode 100644 index 0000000000000000000000000000000000000000..ee8f397a3a2d28aaee475e55c0fef64e3db22175 --- /dev/null +++ b/daemon/src/client/Makefile.am @@ -0,0 +1 @@ +SUBDIRS=dbus diff --git a/daemon/src/client/android/JavaJNI2CJNI_Load.py b/daemon/src/client/android/JavaJNI2CJNI_Load.py new file mode 100755 index 0000000000000000000000000000000000000000..0f3485af5b8091748b08e04b5fbdcc8a25875fa9 --- /dev/null +++ b/daemon/src/client/android/JavaJNI2CJNI_Load.py @@ -0,0 +1,85 @@ +#!/usr/bin/python +import getopt, sys +import re +from string import Template + +def type_to_signature(itype): + if len(itype) > 2: + if itype[-2:] == '[]': + return "[%s" % type_to_signature(itype[:-2]) + if itype == "int": + return "I" + if itype == "long": + return "J" + if itype == "void": + return "V" + if itype == "boolean": + return "Z" + if itype == "byte": + return "B" + if itype == "char": + return "C" + if itype == "short": + return "S" + if itype == "float": + return "F" + if itype == "double": + return "D" + if itype == "String": + return "Ljava/lang/String;" + if itype == "Object": + return "Ljava/lang/Object;" + return "Lcom/savoirfairelinux/sflphone/service/%s;" % itype + +def parse_java_file(input_stream, package, module): + outputs = [] + package_prefix = "Java_%s_%sJNI" % (package.replace(".", "_"), module) + for line in input_stream: + definition = re.match(r'.*public final static native ([^\( ]*) ([^\)]*)\(([^)]*)\).*',line) + if definition is not None: + retour = definition.group(1) + name = definition.group(2) + args = definition.group(3) + args_sigs = [] + args_frags = args.split(',') + for args_frag in args_frags: + argf = re.match(r'(\b)?([^ ]+) .*', args_frag.strip()) + if argf is not None: + args_sigs.append(type_to_signature(argf.group(2))) + sig = "(%s)%s" % (''.join(args_sigs), type_to_signature(retour)) + outputs.append("{\"%s\", \"%s\", (void*)& %s_%s}" % (name, sig, package_prefix, name.replace('_', '_1'))) + return outputs + +def render_to_template(defs, template_string): + template = Template(template_string) + return template.substitute(defs= ",\r\n".join(defs) ) + + +if __name__ == "__main__": + try: + opts, args = getopt.getopt(sys.argv[1:], "i:o:t:m:p:", ["input=", "output=", "template=", "module=", "package="]) + except getopt.GetoptError, err: + # print help information and exit: + print str(err) # will print something like "option -a not recognized" + sys.exit(2) + input_stream = None + output_file = None + template_string = None + package = "" + module = "" + for o, a in opts: + if o in ("-i", "--input"): + input_stream = open(a) + if o in ("-o", "--output"): + output_file = open(a, "w") + if o in ("-t", "--template"): + template_string = open(a).read() + if o in ("-m", "--module"): + module = a + if o in ("-p", "--package"): + package = a + + defs = parse_java_file(input_stream, package, module) + output_file.write(render_to_template(defs, template_string)) + output_file.close() + input_stream.close() diff --git a/daemon/src/client/android/callmanager.cpp b/daemon/src/client/android/callmanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8a1456b6b8ec8b3221b2b12e7d2c657becb6b032 --- /dev/null +++ b/daemon/src/client/android/callmanager.cpp @@ -0,0 +1,500 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> + * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> + * Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ +#include <vector> + +#include "global.h" +#include "client/callmanager.h" +#include "jni_callbacks.h" + +#include "sip/sipcall.h" +#include "sip/sipvoiplink.h" +#include "audio/audiolayer.h" +#include "audio/audiortp/audio_rtp_factory.h" +#if HAVE_ZRTP +#include "audio/audiortp/audio_zrtp_session.h" +#endif + +#include "logger.h" +#include "manager.h" + +CallManager::CallManager() +{} + +bool CallManager::placeCall(const std::string& accountID, + const std::string& callID, + const std::string& to) +{ + // Check if a destination number is available + if (to.empty()) { + DEBUG("No number entered - Call stopped"); + return false; + } else { + return Manager::instance().outgoingCall(accountID, callID, to); + } +} + +bool +CallManager::refuse(const std::string& callID) +{ + return Manager::instance().refuseCall(callID); +} + +bool +CallManager::accept(const std::string& callID) +{ + return Manager::instance().answerCall(callID); +} + +bool +CallManager::hangUp(const std::string& callID) +{ + return Manager::instance().hangupCall(callID); +} + +bool +CallManager::hangUpConference(const std::string& confID) +{ + return Manager::instance().hangupConference(confID); +} + +bool +CallManager::hold(const std::string& callID) +{ + return Manager::instance().onHoldCall(callID); +} + +bool +CallManager::unhold(const std::string& callID) +{ + return Manager::instance().offHoldCall(callID); +} + +bool +CallManager::transfer(const std::string& callID, const std::string& to) +{ + return Manager::instance().transferCall(callID, to); +} + +bool CallManager::attendedTransfer(const std::string& transferID, const std::string& targetID) +{ + return Manager::instance().attendedTransfer(transferID, targetID); +} + +void CallManager::setVolume(const std::string& device, const double& value) +{ + AudioLayer *audiolayer = Manager::instance().getAudioDriver(); + + if(!audiolayer) { + ERROR("Audio layer not valid while updating volume"); + return; + } + + DEBUG("DBUS set volume for %s: %f", device.c_str(), value); + + if (device == "speaker") { + audiolayer->setPlaybackGain((int)(value * 100.0)); + } else if (device == "mic") { + audiolayer->setCaptureGain((int)(value * 100.0)); + } + + //volumeChanged(device, value); +} + +double +CallManager::getVolume(const std::string& device) +{ + AudioLayer *audiolayer = Manager::instance().getAudioDriver(); + + if(!audiolayer) { + ERROR("Audio layer not valid while updating volume"); + return 0.0; + } + + if (device == "speaker") + return audiolayer->getPlaybackGain() / 100.0; + else if (device == "mic") + return audiolayer->getCaptureGain() / 100.0; + + return 0; +} + +void +CallManager::sendTextMessage(const std::string& callID, const std::string& message, const std::string& from) +{ +#if HAVE_INSTANT_MESSAGING + Manager::instance().sendTextMessage(callID, message, from); +#endif +} + +void +CallManager::sendTextMessage(const std::string& callID, const std::string& message) +{ +#if HAVE_INSTANT_MESSAGING + try{ + Manager::instance().sendTextMessage(callID, message, "Me"); + }catch(...){ + ERROR("Could not send \"%s\" text message to %s", message.c_str(), callID.c_str()); + } + +#else + ERROR("Could not send \"%s\" text message to %s since SFLphone daemon does not support it, please recompile with instant messaging support", message.c_str(), callID.c_str()); +#endif +} + + +bool CallManager::toggleRecording(const std::string& id) +{ + return Manager::instance().toggleRecordingCall(id); +} + +bool +CallManager::joinParticipant(const std::string& sel_callID, const std::string& drag_callID) +{ + return Manager::instance().joinParticipant(sel_callID, drag_callID); +} + +void +CallManager::createConfFromParticipantList(const std::vector<std::string>& participants) +{ + Manager::instance().createConfFromParticipantList(participants); +} + +void +CallManager::removeConference(const std::string& conference_id) +{ + Manager::instance().removeConference(conference_id); +} + +bool +CallManager::addParticipant(const std::string& callID, const std::string& confID) +{ + return Manager::instance().addParticipant(callID, confID); +} + +bool +CallManager::addMainParticipant(const std::string& confID) +{ + return Manager::instance().addMainParticipant(confID); +} + +bool +CallManager::detachParticipant(const std::string& callID) +{ + return Manager::instance().detachParticipant(callID); +} + +bool +CallManager::joinConference(const std::string& sel_confID, const std::string& drag_confID) +{ + return Manager::instance().joinConference(sel_confID, drag_confID); +} + +bool +CallManager::holdConference(const std::string& confID) +{ + return Manager::instance().holdConference(confID); +} + +bool +CallManager::unholdConference(const std::string& confID) +{ + return Manager::instance().unHoldConference(confID); +} + +bool +CallManager::isConferenceParticipant(const std::string& call_id) +{ + return Manager::instance().isConferenceParticipant(call_id); +} + +std::map<std::string, std::string> +CallManager::getConferenceDetails(const std::string& callID) +{ + return Manager::instance().getConferenceDetails(callID); +} + +std::vector<std::string> +CallManager::getConferenceList() +{ + return Manager::instance().getConferenceList(); +} + +std::vector<std::string> +CallManager::getParticipantList(const std::string& confID) +{ + return Manager::instance().getParticipantList(confID); +} + +std::string +CallManager::getConferenceId(const std::string& callID) +{ + return Manager::instance().getConferenceId(callID); +} + +bool +CallManager::startRecordedFilePlayback(const std::string& filepath) +{ + return Manager::instance().startRecordedFilePlayback(filepath); +} + +void +CallManager::stopRecordedFilePlayback(const std::string& filepath) +{ + Manager::instance().stopRecordedFilePlayback(filepath); +} + +void +CallManager::recordPlaybackSeek(const double& value) +{ + Manager::instance().recordingPlaybackSeek(value); +} + +bool +CallManager::getIsRecording(const std::string& callID) +{ + return Manager::instance().isRecording(callID); +} + +std::string CallManager::getCurrentAudioCodecName(const std::string& callID) +{ + return Manager::instance().getCurrentAudioCodecName(callID); +} + +std::map<std::string, std::string> +CallManager::getCallDetails(const std::string& callID) +{ + return Manager::instance().getCallDetails(callID); +} + +std::vector<std::string> +CallManager::getCallList() +{ + return Manager::instance().getCallList(); +} + +void +CallManager::playDTMF(const std::string& key) +{ + Manager::instance().sendDtmf(Manager::instance().getCurrentCallId(), key.data()[0]); +} + +void +CallManager::startTone(const int32_t& start , const int32_t& type) +{ + if (start) { + if (type == 0) + Manager::instance().playTone(); + else + Manager::instance().playToneWithMessage(); + } else + Manager::instance().stopTone(); +} + +// TODO: this will have to be adapted +// for conferencing in order to get +// the right pointer for the given +// callID. +#if HAVE_ZRTP +sfl::AudioZrtpSession * +CallManager::getAudioZrtpSession(const std::string& callID) +{ + // IP2IP profile is associated with IP2IP profile anyway + SIPVoIPLink * link = static_cast<SIPVoIPLink *>(Manager::instance().getAccountLink(SIPAccount::IP2IP_PROFILE)); + + if (!link) + throw CallManagerException("Failed to get sip link"); + + SIPCall *call; + + try { + call = link->getSIPCall(callID); + } catch (const VoipLinkException &e) { + throw CallManagerException("Call id " + callID + " is not valid"); + } + + sfl::AudioZrtpSession * zSession = call->getAudioRtp().getAudioZrtpSession(); + + if (!zSession) + throw CallManagerException("Failed to get AudioZrtpSession"); + + return zSession; +} +#endif + +void +CallManager::setSASVerified(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->SASVerified(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManager::resetSASVerified(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->resetSASVerified(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManager::setConfirmGoClear(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->goClearOk(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManager::requestGoClear(const std::string& callID) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->requestGoClear(); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void +CallManager::acceptEnrollment(const std::string& callID, const bool& accepted) +{ +#if HAVE_ZRTP + try { + sfl::AudioZrtpSession * zSession; + zSession = getAudioZrtpSession(callID); + zSession->acceptEnrollment(accepted); + } catch (...) { + } +#else + ERROR("No zrtp support for %s, please recompile SFLphone with zrtp", callID.c_str()); +#endif +} + +void CallManager::callStateChanged(const std::string& callID, const std::string& state) +{ + on_call_state_changed_wrapper(callID, state); +} + +void CallManager::transferFailed() +{ + +} + +void CallManager::transferSucceeded() +{ + +} + +void CallManager::recordPlaybackStopped(const std::string& path) +{ + +} + +void CallManager::voiceMailNotify(const std::string& callID, const std::string& nd_msg) +{ + +} + +void CallManager::incomingMessage(const std::string& ID, const std::string& from, const std::string& msg) +{ + on_incoming_message_wrapper(ID, from, msg); +} + +void CallManager::incomingCall(const std::string& accountID, const std::string& callID, const std::string& from) +{ + on_incoming_call_wrapper(accountID, callID, from); +} + +void CallManager::recordPlaybackFilepath(const std::string& id, const std::string& filename) +{ + on_record_playback_filepath_wrapper(id, filename); +} + +void CallManager::conferenceCreated(const std::string& confID) +{ + on_conference_created_wrapper(confID); +} + +void CallManager::conferenceChanged(const std::string& confID,const std::string& state) +{ + on_conference_state_changed_wrapper(confID, state); +} + +void CallManager::conferenceRemoved(const std::string& confID) +{ + on_conference_removed_wrapper(confID); +} + +void CallManager::newCallCreated(const std::string& accountID, const std::string& callID, const std::string& to) +{ + on_new_call_created_wrapper(accountID, callID, to); +} + +void CallManager::registrationStateChanged(const std::string& accoundID, const std::string& state, const int32_t& code) +{ + on_account_state_changed_with_code_wrapper(accoundID, state, code); +} + +void CallManager::sipCallStateChanged(const std::string& accoundID, const std::string& state, const int32_t& code) +{ + +} + +void CallManager::updatePlaybackScale(const int32_t&, const int32_t&) +{ +} diff --git a/daemon/src/client/android/callmanager.i b/daemon/src/client/android/callmanager.i new file mode 100644 index 0000000000000000000000000000000000000000..33998b9cddda1e8867c77b2d2c5c89bc1a3d7e94 --- /dev/null +++ b/daemon/src/client/android/callmanager.i @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com> + * Alexandre Lision <alexnadre.L@savoirfairelinux.com> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +%header %{ + +#include "client/callmanager.h" + + +typedef struct callmanager_callback +{ + void (*on_new_call_created)(const std::string& accountID, + const std::string& callID, + const std::string& to); + + void (*on_call_state_changed)(const std::string& callID, + const std::string& state); + + void (*on_incoming_call)(const std::string& accountID, + const std::string& callID, + const std::string& from); + + void (*on_transfer_state_changed) (const std::string& result); + + void (*on_conference_created) (const std::string& confID); + + void (*on_conference_removed) (const std::string& confID); + + void (*on_conference_state_changed) (const std::string& confID, + const std::string& state); + + void (*on_incoming_message) (const std::string& ID, + const std::string& from, + const std::string& msg); + + void (*on_record_playback_filepath) (const std::string& id, + const std::string& filename); +} callmanager_callback_t; + + +class Callback { +public: + virtual ~Callback() {} + + virtual void on_new_call_created(const std::string& arg1, + const std::string& arg2, + const std::string& arg3) {} + + virtual void on_call_state_changed(const std::string& arg1, + const std::string& arg2) {} + + virtual void on_incoming_call(const std::string& arg1, + const std::string& arg2, + const std::string& arg3) {} + + virtual void on_transfer_state_changed (const std::string& arg1) {} + + virtual void on_conference_created (const std::string& arg1) {} + + virtual void on_conference_removed (const std::string& arg1) {} + + virtual void on_conference_state_changed (const std::string& arg1, + const std::string& arg2) {} + + virtual void on_incoming_message(const std::string& ID, + const std::string& from, + const std::string& msg) {} + + virtual void on_record_playback_filepath(const std::string& id, + const std::string& filename) {} +}; + + +static Callback* registeredCallbackObject = NULL; + +void on_new_call_created_wrapper (const std::string& accountID, + const std::string& callID, + const std::string& to) { + registeredCallbackObject->on_new_call_created(accountID, callID, to); +} + +void on_call_state_changed_wrapper(const std::string& callID, + const std::string& state) { + registeredCallbackObject->on_call_state_changed(callID, state); +} + +void on_incoming_call_wrapper (const std::string& accountID, + const std::string& callID, + const std::string& from) { + registeredCallbackObject->on_incoming_call(accountID, callID, from); +} + +void on_transfer_state_changed_wrapper (const std::string& result) { + registeredCallbackObject->on_transfer_state_changed(result); +} + +void on_conference_created_wrapper (const std::string& confID) { + registeredCallbackObject->on_conference_created(confID); +} + +void on_conference_removed_wrapper (const std::string& confID) { + registeredCallbackObject->on_conference_removed(confID); +} + +void on_conference_state_changed_wrapper (const std::string& confID, + const std::string& state) { + registeredCallbackObject->on_conference_state_changed(confID, state); +} + +void on_incoming_message_wrapper(const std::string& ID, const std::string& from, const std::string& msg) { + registeredCallbackObject->on_incoming_message(ID, from, msg); +} + +void on_record_playback_filepath_wrapper(const std::string& id, const std::string& filename){ + registeredCallbackObject->on_record_playback_filepath(id, filename); +} + +static struct callmanager_callback wrapper_callback_struct = { + &on_new_call_created_wrapper, + &on_call_state_changed_wrapper, + &on_incoming_call_wrapper, + &on_transfer_state_changed_wrapper, + &on_conference_created_wrapper, + &on_conference_removed_wrapper, + &on_conference_state_changed_wrapper, + &on_incoming_message_wrapper, + &on_record_playback_filepath_wrapper, +}; + +void setCallbackObject(Callback* callback) { + registeredCallbackObject = callback; +} + +%} + +%feature("director") Callback; + +class CallManager { +public: + bool placeCall(const std::string& accountID, const std::string& callID, const std::string& to); + + bool refuse(const std::string& callID); + bool accept(const std::string& callID); + bool hangUp(const std::string& callID); + bool hold(const std::string& callID); + bool unhold(const std::string& callID); + bool transfer(const std::string& callID, const std::string& to); + bool attendedTransfer(const std::string& transferID, const std::string& targetID); + std::map< std::string, std::string > getCallDetails(const std::string& callID); + std::vector< std::string > getCallList(); + + /* Conference related methods */ + void removeConference(const std::string& conference_id); + bool joinParticipant(const std::string& sel_callID, const std::string& drag_callID); + void createConfFromParticipantList(const std::vector< std::string >& participants); + bool isConferenceParticipant(const std::string& call_id); + bool addParticipant(const std::string& callID, const std::string& confID); + bool addMainParticipant(const std::string& confID); + bool detachParticipant(const std::string& callID); + bool joinConference(const std::string& sel_confID, const std::string& drag_confID); + bool hangUpConference(const std::string& confID); + bool holdConference(const std::string& confID); + bool unholdConference(const std::string& confID); + std::vector<std::string> getConferenceList(); + std::vector<std::string> getParticipantList(const std::string& confID); + std::string getConferenceId(const std::string& callID); + std::map<std::string, std::string> getConferenceDetails(const std::string& callID); + + /* File Playback methods */ + bool startRecordedFilePlayback(const std::string& filepath); + void stopRecordedFilePlayback(const std::string& filepath); + + /* General audio methods */ + void setVolume(const std::string& device, const double& value); + double getVolume(const std::string& device); + bool toggleRecording(const std::string& callID); + void recordPlaybackSeek(const double& value); + bool getIsRecording(const std::string& callID); + std::string getCurrentAudioCodecName(const std::string& callID); + void playDTMF(const std::string& key); + void startTone(const int32_t& start, const int32_t& type); + + /* Security related methods */ + void setSASVerified(const std::string& callID); + void resetSASVerified(const std::string& callID); + void setConfirmGoClear(const std::string& callID); + void requestGoClear(const std::string& callID); + void acceptEnrollment(const std::string& callID, const bool& accepted); + + /* Instant messaging */ + void sendTextMessage(const std::string& callID, const std::string& message); +}; + +class Callback { +public: + virtual ~Callback(); + + virtual void on_new_call_created(const std::string& arg1, + const std::string& arg2, + const std::string& arg3); + + virtual void on_call_state_changed(const std::string& arg1, + const std::string& arg2); + + virtual void on_incoming_call(const std::string& arg1, + const std::string& arg2, + const std::string& arg3); + + virtual void on_transfer_state_changed(const std::string& arg1); + + virtual void on_conference_created(const std::string& arg1); + + virtual void on_conference_removed(const std::string& arg1); + + virtual void on_conference_state_changed(const std::string& arg1, + const std::string& arg2); + + virtual void on_incoming_message(const std::string& ID, + const std::string& from, + const std::string& msg); + + virtual void on_record_playback_filepath(const std::string& id, + const std::string& filename); +}; + +static Callback* registeredCallbackObject = NULL; + +void setCallbackObject(Callback* callback) { + registeredCallbackObject = callback; +} diff --git a/daemon/src/client/android/client.cpp b/daemon/src/client/android/client.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5df2630a2101bdf7adb456329271bcaa120c53da --- /dev/null +++ b/daemon/src/client/android/client.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "client/client.h" +#include "client/callmanager.h" +#include "client/configurationmanager.h" + +Client::Client() : callManager_(new CallManager) + , configurationManager_(new ConfigurationManager) + , instanceManager_(0) + , dispatcher_(0) +#ifdef SFL_VIDEO + , videoControls_(0) +#endif +#ifdef USE_NETWORKMANAGER + , networkManager_(0) +#endif +{} + +Client::~Client() +{ +#ifdef USE_NETWORKMANAGER + delete networkManager_; +#endif +#ifdef SFL_VIDEO + delete videoControls_; +#endif + delete dispatcher_; + delete instanceManager_; + delete configurationManager_; + delete callManager_; +} + +void Client::event_loop() +{} + +void Client::exit() +{} diff --git a/daemon/src/client/android/configurationmanager.cpp b/daemon/src/client/android/configurationmanager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d3293e161a3383c3dcac2d4855ef2d132e8bf41 --- /dev/null +++ b/daemon/src/client/android/configurationmanager.cpp @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc. + * Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com> + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com> + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <cerrno> +#include <sstream> + +#include "client/configurationmanager.h" +#include "jni_callbacks.h" +#include "account_schema.h" +#include "manager.h" +#include "sip/sipvoiplink.h" +#include "sip/siptransport.h" +#include "logger.h" +#include "fileutils.h" +#include "sip/sipaccount.h" +#include "history/historynamecache.h" +#include "audio/audiolayer.h" + +namespace { + const char* SERVER_PATH = "/org/sflphone/SFLphone/ConfigurationManager"; +} + +ConfigurationManager::ConfigurationManager() {} + +std::map<std::string, std::string> ConfigurationManager::getIp2IpDetails() +{ + std::map<std::string, std::string> ip2ipAccountDetails; + SIPAccount *sipaccount = Manager::instance().getIP2IPAccount(); + + if (!sipaccount) { + ERROR("Could not find IP2IP account"); + return ip2ipAccountDetails; + } else + return sipaccount->getIp2IpDetails(); + + std::map<std::string, std::string> tlsSettings(getTlsSettings()); + std::copy(tlsSettings.begin(), tlsSettings.end(), + std::inserter(ip2ipAccountDetails, ip2ipAccountDetails.end())); + + return ip2ipAccountDetails; +} + + +std::map<std::string, std::string> ConfigurationManager::getAccountDetails( + const std::string& accountID) +{ + return Manager::instance().getAccountDetails(accountID); +} + +std::map<std::string, std::string> +ConfigurationManager::getTlsSettingsDefault() +{ + std::stringstream portstr; + portstr << DEFAULT_SIP_TLS_PORT; + + std::map<std::string, std::string> tlsSettingsDefault; + tlsSettingsDefault[CONFIG_TLS_LISTENER_PORT] = portstr.str(); + tlsSettingsDefault[CONFIG_TLS_CA_LIST_FILE] = ""; + tlsSettingsDefault[CONFIG_TLS_CERTIFICATE_FILE] = ""; + tlsSettingsDefault[CONFIG_TLS_PRIVATE_KEY_FILE] = ""; + tlsSettingsDefault[CONFIG_TLS_PASSWORD] = ""; + tlsSettingsDefault[CONFIG_TLS_METHOD] = "TLSv1"; + tlsSettingsDefault[CONFIG_TLS_CIPHERS] = ""; + tlsSettingsDefault[CONFIG_TLS_SERVER_NAME] = ""; + tlsSettingsDefault[CONFIG_TLS_VERIFY_SERVER] = "true"; + tlsSettingsDefault[CONFIG_TLS_VERIFY_CLIENT] = "true"; + tlsSettingsDefault[CONFIG_TLS_REQUIRE_CLIENT_CERTIFICATE] = "true"; + tlsSettingsDefault[CONFIG_TLS_NEGOTIATION_TIMEOUT_SEC] = "2"; + tlsSettingsDefault[CONFIG_TLS_NEGOTIATION_TIMEOUT_MSEC] = "0"; + + return tlsSettingsDefault; +} + +std::map<std::string, std::string> ConfigurationManager::getTlsSettings() +{ + std::map<std::string, std::string> tlsSettings; + + SIPAccount *sipaccount = Manager::instance().getIP2IPAccount(); + + if (!sipaccount) + return tlsSettings; + + return sipaccount->getTlsSettings(); +} + +void ConfigurationManager::setTlsSettings(const std::map<std::string, std::string>& details) +{ + SIPAccount *sipaccount = Manager::instance().getIP2IPAccount(); + + if (!sipaccount) { + DEBUG("No valid account in set TLS settings"); + return; + } + + sipaccount->setTlsSettings(details); + + // Manager::instance().saveConfig(); + + // Update account details to the client side + // accountsChanged(); +} + + +void ConfigurationManager::setAccountDetails(const std::string& accountID, const std::map<std::string, std::string>& details) +{ + Manager::instance().setAccountDetails(accountID, details); +} + +void ConfigurationManager::sendRegister(const std::string& accountID, const bool& enable) +{ + Manager::instance().sendRegister(accountID, enable); +} + +void ConfigurationManager::registerAllAccounts() +{ + Manager::instance().registerAllAccounts(); +} + +///This function is used as a base for new accounts for clients that support it +std::map<std::string, std::string> ConfigurationManager::getAccountTemplate() +{ + std::map<std::string, std::string> accTemplate; + accTemplate[ CONFIG_LOCAL_PORT ] = CONFIG_DEFAULT_LOCAL_PORT; + accTemplate[ CONFIG_PUBLISHED_PORT ] = CONFIG_DEFAULT_PUBLISHED_PORT; + accTemplate[ CONFIG_PUBLISHED_SAMEAS_LOCAL ] = CONFIG_DEFAULT_PUBLISHED_SAMEAS_LOCAL; + accTemplate[ CONFIG_INTERFACE ] = CONFIG_DEFAULT_INTERFACE; + accTemplate[ CONFIG_ACCOUNT_REGISTRATION_EXPIRE ] = CONFIG_DEFAULT_REGISTRATION_EXPIRE; + return accTemplate; +} + +std::string ConfigurationManager::addAccount(const std::map<std::string, std::string>& details) +{ + return Manager::instance().addAccount(details); +} + +void ConfigurationManager::removeAccount(const std::string& accoundID) +{ + return Manager::instance().removeAccount(accoundID); +} + +/** + * Send the list of all codecs loaded to the client through DBus. + * Can stay global, as only the active codecs will be set per accounts + */ +std::vector<int32_t> ConfigurationManager::getAudioCodecList() +{ + std::vector<int32_t> list(Manager::instance().audioCodecFactory.getCodecList()); + + // if (list.empty()) + // errorAlert(CODECS_NOT_LOADED); + + return list; +} + +std::vector<std::string> ConfigurationManager::getAccountList() +{ + return Manager::instance().getAccountList(); +} + +std::vector<std::string> ConfigurationManager::getSupportedTlsMethod() +{ + std::vector<std::string> method; + method.push_back("Default"); + method.push_back("TLSv1"); + method.push_back("SSLv3"); + method.push_back("SSLv23"); + return method; +} + +std::vector<std::string> ConfigurationManager::getAudioCodecDetails(const int32_t& payload) +{ + std::vector<std::string> result(Manager::instance().audioCodecFactory.getCodecSpecifications(payload)); + + // if (result.empty()) + // errorAlert(CODECS_NOT_LOADED); + + return result; +} + +std::vector<int32_t> ConfigurationManager::getActiveAudioCodecList(const std::string& accountID) +{ + Account *acc = Manager::instance().getAccount(accountID); + + if (acc) + return acc->getActiveAudioCodecs(); + else { + ERROR("Could not find account %s, returning default", accountID.c_str()); + return Account::getDefaultAudioCodecs(); + } +} + +void ConfigurationManager::setActiveAudioCodecList(const std::vector<std::string>& list, const std::string& accountID) +{ + Account *acc = Manager::instance().getAccount(accountID); + + if (acc) { + acc->setActiveAudioCodecs(list); + Manager::instance().saveConfig(); + } else { + ERROR("Could not find account %s", accountID.c_str()); + } +} + +std::vector<std::string> ConfigurationManager::getAudioPluginList() +{ + std::vector<std::string> v; + + v.push_back(PCM_DEFAULT); + v.push_back(PCM_DMIX_DSNOOP); + + return v; +} + +void ConfigurationManager::setAudioPlugin(const std::string& audioPlugin) +{ + return Manager::instance().setAudioPlugin(audioPlugin); +} + +std::vector<std::string> ConfigurationManager::getAudioOutputDeviceList() +{ + return Manager::instance().getAudioOutputDeviceList(); +} + +std::vector<std::string> ConfigurationManager::getAudioInputDeviceList() +{ + return Manager::instance().getAudioInputDeviceList(); +} + +void ConfigurationManager::setAudioOutputDevice(const int32_t& index) +{ + return Manager::instance().setAudioDevice(index, AudioLayer::SFL_PCM_PLAYBACK); +} + +void ConfigurationManager::setAudioInputDevice(const int32_t& index) +{ + return Manager::instance().setAudioDevice(index, AudioLayer::SFL_PCM_CAPTURE); +} + +void ConfigurationManager::setAudioRingtoneDevice(const int32_t& index) +{ + return Manager::instance().setAudioDevice(index, AudioLayer::SFL_PCM_RINGTONE); +} + +std::vector<std::string> ConfigurationManager::getCurrentAudioDevicesIndex() +{ + return Manager::instance().getCurrentAudioDevicesIndex(); +} + +int32_t ConfigurationManager::getAudioDeviceIndex(const std::string& name) +{ + return Manager::instance().getAudioDeviceIndex(name); +} + +std::string ConfigurationManager::getCurrentAudioOutputPlugin() +{ + DEBUG("Get audio plugin %s", Manager::instance().getCurrentAudioOutputPlugin().c_str()); + + return Manager::instance().getCurrentAudioOutputPlugin(); +} + +std::string ConfigurationManager::getNoiseSuppressState() +{ + return Manager::instance().getNoiseSuppressState(); +} + +void ConfigurationManager::setNoiseSuppressState(const std::string& state) +{ + Manager::instance().setNoiseSuppressState(state); +} + +std::string ConfigurationManager::getEchoCancelState() +{ + return Manager::instance().getEchoCancelState() ? "enabled" : "disabled"; +} + +std::map<std::string, std::string> ConfigurationManager::getRingtoneList() +{ + std::map<std::string, std::string> ringToneList; + std::string r_path(fileutils::get_data_dir()); + struct dirent **namelist; + int n = scandir(r_path.c_str(), &namelist, 0, alphasort); + if (n == -1) { + ERROR("%s", strerror(errno)); + return ringToneList; + } + + while (n--) { + if (strcmp(namelist[n]->d_name, ".") and strcmp(namelist[n]->d_name, "..")) { + std::string file(namelist[n]->d_name); + + if (file.find(".wav") != std::string::npos) + file.replace(file.find(".wav"), 4, ""); + else + file.replace(file.size() - 3, 3, ""); + if (file[0] <= 0x7A and file[0] >= 0x61) file[0] = file[0] - 32; + ringToneList[r_path + namelist[n]->d_name] = file; + } + free(namelist[n]); + } + free(namelist); + return ringToneList; +} + +void ConfigurationManager::setEchoCancelState(const std::string& state) +{ + Manager::instance().setEchoCancelState(state); +} + +int32_t ConfigurationManager::isIax2Enabled() +{ + return HAVE_IAX; +} + +std::string ConfigurationManager::getRecordPath() +{ + return Manager::instance().audioPreference.getRecordPath(); +} + +void ConfigurationManager::setRecordPath(const std::string& recPath) +{ + Manager::instance().audioPreference.setRecordPath(recPath); +} + +bool ConfigurationManager::getIsAlwaysRecording() +{ + return Manager::instance().getIsAlwaysRecording(); +} + +void ConfigurationManager::setIsAlwaysRecording(const bool& rec) +{ + Manager::instance().setIsAlwaysRecording(rec); +} + +/* +void ConfigurationManager::setRecordingCall(const std::string& id) +{ + Manager::instance().setRecordingCall(id); +} +*/ +int32_t ConfigurationManager::getHistoryLimit() +{ + return Manager::instance().getHistoryLimit(); +} + +void ConfigurationManager::clearHistory() +{ + return Manager::instance().clearHistory(); +} + +void ConfigurationManager::setHistoryLimit(const int32_t& days) +{ + Manager::instance().setHistoryLimit(days); +} + +void ConfigurationManager::setAudioManager(const std::string& api) +{ + Manager::instance().setAudioManager(api); +} + +std::string ConfigurationManager::getAudioManager() +{ + return Manager::instance().getAudioManager(); +} + +std::map<std::string, std::string> ConfigurationManager::getHookSettings() +{ + return Manager::instance().hookPreference.toMap(); +} + +void ConfigurationManager::setHookSettings(const std::map<std::string, + std::string>& settings) +{ + Manager::instance().hookPreference = HookPreference(settings); +} + +void ConfigurationManager::setAccountsOrder(const std::string& order) +{ + Manager::instance().setAccountsOrder(order); +} + +std::vector<std::map<std::string, std::string> > ConfigurationManager::getHistory() +{ + return Manager::instance().getHistory(); +} + +std::string +ConfigurationManager::getAddrFromInterfaceName(const std::string& interface) +{ + return SipTransport::getInterfaceAddrFromName(interface); +} + +std::vector<std::string> ConfigurationManager::getAllIpInterface() +{ + return SipTransport::getAllIpInterface(); +} + +std::vector<std::string> ConfigurationManager::getAllIpInterfaceByName() +{ + return SipTransport::getAllIpInterfaceByName(); +} + +std::map<std::string, std::string> ConfigurationManager::getShortcuts() +{ + return Manager::instance().shortcutPreferences.getShortcuts(); +} + +void ConfigurationManager::setShortcuts( + const std::map<std::string, std::string>& shortcutsMap) +{ + Manager::instance().shortcutPreferences.setShortcuts(shortcutsMap); + Manager::instance().saveConfig(); +} + +std::vector<std::map<std::string, std::string> > ConfigurationManager::getCredentials( + const std::string& accountID) +{ + SIPAccount *account = Manager::instance().getSipAccount(accountID); + std::vector<std::map<std::string, std::string> > credentialInformation; + + if (!account) + return credentialInformation; + else + return account->getCredentials(); +} + +void ConfigurationManager::setCredentials(const std::string& accountID, + const std::vector<std::map<std::string, std::string> >& details) +{ + SIPAccount *account = Manager::instance().getSipAccount(accountID); + if (account) + account->setCredentials(details); +} + + + +void ConfigurationManager::accountsChanged() +{ + on_accounts_changed_wrapper(); +} + +void ConfigurationManager::historyChanged() +{ + +} + +void ConfigurationManager::stunStatusFailure(const std::string& accoundID) +{ + +} + +void ConfigurationManager::registrationStateChanged(const std::string& accoundID, int const& state) +{ + on_account_state_changed_wrapper(accoundID, state); +} diff --git a/daemon/src/client/android/configurationmanager.i b/daemon/src/client/android/configurationmanager.i new file mode 100644 index 0000000000000000000000000000000000000000..479da00cf7c99f1b7759773eb0890fbe4b16f7b0 --- /dev/null +++ b/daemon/src/client/android/configurationmanager.i @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +%header %{ +#include "client/configurationmanager.h" + +typedef struct configurationmanager_callback +{ + void (*on_accounts_changed)(void); + void (*on_account_state_changed)(const std::string& accoundID, const int32_t& state); + void (*on_account_state_changed_with_code)(const std::string& accoundID, const std::string& state, const int32_t& code); +} configurationmanager_callback_t; + + +class ConfigurationCallback { +public: + virtual ~ConfigurationCallback() {} + virtual void on_accounts_changed(void) {} + virtual void on_account_state_changed(const std::string& accoundID, const int32_t& state) {} + virtual void on_account_state_changed_with_code(const std::string& accoundID, const std::string& state, const int32_t& code) {} +}; + +static ConfigurationCallback *registeredConfigurationCallbackObject = NULL; + +void on_accounts_changed_wrapper (void) { + registeredConfigurationCallbackObject->on_accounts_changed(); +} + +void on_account_state_changed_wrapper (const std::string& accoundID, const int32_t& state) { + registeredConfigurationCallbackObject->on_account_state_changed(accoundID, state); +} + +void on_account_state_changed_with_code_wrapper (const std::string& accoundID, const std::string& state, const int32_t& code) { + registeredConfigurationCallbackObject->on_account_state_changed_with_code(accoundID, state, code); +} + +static struct configurationmanager_callback wrapper_configurationcallback_struct = { + &on_accounts_changed_wrapper, + &on_account_state_changed_wrapper, + &on_account_state_changed_with_code_wrapper +}; + +void setConfigurationCallbackObject(ConfigurationCallback *callback) { + registeredConfigurationCallbackObject = callback; +} + +%} + +%feature("director") ConfigurationCallback; + +class ConfigurationManager { +public: + std::map< std::string, std::string > getAccountDetails(const std::string& accountID); + void setAccountDetails(const std::string& accountID, const std::map< std::string, std::string >& details); + std::map<std::string, std::string> getAccountTemplate(); + std::string addAccount(const std::map< std::string, std::string >& details); + void removeAccount(const std::string& accoundID); + std::vector< std::string > getAccountList(); + void sendRegister(const std::string& accoundID, const bool& enable); + void registerAllAccounts(void); + + std::map< std::string, std::string > getTlsSettingsDefault(); + + std::vector< int32_t > getAudioCodecList(); + std::vector< std::string > getSupportedTlsMethod(); + std::vector< std::string > getAudioCodecDetails(const int32_t& payload); + std::vector< int32_t > getActiveAudioCodecList(const std::string& accountID); + + void setActiveAudioCodecList(const std::vector< std::string >& list, const std::string& accountID); + + std::vector< std::string > getAudioPluginList(); + void setAudioPlugin(const std::string& audioPlugin); + std::vector< std::string > getAudioOutputDeviceList(); + void setAudioOutputDevice(const int32_t& index); + void setAudioInputDevice(const int32_t& index); + void setAudioRingtoneDevice(const int32_t& index); + std::vector< std::string > getAudioInputDeviceList(); + std::vector< std::string > getCurrentAudioDevicesIndex(); + int32_t getAudioDeviceIndex(const std::string& name); + std::string getCurrentAudioOutputPlugin(); + std::string getNoiseSuppressState(); + void setNoiseSuppressState(const std::string& state); + std::string getEchoCancelState(); + void setEchoCancelState(const std::string& state); + + std::map<std::string, std::string> getRingtoneList(); + + std::string getAudioManager(); + void setAudioManager(const std::string& api); + + int32_t isIax2Enabled(); + std::string getRecordPath(); + void setRecordPath(const std::string& recPath); + bool getIsAlwaysRecording(); + void setIsAlwaysRecording(const bool& rec); + + void setHistoryLimit(const int32_t& days); + int32_t getHistoryLimit(); + void clearHistory(); + + void setAccountsOrder(const std::string& order); + + std::map<std::string, std::string> getHookSettings(); + void setHookSettings(const std::map<std::string, std::string>& settings); + + std::vector<std::map<std::string, std::string> > getHistory(); + + std::map<std::string, std::string> getTlsSettings(); + void setTlsSettings(const std::map< std::string, std::string >& details); + std::map< std::string, std::string > getIp2IpDetails(); + + std::vector< std::map< std::string, std::string > > getCredentials(const std::string& accountID); + void setCredentials(const std::string& accountID, const std::vector< std::map< std::string, std::string > >& details); + + std::string getAddrFromInterfaceName(const std::string& interface); + + std::vector<std::string> getAllIpInterface(); + std::vector<std::string> getAllIpInterfaceByName(); + + std::map<std::string, std::string> getShortcuts(); + void setShortcuts(const std::map<std::string, std::string> &shortcutsMap); +}; + +class ConfigurationCallback { +public: + virtual ~ConfigurationCallback(); + virtual void on_accounts_changed(void); + virtual void on_account_state_changed(const std::string& accoundID, const int32_t& state); + virtual void on_account_state_changed_with_code(const std::string& accoundID, const std::string& state, const int32_t& code); +}; + +static ConfigurationCallback *registeredConfigurationCallbackObject = NULL; + +void setConfigurationCallbackObject(ConfigurationCallback *callback) { + registeredConfigurationCallbackObject = callback; +} diff --git a/daemon/src/client/android/jni-xml2cpp.py b/daemon/src/client/android/jni-xml2cpp.py new file mode 100755 index 0000000000000000000000000000000000000000..067f488d3f644bbfc5afefe7c68c3938b0568328 --- /dev/null +++ b/daemon/src/client/android/jni-xml2cpp.py @@ -0,0 +1,85 @@ +#!/usr/bin/python + +# +# PACKAGE DEPENDENCIES: python python-lxml +# + +#import easy to use xml parser called minidom: +from lxml import etree +#from copy import deepcopy +from lxml import objectify +import re, sys, getopt + +def rreplace(s, old, new, occurrence): + li = s.rsplit(old, occurrence) + return new.join(li) + +def usage(): + print "jni-xml2cpp.py --file <file> | -i <file>" + +# main +inputfile = "./dbus/callmanager-introspec.xml" +outputfile = "./dbus/callmanager-jni.h" +try: + opts, args = getopt.getopt(sys.argv[1:], "hi:o:", ["help", "input=", "output="]) +except getopt.GetoptError, err: + usage() + print str(err) + #print opts + sys.exit(2) + +for opt, arg in opts: + if opt in ("-h", "--help"): + usage() + sys.exit(0) + elif opt in ("-i", "--input"): + inputfile = arg + elif opt in ("-o", "--output"): + outputfile = arg + else: + print "error: argument not recognized" + sys.exit(3) + +print "inputfile = %s" % (inputfile) +print "outputfile = %s" % (outputfile) +source = "".join(args) + +# lxml.objectify +# FIXME relative path +cm_obj_tree = objectify.parse(inputfile) +cm_obj_root = cm_obj_tree.getroot() +# http://www.skymind.com/~ocrow/python_string/ +# method 4: list of strings +prototype = [] +# iteration on methods +for meth in cm_obj_root.interface.iter(tag="method"): +# iteration on arguments + prototype.append(meth.get("name")) + prototype.append("(") + for argum in meth.iter(tag="arg"): + name = argum.get("name") + typ = argum.get("type") +# FIXME + if typ == 's': + prototype.append("string %s, " % (name)) + elif typ == 'i': + prototype.append("int %s, " % (name)) + elif typ == 'd': + prototype.append("unsigned int %s, " % (name)) + elif typ == 'as': + prototype.append("std::vector< std::string > &%s, " % (name)) + else: + prototype.append("void %s, " % (name)) + prototype.append(");\n") + +# starting from the end of string, +# replace the first and 1-only comma by nothing +#rreplace(prototype[tostring(), ',', '', 1) + +p = re.compile(", \);") +prototypes = p.sub(");", ''.join(prototype)) + +# FIXME relative path +outfile = open(outputfile, "w") +outfile.write(prototypes) +outfile.close() diff --git a/daemon/src/client/android/jni_callbacks.h b/daemon/src/client/android/jni_callbacks.h new file mode 100644 index 0000000000000000000000000000000000000000..0ce6e7bcb558b263da7357b44ea0f58bbda885c5 --- /dev/null +++ b/daemon/src/client/android/jni_callbacks.h @@ -0,0 +1,26 @@ + + + + +extern struct callmanager_callback wrapper_callback_struct; +void on_new_call_created_wrapper (const std::string& accountID, + const std::string& callID, + const std::string& to); +void on_call_state_changed_wrapper(const std::string& callID, + const std::string& to); +void on_incoming_call_wrapper (const std::string& accountID, + const std::string& callID, + const std::string& from); +void on_transfer_state_changed_wrapper (const std::string& result); + +void on_conference_created_wrapper (const std::string& confID); +void on_conference_removed_wrapper (const std::string& confID); +void on_conference_state_changed_wrapper(const std::string& confID,const std::string& state); +void on_incoming_message_wrapper(const std::string& ID, const std::string& from, const std::string& msg); + +extern struct configurationmanager_callback wrapper_configurationcallback_struct; +extern void on_accounts_changed_wrapper (); +extern void on_account_state_changed_wrapper (const std::string& accoundID, int const& state); +extern void on_account_state_changed_with_code_wrapper (const std::string& accoundID, const std::string& state, const int32_t& code); + +void on_record_playback_filepath_wrapper(const std::string& id, const std::string& filename); diff --git a/daemon/src/client/android/jni_interface.i b/daemon/src/client/android/jni_interface.i new file mode 100644 index 0000000000000000000000000000000000000000..3d98059825a857c95fde979cb04b9cdcc2a4743b --- /dev/null +++ b/daemon/src/client/android/jni_interface.i @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +/* File : jni_interface.i */ +%module (directors="1") SFLPhoneservice + +#define SWIG_JAVA_ATTACH_CURRENT_THREAD_AS_DAEMON +%include "typemaps.i" +%include "std_string.i" /* std::string typemaps */ +%include "enums.swg" +%include "arrays_java.i"; +%include "carrays.i"; +%include "std_map.i"; +%include "std_vector.i"; +%include "stdint.i"; + +/* void* shall be handled as byte arrays */ +%typemap(jni) void * "void *" +%typemap(jtype) void * "byte[]" +%typemap(jstype) void * "byte[]" +%typemap(javain) void * "$javainput" +%typemap(in) void * %{ + $1 = $input; +%} +%typemap(javadirectorin) void * "$jniinput" +%typemap(out) void * %{ + $result = $1; +%} +%typemap(javaout) void * { + return $jnicall; +} + +namespace std { + %template(StringMap) map<string, string>; + %template(StringVect) vector<string>; + %template(VectMap) vector< map<string,string> >; + %template(IntVect) vector<int32_t>; +} + +/* not parsed by SWIG but needed by generated C files */ +%header %{ + +#include <logger.h> + +%} + +%inline %{ +/* some functions that need to be declared in *_wrap.cpp + * that are not declared elsewhere in the c++ code + */ +%} + +/* parsed by SWIG to generate all the glue */ +/* %include "../managerimpl.h" */ +/* %include <dbus/callmanager.h> */ + +//%constant struct callmanager_callback* WRAPPER_CALLBACK_STRUCT = &wrapper_callback_struct; + +%include "managerimpl.i" +%include "callmanager.i" +%include "configurationmanager.i" + +#ifndef SWIG +/* some bad declarations */ +#endif diff --git a/daemon/src/client/android/managerimpl.i b/daemon/src/client/android/managerimpl.i new file mode 100644 index 0000000000000000000000000000000000000000..d86c546066019368b6488640b2deeb005dac1f79 --- /dev/null +++ b/daemon/src/client/android/managerimpl.i @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Emeric Vigier <emeric.vigier@savoirfairelinux.com> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +/* %nodefaultctor ManagerImpl; +%nodefaultdtor ManagerImpl; */ +%header %{ +#include <managerimpl.h> +namespace Manager { +extern ManagerImpl& instance(); +} +%} + +class ManagerImpl { +public: + void init(const std::string &config_file); + void setPath(const std::string &path); + bool outgoingCall(const std::string&, const std::string&, const std::string&, const std::string& = ""); + void refuseCall(const std::string& id); + bool answerCall(const std::string& id); + void hangupCall(const std::string& id); +}; + +//%rename(Manager_instance) Manager::instance; + +namespace Manager { + +ManagerImpl& Manager::instance() +{ + // Meyers singleton + static ManagerImpl instance_; + return instance_; +} + +} diff --git a/daemon/src/client/android/sflphoneservice.c.template b/daemon/src/client/android/sflphoneservice.c.template new file mode 100644 index 0000000000000000000000000000000000000000..916369e94b02197d3a9667ebee17ed6bf057ed9c --- /dev/null +++ b/daemon/src/client/android/sflphoneservice.c.template @@ -0,0 +1,104 @@ +#include "logger.h" + +JavaVM *gJavaVM; +const char *ksflphoneservicePath = "com/savoirfairelinux/sflphone/service/SFLPhoneserviceJNI"; +//const char *kManagerPath = "com/savoirfairelinux/sflphone/client/ManagerImpl"; +//static jobject gManagerObject, gDataObject; + +//void initClassHelper(JNIEnv *env, const char *path, jobject *objptr) { +// jclass cls; +// +// INFO("initClassHelper"); +// +// cls= env->FindClass(path); +// if(!cls) { +// ERROR("initClassHelper: failed to get %s class reference", path); +// return; +// } +// jmethodID constr = env->GetMethodID(cls, "<init>", "()V"); +// INFO("initClassHelper: %s method found", path); +// +// if(!constr) { +// ERROR("initClassHelper: failed to get %s constructor", path); +// return; +// } +// jobject obj = env->NewObject(cls, constr); +// INFO("initClassHelper: %s constructor found", path); +// +// if(!obj) { +// ERROR("initClassHelper: failed to create a %s object", path); +// return; +// } +// /* protect cached object instances from Android GC */ +// (*objptr) = env->NewGlobalRef(obj); +// INFO("initClassHelper: object found %x", objptr); +//} + +void deinitClassHelper(JNIEnv *env, jobject obj) { + INFO("deinitClassHelper"); + + /* delete cached object instances */ + env->DeleteGlobalRef(obj); + INFO("deinitClassHelper: object %x deleted", obj); +} + +JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv *env; + jclass clazz; + jint r; + + INFO("JNI_OnLoad"); + + //Assume it is c++ + r = vm->GetEnv ((void **) &env, JNI_VERSION_1_6); + if (r != JNI_OK) { + ERROR("JNI_OnLoad: failed to get the environment using GetEnv()"); + return -1; + } + INFO("JNI_Onload: GetEnv %p", env); + + clazz = env->FindClass (ksflphoneservicePath); + if (!clazz) { + ERROR("JNI_Onload: whoops, %s class not found!", ksflphoneservicePath); + } + gJavaVM = vm; + INFO("JNI_Onload: JavaVM %p", gJavaVM); + + /* put instances of class object we need into cache */ + //initClassHelper(env, kManagerPath, &gManagerObject); + + JNINativeMethod methods[] = { + + $defs + + }; + + r = env->RegisterNatives (clazz, methods, (int) (sizeof(methods) / sizeof(methods[0]))); + return JNI_VERSION_1_6; +} + +void JNI_OnUnLoad(JavaVM* vm, void* reserved) { + JNIEnv* env; + jclass clazz; + + INFO("JNI_OnUnLoad"); + + /* get env */ + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + ERROR("JNI_OnUnLoad: failed to get the environment using GetEnv()"); + return; + } + INFO("JNI_OnUnLoad: GetEnv %p", env); + + /* Get jclass with env->FindClass */ + clazz = env->FindClass(ksflphoneservicePath); + if (!clazz) { + ERROR("JNI_OnUnLoad: whoops, %s class not found!", ksflphoneservicePath); + } + + /* remove instances of class object we need into cache */ + //deinitClassHelper(env, gManagerObject); + + env->UnregisterNatives(clazz); + INFO("JNI_OnUnLoad: Native functions unregistered"); +} diff --git a/daemon/src/dbus/callmanager.h b/daemon/src/client/callmanager.h similarity index 75% rename from daemon/src/dbus/callmanager.h rename to daemon/src/client/callmanager.h index 043ebffecda02a05b1bb198fc3c443efcf155aeb..c2189a6dfe69b98afba904e2926d931d65bee2a3 100644 --- a/daemon/src/dbus/callmanager.h +++ b/daemon/src/client/callmanager.h @@ -31,7 +31,14 @@ #ifndef __SFL_CALLMANAGER_H__ #define __SFL_CALLMANAGER_H__ -#include "dbus_cpp.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_DBUS + +#include "dbus/dbus_cpp.h" + #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 /* This warning option only exists for gcc 4.6.0 and greater. */ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" @@ -39,7 +46,7 @@ #pragma GCC diagnostic ignored "-Wignored-qualifiers" #pragma GCC diagnostic ignored "-Wunused-parameter" -#include "callmanager-glue.h" +#include "dbus/callmanager-glue.h" #pragma GCC diagnostic warning "-Wignored-qualifiers" #pragma GCC diagnostic warning "-Wunused-parameter" @@ -48,25 +55,39 @@ #pragma GCC diagnostic warning "-Wunused-but-set-variable" #endif +#else +// these includes normally come with DBus C++ +#include <vector> +#include <map> +#include <string> +#endif // HAVE_DBUS + #include <stdexcept> class CallManagerException: public std::runtime_error { public: - CallManagerException(const std::string& str="") : + CallManagerException(const std::string& str = "") : std::runtime_error("A CallManagerException occured: " + str) {} }; namespace sfl { - class AudioZrtpSession; +class AudioZrtpSession; } class CallManager +#if HAVE_DBUS : public org::sflphone::SFLphone::CallManager_adaptor, public DBus::IntrospectableAdaptor, - public DBus::ObjectAdaptor { + public DBus::ObjectAdaptor +#endif +{ public: +#if HAVE_DBUS CallManager(DBus::Connection& connection); +#else + CallManager(); +#endif /* methods exported by this interface, * you will have to implement them in your ObjectAdaptor @@ -86,8 +107,10 @@ class CallManager std::vector< std::string > getCallList(); /* Conference related methods */ + void removeConference(const std::string& conference_id); bool joinParticipant(const std::string& sel_callID, const std::string& drag_callID); void createConfFromParticipantList(const std::vector< std::string >& participants); + bool isConferenceParticipant(const std::string& call_id); bool addParticipant(const std::string& callID, const std::string& confID); bool addMainParticipant(const std::string& confID); bool detachParticipant(const std::string& callID); @@ -126,6 +149,36 @@ class CallManager /* Instant messaging */ void sendTextMessage(const std::string& callID, const std::string& message); + void sendTextMessage(const std::string& callID, const std::string& message, const std::string& from); + +#ifdef __ANDROID__ + // signals must be implemented manually for Android + void callStateChanged(const std::string& callID, const std::string& state); + + void transferFailed(); + + void transferSucceeded(); + + void recordPlaybackStopped(const std::string& path); + + void voiceMailNotify(const std::string& callID, const std::string& nd_msg); + + void incomingMessage(const std::string& ID, const std::string& from, const std::string& msg); + + void incomingCall(const std::string& accountID, const std::string& callID, const std::string& from); + + void recordPlaybackFilepath(const std::string& id, const std::string& filename); + + void conferenceCreated(const std::string& confID); + + void conferenceChanged(const std::string& confID,const std::string& state); + + void updatePlaybackScale(const int32_t&, const int32_t&); + void conferenceRemoved(const std::string&); + void newCallCreated(const std::string&, const std::string&, const std::string&); + void registrationStateChanged(const std::string&, const std::string&, const int32_t&); + void sipCallStateChanged(const std::string&, const std::string&, const int32_t&); +#endif // __ANDROID__ /* Presence subscription */ void subscribePresence(const std::string& accountID, const std::string& buddySipUri); diff --git a/daemon/src/dbus/dbusmanager.h b/daemon/src/client/client.h similarity index 90% rename from daemon/src/dbus/dbusmanager.h rename to daemon/src/client/client.h index 99ac43b25b379fc62e6ceba8230f95f397ff5555..0ba877b1582baa48baa0965425755d1fb11316b8 100644 --- a/daemon/src/dbus/dbusmanager.h +++ b/daemon/src/client/client.h @@ -28,13 +28,12 @@ * as that of the covered work. */ -#ifndef __DBUSMANAGERIMPL_H__ -#define __DBUSMANAGERIMPL_H__ +#ifndef __CLIENT_H__ +#define __CLIENT_H__ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include "dbus_cpp.h" #include "noncopyable.h" class ConfigurationManager; @@ -43,10 +42,14 @@ class NetworkManager; class Instance; class VideoControls; -class DBusManager { +namespace DBus { + class BusDispatcher; +} + +class Client { public: - DBusManager(); - ~DBusManager(); + Client(); + ~Client(); CallManager * getCallManager() { return callManager_; @@ -60,15 +63,15 @@ class DBusManager { } #endif - void exec(); + void event_loop(); void exit(); private: - NON_COPYABLE(DBusManager); + NON_COPYABLE(Client); CallManager* callManager_; ConfigurationManager* configurationManager_; Instance* instanceManager_; - DBus::BusDispatcher dispatcher_; + DBus::BusDispatcher* dispatcher_; #ifdef SFL_VIDEO VideoControls *videoControls_; #endif diff --git a/daemon/src/dbus/configurationmanager.h b/daemon/src/client/configurationmanager.h similarity index 89% rename from daemon/src/dbus/configurationmanager.h rename to daemon/src/client/configurationmanager.h index 65277d3e797e37def86cc3878252866fe6fcde69..217b47610dd0939e1966583af7bafab362a1ff0d 100644 --- a/daemon/src/dbus/configurationmanager.h +++ b/daemon/src/client/configurationmanager.h @@ -34,6 +34,14 @@ #ifndef CONFIGURATIONMANAGER_H #define CONFIGURATIONMANAGER_H +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_DBUS + +#include "dbus/dbus_cpp.h" + #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 #pragma GCC diagnostic ignored "-Wunused-but-set-variable" #endif @@ -41,7 +49,7 @@ #pragma GCC diagnostic ignored "-Wignored-qualifiers" #pragma GCC diagnostic ignored "-Wunused-parameter" #pragma GCC diagnostic ignored "-Weffc++" -#include "configurationmanager-glue.h" +#include "dbus/configurationmanager-glue.h" #pragma GCC diagnostic warning "-Wignored-qualifiers" #pragma GCC diagnostic warning "-Wunused-parameter" #pragma GCC diagnostic warning "-Weffc++" @@ -50,21 +58,31 @@ #pragma GCC diagnostic warning "-Wunused-but-set-variable" #endif -#include "dbus_cpp.h" +#else +// these includes normally come with DBus C++ +#include <vector> +#include <map> +#include <string> +#endif // HAVE_DBUS class ConfigurationManager +#if HAVE_DBUS : public org::sflphone::SFLphone::ConfigurationManager_adaptor, public DBus::IntrospectableAdaptor, - public DBus::ObjectAdaptor { - + public DBus::ObjectAdaptor +#endif +{ public: +#if HAVE_DBUS ConfigurationManager(DBus::Connection& connection); +#else + ConfigurationManager(); +#endif std::map< std::string, std::string > getAccountDetails(const std::string& accountID); void setAccountDetails(const std::string& accountID, const std::map< std::string, std::string >& details); std::map<std::string, std::string> getAccountTemplate(); std::string addAccount(const std::map< std::string, std::string >& details); void removeAccount(const std::string& accoundID); - void deleteAllCredential(const std::string& accountID); std::vector< std::string > getAccountList(); void sendRegister(const std::string& accoundID, const bool& enable); void registerAllAccounts(void); @@ -129,7 +147,17 @@ class ConfigurationManager std::map<std::string, std::string> getShortcuts(); void setShortcuts(const std::map<std::string, std::string> &shortcutsMap); + +#ifdef __ANDROID__ + // signals must be implemented manually for Android + void accountsChanged(); + + void historyChanged(); + + void stunStatusFailure(const std::string& accoundID); + + void registrationStateChanged(const std::string& accoundID, int const& state); +#endif // __ANDROID__ }; #endif //CONFIGURATIONMANAGER_H - diff --git a/daemon/src/dbus/Makefile.am b/daemon/src/client/dbus/Makefile.am similarity index 82% rename from daemon/src/dbus/Makefile.am rename to daemon/src/client/dbus/Makefile.am index 288f7287a5d7e2a84579acb597a210c839097808..bbd66cc08baa64fb865701ce79abc8d1453d3819 100644 --- a/daemon/src/dbus/Makefile.am +++ b/daemon/src/client/dbus/Makefile.am @@ -1,6 +1,6 @@ include $(top_srcdir)/globals.mak -noinst_LTLIBRARIES = libdbus.la +noinst_LTLIBRARIES = libclient.la BUILT_SOURCES= \ callmanager-glue.h \ @@ -25,41 +25,41 @@ configurationmanager-glue.h: configurationmanager-introspec.xml Makefile.am instance-glue.h: instance-introspec.xml Makefile.am dbusxx-xml2cpp $< --adaptor=$@ -libdbus_la_SOURCES = \ +libclient_la_SOURCES = \ callmanager.cpp \ configurationmanager.cpp \ instance.cpp \ - dbusmanager.cpp + client.cpp if SFL_VIDEO -libdbus_la_SOURCES+=video_controls.cpp +libclient_la_SOURCES+=video_controls.cpp endif if USE_NETWORKMANAGER -libdbus_la_SOURCES += networkmanager.cpp +libclient_la_SOURCES += networkmanager.cpp NETWORKMANAGER=-DUSE_NETWORKMANAGER else NETWORKMANAGER= endif -libdbus_la_CXXFLAGS = \ +libclient_la_CXXFLAGS = -I../ \ -DPREFIX=\"$(prefix)\" \ -DPROGSHAREDIR=\"${datadir}/sflphone\" \ - $(NETWORKMANAGER) - + $(NETWORKMANAGER) \ + $(DBUSCPP_CFLAGS) noinst_HEADERS = \ - callmanager.h \ - configurationmanager.h \ + ../callmanager.h \ + ../configurationmanager.h \ instance.h \ - dbusmanager.h \ + ../client.h \ networkmanager_proxy.h \ networkmanager.h \ dbus_cpp.h \ $(BUILT_SOURCES) if SFL_VIDEO -noinst_HEADERS+=video_controls.h +noinst_HEADERS+=../video_controls.h endif # Dbus service file diff --git a/daemon/src/dbus/README b/daemon/src/client/dbus/README similarity index 57% rename from daemon/src/dbus/README rename to daemon/src/client/dbus/README index 068ed5a7bfe34ec39addffb11e7510651c00b25b..45fdf4b41a5d66fa90282dadfaf4cce603e13eca 100644 --- a/daemon/src/dbus/README +++ b/daemon/src/client/dbus/README @@ -8,3 +8,17 @@ Examples: dbusxx-xml2cpp callmanager-introspec.xml --adaptor=callmanager-glue.h dbusxx-xml2cpp configurationmanager-introspec.xml --adaptor=configurationmanager-glue.h dbusxx-xml2cpp contactmanager-introspec.xml --adaptor=contactmanager-glue.h + +dbusxx-xml2cpp instance-introspec.xml --adaptor=instance-glue.h + +Warning : depending on the dbusxx-xml2cpp version used, it can generate buggy code + +code generated + +::DBus::IntrospectedInterface *const introspect() const + +instead of + +::DBus::IntrospectedInterface *introspect() const + +This issue is dealt with in make-swig.sh diff --git a/daemon/src/dbus/callmanager-introspec.xml b/daemon/src/client/dbus/callmanager-introspec.xml similarity index 99% rename from daemon/src/dbus/callmanager-introspec.xml rename to daemon/src/client/dbus/callmanager-introspec.xml index 863a67e62628d24a1a447ddaafcac42e3b80c262..b0e9954dc0cadd00d811ebe09f9b07e5bdcffefd 100644 --- a/daemon/src/dbus/callmanager-introspec.xml +++ b/daemon/src/client/dbus/callmanager-introspec.xml @@ -211,6 +211,11 @@ <arg type="as" name="participants" direction="in"/> </method> + <method name="isConferenceParticipant" tp:name-for-bindings="isConferenceParticipant"> + <arg type="s" name="callID" direction="in"/> + <arg type="b" name="isParticipant" direction="out"/> + </method> + <method name="addParticipant" tp:name-for-bindings="addParticipant"> <tp:added version="0.9.7"/> <tp:docstring> @@ -392,6 +397,7 @@ <signal name="updatePlaybackScale" tp:name-for-bindings="updatePlaybackScale"> <tp:docstring/> + <arg type="s" name="filepath" /> <arg type="i" name="position" /> <arg type="i" name="size" /> </signal> diff --git a/daemon/src/dbus/callmanager.cpp b/daemon/src/client/dbus/callmanager.cpp similarity index 95% rename from daemon/src/dbus/callmanager.cpp rename to daemon/src/client/dbus/callmanager.cpp index ceb92f5a90b3fe8897e96420465d32738e571661..3dc6e0757caef877bbf87049228ecb8237231852 100644 --- a/daemon/src/dbus/callmanager.cpp +++ b/daemon/src/client/dbus/callmanager.cpp @@ -160,6 +160,18 @@ CallManager::createConfFromParticipantList(const std::vector<std::string>& parti Manager::instance().createConfFromParticipantList(participants); } +bool +CallManager::isConferenceParticipant(const std::string& callID) +{ + return Manager::instance().isConferenceParticipant(callID); +} + +void +CallManager::removeConference(const std::string& conference_id) +{ + Manager::instance().removeConference(conference_id); +} + bool CallManager::addParticipant(const std::string& callID, const std::string& confID) { @@ -393,6 +405,13 @@ CallManager::acceptEnrollment(const std::string& callID, const bool& accepted) #endif } +void CallManager::sendTextMessage(const std::string& callID, const std::string& message, const std::string& from) +{ +#if HAVE_INSTANT_MESSAGING + Manager::instance().sendTextMessage(callID, message, from); +#endif +} + void CallManager::sendTextMessage(const std::string& callID, const std::string& message) { diff --git a/daemon/src/dbus/dbusmanager.cpp b/daemon/src/client/dbus/client.cpp similarity index 91% rename from daemon/src/dbus/dbusmanager.cpp rename to daemon/src/client/dbus/client.cpp index b9aa9a1fe9201b1973844d3ec08f373f32b2269d..fd069f3a09e3ab5d72b919f2fdde3621780360d2 100644 --- a/daemon/src/dbus/dbusmanager.cpp +++ b/daemon/src/client/dbus/client.cpp @@ -33,24 +33,26 @@ #endif #include <cstdlib> -#include "dbusmanager.h" +#include "client/client.h" #include "global.h" #include "manager.h" #include "logger.h" #include "instance.h" +#include "dbus_cpp.h" + #include "callmanager.h" #include "configurationmanager.h" #include "networkmanager.h" #ifdef SFL_VIDEO -#include "dbus/video_controls.h" +#include "video_controls.h" #endif -DBusManager::DBusManager() : callManager_(0) +Client::Client() : callManager_(0) , configurationManager_(0) , instanceManager_(0) - , dispatcher_() + , dispatcher_(new DBus::BusDispatcher) #ifdef SFL_VIDEO , videoControls_(0) #endif @@ -62,7 +64,7 @@ DBusManager::DBusManager() : callManager_(0) DEBUG("DBUS init threading"); DBus::_init_threading(); DEBUG("DBUS instantiate default dispatcher"); - DBus::default_dispatcher = &dispatcher_; + DBus::default_dispatcher = dispatcher_; DEBUG("DBUS session connection to session bus"); DBus::Connection sessionConnection(DBus::Connection::SessionBus()); @@ -93,9 +95,10 @@ DBusManager::DBusManager() : callManager_(0) } DEBUG("DBUS registration done"); + instanceManager_->started(); } -DBusManager::~DBusManager() +Client::~Client() { #ifdef USE_NETWORKMANAGER delete networkManager_; @@ -106,12 +109,13 @@ DBusManager::~DBusManager() delete instanceManager_; delete configurationManager_; delete callManager_; + delete dispatcher_; } -void DBusManager::exec() +void Client::event_loop() { try { - dispatcher_.enter(); + dispatcher_->enter(); } catch (const DBus::Error &err) { ERROR("%s: %s, quitting\n", err.name(), err.what()); return; @@ -121,10 +125,10 @@ void DBusManager::exec() } } -void DBusManager::exit() +void Client::exit() { try { - dispatcher_.leave(); + dispatcher_->leave(); } catch (const DBus::Error &err) { ERROR("%s: %s, quitting\n", err.name(), err.what()); return; diff --git a/daemon/src/dbus/configurationmanager-introspec.xml b/daemon/src/client/dbus/configurationmanager-introspec.xml similarity index 100% rename from daemon/src/dbus/configurationmanager-introspec.xml rename to daemon/src/client/dbus/configurationmanager-introspec.xml diff --git a/daemon/src/dbus/configurationmanager.cpp b/daemon/src/client/dbus/configurationmanager.cpp similarity index 100% rename from daemon/src/dbus/configurationmanager.cpp rename to daemon/src/client/dbus/configurationmanager.cpp diff --git a/daemon/src/dbus/dbus_cpp.h b/daemon/src/client/dbus/dbus_cpp.h similarity index 100% rename from daemon/src/dbus/dbus_cpp.h rename to daemon/src/client/dbus/dbus_cpp.h diff --git a/daemon/src/dbus/instance-introspec.xml b/daemon/src/client/dbus/instance-introspec.xml similarity index 88% rename from daemon/src/dbus/instance-introspec.xml rename to daemon/src/client/dbus/instance-introspec.xml index f564d54cc1ed7bb941af0b35fb063928cd2a9f88..f3d1373a6409b7875a4d80db5bf0f815f285d637 100644 --- a/daemon/src/dbus/instance-introspec.xml +++ b/daemon/src/client/dbus/instance-introspec.xml @@ -29,5 +29,8 @@ </tp:docstring> </arg> </method> + <signal name="started" tp:name-for-bindings="started"> + <tp:docstring>Notify clients that daemon has started</tp:docstring> + </signal> </interface> </node> diff --git a/daemon/src/dbus/instance.cpp b/daemon/src/client/dbus/instance.cpp similarity index 100% rename from daemon/src/dbus/instance.cpp rename to daemon/src/client/dbus/instance.cpp diff --git a/daemon/src/dbus/instance.h b/daemon/src/client/dbus/instance.h similarity index 100% rename from daemon/src/dbus/instance.h rename to daemon/src/client/dbus/instance.h diff --git a/daemon/src/dbus/networkmanager.cpp b/daemon/src/client/dbus/networkmanager.cpp similarity index 93% rename from daemon/src/dbus/networkmanager.cpp rename to daemon/src/client/dbus/networkmanager.cpp index 063522b5f92ea9b56057637f911077d3c631f71e..5495525760b9cd69e831f59b5b06c381ad58c792 100644 --- a/daemon/src/dbus/networkmanager.cpp +++ b/daemon/src/client/dbus/networkmanager.cpp @@ -52,9 +52,8 @@ void NetworkManager::StateChanged(const uint32_t &state) void NetworkManager::PropertiesChanged(const std::map<std::string, ::DBus::Variant> &argin0) { WARN("Properties changed: "); - for (std::map<std::string, ::DBus::Variant>::const_iterator iter = argin0.begin(); - iter != argin0.end(); ++iter) - WARN("%s", iter->first.c_str()); + for (const auto &item : argin0) + WARN("%s", item.first.c_str()); Manager::instance().registerAccounts(); } diff --git a/daemon/src/dbus/networkmanager.h b/daemon/src/client/dbus/networkmanager.h similarity index 99% rename from daemon/src/dbus/networkmanager.h rename to daemon/src/client/dbus/networkmanager.h index 86c6eb5628c55aa520e2abf40903235f5d9f2008..43803381a87d0138199f8c2a1ba1cb00a3f8efde 100644 --- a/daemon/src/dbus/networkmanager.h +++ b/daemon/src/client/dbus/networkmanager.h @@ -47,4 +47,3 @@ class NetworkManager : public org::freedesktop::NetworkManager_proxy, void PropertiesChanged(const std::map<std::string, ::DBus::Variant> &argin0); }; #endif - diff --git a/daemon/src/dbus/networkmanager_proxy.h b/daemon/src/client/dbus/networkmanager_proxy.h similarity index 100% rename from daemon/src/dbus/networkmanager_proxy.h rename to daemon/src/client/dbus/networkmanager_proxy.h diff --git a/daemon/src/dbus/org.freedesktop.NetworkManager.xml b/daemon/src/client/dbus/org.freedesktop.NetworkManager.xml similarity index 99% rename from daemon/src/dbus/org.freedesktop.NetworkManager.xml rename to daemon/src/client/dbus/org.freedesktop.NetworkManager.xml index 591fb7b8edb61bbf3dd0ac5bdad85ae338fda3ee..a98db8123b27cca272b0fd2a46968160cbb52d06 100644 --- a/daemon/src/dbus/org.freedesktop.NetworkManager.xml +++ b/daemon/src/client/dbus/org.freedesktop.NetworkManager.xml @@ -13,4 +13,3 @@ </signal> </interface> </node> - diff --git a/daemon/src/dbus/org.sflphone.SFLphone.service.in b/daemon/src/client/dbus/org.sflphone.SFLphone.service.in similarity index 100% rename from daemon/src/dbus/org.sflphone.SFLphone.service.in rename to daemon/src/client/dbus/org.sflphone.SFLphone.service.in diff --git a/daemon/src/dbus/video_controls-introspec.xml b/daemon/src/client/dbus/video_controls-introspec.xml similarity index 100% rename from daemon/src/dbus/video_controls-introspec.xml rename to daemon/src/client/dbus/video_controls-introspec.xml diff --git a/daemon/src/dbus/video_controls.cpp b/daemon/src/client/dbus/video_controls.cpp similarity index 99% rename from daemon/src/dbus/video_controls.cpp rename to daemon/src/client/dbus/video_controls.cpp index ad7126e8f4497dd1a230a41080465c3914861770..0220130bbdf20dff6f855985e847355030dacfb1 100644 --- a/daemon/src/dbus/video_controls.cpp +++ b/daemon/src/client/dbus/video_controls.cpp @@ -191,4 +191,3 @@ VideoControls::getCurrentCodecName(const std::string &callID) { return Manager::instance().getCurrentVideoCodecName(callID); } - diff --git a/daemon/src/dbus/video_controls.h b/daemon/src/client/video_controls.h similarity index 96% rename from daemon/src/dbus/video_controls.h rename to daemon/src/client/video_controls.h index 55f978cc456bb494a83fd2b6b51f672550be6c7c..fc25c570c8091e52e7d85b1dd64a18d4bdcf15ba 100644 --- a/daemon/src/dbus/video_controls.h +++ b/daemon/src/client/video_controls.h @@ -30,7 +30,13 @@ #ifndef VIDEO_CONTROLS_H_ #define VIDEO_CONTROLS_H_ -#include "dbus_cpp.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_DBUS +#include "dbus/dbus_cpp.h" + #if __GNUC__ >= 4 && __GNUC_MINOR__ >= 6 /* This warning option only exists for gcc 4.6.0 and greater. */ #pragma GCC diagnostic ignored "-Wunused-but-set-variable" @@ -38,7 +44,7 @@ #pragma GCC diagnostic ignored "-Wignored-qualifiers" #pragma GCC diagnostic ignored "-Wunused-parameter" -#include "video_controls-glue.h" +#include "dbus/video_controls-glue.h" #pragma GCC diagnostic warning "-Wignored-qualifiers" #pragma GCC diagnostic warning "-Wunused-parameter" @@ -47,6 +53,7 @@ #pragma GCC diagnostic warning "-Wunused-but-set-variable" #endif +#endif // HAVE_DBUS #include <tr1/memory> // for shared_ptr #include "video/video_preferences.h" @@ -122,4 +129,3 @@ class VideoControls : public org::sflphone::SFLphone::VideoControls_adaptor, }; #endif // VIDEO_CONTROLS_H_ - diff --git a/daemon/src/conference.cpp b/daemon/src/conference.cpp index 1197d86af49f8d9f0ea487e1ce30ac2a9e2ffd21..f252f4589c064220c6c22b647ade1dbe1e4159ee 100644 --- a/daemon/src/conference.cpp +++ b/daemon/src/conference.cpp @@ -66,10 +66,9 @@ void Conference::remove(const std::string &participant_id) void Conference::bindParticipant(const std::string &participant_id) { - for (ParticipantSet::const_iterator iter = participants_.begin(); - iter != participants_.end(); ++iter) - if (participant_id != *iter) - Manager::instance().getMainBuffer().bindCallID(participant_id, *iter); + for (const auto &item : participants_) + if (participant_id != item) + Manager::instance().getMainBuffer().bindCallID(participant_id, item); Manager::instance().getMainBuffer().bindCallID(participant_id, MainBuffer::DEFAULT_ID); } @@ -108,15 +107,15 @@ bool Conference::toggleRecording() // start recording if (startRecording) { - for (ParticipantSet::const_iterator iter = participants_.begin(); iter != participants_.end(); ++iter) - mbuffer.bindHalfDuplexOut(process_id, *iter); + for (const auto &item : participants_) + mbuffer.bindHalfDuplexOut(process_id, item); mbuffer.bindHalfDuplexOut(process_id, MainBuffer::DEFAULT_ID); Recordable::recorder_.start(); } else { - for (ParticipantSet::const_iterator iter = participants_.begin(); iter != participants_.end(); ++iter) - mbuffer.unBindHalfDuplexOut(process_id, *iter); + for (const auto &item : participants_) + mbuffer.unBindHalfDuplexOut(process_id, item); mbuffer.unBindHalfDuplexOut(process_id, MainBuffer::DEFAULT_ID); } diff --git a/daemon/src/config/sfl_config.cpp b/daemon/src/config/sfl_config.cpp index bff618cf4cae3b44626373ab939d64e95f7b608b..4fc4b186ecdee8d200eefbb96d591302a5a11c60 100644 --- a/daemon/src/config/sfl_config.cpp +++ b/daemon/src/config/sfl_config.cpp @@ -91,8 +91,8 @@ ConfigTree::getSections() const { std::list<std::string> sections; - for (SectionMap::const_iterator iter = sections_.begin(); iter != sections_.end(); ++iter) - sections.push_back(iter->first); + for (const auto &item : sections_) + sections.push_back(item.first); return sections; } diff --git a/daemon/src/config/yamlemitter.cpp b/daemon/src/config/yamlemitter.cpp index 2cd569139dce1191d4e8cbe5ed72693364008ca2..d3835c32e429a91a4c810de04fca9ebffd369625 100644 --- a/daemon/src/config/yamlemitter.cpp +++ b/daemon/src/config/yamlemitter.cpp @@ -144,8 +144,8 @@ void YamlEmitter::serializePreference(MappingNode *map, const char *preference_s void YamlEmitter::addMappingItems(int mappingID, YamlNodeMap &iMap) { - for (YamlNodeMap::const_iterator i = iMap.begin(); i != iMap.end(); ++i) - addMappingItem(mappingID, i->first, i->second); + for (const auto &i : iMap) + addMappingItem(mappingID, i.first, i.second); } void YamlEmitter::addMappingItem(int mappingid, const std::string &key, YamlNode *node) @@ -195,8 +195,8 @@ void YamlEmitter::addMappingItem(int mappingid, const std::string &key, YamlNode throw YamlEmitterException("Could not append mapping pair to mapping"); Sequence *seq = seqnode->getSequence(); - for (Sequence::const_iterator it = seq->begin(); it != seq->end(); ++it) { - YamlNode *yamlNode = *it; + for (const auto &it : *seq) { + YamlNode *yamlNode = it; int id; if ((id = yaml_document_add_mapping(&document_, NULL, YAML_BLOCK_MAPPING_STYLE)) == 0) throw YamlEmitterException("Could not add account mapping to document"); diff --git a/daemon/src/config/yamlnode.cpp b/daemon/src/config/yamlnode.cpp index 049129cbf6ccf0db1cbcd28fda5bfc770d95d556..214e04efb5002b620dd46129b153af202c09d72a 100644 --- a/daemon/src/config/yamlnode.cpp +++ b/daemon/src/config/yamlnode.cpp @@ -52,8 +52,8 @@ YamlNode *YamlDocument::popNode() void YamlDocument::deleteChildNodes() { - for (Sequence::iterator it = doc_.begin(); it != doc_.end(); ++it) { - YamlNode *yamlNode = static_cast<YamlNode *>(*it); + for (auto &it : doc_) { + YamlNode *yamlNode = static_cast<YamlNode *>(it); yamlNode->deleteChildNodes(); delete yamlNode; @@ -124,8 +124,8 @@ void MappingNode::getValue(const std::string &key, std::string *v) const void MappingNode::deleteChildNodes() { - for (YamlNodeMap::iterator it = map_.begin(); it != map_.end(); ++it) { - YamlNode *yamlNode = static_cast<YamlNode *>(it->second); + for (auto &it : map_) { + YamlNode *yamlNode = static_cast<YamlNode *>(it.second); if (!yamlNode) continue; @@ -144,8 +144,8 @@ void SequenceNode::addNode(YamlNode *node) void SequenceNode::deleteChildNodes() { - for (Sequence::iterator it = seq_.begin(); it != seq_.end(); ++it) { - YamlNode *yamlNode = static_cast<YamlNode *>(*it); + for (auto &it : seq_) { + YamlNode *yamlNode = static_cast<YamlNode *>(it); yamlNode->deleteChildNodes(); delete yamlNode; diff --git a/daemon/src/config/yamlparser.cpp b/daemon/src/config/yamlparser.cpp index 02cb3434ff659d4822d87c43720dc515fdcba04b..c720e45220ad9a43f701dfb9a3ea56f5d7a67c3a 100644 --- a/daemon/src/config/yamlparser.cpp +++ b/daemon/src/config/yamlparser.cpp @@ -380,8 +380,8 @@ void YamlParser::constructNativeData() { Sequence *seq = doc_.getSequence(); - for (Sequence::iterator iter = seq->begin(); iter != seq->end(); ++iter) { - YamlNode *yamlNode = static_cast<YamlNode *>(*iter); + for (const auto &item : *seq) { + YamlNode *yamlNode = static_cast<YamlNode *>(item); if (yamlNode == NULL) { ERROR("Could not retrieve yaml node from document sequence"); continue; diff --git a/daemon/src/eventthread.cpp b/daemon/src/eventthread.cpp index d4b833fc472c9b923d43c78855f2b92c1fd4bd5b..ee5c47c8089add0dfaa8e20e5372c39c0e5471bd 100644 --- a/daemon/src/eventthread.cpp +++ b/daemon/src/eventthread.cpp @@ -31,6 +31,11 @@ #include "eventthread.h" #include "voiplink.h" + #ifdef __ANDROID__ + #include <sched.h> + #define pthread_yield sched_yield + #endif + EventThread::EventThread(VoIPLink *link) : link_(link), thread_(0) {} diff --git a/daemon/src/fileutils.cpp b/daemon/src/fileutils.cpp index 7a011388279571d5d13d8b2d1601bd04f684ba3a..a6f9f310d491b268a96a7d2ceaf4b1e7ddcabe60 100644 --- a/daemon/src/fileutils.cpp +++ b/daemon/src/fileutils.cpp @@ -71,7 +71,11 @@ bool check_dir(const char *path) return true; } +#ifdef __ANDROID__ +static char *program_dir = "/data/data/com.savoirfairelinux.sflphone"; +#else static char *program_dir = NULL; +#endif void set_program_dir(char *program_path) { @@ -174,9 +178,14 @@ FileHandle::~FileHandle() } } + std::string get_home_dir() { +#ifdef __ANDROID__ + return get_program_dir(); +#else + // 1) try getting user's home directory from the environment const std::string home(PROTECTED_GETENV("HOME")); if (not home.empty()) @@ -192,5 +201,6 @@ get_home_dir() } return ""; +#endif } } diff --git a/daemon/src/global.h b/daemon/src/global.h index 98fc3ec4f740a63690f43bf8ae25e4d8b0415864..1c5e94679232ff9d951be4e715ca73608de58c00 100644 --- a/daemon/src/global.h +++ b/daemon/src/global.h @@ -33,8 +33,11 @@ #ifndef __GLOBAL_H__ #define __GLOBAL_H__ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <cstdio> -#include <libintl.h> #include <locale.h> #include <string> #include <cstdlib> @@ -42,8 +45,6 @@ #include <map> #include <vector> -#include "config.h" - const char * const ZRTP_ZID_FILENAME = "sfl.zid"; #define ALSA_DFT_CARD_ID 0 /** Index of the default soundcard */ diff --git a/daemon/src/history/history.cpp b/daemon/src/history/history.cpp index b4c612ba49efa03044170aa86f7e0046f38e18b2..ad24587b8c958ed30bf04ca3691d775076072acc 100644 --- a/daemon/src/history/history.cpp +++ b/daemon/src/history/history.cpp @@ -36,6 +36,7 @@ #include <fstream> #include <sys/stat.h> // for mkdir #include <ctime> +#include <cstring> #include "scoped_lock.h" #include "fileutils.h" #include "logger.h" @@ -43,6 +44,7 @@ namespace sfl { + using std::map; using std::string; using std::vector; @@ -65,9 +67,12 @@ bool History::load(int limit) DEBUG("No history file to load"); return false; } - while (!infile.eof()) { + + int counter = 0; + while (!infile.eof() and counter < limit) { HistoryItem item(infile); addEntry(item, limit); + ++counter; } return true; } @@ -81,9 +86,8 @@ bool History::save() std::ofstream outfile(path_.c_str()); if (outfile.fail()) return false; - for (vector<HistoryItem>::const_iterator iter = items_.begin(); - iter != items_.end(); ++iter) - outfile << *iter << std::endl; + for (const auto &item : items_) + outfile << item << std::endl; return true; } @@ -97,9 +101,11 @@ void History::addEntry(const HistoryItem &item, int oldest) void History::ensurePath() { if (path_.empty()) { +#ifdef __ANDROID__ + path_ = fileutils::get_home_dir() + DIR_SEPARATOR_STR "history"; +#else const string xdg_data = fileutils::get_home_dir() + DIR_SEPARATOR_STR + ".local/share/sflphone"; - // If the environment variable is set (not null and not empty), we'll use it to save the history // Else we 'll the standard one, ie: XDG_DATA_HOME = $HOME/.local/share/sflphone string xdg_env(XDG_DATA_HOME); @@ -108,12 +114,13 @@ void History::ensurePath() if (mkdir(userdata.data(), 0755) != 0) { // If directory creation failed if (errno != EEXIST) { - DEBUG("Cannot create directory: %m"); + DEBUG("Cannot create directory: %s!: %s", userdata.c_str(), strerror(errno)); return; } } // Load user's history path_ = userdata + DIR_SEPARATOR_STR + "history"; +#endif } } @@ -121,9 +128,8 @@ vector<map<string, string> > History::getSerialized() { sfl::ScopedLock lock(historyItemsMutex_); vector<map<string, string> > result; - for (vector<HistoryItem>::const_iterator iter = items_.begin(); - iter != items_.end(); ++iter) - result.push_back(iter->toMap()); + for (const auto &item : items_) + result.push_back(item.toMap()); return result; } diff --git a/daemon/src/history/history.h b/daemon/src/history/history.h index 886cd40eebb5f7ecbf433fbc1cb393149b69475c..cac9b9b9ebfef299fcb3baef49f50c203e9cc093 100644 --- a/daemon/src/history/history.h +++ b/daemon/src/history/history.h @@ -66,11 +66,11 @@ class History { void addCall(Call *call, int limit); void clear(); + void setPath(const std::string &path); private: /* Mutex to protect the history items */ pthread_mutex_t historyItemsMutex_; - void setPath(const std::string &path); /* If no path has been set, this will initialize path to a * system-dependent location */ void ensurePath(); diff --git a/daemon/src/history/historyitem.cpp b/daemon/src/history/historyitem.cpp index ff09c0ea6c7f847c1e7843cd951cdf188f3f89f6..c7419e00f4217f022a4a640443003b8edaa3e5fa 100644 --- a/daemon/src/history/historyitem.cpp +++ b/daemon/src/history/historyitem.cpp @@ -103,13 +103,12 @@ bool HistoryItem::hasPeerNumber() const void HistoryItem::print(std::ostream &o) const { // every entry starts with "[" + random integer = "]" - for (map<string, string>::const_iterator iter = entryMap_.begin(); - iter != entryMap_.end(); ++iter) { + for (const auto &item : entryMap_) { // if the file does not exist anymore, we do not save it - if (iter->first == RECORDING_PATH_KEY and not file_exists(iter->second)) - o << iter->first << "=" << "" << std::endl; + if (item.first == RECORDING_PATH_KEY and not file_exists(item.second)) + o << item.first << "=" << "" << std::endl; else - o << iter->first << "=" << iter->second << std::endl; + o << item.first << "=" << item.second << std::endl; } } diff --git a/daemon/src/history/historynamecache.cpp b/daemon/src/history/historynamecache.cpp index 24ec499da08fdedc5aa50626565c2cb7a451cf08..828448b28b79457c365cd35bf48d61c6f32a7aef 100644 --- a/daemon/src/history/historynamecache.cpp +++ b/daemon/src/history/historynamecache.cpp @@ -39,10 +39,10 @@ HistoryNameCache::HistoryNameCache() : hNameCache_() typedef vector<map<string, string> > HistoryList; HistoryList history(Manager::instance().getHistory()); - for (HistoryList::iterator i = history.begin(); i != history.end(); ++i) { - string name((*i)["display_name"]); - string account((*i)["accountid"]); - string number((*i)["peer_number"]); + for (auto &i : history) { + string name(i["display_name"]); + string account(i["accountid"]); + string number(i["peer_number"]); if (hNameCache_[account][number].empty() and not name.empty() and not number.empty()) hNameCache_[account][number] = name; } diff --git a/daemon/src/iax/iaxaccount.cpp b/daemon/src/iax/iaxaccount.cpp index 302d4502010d34b1d3142bf27c93e169eb19689c..06a934f3c8f3d922463feb83d1b558030b0bad1c 100644 --- a/daemon/src/iax/iaxaccount.cpp +++ b/daemon/src/iax/iaxaccount.cpp @@ -77,6 +77,9 @@ void IAXAccount::serialize(Conf::YamlEmitter &emitter) accountmap.setKeyValue(DISPLAY_NAME_KEY, &displayName); accountmap.setKeyValue(AUDIO_CODECS_KEY, &codecs); + Conf::ScalarNode userAgent(userAgent_); + accountmap.setKeyValue(USER_AGENT_KEY, &userAgent); + try { emitter.serializeAccount(&accountmap); } catch (const Conf::YamlEmitterException &e) { @@ -97,6 +100,8 @@ void IAXAccount::unserialize(const Conf::YamlNode &map) // Update codec list which one is used for SDP offer setActiveAudioCodecs(split_string(audioCodecStr_)); map.getValue(DISPLAY_NAME_KEY, &displayName_); + + map.getValue(USER_AGENT_KEY, &userAgent_); } void IAXAccount::setAccountDetails(std::map<std::string, std::string> details) diff --git a/daemon/src/iax/iaxcall.cpp b/daemon/src/iax/iaxcall.cpp index 934ab02a92cb5bba7015e0eda6a97364a90883d0..3c7c725bd222b52b51e6b806e290d3bec9099d88 100644 --- a/daemon/src/iax/iaxcall.cpp +++ b/daemon/src/iax/iaxcall.cpp @@ -74,8 +74,8 @@ int IAXCall::getSupportedFormat(const std::string &accountID) const if (account) { vector<int> codecs(account->getActiveAudioCodecs()); - for (vector<int>::const_iterator i = codecs.begin(); i != codecs.end(); ++i) - format_mask |= codecToASTFormat(*i); + for (const auto &i : codecs) + format_mask |= codecToASTFormat(i); } else ERROR("No IAx account could be found"); @@ -90,8 +90,8 @@ int IAXCall::getFirstMatchingFormat(int needles, const std::string &accountID) c if (account != NULL) { vector<int> codecs(account->getActiveAudioCodecs()); - for (vector<int>::const_iterator i = codecs.begin(); i != codecs.end(); ++i) { - int format_mask = codecToASTFormat(*i); + for (const auto &i : codecs) { + int format_mask = codecToASTFormat(i); // Return the first that matches if (format_mask & needles) diff --git a/daemon/src/iax/iaxvoiplink.cpp b/daemon/src/iax/iaxvoiplink.cpp index 6ff8a6e2e7749a5f792bd3a5b1ddc5cdd0b38ae6..381df6eea64b61f36c1534fad929aa78af1a5d14 100644 --- a/daemon/src/iax/iaxvoiplink.cpp +++ b/daemon/src/iax/iaxvoiplink.cpp @@ -56,8 +56,8 @@ IAXVoIPLink::IAXVoIPLink(const std::string& accountID) : regSession_(NULL) , nextRefreshStamp_(0) , mutexIAX_() - , decData_() - , resampledData_() + , decData_(DEC_BUFFER_SIZE) + , resampledData_(DEC_BUFFER_SIZE*4) , encodedData_() , converter_(44100) , initDone_(false) @@ -105,8 +105,8 @@ IAXVoIPLink::terminate() sfl::ScopedLock m(iaxCallMapMutex_); - for (IAXCallMap::iterator iter = iaxCallMap_.begin(); iter != iaxCallMap_.end(); ++iter) { - IAXCall *call = static_cast<IAXCall*>(iter->second); + for (auto &item : iaxCallMap_) { + IAXCall *call = static_cast<IAXCall*>(item.second); if (call) { sfl::ScopedLock lock(mutexIAX_); @@ -182,8 +182,8 @@ IAXVoIPLink::getCallIDs() void IAXVoIPLink::sendAudioFromMic() { - for (IAXCallMap::const_iterator iter = iaxCallMap_.begin(); iter != iaxCallMap_.end() ; ++iter) { - IAXCall *currentCall = static_cast<IAXCall*>(iter->second); + for (const auto &item : iaxCallMap_) { + IAXCall *currentCall = static_cast<IAXCall*>(item.second); if (!currentCall or currentCall->getState() != Call::ACTIVE) continue; @@ -200,33 +200,34 @@ IAXVoIPLink::sendAudioFromMic() // we have to get 20ms of data from the mic *20/1000 = /50 // rate/50 shall be lower than IAX__20S_48KHZ_MAX - const size_t bytesNeeded = mainBufferSampleRate * 20 / 1000 * sizeof(SFLDataFormat); + size_t samples = mainBufferSampleRate * 20 / 1000; - if (Manager::instance().getMainBuffer().availableForGet(currentCall->getCallId()) < bytesNeeded) + if (Manager::instance().getMainBuffer().availableForGet(currentCall->getCallId()) < samples) continue; // Get bytes from micRingBuffer to data_from_mic - int bytes = Manager::instance().getMainBuffer().getData(decData_, bytesNeeded, currentCall->getCallId()); - int samples = bytes / sizeof(SFLDataFormat); + decData_.resize(samples); + samples = Manager::instance().getMainBuffer().getData(decData_, currentCall->getCallId()); int compSize; unsigned int audioRate = audioCodec->getClockRate(); int outSamples; - SFLDataFormat *in; + AudioBuffer *in; if (audioRate != mainBufferSampleRate) { - converter_.resample(decData_, resampledData_, ARRAYSIZE(resampledData_), - audioRate, mainBufferSampleRate, samples); - in = resampledData_; + decData_.setSampleRate(audioRate); + resampledData_.setSampleRate(mainBufferSampleRate); + converter_.resample(decData_, resampledData_); + in = &resampledData_; outSamples = 0; } else { outSamples = samples; - in = decData_; + in = &decData_; } - compSize = audioCodec->encode(encodedData_, in, DEC_BUFFER_SIZE); + compSize = audioCodec->encode(encodedData_, in->getData(), DEC_BUFFER_SIZE); - if (currentCall->session and bytes > 0) { + if (currentCall->session and samples > 0) { sfl::ScopedLock m(mutexIAX_); if (iax_send_voice(currentCall->session, currentCall->format, encodedData_, compSize, outSamples) == -1) @@ -459,9 +460,8 @@ IAXVoIPLink::clearIaxCallMap() { sfl::ScopedLock m(iaxCallMapMutex_); - for (IAXCallMap::const_iterator iter = iaxCallMap_.begin(); - iter != iaxCallMap_.end(); ++iter) - delete iter->second; + for (const auto &item : iaxCallMap_) + delete item.second; iaxCallMap_.clear(); @@ -539,8 +539,8 @@ IAXVoIPLink::iaxFindCallBySession(iax_session* session) { sfl::ScopedLock m(iaxCallMapMutex_); - for (IAXCallMap::const_iterator iter = iaxCallMap_.begin(); iter != iaxCallMap_.end(); ++iter) { - IAXCall* call = static_cast<IAXCall*>(iter->second); + for (const auto &item : iaxCallMap_) { + IAXCall* call = static_cast<IAXCall*>(item.second); if (call and call->session == session) return call; @@ -660,19 +660,18 @@ void IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, IAXCall* call) if (size > max) size = max; - int samples = audioCodec->decode(decData_, data , size); - int outSize = samples * sizeof(SFLDataFormat); - SFLDataFormat *out = decData_; + audioCodec->decode(decData_.getData(), data , size); + AudioBuffer *out = &decData_; unsigned int audioRate = audioCodec->getClockRate(); if (audioRate != mainBufferSampleRate) { - outSize = (double)outSize * (mainBufferSampleRate / audioRate); - converter_.resample(decData_, resampledData_, ARRAYSIZE(resampledData_), - mainBufferSampleRate, audioRate, samples); - out = resampledData_; + decData_.setSampleRate(mainBufferSampleRate); + resampledData_.setSampleRate(audioRate); + converter_.resample(decData_, resampledData_); + out = &resampledData_; } - Manager::instance().getMainBuffer().putData(out, outSize, call->getCallId()); + Manager::instance().getMainBuffer().putData(*out, call->getCallId()); } /** diff --git a/daemon/src/iax/iaxvoiplink.h b/daemon/src/iax/iaxvoiplink.h index d6f9ba14d54565ef74c6e6a34dee08f535e89821..6de169ca7a3dc4f2a16a6425d48391adb5a78da3 100644 --- a/daemon/src/iax/iaxvoiplink.h +++ b/daemon/src/iax/iaxvoiplink.h @@ -39,6 +39,7 @@ #include <pthread.h> #include "account.h" #include "voiplink.h" +#include "audio/audiobuffer.h" #include "audio/codecs/audiocodec.h" // for DEC_BUFFER_SIZE #include "sfl_types.h" #include "noncopyable.h" @@ -286,8 +287,10 @@ class IAXVoIPLink : public VoIPLink { pthread_mutex_t mutexIAX_; /** encoder/decoder/resampler buffers */ - SFLDataFormat decData_[DEC_BUFFER_SIZE]; - SFLDataFormat resampledData_[DEC_BUFFER_SIZE * 4]; + AudioBuffer decData_; + AudioBuffer resampledData_; + //SFLAudioSample decData_[DEC_BUFFER_SIZE]; + //SFLAudioSample resampledData_[DEC_BUFFER_SIZE * 4]; unsigned char encodedData_[DEC_BUFFER_SIZE]; /** Sample rate converter object */ diff --git a/daemon/src/im/instant_messaging.cpp b/daemon/src/im/instant_messaging.cpp index c25490a5d330c01a57e03adf8e4fbbe0660003db..8e1e2c3ed5c5ecf075b722fc9021b3a0cb27c513 100644 --- a/daemon/src/im/instant_messaging.cpp +++ b/daemon/src/im/instant_messaging.cpp @@ -31,7 +31,7 @@ #include "instant_messaging.h" #include "logger.h" -#include "expat.h" +#include <expat.h> namespace { void XMLCALL @@ -99,20 +99,17 @@ void InstantMessaging::sip_send(pjsip_inv_session *session, const std::string& i void InstantMessaging::send_sip_message(pjsip_inv_session *session, const std::string &id, const std::string &message) { std::vector<std::string> msgs(split_message(message)); - std::vector<std::string>::const_iterator iter; - - for (iter = msgs.begin(); iter != msgs.end(); ++iter) - sip_send(session, id, *iter); + for (const auto &item : msgs) + sip_send(session, id, item); } #if HAVE_IAX void InstantMessaging::send_iax_message(iax_session *session, const std::string &/* id */, const std::string &message) { std::vector<std::string> msgs(split_message(message)); - std::vector<std::string>::const_iterator iter; - for (iter = msgs.begin(); iter != msgs.end(); ++iter) - iax_send_text(session, (*iter).c_str()); + for (const auto &item : msgs) + iax_send_text(session, item.c_str()); } #endif @@ -138,8 +135,8 @@ std::string InstantMessaging::generateXmlUriList(UriList &list) "<resource-lists xmlns=\"urn:ietf:params:xml:ns:resource-lists\" xmlns:cp=\"urn:ietf:params:xml:ns:copycontrol\">" "<list>"; - for (UriList::iterator iter = list.begin(); iter != list.end(); ++iter) - xmlbuffer += "<entry uri=" + (*iter)[sfl::IM_XML_URI] + " cp:copyControl=\"to\" />"; + for (auto &item : list) + xmlbuffer += "<entry uri=" + item[sfl::IM_XML_URI] + " cp:copyControl=\"to\" />"; return xmlbuffer + "</list></resource-lists>"; } diff --git a/daemon/src/im/instant_messaging.h b/daemon/src/im/instant_messaging.h index f80113eebcd8246c12c94daa13536b737b940351..db01eeb718ffc66cb9a3bb17dbb4fbdb442f698f 100644 --- a/daemon/src/im/instant_messaging.h +++ b/daemon/src/im/instant_messaging.h @@ -45,10 +45,12 @@ #include <list> #include <stdexcept> -#include <iax-client.h> - #include "config.h" +#if HAVE_IAX +#include <iax-client.h> +#endif + #define EMPTY_MESSAGE pj_str((char*)"") #define MAXIMUM_MESSAGE_LENGTH 1560 /* PJSIP's sip message limit */ diff --git a/daemon/src/logger.h b/daemon/src/logger.h index dd08deb6eafe1687524a3d5504e3e004d7e11682..95a1de47646dab69d3a21d7dc69563a2c21875c0 100644 --- a/daemon/src/logger.h +++ b/daemon/src/logger.h @@ -31,8 +31,13 @@ #ifndef LOGGER_H_ #define LOGGER_H_ -#include <syslog.h> #include <pthread.h> +#ifdef __ANDROID__ +#include <cstring> +#include <android/log.h> +#else +#include <syslog.h> +#endif namespace Logger { void log(const int, const char*, ...); @@ -42,13 +47,32 @@ void setDebugMode(bool); bool getDebugMode(); }; -#define LOGGER(M, LEVEL, ...) Logger::log(LEVEL, "%s:%d:tid %lu:\t" M, __FILE__, \ - __LINE__, pthread_self() & 0xffff, ##__VA_ARGS__) +#define LOG_FORMAT(M, ...) "%s:%d:0x%x: " M, FILE_NAME, __LINE__, (unsigned long) pthread_self() & 0xffff, ##__VA_ARGS__ +#ifndef __ANDROID__ + +#define FILE_NAME __FILE__ #define ERROR(M, ...) LOGGER(M, LOG_ERR, ##__VA_ARGS__) #define WARN(M, ...) LOGGER(M, LOG_WARNING, ##__VA_ARGS__) #define INFO(M, ...) LOGGER(M, LOG_INFO, ##__VA_ARGS__) #define DEBUG(M, ...) LOGGER(M, LOG_DEBUG, ##__VA_ARGS__) +#define LOGGER(M, LEVEL, ...) Logger::log(LEVEL, LOG_FORMAT(M, ##__VA_ARGS__)) + +#else /* ANDROID */ + +#ifndef APP_NAME +#define APP_NAME "libsflphone" +#endif + +// Avoid printing whole path on android +#define FILE_NAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) + +#define ERROR(M, ...) LOGGER(M, ANDROID_LOG_ERROR, ##__VA_ARGS__) +#define WARN(M, ...) LOGGER(M, ANDROID_LOG_WARN, ##__VA_ARGS__) +#define INFO(M, ...) LOGGER(M, ANDROID_LOG_INFO, ##__VA_ARGS__) +#define DEBUG(M, ...) LOGGER(M, ANDROID_LOG_DEBUG, ##__VA_ARGS__) +#define LOGGER(M, LEVEL, ...) __android_log_print(LEVEL, APP_NAME, LOG_FORMAT(M, ##__VA_ARGS__)) +#endif /* ANDROID */ #define BLACK "\033[22;30m" #define RED "\033[22;31m" diff --git a/daemon/src/main.cpp b/daemon/src/main.cpp index 26095f95f72b89a80168820accb34d95ea1db360..ce1aae67bb55721b37fb036842911aa1bf64af43 100644 --- a/daemon/src/main.cpp +++ b/daemon/src/main.cpp @@ -35,6 +35,7 @@ #endif #include <iostream> +#include <signal.h> #include <getopt.h> #include "fileutils.h" #include "logger.h" @@ -143,7 +144,7 @@ int main(int argc, char *argv []) std::vector<char> writable(programName.size() + 1); std::copy(programName.begin(), programName.end(), writable.begin()); - fileutils::set_program_dir(&*writable.begin()); + fileutils::set_program_dir(writable.data()); print_title(); if (parse_args(argc, argv)) @@ -170,8 +171,9 @@ int main(int argc, char *argv []) #ifdef SFL_VIDEO WARN("Built with video support"); #endif - +#if HAVE_DBUS Manager::instance().run(); +#endif Manager::instance().saveHistory(); return 0; diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 858e45fbdbccfbc403cce54864dc678761daa71d..0570709039d7d68da815ffcc004ff9c4eea97fe4 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -40,7 +40,6 @@ #include "managerimpl.h" #include "account_schema.h" -#include "dbus/callmanager.h" #include "global.h" #include "fileutils.h" #include "map_utils.h" @@ -59,16 +58,23 @@ #include "numbercleaner.h" #include "config/yamlparser.h" #include "config/yamlemitter.h" + +#ifndef __ANDROID__ #include "audio/alsa/alsalayer.h" +#endif + #include "audio/sound/tonelist.h" #include "audio/sound/audiofile.h" #include "audio/sound/dtmf.h" #include "history/historynamecache.h" +#include "history/history.h" #include "manager.h" -#include "dbus/configurationmanager.h" +#include "client/configurationmanager.h" +#include "client/callmanager.h" + #ifdef SFL_VIDEO -#include "dbus/video_controls.h" +#include "client/video_controls.h" #endif #include "conference.h" @@ -89,7 +95,7 @@ ManagerImpl::ManagerImpl() : preferences(), voipPreferences(), hookPreference(), audioPreference(), shortcutPreferences(), - hasTriedToRegister_(false), audioCodecFactory(), dbus_(), config_(), + hasTriedToRegister_(false), audioCodecFactory(), client_(), config_(), currentCallId_(), currentCallMutex_(), audiodriver_(0), dtmfKey_(), toneMutex_(), telephoneTone_(), audiofile_(), audioLayerMutex_(), waitingCalls_(), waitingCallsMutex_(), path_(), @@ -113,29 +119,36 @@ ManagerImpl::~ManagerImpl() } namespace { - // Creates a backup of the file at "path" with a .bak suffix appended - void make_backup(const std::string &path) + + void copy_over(const std::string &srcPath, const std::string &destPath) { - const std::string backup_path(path + ".bak"); - std::ifstream src(path.c_str()); - std::ofstream dest(backup_path.c_str()); + std::ifstream src(srcPath.c_str()); + std::ofstream dest(destPath.c_str()); dest << src.rdbuf(); src.close(); dest.close(); } + // Creates a backup of the file at "path" with a .bak suffix appended + void make_backup(const std::string &path) + { + const std::string backup_path(path + ".bak"); + copy_over(path, backup_path); + } + // Restore last backup of the configuration file + void restore_backup(const std::string &path) + { + const std::string backup_path(path + ".bak"); + copy_over(backup_path, path); + } } - -void ManagerImpl::init(const std::string &config_file) +bool ManagerImpl::parseConfiguration() { - path_ = config_file.empty() ? createConfigFile() : config_file; - DEBUG("Configuration file path: %s", path_.c_str()); + bool result = true; - bool no_errors = true; + FILE *file = fopen(path_.c_str(), "rb"); try { - FILE *file = fopen(path_.c_str(), "rb"); - if (file) { Conf::YamlParser parser(file); parser.serializeEvents(); @@ -145,20 +158,50 @@ void ManagerImpl::init(const std::string &config_file) fclose(file); if (error_count > 0) { WARN("Errors while parsing %s", path_.c_str()); - no_errors = false; + result = false; } } else { WARN("Config file not found: creating default account map"); loadDefaultAccountMap(); } + } catch (const Conf::YamlParserException &e) { + // we only want to close the local file here and then rethrow the exception + fclose(file); + throw; + } + + return result; +} + +void ManagerImpl::init(const std::string &config_file) +{ + path_ = config_file.empty() ? retrieveConfigPath() : config_file; + DEBUG("Configuration file path: %s", path_.c_str()); + + bool no_errors = true; + + try { + no_errors = parseConfiguration(); } catch (const Conf::YamlParserException &e) { ERROR("%s", e.what()); no_errors = false; } // always back up last error-free configuration - if (no_errors) + if (no_errors) { make_backup(path_); + } else { + // restore previous configuration + WARN("Restoring last working configuration"); + try { + restore_backup(path_); + parseConfiguration(); + } catch (const Conf::YamlParserException &e) { + ERROR("%s", e.what()); + WARN("Restoring backup failed, creating default account map"); + loadDefaultAccountMap(); + } + } initAudioDriver(); @@ -177,11 +220,17 @@ void ManagerImpl::init(const std::string &config_file) registerAccounts(); } +void ManagerImpl::setPath(const std::string &path) { + history_.setPath(path); +} + +#if HAVE_DBUS void ManagerImpl::run() { - DEBUG("Starting DBus event loop"); - dbus_.exec(); + DEBUG("Starting client event loop"); + client_.event_loop(); } +#endif void ManagerImpl::finish() { @@ -197,9 +246,8 @@ void ManagerImpl::finish() std::vector<std::string> callList(getCallList()); DEBUG("Hangup %zu remaining call(s)", callList.size()); - for (std::vector<std::string>::iterator iter = callList.begin(); - iter != callList.end(); ++iter) - hangupCall(*iter); + for (const auto &item : callList) + hangupCall(item); saveConfig(); @@ -217,7 +265,7 @@ void ManagerImpl::finish() audiodriver_ = NULL; } - dbus_.exit(); + client_.exit(); } bool ManagerImpl::isCurrentCall(const std::string& callId) const @@ -343,8 +391,7 @@ bool ManagerImpl::answerCall(const std::string& call_id) stopTone(); // set playback mode to VOICE - AudioLayer *al = getAudioDriver(); - if(al) al->setPlaybackMode(AudioLayer::VOICE); + if (audiodriver_) audiodriver_->setPlaybackMode(AudioLayer::VOICE); // store the current call id std::string current_call_id(getCurrentCallId()); @@ -391,8 +438,8 @@ bool ManagerImpl::answerCall(const std::string& call_id) if (audioPreference.getIsAlwaysRecording()) toggleRecordingCall(call_id); - // update call state on client side - dbus_.getCallManager()->callStateChanged(call_id, "CURRENT"); + client_.getCallManager()->callStateChanged(call_id, "CURRENT"); + return result; } @@ -403,6 +450,7 @@ void ManagerImpl::checkAudio() if (audiodriver_) audiodriver_->stopStream(); } + } //THREAD=Main @@ -414,12 +462,10 @@ bool ManagerImpl::hangupCall(const std::string& callId) stopTone(); // set playback mode to NONE - AudioLayer *al = getAudioDriver(); - if(al) al->setPlaybackMode(AudioLayer::NONE); + if (audiodriver_) audiodriver_->setPlaybackMode(AudioLayer::NONE); - /* Broadcast a signal over DBus */ - DEBUG("Send DBUS call state change (HUNGUP) for id %s", callId.c_str()); - dbus_.getCallManager()->callStateChanged(callId, "HUNGUP"); + DEBUG("Send call state change (HUNGUP) for id %s", callId.c_str()); + client_.getCallManager()->callStateChanged(callId, "HUNGUP"); /* We often get here when the call was hungup before being created */ if (not isValidCall(callId) and not isIPToIP(callId)) { @@ -480,9 +526,8 @@ bool ManagerImpl::hangupConference(const std::string& id) if (conf) { ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator iter = participants.begin(); - iter != participants.end(); ++iter) - hangupCall(*iter); + for (const auto &item : participants) + hangupCall(item); } else { ERROR("No such conference %s", id.c_str()); return false; @@ -536,7 +581,7 @@ bool ManagerImpl::onHoldCall(const std::string& callId) if (current_call_id == callId) unsetCurrentCall(); - dbus_.getCallManager()->callStateChanged(callId, "HOLD"); + client_.getCallManager()->callStateChanged(callId, "HOLD"); getMainBuffer().dumpInfo(); return result; @@ -574,7 +619,7 @@ bool ManagerImpl::offHoldCall(const std::string& callId) result = false; } - dbus_.getCallManager()->callStateChanged(callId, "UNHOLD"); + client_.getCallManager()->callStateChanged(callId, "UNHOLD"); if (isConferenceParticipant(callId)) { Call *call = getCallFromCallID(callId); @@ -622,12 +667,12 @@ bool ManagerImpl::transferCall(const std::string& callId, const std::string& to) void ManagerImpl::transferFailed() { - dbus_.getCallManager()->transferFailed(); + client_.getCallManager()->transferFailed(); } void ManagerImpl::transferSucceeded() { - dbus_.getCallManager()->transferSucceeded(); + client_.getCallManager()->transferSucceeded(); } bool ManagerImpl::attendedTransfer(const std::string& transferID, const std::string& targetID) @@ -674,7 +719,8 @@ bool ManagerImpl::refuseCall(const std::string& id) } removeWaitingCall(id); - dbus_.getCallManager()->callStateChanged(id, "HUNGUP"); + + client_.getCallManager()->callStateChanged(id, "HUNGUP"); // Disconnect streams removeStream(id); @@ -696,8 +742,7 @@ ManagerImpl::createConference(const std::string& id1, const std::string& id2) // Add conference to map conferenceMap_.insert(std::make_pair(conf->getConfID(), conf)); - // broadcast a signal over dbus - dbus_.getCallManager()->conferenceCreated(conf->getConfID()); + client_.getCallManager()->conferenceCreated(conf->getConfID()); return conf; } @@ -718,8 +763,7 @@ void ManagerImpl::removeConference(const std::string& conference_id) return; } - // broadcast a signal over dbus - dbus_.getCallManager()->conferenceRemoved(conference_id); + client_.getCallManager()->conferenceRemoved(conference_id); // We now need to bind the audio to the remain participant @@ -774,14 +818,15 @@ ManagerImpl::holdConference(const std::string& id) ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator iter = participants.begin(); - iter != participants.end(); ++iter) { - switchCall(*iter); - onHoldCall(*iter); + for (const auto &item : participants) { + switchCall(item); + onHoldCall(item); } conf->setState(isRec ? Conference::HOLD_REC : Conference::HOLD); - dbus_.getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + + client_.getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + return true; } @@ -801,19 +846,21 @@ ManagerImpl::unHoldConference(const std::string& id) ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator iter = participants.begin(); iter!= participants.end(); ++iter) { - Call *call = getCallFromCallID(*iter); + for (const auto &item : participants) { + Call *call = getCallFromCallID(item); if (call) { // if one call is currently recording, the conference is in state recording isRec |= call->isRecording(); - switchCall(*iter); - offHoldCall(*iter); + switchCall(item); + offHoldCall(item); } } conf->setState(isRec ? Conference::ACTIVE_ATTACHED_REC : Conference::ACTIVE_ATTACHED); - dbus_.getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + + client_.getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + return true; } @@ -897,9 +944,8 @@ ManagerImpl::addParticipant(const std::string& callId, const std::string& confer // reset ring buffer for all conference participant // flush conference participants only - for (ParticipantSet::const_iterator p = participants.begin(); - p != participants.end(); ++p) - getMainBuffer().flush(*p); + for (const auto &p : participants) + getMainBuffer().flush(p); getMainBuffer().flush(MainBuffer::DEFAULT_ID); @@ -932,11 +978,10 @@ ManagerImpl::addMainParticipant(const std::string& conference_id) ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator iter_p = participants.begin(); - iter_p != participants.end(); ++iter_p) { - getMainBuffer().bindCallID(*iter_p, MainBuffer::DEFAULT_ID); + for (const auto &item_p : participants) { + getMainBuffer().bindCallID(item_p, MainBuffer::DEFAULT_ID); // Reset ringbuffer's readpointers - getMainBuffer().flush(*iter_p); + getMainBuffer().flush(item_p); } getMainBuffer().flush(MainBuffer::DEFAULT_ID); @@ -948,7 +993,7 @@ ManagerImpl::addMainParticipant(const std::string& conference_id) else WARN("Invalid conference state while adding main participant"); - dbus_.getCallManager()->conferenceChanged(conference_id, conf->getStateStr()); + client_.getCallManager()->conferenceChanged(conference_id, conf->getStateStr()); } switchCall(conference_id); @@ -1088,9 +1133,8 @@ void ManagerImpl::createConfFromParticipantList(const std::vector< std::string > int successCounter = 0; - for (std::vector<std::string>::const_iterator p = participantList.begin(); - p != participantList.end(); ++p) { - std::string numberaccount(*p); + for (const auto &p : participantList) { + std::string numberaccount(p); std::string tostr(numberaccount.substr(0, numberaccount.find(","))); std::string account(numberaccount.substr(numberaccount.find(",") + 1, numberaccount.size())); @@ -1108,7 +1152,7 @@ void ManagerImpl::createConfFromParticipantList(const std::vector< std::string > if (!callSuccess) conf->remove(generatedCallID); else { - dbus_.getCallManager()->newCallCreated(account, generatedCallID, tostr); + client_.getCallManager()->newCallCreated(account, generatedCallID, tostr); successCounter++; } } @@ -1116,7 +1160,7 @@ void ManagerImpl::createConfFromParticipantList(const std::vector< std::string > // Create the conference if and only if at least 2 calls have been successfully created if (successCounter >= 2) { conferenceMap_[conf->getConfID()] = conf; - dbus_.getCallManager()->conferenceCreated(conf->getConfID()); + client_.getCallManager()->conferenceCreated(conf->getConfID()); { sfl::ScopedLock lock(audioLayerMutex_); @@ -1189,7 +1233,7 @@ ManagerImpl::detachParticipant(const std::string& call_id) else WARN("Undefined behavior, invalid conference state in detach participant"); - dbus_.getCallManager()->conferenceChanged(conf->getConfID(), + client_.getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); unsetCurrentCall(); @@ -1221,8 +1265,11 @@ void ManagerImpl::removeParticipant(const std::string& call_id) call->setConfId(""); removeStream(call_id); + getMainBuffer().dumpInfo(); - dbus_.getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + + client_.getCallManager()->conferenceChanged(conf->getConfID(), conf->getStateStr()); + processRemainingParticipants(*conf); } @@ -1236,9 +1283,8 @@ void ManagerImpl::processRemainingParticipants(Conference &conf) if (n > 1) { // Reset ringbuffer's readpointers - for (ParticipantSet::const_iterator p = participants.begin(); - p != participants.end(); ++p) - getMainBuffer().flush(*p); + for (const auto &p : participants) + getMainBuffer().flush(p); getMainBuffer().flush(MainBuffer::DEFAULT_ID); } else if (n == 1) { @@ -1282,9 +1328,8 @@ ManagerImpl::joinConference(const std::string& conf_id1, Conference *conf = conferenceMap_.find(conf_id1)->second; ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator p = participants.begin(); - p != participants.end(); ++p) - addParticipant(*p, conf_id2); + for (const auto &p : participants) + addParticipant(p, conf_id2); return true; } @@ -1308,9 +1353,8 @@ void ManagerImpl::addStream(const std::string& call_id) ParticipantSet participants(conf->getParticipantList()); // reset ring buffer for all conference participant - for (ParticipantSet::const_iterator iter_p = participants.begin(); - iter_p != participants.end(); ++iter_p) - getMainBuffer().flush(*iter_p); + for (const auto &participant : participants) + getMainBuffer().flush(participant); getMainBuffer().flush(MainBuffer::DEFAULT_ID); } @@ -1340,22 +1384,20 @@ void ManagerImpl::removeStream(const std::string& call_id) void ManagerImpl::saveConfig() { DEBUG("Saving Configuration to XDG directory %s", path_.c_str()); - AudioLayer *audiolayer = getAudioDriver(); - if (audiolayer != NULL) { - audioPreference.setVolumemic(audiolayer->getCaptureGain()); - audioPreference.setVolumespkr(audiolayer->getPlaybackGain()); + if (audiodriver_ != NULL) { + audioPreference.setVolumemic(audiodriver_->getCaptureGain()); + audioPreference.setVolumespkr(audiodriver_->getPlaybackGain()); } try { Conf::YamlEmitter emitter(path_.c_str()); - for (AccountMap::iterator iter = SIPVoIPLink::instance()->getAccounts().begin(); - iter != SIPVoIPLink::instance()->getAccounts().end(); ++iter) - iter->second->serialize(emitter); + for (auto &item : SIPVoIPLink::instance()->getAccounts()) + item.second->serialize(emitter); #if HAVE_IAX - for (AccountMap::iterator iter = IAXVoIPLink::getAccounts().begin(); iter != IAXVoIPLink::getAccounts().end(); ++iter) - iter->second->serialize(emitter); + for (auto &item : IAXVoIPLink::getAccounts()) + item.second->serialize(emitter); #endif preferences.serialize(emitter); @@ -1423,19 +1465,20 @@ void ManagerImpl::playDtmf(char code) // this buffer is for mono // TODO <-- this should be global and hide if same size - std::vector<SFLDataFormat> buf(size); + //std::vector<SFLAudioSample> buf(size); + AudioBuffer buf(size); // Handle dtmf dtmfKey_->startTone(code); // copy the sound - if (dtmfKey_->generateDTMF(buf)) { + if (dtmfKey_->generateDTMF(*buf.getChannel(0))) { // Put buffer to urgentRingBuffer // put the size in bytes... // so size * 1 channel (mono) * sizeof (bytes for the data) // audiolayer->flushUrgent(); audiodriver_->startStream(); - audiodriver_->putUrgent(&(*buf.begin()), size * sizeof(SFLDataFormat)); + audiodriver_->putUrgent(buf); } // TODO Cache the DTMF @@ -1485,7 +1528,7 @@ void ManagerImpl::incomingCall(Call &call, const std::string& accountId) if (not hasCurrentCall()) { call.setConnectionState(Call::RINGING); - ringtone(accountId); + playRingtone(accountId); } addWaitingCall(callID); @@ -1493,7 +1536,8 @@ void ManagerImpl::incomingCall(Call &call, const std::string& accountId) std::string number(call.getPeerNumber()); std::string from("<" + number + ">"); - dbus_.getCallManager()->incomingCall(accountId, callID, call.getDisplayName() + " " + from); + + client_.getCallManager()->incomingCall(accountId, callID, call.getDisplayName() + " " + from); } @@ -1508,15 +1552,14 @@ void ManagerImpl::incomingMessage(const std::string& callID, ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator iter_p = participants.begin(); - iter_p != participants.end(); ++iter_p) { + for (const auto &item_p : participants) { - if (*iter_p == callID) + if (item_p == callID) continue; - std::string accountId(getAccountFromCall(*iter_p)); + std::string accountId(getAccountFromCall(item_p)); - DEBUG("Send message to %s, (%s)", (*iter_p).c_str(), accountId.c_str()); + DEBUG("Send message to %s, (%s)", item_p.c_str(), accountId.c_str()); Account *account = getAccount(accountId); @@ -1529,10 +1572,10 @@ void ManagerImpl::incomingMessage(const std::string& callID, } // in case of a conference we must notify client using conference id - dbus_.getCallManager()->incomingMessage(conf->getConfID(), from, message); + client_.getCallManager()->incomingMessage(conf->getConfID(), from, message); } else - dbus_.getCallManager()->incomingMessage(callID, from, message); + client_.getCallManager()->incomingMessage(callID, from, message); } //THREAD=VoIP @@ -1552,10 +1595,9 @@ bool ManagerImpl::sendTextMessage(const std::string& callID, const std::string& ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator iter_p = participants.begin(); - iter_p != participants.end(); ++iter_p) { + for (const auto &participant : participants) { - std::string accountId = getAccountFromCall(*iter_p); + std::string accountId = getAccountFromCall(participant); Account *account = getAccount(accountId); @@ -1564,7 +1606,7 @@ bool ManagerImpl::sendTextMessage(const std::string& callID, const std::string& return false; } - account->getVoIPLink()->sendTextMessage(*iter_p, message, from); + account->getVoIPLink()->sendTextMessage(participant, message, from); } return true; @@ -1579,10 +1621,9 @@ bool ManagerImpl::sendTextMessage(const std::string& callID, const std::string& ParticipantSet participants(conf->getParticipantList()); - for (ParticipantSet::const_iterator iter_p = participants.begin(); - iter_p != participants.end(); ++iter_p) { + for (const auto &item_p : participants) { - const std::string accountId(getAccountFromCall(*iter_p)); + const std::string accountId(getAccountFromCall(item_p)); Account *account = getAccount(accountId); @@ -1591,7 +1632,7 @@ bool ManagerImpl::sendTextMessage(const std::string& callID, const std::string& return false; } - account->getVoIPLink()->sendTextMessage(*iter_p, message, from); + account->getVoIPLink()->sendTextMessage(item_p, message, from); } } else { Account *account = getAccount(getAccountFromCall(callID)); @@ -1617,8 +1658,7 @@ void ManagerImpl::peerAnsweredCall(const std::string& id) stopTone(); // set playback mode to VOICE - AudioLayer *al = getAudioDriver(); - if(al) al->setPlaybackMode(AudioLayer::VOICE); + if (audiodriver_) audiodriver_->setPlaybackMode(AudioLayer::VOICE); } // Connect audio streams @@ -1633,7 +1673,7 @@ void ManagerImpl::peerAnsweredCall(const std::string& id) if (audioPreference.getIsAlwaysRecording()) toggleRecordingCall(id); - dbus_.getCallManager()->callStateChanged(id, "CURRENT"); + client_.getCallManager()->callStateChanged(id, "CURRENT"); } //THREAD=VoIP Call=Outgoing @@ -1644,7 +1684,7 @@ void ManagerImpl::peerRingingCall(const std::string& id) if (isCurrentCall(id)) ringback(); - dbus_.getCallManager()->callStateChanged(id, "RINGING"); + client_.getCallManager()->callStateChanged(id, "RINGING"); } //THREAD=VoIP Call=Outgoing/Ingoing @@ -1659,8 +1699,7 @@ void ManagerImpl::peerHungupCall(const std::string& call_id) unsetCurrentCall(); // set playback mode to NONE - AudioLayer *al = getAudioDriver(); - if(al) al->setPlaybackMode(AudioLayer::NONE); + if (audiodriver_) audiodriver_->setPlaybackMode(AudioLayer::NONE); } /* Direct IP to IP call */ @@ -1681,8 +1720,7 @@ void ManagerImpl::peerHungupCall(const std::string& call_id) } } - /* Broadcast a signal over DBus */ - dbus_.getCallManager()->callStateChanged(call_id, "HUNGUP"); + client_.getCallManager()->callStateChanged(call_id, "HUNGUP"); removeWaitingCall(call_id); if (not incomingCallsWaiting()) @@ -1694,8 +1732,7 @@ void ManagerImpl::peerHungupCall(const std::string& call_id) //THREAD=VoIP void ManagerImpl::callBusy(const std::string& id) { - DEBUG("Call %s busy", id.c_str()); - dbus_.getCallManager()->callStateChanged(id, "BUSY"); + client_.getCallManager()->callStateChanged(id, "BUSY"); if (isCurrentCall(id)) { playATone(Tone::TONE_BUSY); @@ -1709,7 +1746,7 @@ void ManagerImpl::callBusy(const std::string& id) //THREAD=VoIP void ManagerImpl::callFailure(const std::string& call_id) { - dbus_.getCallManager()->callStateChanged(call_id, "FAILURE"); + client_.getCallManager()->callStateChanged(call_id, "FAILURE"); if (isCurrentCall(call_id)) { playATone(Tone::TONE_BUSY); @@ -1730,7 +1767,7 @@ void ManagerImpl::callFailure(const std::string& call_id) void ManagerImpl::startVoiceMessageNotification(const std::string& accountId, int nb_msg) { - dbus_.getCallManager()->voiceMailNotify(accountId, nb_msg); + client_.getCallManager()->voiceMailNotify(accountId, nb_msg); } /** @@ -1774,7 +1811,8 @@ void ManagerImpl::stopTone() if (audiofile_.get()) { std::string filepath(audiofile_->getFilePath()); - dbus_.getCallManager()->recordPlaybackStopped(filepath); + + client_.getCallManager()->recordPlaybackStopped(filepath); audiofile_.reset(); } } @@ -1811,10 +1849,21 @@ void ManagerImpl::ringback() playATone(Tone::TONE_RINGTONE); } +// Caller must hold toneMutex +void +ManagerImpl::updateAudioFile(const std::string &file, int sampleRate) +{ + try { + audiofile_.reset(new AudioFile(file, sampleRate)); + } catch (const AudioFileException &e) { + ERROR("Exception: %s", e.what()); + } +} + /** * Multi Thread */ -void ManagerImpl::ringtone(const std::string& accountID) +void ManagerImpl::playRingtone(const std::string& accountID) { Account *account = getAccount(accountID); @@ -1853,25 +1902,11 @@ void ManagerImpl::ringtone(const std::string& accountID) sfl::ScopedLock m(toneMutex_); if (audiofile_.get()) { - dbus_.getCallManager()->recordPlaybackStopped(audiofile_->getFilePath()); + client_.getCallManager()->recordPlaybackStopped(audiofile_->getFilePath()); audiofile_.reset(); } - try { - if (ringchoice.find(".wav") != std::string::npos) - audiofile_.reset(new WaveFile(ringchoice, audioLayerSmplr)); - else { - sfl::AudioCodec *codec; - if (ringchoice.find(".ul") != std::string::npos or ringchoice.find(".au") != std::string::npos) - codec = audioCodecFactory.getCodec(PAYLOAD_CODEC_ULAW); - else - throw AudioFileException("Couldn't guess an appropriate decoder"); - - audiofile_.reset(new RawFile(ringchoice, static_cast<sfl::AudioCodec *>(codec), audioLayerSmplr)); - } - } catch (const AudioFileException &e) { - ERROR("Exception: %s", e.what()); - } + updateAudioFile(ringchoice, audioLayerSmplr); } // leave mutex sfl::ScopedLock lock(audioLayerMutex_); @@ -1901,10 +1936,14 @@ ManagerImpl::getTelephoneFile() /** * Initialization: Main Thread */ -std::string ManagerImpl::createConfigFile() const +std::string ManagerImpl::retrieveConfigPath() const { +#ifdef __ANDROID__ + std::string configdir = "/data/data/com.savoirfairelinux.sflphone"; +#else std::string configdir = fileutils::get_home_dir() + DIR_SEPARATOR_STR + ".config" + DIR_SEPARATOR_STR + PACKAGE; +#endif const std::string xdg_env(XDG_CONFIG_HOME); if (not xdg_env.empty()) @@ -1913,7 +1952,7 @@ std::string ManagerImpl::createConfigFile() const if (mkdir(configdir.data(), 0700) != 0) { // If directory creation failed if (errno != EEXIST) - DEBUG("Cannot create directory: %m"); + DEBUG("Cannot create directory: %s!", configdir.c_str()); } static const char * const PROGNAME = "sflphoned"; @@ -2091,7 +2130,7 @@ bool ManagerImpl::toggleRecordingCall(const std::string& id) } const bool result = rec->toggleRecording(); - dbus_.getCallManager()->recordPlaybackFilepath(id, rec->getFilename()); + client_.getCallManager()->recordPlaybackFilepath(id, rec->getFilename()); return result; } @@ -2121,16 +2160,13 @@ bool ManagerImpl::startRecordedFilePlayback(const std::string& filepath) sfl::ScopedLock m(toneMutex_); if (audiofile_.get()) { - dbus_.getCallManager()->recordPlaybackStopped(audiofile_->getFilePath()); + client_.getCallManager()->recordPlaybackStopped(audiofile_->getFilePath()); audiofile_.reset(); } - try { - audiofile_.reset(new WaveFile(filepath, sampleRate)); - audiofile_->setIsRecording(true); - } catch (const AudioFileException &e) { - ERROR("Exception: %s", e.what()); - } + updateAudioFile(filepath, sampleRate); + if (not audiofile_) + return false; } // release toneMutex sfl::ScopedLock lock(audioLayerMutex_); @@ -2160,6 +2196,7 @@ void ManagerImpl::stopRecordedFilePlayback(const std::string& filepath) sfl::ScopedLock m(toneMutex_); audiofile_.reset(); } + client_.getCallManager()->recordPlaybackStopped(filepath); } void ManagerImpl::setHistoryLimit(int days) @@ -2350,20 +2387,20 @@ std::vector<std::string> ManagerImpl::getAccountList() const // If no order has been set, load the default one ie according to the creation date. if (account_order.empty()) { - for (AccountMap::const_iterator iter = allAccounts.begin(); iter != allAccounts.end(); ++iter) { - if (iter->first == SIPAccount::IP2IP_PROFILE || iter->first.empty()) + for (const auto &item : allAccounts) { + if (item.first == SIPAccount::IP2IP_PROFILE || item.first.empty()) continue; - if (iter->second) - v.push_back(iter->second->getAccountID()); + if (item.second) + v.push_back(item.second->getAccountID()); } } else { - for (vector<string>::const_iterator iter = account_order.begin(); iter != account_order.end(); ++iter) { - if (*iter == SIPAccount::IP2IP_PROFILE or iter->empty()) + for (const auto &item : account_order) { + if (item == SIPAccount::IP2IP_PROFILE or item.empty()) continue; - AccountMap::const_iterator account_iter = allAccounts.find(*iter); + AccountMap::const_iterator account_iter = allAccounts.find(item); if (account_iter != allAccounts.end() and account_iter->second) v.push_back(account_iter->second->getAccountID()); @@ -2420,7 +2457,7 @@ void ManagerImpl::setAccountDetails(const std::string& accountID, account->unregisterVoIPLink(); // Update account details to the client side - dbus_.getConfigurationManager()->accountsChanged(); + client_.getConfigurationManager()->accountsChanged(); } std::string @@ -2483,7 +2520,7 @@ ManagerImpl::addAccount(const std::map<std::string, std::string>& details) saveConfig(); - dbus_.getConfigurationManager()->accountsChanged(); + client_.getConfigurationManager()->accountsChanged(); return accountID.str(); } @@ -2507,7 +2544,7 @@ void ManagerImpl::removeAccount(const std::string& accountID) saveConfig(); - dbus_.getConfigurationManager()->accountsChanged(); + client_.getConfigurationManager()->accountsChanged(); } std::string ManagerImpl::getAccountFromCall(const std::string& callID) @@ -2881,7 +2918,7 @@ void ManagerImpl::saveHistory() if (!history_.save()) ERROR("Could not save history!"); else - dbus_.getConfigurationManager()->historyChanged(); + client_.getConfigurationManager()->historyChanged(); } void ManagerImpl::clearHistory() @@ -2912,3 +2949,57 @@ void ManagerImpl::sendPresence(const std::string& accountID, const std::string& SIPAccount *account = Manager::instance().getSipAccount(accountID); account->getPresence()->sendPresence(status,note); } + +void +ManagerImpl::registerAccounts() +{ + AccountMap allAccounts(getAllAccounts()); + + for (auto &item : allAccounts) { + Account *a = item.second; + + if (!a) + continue; + + a->loadConfig(); + + if (a->isEnabled()) + a->registerVoIPLink(); + } +} + + +VoIPLink* ManagerImpl::getAccountLink(const std::string& accountID) +{ + Account *account = getAccount(accountID); + if (account == NULL) { + DEBUG("Could not find account for account %s, returning sip voip", accountID.c_str()); + return SIPVoIPLink::instance(); + } + + if (not accountID.empty()) + return account->getVoIPLink(); + else { + DEBUG("Account id is empty for voip link, returning sip voip"); + return SIPVoIPLink::instance(); + } +} + + +void +ManagerImpl::sendRegister(const std::string& accountID, bool enable) +{ + Account* acc = getAccount(accountID); + if (!acc) + return; + + acc->setEnabled(enable); + acc->loadConfig(); + + Manager::instance().saveConfig(); + + if (acc->isEnabled()) + acc->registerVoIPLink(); + else + acc->unregisterVoIPLink(); +} diff --git a/daemon/src/managerimpl.h b/daemon/src/managerimpl.h index c02431c63e8e64c4114655ab52e5d959c64d1e1d..db78baec8ca6aa8ada62b2fd081406cbae5c2055 100644 --- a/daemon/src/managerimpl.h +++ b/daemon/src/managerimpl.h @@ -43,10 +43,10 @@ #include <vector> #include <set> #include <map> -#include <tr1/memory> - +#include <memory> #include <pthread.h> -#include "dbus/dbusmanager.h" + +#include "client/client.h" #include "config/sfl_config.h" @@ -129,10 +129,14 @@ class ManagerImpl { */ void init(const std::string &config_file); + void setPath(const std::string &path); + +#ifdef HAVE_DBUS /** * Enter Dbus mainloop */ void run(); +#endif /* * Terminate all threads and exit DBus loop @@ -706,13 +710,6 @@ class ManagerImpl { */ std::string getConfigString(const std::string& section, const std::string& name) const; - /** - * Retrieve the soundcards index in the user config file and try to open audio devices - * with a specific alsa plugin. - * Set the audio layer sample rate - */ - void selectAudioDriver(); - /** * Handle audio sounds heard by a caller while they wait for their * connection to a called party to be completed. @@ -722,7 +719,7 @@ class ManagerImpl { /** * Handle played music when an incoming call occurs */ - void ringtone(const std::string& accountID); + void playRingtone(const std::string& accountID); /** * Handle played music when a congestion occurs @@ -788,6 +785,10 @@ class ManagerImpl { const AudioCodecFactory audioCodecFactory; private: + bool parseConfiguration(); + + // Set the ringtone or recorded call to be played + void updateAudioFile(const std::string &file, int sampleRate); /** * Get the Call referred to by callID. If the Call does not exist, return NULL @@ -811,7 +812,7 @@ class ManagerImpl { /** * Create config directory in home user and return configuration file path */ - std::string createConfigFile() const; + std::string retrieveConfigPath() const; /* * Initialize zeroconf module and scanning @@ -835,7 +836,7 @@ class ManagerImpl { */ void playATone(Tone::TONEID toneId); - DBusManager dbus_; + Client client_; /** The configuration tree. It contains accounts parameters, general user settings ,audio settings, ... */ Conf::ConfigTree config_; @@ -850,14 +851,14 @@ class ManagerImpl { AudioLayer* audiodriver_; // Main thread - std::tr1::shared_ptr<DTMF> dtmfKey_; + std::unique_ptr<DTMF> dtmfKey_; ///////////////////// // Protected by Mutex ///////////////////// pthread_mutex_t toneMutex_; - std::tr1::shared_ptr<TelephoneTone> telephoneTone_; - std::tr1::shared_ptr<AudioFile> audiofile_; + std::unique_ptr<TelephoneTone> telephoneTone_; + std::unique_ptr<AudioFile> audiofile_; // To handle volume control // short speakerVolume_; @@ -950,16 +951,15 @@ class ManagerImpl { bool hasCurrentCall() const; /** - * Return the current DBusManager - * @return A pointer to the DBusManager instance + * Return the current Client + * @return A pointer to the Client instance */ - DBusManager * getDbusManager() { - return &dbus_; + Client* getClient() { + return &client_; } - #ifdef SFL_VIDEO VideoControls * getVideoControls() { - return dbus_.getVideoControls(); + return client_.getVideoControls(); } #endif @@ -1017,12 +1017,6 @@ class ManagerImpl { */ VoIPLink* getAccountLink(const std::string& accountID); - std::string getStunServer() const; - void setStunServer(const std::string &server); - - int isStunEnabled(); - void enableStun(); - // Map containing conference pointers ConferenceMap conferenceMap_; diff --git a/daemon/src/managerimpl_registration.cpp b/daemon/src/managerimpl_registration.cpp deleted file mode 100644 index 0e839cb66a5cd50e3dbd8298ce5671c9901f250f..0000000000000000000000000000000000000000 --- a/daemon/src/managerimpl_registration.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. - * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> - * Author: Yan Morin <yan.morin@savoirfairelinux.com> - * Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com> - * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> - * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> - * Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Additional permission under GNU GPL version 3 section 7: - * - * If you modify this program, or any covered work, by linking or - * combining it with the OpenSSL project's OpenSSL library (or a - * modified version of that library), containing parts covered by the - * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. - * grants you additional permission to convey the resulting work. - * Corresponding Source for a non-source form of such a combination - * shall include the source code for the parts of OpenSSL used as well - * as that of the covered work. - */ - -#include "managerimpl.h" - -#include "account.h" -#include "dbus/callmanager.h" -#include "global.h" -#include "logger.h" - -#include "audio/audiolayer.h" -#include "sip/sipvoiplink.h" -#include "manager.h" -#include "dbus/configurationmanager.h" - -#include <cstdlib> - -void -ManagerImpl::registerAccounts() -{ - AccountMap allAccounts(getAllAccounts()); - - for (AccountMap::iterator iter = allAccounts.begin(); iter != allAccounts.end(); ++iter) { - Account *a = iter->second; - - if (!a) - continue; - - a->loadConfig(); - - if (a->isEnabled()) - a->registerVoIPLink(); - } -} - - -VoIPLink* ManagerImpl::getAccountLink(const std::string& accountID) -{ - Account *account = getAccount(accountID); - if (account == NULL) { - DEBUG("Could not find account for account %s, returning sip voip", accountID.c_str()); - return SIPVoIPLink::instance(); - } - - if (not accountID.empty()) - return account->getVoIPLink(); - else { - DEBUG("Account id is empty for voip link, returning sip voip"); - return SIPVoIPLink::instance(); - } -} - - -void -ManagerImpl::sendRegister(const std::string& accountID, bool enable) -{ - Account* acc = getAccount(accountID); - if (!acc) - return; - - acc->setEnabled(enable); - acc->loadConfig(); - - Manager::instance().saveConfig(); - - if (acc->isEnabled()) - acc->registerVoIPLink(); - else - acc->unregisterVoIPLink(); -} diff --git a/daemon/src/numbercleaner.cpp b/daemon/src/numbercleaner.cpp index 1044132d811a0543d9872b9e62f86a7c6cbbf24b..67b509dd75cc52a198ca48b57c7165c7a84be73c 100644 --- a/daemon/src/numbercleaner.cpp +++ b/daemon/src/numbercleaner.cpp @@ -37,9 +37,8 @@ namespace { void strip_chars(const std::string &to_strip, std::string &num) { - for (std::string::const_iterator iter = to_strip.begin(); - iter != to_strip.end(); ++iter) - num.erase(std::remove(num.begin(), num.end(), *iter), num.end()); + for (const auto &item : to_strip) + num.erase(std::remove(num.begin(), num.end(), item), num.end()); } } diff --git a/daemon/src/preferences.cpp b/daemon/src/preferences.cpp index 14038390d19f60eadc3e52572efa04d4e4ac02f7..1ac16dadd434d64071caaa1f24c6281409e7b61f 100644 --- a/daemon/src/preferences.cpp +++ b/daemon/src/preferences.cpp @@ -34,10 +34,17 @@ #include "preferences.h" #include "logger.h" +#include "audio/audiolayer.h" +#ifdef __ANDROID__ +#include "audio/opensl/opensllayer.h" +#else +#if HAVE_ALSA #include "audio/alsa/alsalayer.h" +#endif #if HAVE_PULSE #include "audio/pulseaudio/pulselayer.h" #endif +#endif #include "config/yamlemitter.h" #include "config/yamlnode.h" #include "hooks/urlhook.h" @@ -77,7 +84,9 @@ static const char * const URL_COMMAND_KEY = "urlCommand"; static const char * const URL_SIP_FIELD_KEY = "urlSipField"; // audio preferences +#if HAVE_ALSA static const char * const ALSAMAP_KEY = "alsa"; +#endif #if HAVE_PULSE static const char * const PULSEMAP_KEY = "pulse"; #endif @@ -103,11 +112,11 @@ static const char * const POPUP_SHORT_KEY = "popupWindow"; static const char * const TOGGLE_HOLD_SHORT_KEY = "toggleHold"; static const char * const TOGGLE_PICKUP_HANGUP_SHORT_KEY = "togglePickupHangup"; -static const char * const DFT_PULSE_LENGTH_STR ="250"; /** Default DTMF lenght */ +static const char * const DFT_PULSE_LENGTH_STR = "250"; /** Default DTMF lenght */ static const char * const ZRTP_ZIDFILE = "zidFile"; /** The filename used for storing ZIDs */ -static const char * const ALSA_DFT_CARD = "0"; /** Default sound card index */ +static const char * const ALSA_DFT_CARD = "0"; /** Default sound card index */ static const char * const DFT_VOL_SPKR_STR = "100"; /** Default speaker volume */ -static const char * const DFT_VOL_MICRO_STR = "100"; /** Default mic volume */ +static const char * const DFT_VOL_MICRO_STR = "100"; /** Default mic volume */ } // end anonymous namespace Preferences::Preferences() : @@ -297,32 +306,47 @@ AudioPreference::AudioPreference() : {} namespace { +#if HAVE_ALSA void checkSoundCard(int &card, AudioLayer::PCMType stream) { if (not AlsaLayer::soundCardIndexExists(card, stream)) { WARN(" Card with index %d doesn't exist or is unusable.", card); card = ALSA_DFT_CARD_ID; } + + card = ALSA_DFT_CARD_ID; } +#endif } AudioLayer* AudioPreference::createAudioLayer() { +#ifdef __ANDROID__ + return new OpenSLLayer(); +#endif + #if HAVE_PULSE + if (audioApi_ == PULSEAUDIO_API_STR) { if (system("pactl info > /dev/null") == 0) return new PulseLayer(*this); else WARN("pulseaudio daemon not running, falling back to ALSA"); } + #endif +#if HAVE_ALSA + audioApi_ = ALSA_API_STR; checkSoundCard(alsaCardin_, AudioLayer::SFL_PCM_CAPTURE); checkSoundCard(alsaCardout_, AudioLayer::SFL_PCM_PLAYBACK); checkSoundCard(alsaCardring_, AudioLayer::SFL_PCM_RINGTONE); return new AlsaLayer(*this); +#else + return NULL; +#endif } AudioLayer* AudioPreference::switchAndCreateAudioLayer() @@ -379,12 +403,14 @@ void AudioPreference::serialize(Conf::YamlEmitter &emitter) preferencemap.setKeyValue(VOLUMESPKR_KEY, &volumespkr); Conf::MappingNode alsapreferencemap(NULL); +#if HAVE_ALSA preferencemap.setKeyValue(ALSAMAP_KEY, &alsapreferencemap); alsapreferencemap.setKeyValue(CARDIN_KEY, &cardin); alsapreferencemap.setKeyValue(CARDOUT_KEY, &cardout); alsapreferencemap.setKeyValue(CARDRING_KEY, &cardring); alsapreferencemap.setKeyValue(PLUGIN_KEY, &plugin); alsapreferencemap.setKeyValue(SMPLRATE_KEY, &alsaSmplrate); +#endif #if HAVE_PULSE Conf::MappingNode pulsepreferencemap(NULL); @@ -417,6 +443,7 @@ void AudioPreference::unserialize(const Conf::YamlNode &map) map.getValue(AUDIO_API_KEY, &audioApi_); std::string tmpRecordPath; map.getValue(RECORDPATH_KEY, &tmpRecordPath); + if (not setRecordPath(tmpRecordPath)) setRecordPath(fileutils::get_home_dir()); @@ -426,7 +453,7 @@ void AudioPreference::unserialize(const Conf::YamlNode &map) map.getValue(NOISE_REDUCE_KEY, &noisereduce_); map.getValue(ECHO_CANCEL_KEY, &echocancel_); - Conf::MappingNode *alsamap =(Conf::MappingNode *) map.getValue("alsa"); + Conf::MappingNode *alsamap = (Conf::MappingNode *) map.getValue("alsa"); if (alsamap) { alsamap->getValue(CARDIN_KEY, &alsaCardin_); @@ -437,13 +464,14 @@ void AudioPreference::unserialize(const Conf::YamlNode &map) } #if HAVE_PULSE - Conf::MappingNode *pulsemap =(Conf::MappingNode *)(map.getValue("pulse")); + Conf::MappingNode *pulsemap = (Conf::MappingNode *)(map.getValue("pulse")); if (pulsemap) { pulsemap->getValue(DEVICE_PLAYBACK_KEY, &pulseDevicePlayback_); pulsemap->getValue(DEVICE_RECORD_KEY, &pulseDeviceRecord_); pulsemap->getValue(DEVICE_RINGTONE_KEY, &pulseDeviceRingtone_); } + #endif } diff --git a/daemon/src/sfl_types.h b/daemon/src/sfl_types.h index a69f0d19ab93f9ba0a14287aefa48a4c606bbb00..a95394493f7795a1854fd4650113379e37a870c0 100644 --- a/daemon/src/sfl_types.h +++ b/daemon/src/sfl_types.h @@ -32,10 +32,10 @@ #define SFL_TYPES_H_ #include <cstddef> // for size_t +#include <stdint.h> -typedef short SFLDataFormat; -typedef signed short SINT16; -typedef signed int SINT32; +typedef int16_t SFLAudioSample; +#define SFL_DATA_FORMAT_MAX SHRT_MAX static const size_t SIZEBUF = 400000; /** About 12 sec of buffering at 8000 Hz*/ diff --git a/daemon/src/sip/sdes_negotiator.cpp b/daemon/src/sip/sdes_negotiator.cpp index df8c6085791f2053bfd1ac37669c7f0134a1ce27..26631e518d0c42fc1f003ade220bb1f26c15d4c4 100644 --- a/daemon/src/sip/sdes_negotiator.cpp +++ b/daemon/src/sip/sdes_negotiator.cpp @@ -32,7 +32,7 @@ #include "pattern.h" #include <cstdio> -#include <tr1/memory> +#include <memory> #include <iostream> #include <sstream> #include <algorithm> @@ -61,7 +61,7 @@ std::vector<CryptoAttribute *> SdesNegotiator::parse() // syntax : //a=crypto:tag 1*WSP crypto-suite 1*WSP key-params *(1*WSP session-param) - std::tr1::shared_ptr<Pattern> generalSyntaxPattern, tagPattern, cryptoSuitePattern, + std::unique_ptr<Pattern> generalSyntaxPattern, tagPattern, cryptoSuitePattern, keyParamsPattern; try { @@ -93,14 +93,13 @@ std::vector<CryptoAttribute *> SdesNegotiator::parse() std::vector<CryptoAttribute *> cryptoAttributeVector; - for (std::vector<std::string>::iterator iter = remoteAttribute_.begin(); - iter != remoteAttribute_.end(); ++iter) { + for (const auto &item : remoteAttribute_) { // Split the line into its component // that we will analyze further down. std::vector<std::string> sdesLine; - *generalSyntaxPattern << (*iter); + *generalSyntaxPattern << item; try { sdesLine = generalSyntaxPattern->split(); diff --git a/daemon/src/sip/sdp.cpp b/daemon/src/sip/sdp.cpp index 1436af130087849f3b22cc4b415e65fe4215136f..64766b9dcb286a64905801ebc93f9aa001046302 100644 --- a/daemon/src/sip/sdp.cpp +++ b/daemon/src/sip/sdp.cpp @@ -40,6 +40,10 @@ #include <algorithm> +#ifdef HAVE_OPUS +#include "audio/codecs/opus.h" +#endif + #ifdef SFL_VIDEO #include "video/libav_utils.h" #endif @@ -76,8 +80,8 @@ Sdp::Sdp(pj_pool_t *pool) namespace { bool hasPayload(const std::vector<sfl::AudioCodec*> &codecs, int pt) { - for (std::vector<sfl::AudioCodec*>::const_iterator i = codecs.begin(); i != codecs.end(); ++i) - if (*i and (*i)->getPayloadType() == pt) + for (const auto &i : codecs) + if (i and i->getPayloadType() == pt) return true; return false; } @@ -219,12 +223,14 @@ Sdp::setMediaDescriptorLines(bool audio) unsigned clock_rate; string enc_name; int payload; + unsigned channels; if (audio) { sfl::AudioCodec *codec = audio_codec_list_[i]; payload = codec->getPayloadType(); enc_name = codec->getMimeSubtype(); clock_rate = codec->getClockRate(); + channels = codec->getChannels(); // G722 require G722/8000 media description even if it is 16000 codec if (codec->getPayloadType () == 9) clock_rate = 8000; @@ -248,13 +254,34 @@ Sdp::setMediaDescriptorLines(bool audio) rtpmap.pt = med->desc.fmt[i]; rtpmap.enc_name = pj_str((char*) enc_name.c_str()); rtpmap.clock_rate = clock_rate; - rtpmap.param.ptr = ((char* const)""); - rtpmap.param.slen = 0; + +#ifdef HAVE_OPUS + // Opus sample rate is allways declared as 48000 and channel num is allways 2 in rtpmap as per + // http://tools.ietf.org/html/draft-spittka-payload-rtp-opus-03#section-6.2 + if(payload == Opus::PAYLOAD_TYPE) { + rtpmap.clock_rate = 48000; + rtpmap.param.ptr = ((char* const)"2"); + rtpmap.param.slen = 1; + } else +#endif + { + rtpmap.param.ptr = ((char* const)""); + rtpmap.param.slen = 0; + } pjmedia_sdp_attr *attr; pjmedia_sdp_rtpmap_to_attr(memPool_, &rtpmap, &attr); med->attr[med->attr_count++] = attr; + +#ifdef HAVE_OPUS + // Declare stereo support for opus + if(payload == Opus::PAYLOAD_TYPE) { + std::ostringstream os; + os << "fmtp:" << payload << " stereo=1; sprop-stereo=" << (channels>1 ? 1 : 0); + med->attr[med->attr_count++] = pjmedia_sdp_attr_create(memPool_, os.str().c_str(), NULL); + } +#endif #ifdef SFL_VIDEO if (enc_name == "H264") { std::ostringstream os; @@ -350,8 +377,8 @@ void Sdp::setLocalMediaAudioCapabilities(const vector<int> &selectedCodecs) WARN("No selected codec while building local SDP offer"); audio_codec_list_.clear(); - for (vector<int>::const_iterator i = selectedCodecs.begin(); i != selectedCodecs.end(); ++i) { - sfl::AudioCodec *codec = Manager::instance().audioCodecFactory.getCodec(*i); + for (const auto &i : selectedCodecs) { + sfl::AudioCodec *codec = Manager::instance().audioCodecFactory.getCodec(i); if (codec) audio_codec_list_.push_back(codec); @@ -455,8 +482,9 @@ void Sdp::receiveOffer(const pjmedia_sdp_session* remote, remoteSession_ = pjmedia_sdp_session_clone(memPool_, remote); - pjmedia_sdp_neg_create_w_remote_offer(memPool_, localSession_, - remoteSession_, &negotiator_); + if (pjmedia_sdp_neg_create_w_remote_offer(memPool_, localSession_, + remoteSession_, &negotiator_) != PJ_SUCCESS) + ERROR("Failed to initialize negotiator"); } void Sdp::startNegotiation() @@ -505,9 +533,9 @@ string Sdp::getLineFromSession(const pjmedia_sdp_session *sess, const string &ke int size = pjmedia_sdp_print(sess, buffer, sizeof buffer); string sdp(buffer, size); const vector<string> tokens(split(sdp, '\n')); - for (vector<string>::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) - if ((*iter).find(keyword) != string::npos) - return *iter; + for (const auto &item : tokens) + if (item.find(keyword) != string::npos) + return item; return ""; } @@ -619,9 +647,8 @@ Sdp::getProfileLevelID(const pjmedia_sdp_session *session, void Sdp::addSdesAttribute(const vector<std::string>& crypto) { - for (vector<std::string>::const_iterator iter = crypto.begin(); - iter != crypto.end(); ++iter) { - pj_str_t val = { (char*)(*iter).c_str(), static_cast<pj_ssize_t>((*iter).size()) }; + for (const auto &item : crypto) { + pj_str_t val = { (char*) item.c_str(), static_cast<pj_ssize_t>(item.size()) }; pjmedia_sdp_attr *attr = pjmedia_sdp_attr_create(memPool_, "crypto", &val); for (unsigned i = 0; i < localSession_->media_count; i++) @@ -765,6 +792,8 @@ bool Sdp::getOutgoingVideoSettings(map<string, string> &args) const } return true; } +#else + (void) args; #endif return false; } diff --git a/daemon/src/sip/sip_utils.cpp b/daemon/src/sip/sip_utils.cpp index e61b286a9dcf3320840724b6ee2cc3b6da3f5ff4..82a3b07dd334ec9edd000bf0c75cbc1fbafbd717 100644 --- a/daemon/src/sip/sip_utils.cpp +++ b/daemon/src/sip/sip_utils.cpp @@ -165,7 +165,7 @@ sip_utils::getIPList(const std::string &name) for (struct addrinfo *res = result; res != NULL; res = res->ai_next) { void *ptr = 0; - std::string addrstr; + std::vector<char> addrstr; static const int AF_INET_STRLEN = 16, AF_INET6_STRLEN = 40; switch (res->ai_family) { case AF_INET: @@ -180,11 +180,12 @@ sip_utils::getIPList(const std::string &name) ERROR("Unexpected address family type, skipping."); continue; } - inet_ntop(res->ai_family, ptr, &(*addrstr.begin()), addrstr.size()); + inet_ntop(res->ai_family, ptr, addrstr.data(), addrstr.size()); // don't add duplicates, and don't use an std::set because // we want this order preserved. - if (std::find(ipList.begin(), ipList.end(), addrstr) == ipList.end()) - ipList.push_back(addrstr); + const std::string tmp(addrstr.begin(), addrstr.end()); + if (std::find(ipList.begin(), ipList.end(), tmp) == ipList.end()) + ipList.push_back(tmp); } freeaddrinfo(result); diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp index f5b83284e9999a287c3b75cfd5ef81dc4b8ce216..c37b515285f9bd3aa1bf9882cb6ac9b3c88aa3b0 100644 --- a/daemon/src/sip/sipaccount.cpp +++ b/daemon/src/sip/sipaccount.cpp @@ -43,6 +43,7 @@ #include "config/yamlemitter.h" #include "logger.h" #include "manager.h" +#include <unistd.h> #include <pwd.h> #include <sstream> #include <algorithm> @@ -60,10 +61,10 @@ const char * const SIPAccount::SIPINFO_STR = "sipinfo"; const char * const SIPAccount::ACCOUNT_TYPE = "SIP"; namespace { - const int MIN_REGISTRATION_TIME = 60; - const int DEFAULT_REGISTRATION_TIME = 3600; - const char *const TRUE_STR = "true"; - const char *const FALSE_STR = "false"; +const int MIN_REGISTRATION_TIME = 60; +const int DEFAULT_REGISTRATION_TIME = 3600; +const char *const TRUE_STR = "true"; +const char *const FALSE_STR = "false"; } SIPAccount::SIPAccount(const std::string& accountID) @@ -83,7 +84,7 @@ SIPAccount::SIPAccount(const std::string& accountID) , transportType_(PJSIP_TRANSPORT_UNSPECIFIED) , cred_() , tlsSetting_() - , ciphers(100) + , ciphers_(100) , stunServerName_() , stunPort_(PJ_STUN_PORT) , dtmfType_(OVERRTP_STR) @@ -117,6 +118,8 @@ SIPAccount::SIPAccount(const std::string& accountID) , receivedParameter_("") , rPort_(-1) , via_addr_() + , audioPortRange_(16384, 32766) + , videoPortRange_(49152, 65534) { via_addr_.host.ptr = 0; via_addr_.host.slen = 0; @@ -171,8 +174,8 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) #ifdef SFL_VIDEO SequenceNode videoCodecs(NULL); accountmap.setKeyValue(VIDEO_CODECS_KEY, &videoCodecs); - for (vector<map<string, string> >::iterator i = videoCodecList_.begin(); i != videoCodecList_.end(); ++i) { - map<string, string> &codec = *i; + + for (auto &codec : videoCodecList_) { MappingNode *mapNode = new MappingNode(NULL); mapNode->setKeyValue(VIDEO_CODEC_NAME, new ScalarNode(codec[VIDEO_CODEC_NAME])); mapNode->setKeyValue(VIDEO_CODEC_BITRATE, new ScalarNode(codec[VIDEO_CODEC_BITRATE])); @@ -180,6 +183,7 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) mapNode->setKeyValue(VIDEO_CODEC_PARAMETERS, new ScalarNode(codec[VIDEO_CODEC_PARAMETERS])); videoCodecs.addNode(mapNode); } + #endif ScalarNode ringtonePath(ringtonePath_); @@ -256,10 +260,8 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) SequenceNode credentialseq(NULL); accountmap.setKeyValue(CRED_KEY, &credentialseq); - std::vector<std::map<std::string, std::string> >::const_iterator it; - - for (it = credentials_.begin(); it != credentials_.end(); ++it) { - std::map<std::string, std::string> cred = *it; + for (const auto &it : credentials_) { + std::map<std::string, std::string> cred = it; MappingNode *map = new MappingNode(NULL); map->setKeyValue(CONFIG_ACCOUNT_USERNAME, new ScalarNode(cred[CONFIG_ACCOUNT_USERNAME])); map->setKeyValue(CONFIG_ACCOUNT_PASSWORD, new ScalarNode(cred[CONFIG_ACCOUNT_PASSWORD])); @@ -282,6 +284,9 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) tlsmap.setKeyValue(VERIFY_CLIENT_KEY, &verifyclient); tlsmap.setKeyValue(VERIFY_SERVER_KEY, &verifyserver); + ScalarNode userAgent(userAgent_); + accountmap.setKeyValue(USER_AGENT_KEY, &userAgent); + try { emitter.serializeAccount(&accountmap); } catch (const YamlEmitterException &e) { @@ -290,8 +295,9 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) // Cleanup Sequence *credSeq = credentialseq.getSequence(); - for (Sequence::iterator seqit = credSeq->begin(); seqit != credSeq->end(); ++seqit) { - MappingNode *node = static_cast<MappingNode*>(*seqit); + + for (const auto &seqit : *credSeq) { + MappingNode *node = static_cast<MappingNode*>(seqit); delete node->getValue(CONFIG_ACCOUNT_USERNAME); delete node->getValue(CONFIG_ACCOUNT_PASSWORD); delete node->getValue(CONFIG_ACCOUNT_REALM); @@ -300,14 +306,16 @@ void SIPAccount::serialize(Conf::YamlEmitter &emitter) #ifdef SFL_VIDEO Sequence *videoCodecSeq = videoCodecs.getSequence(); - for (Sequence::iterator i = videoCodecSeq->begin(); i != videoCodecSeq->end(); ++i) { - MappingNode *node = static_cast<MappingNode*>(*i); + + for (auto &i : *videoCodecSeq) { + MappingNode *node = static_cast<MappingNode*>(i); delete node->getValue(VIDEO_CODEC_NAME); delete node->getValue(VIDEO_CODEC_BITRATE); delete node->getValue(VIDEO_CODEC_ENABLED); delete node->getValue(VIDEO_CODEC_PARAMETERS); delete node; } + #endif } @@ -320,10 +328,14 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) mapNode.getValue(ALIAS_KEY, &alias_); mapNode.getValue(USERNAME_KEY, &username_); + if (not isIP2IP()) mapNode.getValue(HOSTNAME_KEY, &hostname_); + mapNode.getValue(ACCOUNT_ENABLE_KEY, &enabled_); mapNode.getValue(ACCOUNT_AUTOANSWER_KEY, &autoAnswerEnabled_); + if (not isIP2IP()) mapNode.getValue(MAILBOX_KEY, &mailBox_); + mapNode.getValue(AUDIO_CODECS_KEY, &audioCodecStr_); // Update codec list which one is used for SDP offer setActiveAudioCodecs(split_string(audioCodecStr_)); @@ -333,14 +345,16 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) if (videoCodecsNode and videoCodecsNode->getType() == SEQUENCE) { SequenceNode *videoCodecs = static_cast<SequenceNode *>(videoCodecsNode); Sequence *seq = videoCodecs->getSequence(); + if (seq->empty()) { // Video codecs are an empty list WARN("Loading default video codecs"); videoCodecList_ = libav_utils::getDefaultCodecs(); } else { vector<map<string, string> > videoCodecDetails; - for (Sequence::iterator it = seq->begin(); it != seq->end(); ++it) { - MappingNode *codec = static_cast<MappingNode *>(*it); + + for (auto it : *seq) { + MappingNode *codec = static_cast<MappingNode *>(it); map<string, string> codecMap; codec->getValue(VIDEO_CODEC_NAME, &codecMap[VIDEO_CODEC_NAME]); codec->getValue(VIDEO_CODEC_BITRATE, &codecMap[VIDEO_CODEC_BITRATE]); @@ -348,6 +362,7 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) codec->getValue(VIDEO_CODEC_PARAMETERS, &codecMap[VIDEO_CODEC_PARAMETERS]); videoCodecDetails.push_back(codecMap); } + // these must be validated setVideoCodecs(videoCodecDetails); } @@ -357,11 +372,14 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) WARN("Loading default video codecs"); videoCodecList_ = libav_utils::getDefaultCodecs(); } + #endif mapNode.getValue(RINGTONE_PATH_KEY, &ringtonePath_); mapNode.getValue(RINGTONE_ENABLED_KEY, &ringtoneEnabled_); + if (not isIP2IP()) mapNode.getValue(Preferences::REGISTRATION_EXPIRE_KEY, ®istrationExpire_); + mapNode.getValue(INTERFACE_KEY, &interface_); int port = DEFAULT_SIP_PORT; mapNode.getValue(PORT_KEY, &port); @@ -370,6 +388,7 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) mapNode.getValue(PUBLISH_PORT_KEY, &port); publishedPort_ = port; mapNode.getValue(SAME_AS_LOCAL_KEY, &publishedSameasLocal_); + if (not isIP2IP()) mapNode.getValue(KEEP_ALIVE_ENABLED, &keepAliveEnabled_); std::string dtmfType; @@ -380,6 +399,7 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) // stun enabled if (not isIP2IP()) mapNode.getValue(STUN_ENABLED_KEY, &stunEnabled_); + if (not isIP2IP()) mapNode.getValue(STUN_SERVER_KEY, &stunServer_); // Init stun server name with default server name @@ -397,11 +417,10 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) */ if (credNode && credNode->getType() == SEQUENCE) { SequenceNode *credSeq = static_cast<SequenceNode *>(credNode); - Sequence::iterator it; Sequence *seq = credSeq->getSequence(); - for (it = seq->begin(); it != seq->end(); ++it) { - MappingNode *cred = static_cast<MappingNode *>(*it); + for (auto it : *seq) { + MappingNode *cred = static_cast<MappingNode *>(it); std::string user; std::string pass; std::string realm; @@ -420,6 +439,7 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) // migration from old file format std::map<std::string, std::string> credmap; std::string password; + if (not isIP2IP()) mapNode.getValue(PASSWORD_KEY, &password); credmap[CONFIG_ACCOUNT_USERNAME] = username_; @@ -471,6 +491,7 @@ void SIPAccount::unserialize(const Conf::YamlNode &mapNode) tlsMap->getValue(TIMEOUT_KEY, &tlsNegotiationTimeoutSec_); tlsMap->getValue(TIMEOUT_KEY, &tlsNegotiationTimeoutMsec_); } + mapNode.getValue(USER_AGENT_KEY, &userAgent_); } void SIPAccount::setAccountDetails(std::map<std::string, std::string> details) @@ -495,15 +516,18 @@ void SIPAccount::setAccountDetails(std::map<std::string, std::string> details) publishedIpAddress_ = details[CONFIG_PUBLISHED_ADDRESS]; localPort_ = atoi(details[CONFIG_LOCAL_PORT].c_str()); publishedPort_ = atoi(details[CONFIG_PUBLISHED_PORT].c_str()); + if (stunServer_ != details[CONFIG_STUN_SERVER]) { link_->sipTransport.destroyStunResolver(stunServer_); // pj_stun_sock_destroy(pj_stun_sock *stun_sock); } + stunServer_ = details[CONFIG_STUN_SERVER]; stunEnabled_ = details[CONFIG_STUN_ENABLE] == TRUE_STR; dtmfType_ = details[CONFIG_ACCOUNT_DTMF_TYPE]; registrationExpire_ = atoi(details[CONFIG_ACCOUNT_REGISTRATION_EXPIRE].c_str()); - if(registrationExpire_ < MIN_REGISTRATION_TIME) + + if (registrationExpire_ < MIN_REGISTRATION_TIME) registrationExpire_ = MIN_REGISTRATION_TIME; userAgent_ = details[CONFIG_ACCOUNT_USERAGENT]; @@ -545,6 +569,25 @@ void SIPAccount::setAccountDetails(std::map<std::string, std::string> details) } } +static std::string retrievePassword(const std::map<std::string, std::string>& map, const std::string &username) +{ + std::map<std::string, std::string>::const_iterator map_iter_username; + std::map<std::string, std::string>::const_iterator map_iter_password; + map_iter_username = map.find(CONFIG_ACCOUNT_USERNAME); + + if (map_iter_username != map.end()) { + if (map_iter_username->second == username) { + map_iter_password = map.find(CONFIG_ACCOUNT_PASSWORD); + + if (map_iter_password != map.end()) { + return map_iter_password->second; + } + } + } + + return ""; +} + std::map<std::string, std::string> SIPAccount::getAccountDetails() const { std::map<std::string, std::string> a; @@ -554,10 +597,22 @@ std::map<std::string, std::string> SIPAccount::getAccountDetails() const a[CONFIG_ACCOUNT_ALIAS] = alias_; a[CONFIG_ACCOUNT_ENABLE] = enabled_ ? TRUE_STR : FALSE_STR; - a[CONFIG_ACCOUNT_AUTOANSWER]= autoAnswerEnabled_ ? TRUE_STR : FALSE_STR; + a[CONFIG_ACCOUNT_AUTOANSWER] = autoAnswerEnabled_ ? TRUE_STR : FALSE_STR; a[CONFIG_ACCOUNT_TYPE] = ACCOUNT_TYPE; a[CONFIG_ACCOUNT_HOSTNAME] = hostname_; a[CONFIG_ACCOUNT_USERNAME] = username_; + // get password for this username + a[CONFIG_ACCOUNT_PASSWORD] = ""; + + if (hasCredentials()) { + + for (const auto &vect_item : credentials_) { + const std::string password = retrievePassword(vect_item, username_); + + if (not password.empty()) + a[CONFIG_ACCOUNT_PASSWORD] = password; + } + } a[CONFIG_RINGTONE_PATH] = ringtonePath_; a[CONFIG_RINGTONE_ENABLED] = ringtoneEnabled_ ? TRUE_STR : FALSE_STR; @@ -578,7 +633,7 @@ std::map<std::string, std::string> SIPAccount::getAccountDetails() const registrationStateDescription = registrationStateDetailed_.second; } - a[CONFIG_ACCOUNT_REGISTRATION_STATUS] = isIP2IP() ? "READY": mapStateNumberToString(state); + a[CONFIG_ACCOUNT_REGISTRATION_STATUS] = isIP2IP() ? "READY" : mapStateNumberToString(state); a[CONFIG_ACCOUNT_REGISTRATION_STATE_CODE] = registrationStateCode; a[CONFIG_ACCOUNT_REGISTRATION_STATE_DESC] = registrationStateDescription; @@ -640,12 +695,14 @@ void SIPAccount::registerVoIPLink() return; #if HAVE_TLS + // Init TLS settings if the user wants to use TLS if (tlsEnable_ == TRUE_STR) { DEBUG("TLS is enabled for account %s", accountID_.c_str()); transportType_ = PJSIP_TRANSPORT_TLS; initTlsConfiguration(); } + #endif // Init STUN settings for this account if the user selected it @@ -681,7 +738,8 @@ void SIPAccount::unregisterVoIPLink() } } -void SIPAccount::startKeepAliveTimer() { +void SIPAccount::startKeepAliveTimer() +{ if (isTlsEnabled()) return; @@ -745,26 +803,39 @@ pjsip_ssl_method SIPAccount::sslMethodStringToPjEnum(const std::string& method) return PJSIP_SSL_UNSPECIFIED_METHOD; } -void SIPAccount::displayCipherSuite() +void SIPAccount::trimCiphers() { - CipherArray::const_iterator iter; - for (iter = ciphers.begin(); iter != ciphers.end(); ++iter) - DEBUG("Cipher: %s", pj_ssl_cipher_name(*iter)); + int sum = 0; + int count = 0; + // PJSIP aborts if our cipher list exceeds 1010 characters + static const int MAX_CIPHERS_STRLEN = 1010; + + for (const auto &item : ciphers_) { + sum += strlen(pj_ssl_cipher_name(item)); + + if (sum > MAX_CIPHERS_STRLEN) + break; + + ++count; + } + + ciphers_.resize(count); + DEBUG("Using %u ciphers", ciphers_.size()); } void SIPAccount::initTlsConfiguration() { - pj_status_t status; unsigned cipherNum; // Determine the cipher list supported on this machine - cipherNum = ciphers.size(); - status = pj_ssl_cipher_get_availables(&ciphers.front(), &cipherNum); - if (status != PJ_SUCCESS) { + cipherNum = ciphers_.size(); + + if (pj_ssl_cipher_get_availables(&ciphers_.front(), &cipherNum) != PJ_SUCCESS) ERROR("Could not determine cipher list on this system"); - } - ciphers.resize(cipherNum); + ciphers_.resize(cipherNum); + + trimCiphers(); // TLS listener is unique and should be only modified through IP2IP_PROFILE pjsip_tls_setting_default(&tlsSetting_); @@ -774,12 +845,12 @@ void SIPAccount::initTlsConfiguration() pj_cstr(&tlsSetting_.privkey_file, tlsPrivateKeyFile_.c_str()); pj_cstr(&tlsSetting_.password, tlsPassword_.c_str()); tlsSetting_.method = sslMethodStringToPjEnum(tlsMethod_); - tlsSetting_.ciphers_num = ciphers.size(); - tlsSetting_.ciphers = &ciphers.front(); + tlsSetting_.ciphers_num = ciphers_.size(); + tlsSetting_.ciphers = &ciphers_.front(); - tlsSetting_.verify_server = tlsVerifyServer_ ? PJ_TRUE: PJ_FALSE; - tlsSetting_.verify_client = tlsVerifyClient_ ? PJ_TRUE: PJ_FALSE; - tlsSetting_.require_client_cert = tlsRequireClientCertificate_ ? PJ_TRUE: PJ_FALSE; + tlsSetting_.verify_server = tlsVerifyServer_; + tlsSetting_.verify_client = tlsVerifyClient_; + tlsSetting_.require_client_cert = tlsRequireClientCertificate_; tlsSetting_.timeout.sec = atol(tlsNegotiationTimeoutSec_.c_str()); tlsSetting_.timeout.msec = atol(tlsNegotiationTimeoutMsec_.c_str()); @@ -787,6 +858,7 @@ void SIPAccount::initTlsConfiguration() tlsSetting_.qos_type = PJ_QOS_TYPE_BEST_EFFORT; tlsSetting_.qos_ignore_error = PJ_TRUE; } + #endif void SIPAccount::initStunConfiguration() @@ -817,6 +889,7 @@ void SIPAccount::loadConfig() registrationExpire_ = DEFAULT_REGISTRATION_TIME; /** Default expire value for registration */ #if HAVE_TLS + if (tlsEnable_ == TRUE_STR) { initTlsConfiguration(); transportType_ = PJSIP_TRANSPORT_TLS; @@ -836,19 +909,21 @@ bool SIPAccount::userMatch(const std::string& username) const } namespace { - bool haveValueInCommon(const std::vector<std::string> &a, const std::vector<std::string> &b) - { - for (std::vector<std::string>::const_iterator i = a.begin(); i != a.end(); ++i) - if (std::find(b.begin(), b.end(), *i) != b.end()) - return true; - return false; - } +bool haveValueInCommon(const std::vector<std::string> &a, const std::vector<std::string> &b) +{ + for (const auto &i : a) + if (std::find(b.begin(), b.end(), i) != b.end()) + return true; + + return false; +} } bool SIPAccount::hostnameMatch(const std::string& hostname, pjsip_endpoint * /*endpt*/, pj_pool_t * /*pool*/) const { if (hostname == hostname_) return true; + const std::vector<std::string> a(sip_utils::getIPList(hostname)); const std::vector<std::string> b(sip_utils::getIPList(hostname_)); return haveValueInCommon(a, b); @@ -858,6 +933,7 @@ bool SIPAccount::proxyMatch(const std::string& hostname, pjsip_endpoint * /*endp { if (hostname == serviceRoute_) return true; + const std::vector<std::string> a(sip_utils::getIPList(hostname)); const std::vector<std::string> b(sip_utils::getIPList(serviceRoute_)); return haveValueInCommon(a, b); @@ -943,6 +1019,7 @@ std::string SIPAccount::getContactHeader() const // The transport type must be specified, in our case START_OTHER refers to stun transport pjsip_transport_type_e transportType = transportType_; + if (transportType == PJSIP_TRANSPORT_START_OTHER) transportType = PJSIP_TRANSPORT_UDP; @@ -953,7 +1030,7 @@ std::string SIPAccount::getContactHeader() const link_->sipTransport.findLocalAddressFromTransport(transport_, transportType, address, port); if (!receivedParameter_.empty()) - address = receivedParameter_; + address = receivedParameter_; if (rPort_ != -1) { portstr << rPort_; @@ -963,6 +1040,7 @@ std::string SIPAccount::getContactHeader() const // UDP does not require the transport specification std::string scheme; std::string transport; + if (transportType_ == PJSIP_TRANSPORT_TLS) { scheme = "sips:"; transport = ";transport=" + std::string(pjsip_transport_get_type_name(transportType)); @@ -1002,8 +1080,8 @@ void SIPAccount::keepAliveRegistrationCb(UNUSED pj_timer_heap_t *th, pj_timer_en namespace { std::string computeMd5HashFromCredential(const std::string& username, - const std::string& password, - const std::string& realm) + const std::string& password, + const std::string& realm) { #define MD5_APPEND(pms,buf,len) pj_md5_update(pms, (const pj_uint8_t*)buf, len) @@ -1024,7 +1102,7 @@ std::string computeMd5HashFromCredential(const std::string& username, char hash[32]; for (int i = 0; i < 16; ++i) - pj_val_to_hex_digit(digest[i], &hash[2*i]); + pj_val_to_hex_digit(digest[i], &hash[2 * i]); return std::string(hash, 32); } @@ -1047,13 +1125,13 @@ void SIPAccount::setCredentials(const std::vector<std::map<std::string, std::str credentials_ = creds; /* md5 hashing */ - for (vector<map<string, string> >::iterator it = credentials_.begin(); it != credentials_.end(); ++it) { - map<string, string>::const_iterator val = (*it).find(CONFIG_ACCOUNT_USERNAME); - const std::string username = val != (*it).end() ? val->second : ""; - val = (*it).find(CONFIG_ACCOUNT_REALM); - const std::string realm(val != (*it).end() ? val->second : ""); - val = (*it).find(CONFIG_ACCOUNT_PASSWORD); - const std::string password(val != (*it).end() ? val->second : ""); + for (auto &it : credentials_) { + map<string, string>::const_iterator val = it.find(CONFIG_ACCOUNT_USERNAME); + const std::string username = val != it.end() ? val->second : ""; + val = it.find(CONFIG_ACCOUNT_REALM); + const std::string realm(val != it.end() ? val->second : ""); + val = it.find(CONFIG_ACCOUNT_PASSWORD); + const std::string password(val != it.end() ? val->second : ""); if (md5HashingEnabled) { // TODO: Fix this. @@ -1066,7 +1144,7 @@ void SIPAccount::setCredentials(const std::vector<std::map<std::string, std::str // re-hash a hashed password. if (password.length() != 32) - (*it)[CONFIG_ACCOUNT_PASSWORD] = computeMd5HashFromCredential(username, password, realm); + it[CONFIG_ACCOUNT_PASSWORD] = computeMd5HashFromCredential(username, password, realm); } } @@ -1074,24 +1152,24 @@ void SIPAccount::setCredentials(const std::vector<std::map<std::string, std::str cred_.resize(credentials_.size()); size_t i = 0; - for (vector<map<string, string > >::const_iterator iter = credentials_.begin(); - iter != credentials_.end(); ++iter) { - map<string, string>::const_iterator val = (*iter).find(CONFIG_ACCOUNT_PASSWORD); - const std::string password = val != (*iter).end() ? val->second : ""; + + for (const auto &item : credentials_) { + map<string, string>::const_iterator val = item.find(CONFIG_ACCOUNT_PASSWORD); + const std::string password = val != item.end() ? val->second : ""; int dataType = (md5HashingEnabled and password.length() == 32) ? PJSIP_CRED_DATA_DIGEST : PJSIP_CRED_DATA_PLAIN_PASSWD; - val = (*iter).find(CONFIG_ACCOUNT_USERNAME); + val = item.find(CONFIG_ACCOUNT_USERNAME); - if (val != (*iter).end()) + if (val != item.end()) cred_[i].username = pj_str((char*) val->second.c_str()); cred_[i].data = pj_str((char*) password.c_str()); - val = (*iter).find(CONFIG_ACCOUNT_REALM); + val = item.find(CONFIG_ACCOUNT_REALM); - if (val != (*iter).end()) + if (val != item.end()) cred_[i].realm = pj_str((char*) val->second.c_str()); cred_[i].data_type = dataType; @@ -1108,12 +1186,7 @@ SIPAccount::getCredentials() const std::string SIPAccount::getUserAgentName() const { - std::string result(userAgent_); - - if (result == "sflphone" or result.empty()) - result += "/" PACKAGE_VERSION; - - return result; + return userAgent_.empty() ? DEFAULT_USER_AGENT : userAgent_; } std::map<std::string, std::string> SIPAccount::getIp2IpDetails() const @@ -1314,3 +1387,27 @@ bool SIPAccount::matches(const std::string &userName, const std::string &server, } else return false; } + +namespace { + // returns even number in range [lower, upper] + unsigned int getRandomEvenNumber(const std::pair<unsigned, unsigned> &range) + { + const unsigned halfUpper = range.second * 0.5; + const unsigned halfLower = range.first * 0.5; + return 2 * (halfLower + rand() % (halfUpper - halfLower + 1)); + } +} + +unsigned +SIPAccount::generateAudioPort() const +{ + return getRandomEvenNumber(audioPortRange_); +} + +#ifdef SFL_VIDEO +unsigned +SIPAccount::generateVideoPort() const +{ + return getRandomEvenNumber(videoPortRange_); +} +#endif diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h index f1d5c81ec2d26172740a3205c327680e557fca0c..c4b3c520c77e9e22805c622397c5db2761a2e451 100644 --- a/daemon/src/sip/sipaccount.h +++ b/daemon/src/sip/sipaccount.h @@ -199,7 +199,7 @@ class SIPAccount : public Account { const pjsip_cred_info* getCredInfo() const { - return &(*cred_.begin()); + return cred_.data(); } /** @@ -525,7 +525,12 @@ class SIPAccount : public Account { */ SIPPresence * getPresence(); -private: + unsigned generateAudioPort() const; +#ifdef SFL_VIDEO + unsigned generateVideoPort() const; +#endif + + private: NON_COPYABLE(SIPAccount); bool fullMatch(const std::string &username, const std::string &hostname, pjsip_endpoint *endpt, pj_pool_t *pool) const; @@ -553,9 +558,10 @@ private: void initTlsConfiguration(); /** - * Display the list of ciphers currently supported on the + * PJSIP aborts if the string length of our cipher list is too + * great, so this function forces our cipher list to fit this constraint. */ - void displayCipherSuite(); + void trimCiphers(); #endif /** @@ -642,9 +648,9 @@ private: pjsip_tls_setting tlsSetting_; /** - * Allocate a static array to be used by pjsip to store the supported ciphers on this system. + * Allocate a vector to be used by pjsip to store the supported ciphers on this system. */ - CipherArray ciphers; + CipherArray ciphers_; /** * The STUN server name (hostname) @@ -777,6 +783,17 @@ private: */ SIPPresence * presence_; + /* + * Port range for audio RTP ports + */ + std::pair<unsigned, unsigned> audioPortRange_; + +#ifdef SFL_VIDEO + /** + * Port range for video RTP ports + */ + std::pair<unsigned, unsigned> videoPortRange_; +#endif }; #endif diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp index 904daadcf5ce32a9a7b7c9d4c41e2d8a23499bd8..5a1b7a0eb992eb8f714506fd4b2eb4f78ee3c415 100644 --- a/daemon/src/sip/sipcall.cpp +++ b/daemon/src/sip/sipcall.cpp @@ -36,7 +36,7 @@ #include "sdp.h" #include "manager.h" #ifdef SFL_VIDEO -#include "dbus/video_controls.h" +#include "client/video_controls.h" #endif namespace { @@ -51,7 +51,7 @@ SIPCall::SIPCall(const std::string& id, Call::CallType type, , audiortp_(this) #ifdef SFL_VIDEO // The ID is used to associate video streams to calls - , videortp_(id, Manager::instance().getDbusManager()->getVideoControls()->getSettings()) + , videortp_(id, Manager::instance().getClient()->getVideoControls()->getSettings()) #endif , pool_(pj_pool_create(&caching_pool->factory, id.c_str(), INITIAL_SIZE, INCREMENT_SIZE, NULL)) , local_sdp_(new Sdp(pool_)) diff --git a/daemon/src/sip/siptransport.cpp b/daemon/src/sip/siptransport.cpp index 5e2729781ea3770c72613a3c3136e8cdfd05ff4b..85f7c19bf2cf3142d17916d97d4899594d16df50 100644 --- a/daemon/src/sip/siptransport.cpp +++ b/daemon/src/sip/siptransport.cpp @@ -29,6 +29,10 @@ * as that of the covered work. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include <map> #include <pjsip.h> @@ -40,6 +44,7 @@ #include <netinet/in.h> #include <arpa/nameser.h> #include <resolv.h> +#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/ioctl.h> @@ -59,8 +64,7 @@ #include "pjsip/sip_transport_tls.h" #endif -#include "dbus/dbusmanager.h" -#include "dbus/configurationmanager.h" +#include "client/configurationmanager.h" static const char * const DEFAULT_INTERFACE = "default"; static const char * const ANY_HOSTS = "0.0.0.0"; @@ -474,9 +478,8 @@ SipTransport::getSTUNAddresses(const SIPAccount &account, &serverName, port, &serverName, port, &result[0]) != PJ_SUCCESS) throw std::runtime_error("Can't contact STUN server"); - for (std::vector<pj_sockaddr_in>::const_iterator it = result.begin(); - it != result.end(); ++it) - WARN("STUN PORTS: %ld", pj_ntohs(it->sin_port)); + for (const auto & it : result) + WARN("STUN PORTS: %ld", pj_ntohs(it.sin_port)); return result; } @@ -484,11 +487,15 @@ SipTransport::getSTUNAddresses(const SIPAccount &account, pjsip_transport *SipTransport::createStunTransport(SIPAccount &account) { +#if HAVE_DBUS #define RETURN_IF_STUN_FAIL(A, M, ...) \ if (!(A)) { \ ERROR(M, ##__VA_ARGS__); \ - Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure(account.getAccountID()); \ + Manager::instance().getClient()->getConfigurationManager()->stunStatusFailure(account.getAccountID()); \ return NULL; } +#else /* HAVE_DBUS */ +#define RETURN_IF_STUN_FAIL(A, M, ...) +#endif /* HAVE_DBUS */ pj_str_t serverName = account.getStunServerName(); pj_uint16_t port = account.getStunPort(); @@ -511,7 +518,8 @@ pjsip_transport *SipTransport::createStunTransport(SIPAccount &account) if (pjstun_get_mapped_addr(&cp_->factory, 1, &sock, &serverName, port, &serverName, port, &pub_addr) != PJ_SUCCESS) { ERROR("Can't contact STUN server"); pj_sock_close(sock); - Manager::instance().getDbusManager()->getConfigurationManager()->stunStatusFailure(account.getAccountID()); + + Manager::instance().getClient()->getConfigurationManager()->stunStatusFailure(account.getAccountID()); return NULL; } diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index 0a2865c9017ffdfde3a63e7655e4638d5dac8604..0d413698b5669a8ba3e8d9bb38a85997762427f0 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -52,9 +52,6 @@ #endif #include "array_size.h" -#include "dbus/dbusmanager.h" -#include "dbus/callmanager.h" -#include "dbus/configurationmanager.h" #if HAVE_INSTANT_MESSAGING #include "im/instant_messaging.h" @@ -64,9 +61,13 @@ #ifdef SFL_VIDEO #include "video/video_rtp_session.h" -#include "dbus/video_controls.h" +#include "client/video_controls.h" #endif +#include "client/client.h" +#include "client/callmanager.h" +#include "client/configurationmanager.h" + #include "pjsip/sip_endpoint.h" #include "pjsip/sip_uri.h" #include "pjnath.h" @@ -123,6 +124,11 @@ void registration_cb(pjsip_regc_cbparam *param); pj_bool_t transaction_request_cb(pjsip_rx_data *rdata); pj_bool_t transaction_response_cb(pjsip_rx_data *rdata) ; +#ifdef __ANDROID__ +void showLog(int level, const char *data, int len); +void showMsg(const char *format, ...); +#endif + void transfer_client_cb(pjsip_evsub *sub, pjsip_event *event); /** @@ -193,6 +199,26 @@ pj_bool_t transaction_response_cb(pjsip_rx_data *rdata) return PJ_FALSE; } +#ifdef __ANDROID__ +void showMsg(const char *format, ...) +{ + va_list arg; + + va_start(arg, format); + __android_log_vprint(ANDROID_LOG_INFO, "apjsua", format, arg); + //vsnprintf(app_var.out_buf, sizeof(app_var.out_buf), format, arg); + va_end(arg); + + /* pj_sem_post(app_var.output_sem); + pj_sem_wait(app_var.out_print_sem); */ +} + +void showLog(int level, const char *data, int len) +{ + showMsg("%s", data); +} +#endif + void updateSDPFromSTUN(SIPCall &call, SIPAccount &account, const SipTransport &transport) { std::vector<long> socketDescriptors(call.getAudioRtp().getSocketDescriptors()); @@ -210,9 +236,20 @@ void updateSDPFromSTUN(SIPCall &call, SIPAccount &account, const SipTransport &t } } +void +addContactHeader(const std::string &contactStr, pjsip_tx_data *tdata) +{ + pj_str_t pjContact = pj_str((char*) contactStr.c_str()); + + pjsip_contact_hdr *contact = pjsip_contact_hdr_create(tdata->pool); + contact->uri = pjsip_parse_uri(tdata->pool, pjContact.ptr, + pjContact.slen, PJSIP_PARSE_URI_AS_NAMEADDR); + pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) contact); +} pj_bool_t transaction_request_cb(pjsip_rx_data *rdata) { + if (!rdata or !rdata->msg_info.msg) { ERROR("rx_data is NULL"); return PJ_FALSE; @@ -424,11 +461,30 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata) if (pjsip_inv_end_session(replaced_inv, PJSIP_SC_GONE, NULL, &tdata) == PJ_SUCCESS && tdata) pjsip_inv_send_msg(replaced_inv, tdata); } else { // Proceed with normal call flow - if (pjsip_inv_initial_answer(call->inv, rdata, PJSIP_SC_RINGING, NULL, NULL, &tdata) != PJ_SUCCESS) { + if (pjsip_inv_initial_answer(call->inv, rdata, PJSIP_SC_TRYING, NULL, NULL, &tdata) != PJ_SUCCESS) { ERROR("Could not answer invite"); delete call; return PJ_FALSE; } + + if (pjsip_inv_send_msg(call->inv, tdata) != PJ_SUCCESS) { + ERROR("Could not send msg for invite"); + delete call; + return PJ_FALSE; + } + + call->setConnectionState(Call::TRYING); + + if (pjsip_inv_answer(call->inv, PJSIP_SC_RINGING, NULL, NULL, &tdata) != PJ_SUCCESS) { + ERROR("Could not answer invite"); + delete call; + return PJ_FALSE; + } + + // contactStr must stay in scope as long as tdata + const std::string contactStr(account->getContactHeader()); + addContactHeader(contactStr, tdata); + if (pjsip_inv_send_msg(call->inv, tdata) != PJ_SUCCESS) { ERROR("Could not send msg for invite"); delete call; @@ -440,7 +496,6 @@ pj_bool_t transaction_request_cb(pjsip_rx_data *rdata) Manager::instance().incomingCall(*call, account_id); SIPVoIPLink::instance()->addSipCall(call); } - return PJ_FALSE; } } // end anonymous namespace @@ -462,6 +517,7 @@ SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), sipAccountMap_(), #endif , presenceState() { + #define TRY(ret) do { \ if (ret != PJ_SUCCESS) \ throw VoipLinkException(#ret " failed"); \ @@ -476,8 +532,12 @@ SIPVoIPLink::SIPVoIPLink() : sipTransport(endpt_, cp_, pool_), sipAccountMap_(), srand(time(NULL)); // to get random number for RANDOM_PORT TRY(pj_init()); + TRY(pjlib_util_init()); +#ifdef __ANDROID__ + setSipLogger(); +#endif setSipLogLevel(); TRY(pjnath_init()); @@ -593,8 +653,10 @@ SIPVoIPLink::~SIPVoIPLink() SIPVoIPLink* SIPVoIPLink::instance() { assert(!destroyed_); - if (!instance_) + if (!instance_) { + DEBUG("creating SIPVoIPLink instance"); instance_ = new SIPVoIPLink; + } return instance_; } @@ -612,10 +674,10 @@ SIPVoIPLink::getAccountIdFromNameAndServer(const std::string &userName, DEBUG("username = %s, server = %s", userName.c_str(), server.c_str()); // Try to find the account id from username and server name by full match - for (AccountMap::const_iterator iter = sipAccountMap_.begin(); iter != sipAccountMap_.end(); ++iter) { - SIPAccount *account = static_cast<SIPAccount*>(iter->second); + for (const auto &item : sipAccountMap_) { + SIPAccount *account = static_cast<SIPAccount*>(item.second); if (account and account->matches(userName, server, endpt_, pool_)) - return iter->first; + return item.first; } DEBUG("Username %s or server %s doesn't match any account, using IP2IP", userName.c_str(), server.c_str()); @@ -627,7 +689,7 @@ void SIPVoIPLink::setSipLogLevel() char *envvar = getenv(SIPLOGLEVEL); int level = 0; - if(envvar != NULL) { + if (envvar != NULL) { std::string loglevel = envvar; if ( ! (std::istringstream(loglevel) >> level) ) level = 0; @@ -636,10 +698,22 @@ void SIPVoIPLink::setSipLogLevel() level = level < 0 ? 0 : level; } +#ifdef __ANDROID__ + level = 6; +#endif + // From 0 (min) to 6 (max) pj_log_set_level(level); } +#ifdef __ANDROID__ +void SIPVoIPLink::setSipLogger() +{ + static pj_log_func *currentFunc = (pj_log_func*) pj_log_get_log_func(); + pj_log_set_log_func(&showLog); +} +#endif + // Called from EventThread::run (not main thread) bool SIPVoIPLink::getEvent() { @@ -696,6 +770,7 @@ void SIPVoIPLink::sendRegister(Account *a) std::string contact = account->getContactHeader(); pj_str_t pjContact = pj_str((char*) contact.c_str()); + if (account->transport_) { if (account->isStunEnabled()) { DEBUG("Setting VIA sent-by to %s:%u", account->transport_->local_name.host.ptr, account->transport_->local_name.port); @@ -1035,14 +1110,9 @@ SIPVoIPLink::hangup(const std::string& id, int reason) if (pjsip_inv_end_session(inv, status, NULL, &tdata) != PJ_SUCCESS || !tdata) return; - // add contact header + // contactStr must stay in scope as long as tdata const std::string contactStr(account->getContactHeader()); - pj_str_t pjContact = pj_str((char*) contactStr.c_str()); - - pjsip_contact_hdr *contact = pjsip_contact_hdr_create(tdata->pool); - contact->uri = pjsip_parse_uri(tdata->pool, pjContact.ptr, - pjContact.slen, PJSIP_PARSE_URI_AS_NAMEADDR); - pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) contact); + addContactHeader(contactStr, tdata); if (pjsip_inv_send_msg(inv, tdata) != PJ_SUCCESS) return; @@ -1125,14 +1195,13 @@ SIPVoIPLink::offhold(const std::string& id) std::vector<sfl::AudioCodec*> sessionMedia; sdpSession->getSessionAudioMedia(sessionMedia); std::vector<sfl::AudioCodec*> audioCodecs; - for (std::vector<sfl::AudioCodec*>::const_iterator i = sessionMedia.begin(); - i != sessionMedia.end(); ++i) { + for (auto &i : sessionMedia) { - if (!*i) + if (!i) continue; // Create a new instance for this codec - sfl::AudioCodec* ac = Manager::instance().audioCodecFactory.instantiateCodec((*i)->getPayloadType()); + sfl::AudioCodec* ac = Manager::instance().audioCodecFactory.instantiateCodec(i->getPayloadType()); if (ac == NULL) throw VoipLinkException("Could not instantiate codec"); @@ -1199,9 +1268,8 @@ SIPVoIPLink::clearSipCallMap() { sfl::ScopedLock m(sipCallMapMutex_); - for (SipCallMap::const_iterator iter = sipCallMap_.begin(); - iter != sipCallMap_.end(); ++iter) - delete iter->second; + for (const auto &item : sipCallMap_) + delete item.second; sipCallMap_.clear(); } @@ -1251,7 +1319,7 @@ SIPVoIPLink::getSipCall(const std::string& id) if (iter != sipCallMap_.end()) return iter->second; else { - ERROR("No SIP call with ID %s", id.c_str()); + DEBUG("No SIP call with ID %s", id.c_str()); return NULL; } } @@ -1674,7 +1742,8 @@ void invite_session_state_changed_cb(pjsip_inv_session *inv, pjsip_event *ev) if (statusCode) { const pj_str_t * description = pjsip_get_status_text(statusCode); std::string desc(description->ptr, description->slen); - CallManager *cm = Manager::instance().getDbusManager()->getCallManager(); + + CallManager *cm = Manager::instance().getClient()->getCallManager(); cm->sipCallStateChanged(call->getCallId(), desc, statusCode); } } @@ -1839,7 +1908,12 @@ void sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status) // Update internal field for sdpSession->setMediaTransportInfoFromRemoteSdp(); - call->getAudioRtp().updateDestinationIpAddress(); + try { + call->getAudioRtp().updateDestinationIpAddress(); + } catch (const AudioRtpFactoryException &e) { + ERROR("%s", e.what()); + } + call->getAudioRtp().setDtmfPayloadType(sdpSession->getTelephoneEventType()); #ifdef SFL_VIDEO Manager::instance().getVideoControls()->stopPreview(); @@ -1870,10 +1944,10 @@ void sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status) call->getAudioRtp().setRemoteCryptoInfo(sdesnego); } catch (...) {} - Manager::instance().getDbusManager()->getCallManager()->secureSdesOn(call->getCallId()); + Manager::instance().getClient()->getCallManager()->secureSdesOn(call->getCallId()); } else { ERROR("SDES negotiation failure"); - Manager::instance().getDbusManager()->getCallManager()->secureSdesOff(call->getCallId()); + Manager::instance().getClient()->getCallManager()->secureSdesOff(call->getCallId()); } } else { @@ -1907,10 +1981,10 @@ void sdp_media_update_cb(pjsip_inv_session *inv, pj_status_t status) Manager::instance().startAudioDriverStream(); std::vector<AudioCodec*> audioCodecs; - for (std::vector<sfl::AudioCodec*>::const_iterator i = sessionMedia.begin(); i != sessionMedia.end(); ++i) { - if (!*i) + for (const auto &i : sessionMedia) { + if (!i) continue; - const int pl = (*i)->getPayloadType(); + const int pl = i->getPayloadType(); sfl::AudioCodec *ac = Manager::instance().audioCodecFactory.instantiateCodec(pl); if (!ac) @@ -2128,7 +2202,8 @@ void registration_cb(pjsip_regc_cbparam *param) if (param->code && description) { std::string state(description->ptr, description->slen); - Manager::instance().getDbusManager()->getCallManager()->registrationStateChanged(accountID, state, param->code); + + Manager::instance().getClient()->getCallManager()->registrationStateChanged(accountID, state, param->code); std::pair<int, std::string> details(param->code, state); // TODO: there id a race condition for this ressource when closing the application account->setRegistrationStateDetailed(details); @@ -2298,16 +2373,6 @@ void transfer_client_cb(pjsip_evsub *sub, pjsip_event *event) } } -namespace { - // returns even number in range [lower, upper] - unsigned int getRandomEvenNumber(int lower, int upper) - { - const unsigned halfUpper = upper * 0.5; - const unsigned halfLower = lower * 0.5; - return 2 * (halfLower + rand() % (halfUpper - halfLower + 1)); - } -} - void setCallMediaLocal(SIPCall* call, const std::string &localIP) { std::string account_id(call->getAccountId()); @@ -2318,7 +2383,7 @@ void setCallMediaLocal(SIPCall* call, const std::string &localIP) // Reference: http://www.cs.columbia.edu/~hgs/rtp/faq.html#ports // We only want to set ports to new values if they haven't been set if (call->getLocalAudioPort() == 0) { - const unsigned callLocalAudioPort = getRandomEvenNumber(16384, 32766); + const unsigned callLocalAudioPort = account->generateAudioPort(); call->setLocalAudioPort(callLocalAudioPort); call->getLocalSDP()->setLocalPublishedAudioPort(callLocalAudioPort); } @@ -2330,7 +2395,7 @@ void setCallMediaLocal(SIPCall* call, const std::string &localIP) // https://projects.savoirfairelinux.com/issues/17498 unsigned int callLocalVideoPort; do - callLocalVideoPort = getRandomEvenNumber(49152, 65534); + callLocalVideoPort = account->generateVideoPort(); while (call->getLocalAudioPort() == callLocalVideoPort); call->setLocalVideoPort(callLocalVideoPort); diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h index 224dc51868e4940d153d04afac0d224005aa86aa..8c2db215b60b669ee232c023101eff6152926302 100644 --- a/daemon/src/sip/sipvoiplink.h +++ b/daemon/src/sip/sipvoiplink.h @@ -91,6 +91,10 @@ class SIPVoIPLink : public VoIPLink { */ static void setSipLogLevel(); +#ifdef __ANDROID__ + static void setSipLogger(); +#endif + /** * Event listener. Each event send by the call manager is received and handled from here */ diff --git a/daemon/src/video/libav_utils.cpp b/daemon/src/video/libav_utils.cpp index a70342cad1ab8be9f51cb2022d5a89c46a48a4f4..99b18a6589d6dc6175770c4b7ef386f05e4742cb 100644 --- a/daemon/src/video/libav_utils.cpp +++ b/daemon/src/video/libav_utils.cpp @@ -58,11 +58,11 @@ void findInstalledVideoCodecs() if (p->type == AVMEDIA_TYPE_VIDEO) libav_codecs.push_back(p->name); - for (map<string, string>::const_iterator it = encoders_.begin(); it != encoders_.end(); ++it) { - if (std::find(libav_codecs.begin(), libav_codecs.end(), it->second) != libav_codecs.end()) - installed_video_codecs_.push_back(it->first); + for (const auto &it : encoders_) { + if (std::find(libav_codecs.begin(), libav_codecs.end(), it.second) != libav_codecs.end()) + installed_video_codecs_.push_back(it.first); else - ERROR("Didn't find \"%s\" encoder", it->second.c_str()); + ERROR("Didn't find \"%s\" encoder", it.second.c_str()); } } @@ -160,15 +160,14 @@ getDefaultCodecs() const char * const DEFAULT_BITRATE = "400"; sfl_avcodec_init(); std::vector<std::map<std::string, std::string> > result; - for (std::vector<std::string>::const_iterator iter = installed_video_codecs_.begin(); - iter != installed_video_codecs_.end(); ++iter) { + for (const auto &item : installed_video_codecs_) { std::map<std::string, std::string> codec; // FIXME: get these keys from proper place - codec["name"] = *iter; + codec["name"] = item; codec["bitrate"] = DEFAULT_BITRATE; codec["enabled"] = "true"; // FIXME: make a nicer version of this - if (*iter == "H264") + if (item == "H264") codec["parameters"] = DEFAULT_H264_PROFILE_LEVEL_ID; result.push_back(codec); } diff --git a/daemon/src/video/shm_sink.cpp b/daemon/src/video/shm_sink.cpp index ff48b2457637b9d349906a502ec1d9cde07c5110..ab3c4f5937a9727cd57663aaee712f0199a729b9 100644 --- a/daemon/src/video/shm_sink.cpp +++ b/daemon/src/video/shm_sink.cpp @@ -183,7 +183,7 @@ void SHMSink::render(const std::vector<unsigned char> &data) if (!resize_area(sizeof(SHMHeader) + data.size())) return; - memcpy(shm_area_->data, &(*data.begin()), data.size()); + memcpy(shm_area_->data, data.data(), data.size()); shm_area_->buffer_size = data.size(); shm_area_->buffer_gen++; sem_post(&shm_area_->notification); diff --git a/daemon/src/video/socket_pair.cpp b/daemon/src/video/socket_pair.cpp index 86769698d56fb992b083f8e2d851e0c137dbcd18..c670e5da0ede87cc0ca6b2caeab10c80a383bbba 100644 --- a/daemon/src/video/socket_pair.cpp +++ b/daemon/src/video/socket_pair.cpp @@ -181,7 +181,6 @@ void SocketPair::openSockets(const char *uri, int local_rtp_port) { char hostname[256]; - char buf[1024]; char path[1024]; int rtp_port; diff --git a/daemon/src/video/test/Makefile.am b/daemon/src/video/test/Makefile.am index b5138618eb80f879df8137e3ebf943ddc41b0fef..c1bf99db9301b0f34b8081528dc72719194b460d 100644 --- a/daemon/src/video/test/Makefile.am +++ b/daemon/src/video/test/Makefile.am @@ -17,6 +17,6 @@ test_v4l2_LDADD=$(top_builddir)/src/libsflphone.la $(top_builddir)/src/video/lib test_shm_SOURCES=test_shm.cpp shm_src.cpp shm_src.h test_shm_LDADD=$(top_builddir)/src/libsflphone.la $(top_builddir)/src/video/libvideo.la $(YAML_LIBS) -test_shm_CXXFLAGS=$(AM_CXXFLAGS) -std=c++0x +test_shm_CXXFLAGS=$(AM_CXXFLAGS) AM_CXXFLAGS=-I$(top_builddir)/src/video -I$(top_builddir)/src diff --git a/daemon/src/video/test/test_shm.cpp b/daemon/src/video/test/test_shm.cpp index 199166b7a84a3e3e972ec49bab526d444f75da45..1ac94610ac9486d75467a017755db0fdb2ea8086 100644 --- a/daemon/src/video/test/test_shm.cpp +++ b/daemon/src/video/test/test_shm.cpp @@ -80,12 +80,12 @@ void run_client() return; // initialize destination string to 0's - std::string dest(sizeof(test_data), 0); - const std::string test_data_str(test_data, sizeof(test_data)); + std::vector<char> dest(sizeof(test_data), 0); + const std::vector<char> test_data_str(test_data, test_data + sizeof(test_data)); assert(test_data_str.size() == 27); assert(dest.size() == test_data_str.size()); while (not done and dest != test_data_str) { - src.render(&(*dest.begin()), dest.size()); + src.render(dest.data(), dest.size()); usleep(1000); } src.stop(); diff --git a/daemon/src/video/video_receive_thread.cpp b/daemon/src/video/video_receive_thread.cpp index 31ca3337a0f565be742f2d9e2a4aa74793f59324..6b41a893f85bb7af97c659850a3f3d6250e488db 100644 --- a/daemon/src/video/video_receive_thread.cpp +++ b/daemon/src/video/video_receive_thread.cpp @@ -31,7 +31,7 @@ #include "video_receive_thread.h" #include "socket_pair.h" -#include "dbus/video_controls.h" +#include "client/video_controls.h" #include "check.h" #include "packet_handle.h" @@ -42,6 +42,7 @@ extern "C" { #include <libavdevice/avdevice.h> #include <libswscale/swscale.h> } +#include <unistd.h> #include <map> #include "manager.h" diff --git a/daemon/src/video/video_send_thread.cpp b/daemon/src/video/video_send_thread.cpp index 74566b311c3ba700ad505358f66c7bed9d0314d6..f15b7d25105ac03da3fae459e19a2afd25569748 100644 --- a/daemon/src/video/video_send_thread.cpp +++ b/daemon/src/video/video_send_thread.cpp @@ -30,7 +30,7 @@ #include "video_send_thread.h" #include "socket_pair.h" -#include "dbus/video_controls.h" +#include "client/video_controls.h" #include "packet_handle.h" #include "check.h" @@ -62,7 +62,7 @@ void VideoSendThread::print_sdp() /* theora sdp can be huge */ const size_t sdp_size = outputCtx_->streams[0]->codec->extradata_size + 2048; std::string sdp(sdp_size, 0); - av_sdp_create(&outputCtx_, 1, &(*sdp.begin()), sdp_size); + av_sdp_create(&outputCtx_, 1, &sdp[0], sdp_size); std::istringstream iss(sdp); string line; sdp_ = ""; diff --git a/daemon/src/video/video_v4l2.cpp b/daemon/src/video/video_v4l2.cpp index 04e594c1dc4777d65360290d2f51569a93e10b88..343a5d615cad2c86ce017c525f8e9991724f8041 100644 --- a/daemon/src/video/video_v4l2.cpp +++ b/daemon/src/video/video_v4l2.cpp @@ -121,10 +121,9 @@ static const unsigned pixelformats_supported[] = { namespace { unsigned int pixelformat_score(unsigned pixelformat) { - size_t n = sizeof pixelformats_supported / sizeof *pixelformats_supported; - for (unsigned int i = 0; i < n ; ++i) - if (pixelformats_supported[i] == pixelformat) - return i; + for (const auto &item : pixelformats_supported) + if (item == pixelformat) + return item; return UINT_MAX - 1; } @@ -137,9 +136,9 @@ vector<string> VideoV4l2Size::getRateList() { vector<string> v; - for (vector<float>::const_iterator i = rates_.begin() ; i != rates_.end(); ++i) { + for (const auto &item : rates_) { std::stringstream ss; - ss << *i; + ss << item; v.push_back(ss.str()); } @@ -201,9 +200,9 @@ vector<string> VideoV4l2Channel::getSizeList() const { vector<string> v; - for (vector<VideoV4l2Size>::const_iterator itr = sizes_.begin(); itr != sizes_.end(); ++itr) { + for (const auto &item : sizes_) { std::stringstream ss; - ss << itr->width << "x" << itr->height; + ss << item.width << "x" << item.height; v.push_back(ss.str()); } @@ -309,11 +308,11 @@ void VideoV4l2Channel::getFormat(int fd) VideoV4l2Size VideoV4l2Channel::getSize(const string &name) const { - for (vector<VideoV4l2Size>::const_iterator i = sizes_.begin(); i != sizes_.end(); ++i) { + for (const auto &item : sizes_) { std::stringstream ss; - ss << i->width << "x" << i->height; + ss << item.width << "x" << item.height; if (ss.str() == name) - return *i; + return item; } // fallback to last size @@ -354,8 +353,8 @@ vector<string> VideoV4l2Device::getChannelList() const { vector<string> v; - for (vector<VideoV4l2Channel>::const_iterator itr = channels_.begin(); itr != channels_.end(); ++itr) - v.push_back(itr->name); + for (const auto &itr : channels_) + v.push_back(itr.name); return v; } @@ -363,9 +362,9 @@ vector<string> VideoV4l2Device::getChannelList() const const VideoV4l2Channel & VideoV4l2Device::getChannel(const string &name) const { - for (vector<VideoV4l2Channel>::const_iterator itr = channels_.begin(); itr != channels_.end(); ++itr) - if (itr->name == name) - return *itr; + for (const auto &item : channels_) + if (item.name == name) + return item; return channels_.back(); } diff --git a/daemon/src/video/video_v4l2_list.cpp b/daemon/src/video/video_v4l2_list.cpp index 9e592bba7ca94f26cf80b92c2ca6cb7c7aa25173..8cdc806554e926014436924fbb9d20845fdb2ce1 100644 --- a/daemon/src/video/video_v4l2_list.cpp +++ b/daemon/src/video/video_v4l2_list.cpp @@ -34,6 +34,7 @@ #include <stdexcept> // for std::runtime_error #include <sstream> #include <algorithm> +#include <unistd.h> #include "logger.h" #include "scoped_lock.h" @@ -51,7 +52,7 @@ extern "C" { #include "video_v4l2_list.h" #include "manager.h" -#include "dbus/video_controls.h" +#include "client/video_controls.h" namespace sfl_video { @@ -194,8 +195,8 @@ namespace { void giveUniqueName(VideoV4l2Device &dev, const vector<VideoV4l2Device> &devices) { start: - for (size_t i = 0; i < devices.size(); ++i) { - if (dev.name == devices[i].name) { + for (auto &item : devices) { + if (dev.name == item.name) { size_t sharp; int num = getNumber(dev.name, &sharp); if (num < 0) // not numbered @@ -287,7 +288,7 @@ void VideoV4l2ListThread::delDevice(const string &node) { ScopedLock lock(mutex_); - for (std::vector<VideoV4l2Device>::iterator itr = devices_.begin(); itr != devices_.end(); ++itr) { + for (auto itr = devices_.begin(); itr != devices_.end(); ++itr) { if (itr->device == node) { devices_.erase(itr); Manager::instance().getVideoControls()->deviceEvent(); @@ -351,8 +352,8 @@ vector<string> VideoV4l2ListThread::getDeviceList() ScopedLock lock(mutex_); vector<string> v; - for (std::vector<VideoV4l2Device>::iterator itr = devices_.begin(); itr != devices_.end(); ++itr) - v.push_back(itr->name.empty() ? itr->device : itr->name); + for (const auto &itr : devices_) + v.push_back(itr.name.empty() ? itr.device : itr.name); return v; } diff --git a/daemon/test/Makefile.am b/daemon/test/Makefile.am index 3c9fc09df60f82dd2733f5c0313a4cd6626da643..e945b75282a718498dfa23df187b4d8e7cc87b4b 100644 --- a/daemon/test/Makefile.am +++ b/daemon/test/Makefile.am @@ -35,7 +35,9 @@ test_SOURCES = constants.h \ resamplertest.h \ resamplertest.cpp \ hooktest.h \ - hooktest.cpp + hooktest.cpp \ + audiobuffertest.h \ + audiobuffertest.cpp if BUILD_SDES test_SOURCES+=sdesnegotiatortest.h \ diff --git a/daemon/test/audiobuffertest.cpp b/daemon/test/audiobuffertest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b6143fe2624dc9a42c6eaf2acf06cb84fddf2626 --- /dev/null +++ b/daemon/test/audiobuffertest.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Adrien Beraud <adrienberaud@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include <string> +#include "audiobuffertest.h" +#include "audio/audiobuffer.h" +#include "audio/ringbuffer.h" +#include "logger.h" +#include "test_utils.h" + +void AudioBufferTest::testAudioBufferConstructors() +{ + TITLE(); + + SFLAudioSample test_samples1[] = {}; + SFLAudioSample test_samples2[] = {10, 11, 12, 13, 14, 15, 16, 17}; + + AudioBuffer empty_buf; + CPPUNIT_ASSERT(empty_buf.samples() == 0); + CPPUNIT_ASSERT(empty_buf.channels() == 1); + CPPUNIT_ASSERT(empty_buf.getChannel(0)->size() == 0); + + AudioBuffer test_buf1(8, 2); + CPPUNIT_ASSERT(test_buf1.samples() == 8); + CPPUNIT_ASSERT(test_buf1.channels() == 2); + CPPUNIT_ASSERT(test_buf1.getChannel(0)->size() == 8); + CPPUNIT_ASSERT(test_buf1.getChannel(1)->size() == 8); + CPPUNIT_ASSERT(test_buf1.getChannel(2) == NULL); + + AudioBuffer test_buf2(test_samples1, 0, 0); + CPPUNIT_ASSERT(test_buf2.samples() == 0); + CPPUNIT_ASSERT(test_buf2.channels() == 1); + CPPUNIT_ASSERT(test_buf2.getChannel(0)->size() == 0); + + AudioBuffer test_buf3(test_samples2, 4, 2); + CPPUNIT_ASSERT(test_buf3.samples() == 4); + CPPUNIT_ASSERT(test_buf3.channels() == 2); + CPPUNIT_ASSERT(test_buf3.getChannel(0)->size() == 4); +} + +void AudioBufferTest::testAudioBufferMix() +{ + TITLE(); + + SFLAudioSample test_samples1[] = {18, 19, 20, 21, 22, 23, 24, 25}; + SFLAudioSample test_samples2[] = {10, 11, 12, 13, 14, 15, 16, 17, 18}; + + AudioBuffer test_buf1(test_samples1, 4, 2); + CPPUNIT_ASSERT(test_buf1.channels() == 2); + test_buf1.setChannelNum(1); + CPPUNIT_ASSERT(test_buf1.channels() == 1); + test_buf1.setChannelNum(2); + CPPUNIT_ASSERT(test_buf1.channels() == 2); + CPPUNIT_ASSERT(test_buf1.getChannel(1)->size() == 4); + CPPUNIT_ASSERT((*test_buf1.getChannel(1))[0] == 0); + test_buf1.setChannelNum(1); + test_buf1.setChannelNum(2, true); + CPPUNIT_ASSERT((*test_buf1.getChannel(1))[0] == test_samples1[0]); + + AudioBuffer test_buf2; + test_buf2.deinterleave(test_samples2, 3, 3); + CPPUNIT_ASSERT((*test_buf2.getChannel(0))[2] == test_samples2[6]); + CPPUNIT_ASSERT((*test_buf2.getChannel(1))[1] == test_samples2[4]); + CPPUNIT_ASSERT((*test_buf2.getChannel(2))[0] == test_samples2[2]); + CPPUNIT_ASSERT(test_buf2.capacity() == 9); + + SFLAudioSample *output = new SFLAudioSample[test_buf2.capacity()]; + test_buf2.interleave(output); + CPPUNIT_ASSERT(std::equal(test_samples2, test_samples2 + sizeof test_samples2 / sizeof *test_samples2, output)); + //CPPUNIT_ASSERT(std::equal(std::begin(test_samples2), std::end(test_samples2), std::begin(output))); C++11 + + test_buf1.mix(test_buf2); + CPPUNIT_ASSERT(test_buf1.channels() == 2); + CPPUNIT_ASSERT(test_buf1.samples() == 4); + CPPUNIT_ASSERT((*test_buf1.getChannel(0))[0] == test_samples1[0]+test_samples2[0]); + CPPUNIT_ASSERT((*test_buf1.getChannel(1))[0] == test_samples1[0]+test_samples2[1]); +} + + +AudioBufferTest::AudioBufferTest() : CppUnit::TestCase("Audio Buffer Tests") {} diff --git a/daemon/test/audiobuffertest.h b/daemon/test/audiobuffertest.h new file mode 100644 index 0000000000000000000000000000000000000000..8797a0bbc44ee1a350b9f9e45b499fb5a9a0083d --- /dev/null +++ b/daemon/test/audiobuffertest.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2004-2012 Savoir-Faire Linux Inc. + * Author: Adrien Beraud <adrienberaud@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef AUDIOBUFFER_TEST_ +#define AUDIOBUFFER_TEST_ + +// Cppunit import +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCaller.h> +#include <cppunit/TestCase.h> +#include <cppunit/TestSuite.h> + +#include <tr1/memory> + +/* + * @file audiobuffertest.cpp + * @brief Regroups unit tests related to an audio buffer. + */ + +class AudioBufferTest : public CppUnit::TestCase { + + /* + * Use cppunit library macros to add unit test the factory + */ + CPPUNIT_TEST_SUITE(AudioBufferTest); + CPPUNIT_TEST(testAudioBufferConstructors); + CPPUNIT_TEST(testAudioBufferMix); + CPPUNIT_TEST_SUITE_END(); + + public: + + AudioBufferTest(); + + void testAudioBufferConstructors(); + + void testAudioBufferMix(); +}; + +/* Register our test module */ +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(AudioBufferTest, "AudioBufferTest"); +CPPUNIT_TEST_SUITE_REGISTRATION(AudioBufferTest); + +#endif // AUDIOBUFFER_TEST_ diff --git a/daemon/test/instantmessagingtest.cpp b/daemon/test/instantmessagingtest.cpp index f12df31d78f0951ff82e16345af7f2cc82ecd73f..c07889ed07b9a2d0158a89f3e2101095c00b3a57 100644 --- a/daemon/test/instantmessagingtest.cpp +++ b/daemon/test/instantmessagingtest.cpp @@ -192,9 +192,7 @@ void InstantMessagingTest::testXmlUriListParsing() sfl::InstantMessaging::UriEntry::iterator iterAttr; // An iterator over list entries - for (sfl::InstantMessaging::UriList::iterator iterEntry = list.begin(); - iterEntry != list.end(); ++iterEntry) { - sfl::InstantMessaging::UriEntry entry = static_cast<sfl::InstantMessaging::UriEntry>(*iterEntry); + for (auto &entry : list) { iterAttr = entry.find(sfl::IM_XML_URI); CPPUNIT_ASSERT((iterAttr->second == std::string("sip:alex@example.com")) or diff --git a/daemon/test/mainbuffertest.cpp b/daemon/test/mainbuffertest.cpp index f33e927db784f4dd426b4b78239753960b9a9b79..cfc70f6e3e8bfb2dc65a54f0ecf1c5bc043c3d1e 100644 --- a/daemon/test/mainbuffertest.cpp +++ b/daemon/test/mainbuffertest.cpp @@ -216,8 +216,11 @@ void MainBufferTest::testRingBufferInt() { TITLE(); - int testint1 = 12; - int testint2 = 13; + SFLAudioSample testsample1 = 12; + SFLAudioSample testsample2[] = {13, 14, 15, 16, 17, 18}; + + AudioBuffer testbuf1(&testsample1, 1); // 1 sample, 1 channel + AudioBuffer testbuf2(testsample2, 3, 2); // 3 samples, 2 channels // test with default ring buffer mainbuffer_->createRingBuffer(MainBuffer::DEFAULT_ID); @@ -228,25 +231,25 @@ void MainBufferTest::testRingBufferInt() CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 0); // add some data - test_ring_buffer->put(&testint1, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); + test_ring_buffer->put(testbuf1); // +1 sample + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 0); // add some other data - test_ring_buffer->put(&testint2, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == 2*sizeof(int)); + test_ring_buffer->put(testbuf2); // +3 samples + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 4); CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 0); - int testget = (int) NULL; + AudioBuffer testget(&testsample1, 1); // get some data (without any read pointers) CPPUNIT_ASSERT(test_ring_buffer->hasNoReadPointers()); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->get(&testget, sizeof(int), MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 2*sizeof(int)); - CPPUNIT_ASSERT(testget == (int) NULL); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4); + CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 4); + CPPUNIT_ASSERT(test_ring_buffer->get(testget, MainBuffer::DEFAULT_ID) == 0); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4); + CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 4); + CPPUNIT_ASSERT((*testget.getChannel(0))[0] == testsample1); CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 0); // get some data (with a read pointer) @@ -257,39 +260,39 @@ void MainBufferTest::testRingBufferInt() CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 0); // add some data - test_ring_buffer->put(&testint1, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 2*sizeof(int)); + test_ring_buffer->put(testbuf1); // +1 sample + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 4); // add some other data - test_ring_buffer->put(&testint2, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 2*sizeof(int)); + test_ring_buffer->put(testbuf2); // +3 samples + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 4); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 4); - CPPUNIT_ASSERT(test_ring_buffer->get(&testget, sizeof(int), MainBuffer::DEFAULT_ID) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->get(testget, MainBuffer::DEFAULT_ID) == 1); // test flush data - test_ring_buffer->put(&testint1, sizeof(int)); + test_ring_buffer->put(testbuf1); test_ring_buffer->flush(MainBuffer::DEFAULT_ID); CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 0); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 5*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 9); // test flush data CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); - test_ring_buffer->put(&testint1, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 5*sizeof(int)); + test_ring_buffer->put(testbuf1); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 1); + CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 1); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 9); - test_ring_buffer->discard(sizeof(int), MainBuffer::DEFAULT_ID); + test_ring_buffer->discard(1, MainBuffer::DEFAULT_ID); CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); CPPUNIT_ASSERT(test_ring_buffer->getLength(MainBuffer::DEFAULT_ID) == 0); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 6*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 10); } @@ -299,8 +302,11 @@ void MainBufferTest::testRingBufferNonDefaultID() std::string test_id = "test_int"; - int testint1 = 12; - int testint2 = 13; + SFLAudioSample testsample1 = 12; + SFLAudioSample testsample2[] = {13, 14, 15, 16, 17, 18}; + + AudioBuffer testbuf1(&testsample1, 1); // 1 sample, 1 channel + AudioBuffer testbuf2(testsample2, 3, 2); // 3 samples, 2 channels // test putData, getData with arbitrary read pointer id mainbuffer_->createRingBuffer(MainBuffer::DEFAULT_ID); @@ -310,64 +316,63 @@ void MainBufferTest::testRingBufferNonDefaultID() CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 0); - test_ring_buffer->put(&testint1, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); + test_ring_buffer->put(testbuf1); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 0); - test_ring_buffer->put(&testint2, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == 2*sizeof(int)); + test_ring_buffer->put(testbuf2); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 4); CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(MainBuffer::DEFAULT_ID) == 0); - int testget; + AudioBuffer testget(1); + AudioBuffer testgetlarge(100); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->get(&testget, sizeof(int), test_id) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == sizeof(int)); - CPPUNIT_ASSERT(testget == testint1); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 4); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 4); + CPPUNIT_ASSERT(test_ring_buffer->get(testget, test_id) == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 3); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 3); + CPPUNIT_ASSERT((*testget.getChannel(0))[0] == testsample1); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 1); - CPPUNIT_ASSERT(test_ring_buffer->get(&testget, 100, test_id) == sizeof(int)); - CPPUNIT_ASSERT(testget == testint2); + CPPUNIT_ASSERT(test_ring_buffer->get(testgetlarge, test_id) == 3); + CPPUNIT_ASSERT((*testgetlarge.getChannel(0))[1] == testsample2[2]); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 0); CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 0); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 2*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 4); // test flush data CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); - test_ring_buffer->put(&testint1, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == sizeof(int)); - + test_ring_buffer->put(testbuf1); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 1); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 1); test_ring_buffer->flush(test_id); CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 0); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 0); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 3*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 5); // test flush data CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); - test_ring_buffer->put(&testint1, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 3*sizeof(int)); + test_ring_buffer->put(testbuf1); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 1); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 1); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 5); - test_ring_buffer->discard(sizeof(int), test_id); + test_ring_buffer->discard(1, test_id); CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); CPPUNIT_ASSERT(test_ring_buffer->getLength(test_id) == 0); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id) == 0); - CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 4*sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->getReadPointer(test_id) == 6); test_ring_buffer->removeReadPointer(test_id); - } - +/* void MainBufferTest::testRingBufferFloat() { TITLE(); @@ -399,7 +404,7 @@ void MainBufferTest::testRingBufferFloat() test_ring_buffer->flush(MainBuffer::DEFAULT_ID); CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); -} +}*/ void MainBufferTest::testTwoPointer() @@ -410,12 +415,14 @@ void MainBufferTest::testTwoPointer() input_buffer->createReadPointer(MainBuffer::DEFAULT_ID); RingBuffer* output_buffer = mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID); - int test_input = 12; - int test_output = 0; + SFLAudioSample test_sample = 12; + + AudioBuffer test_input(&test_sample, 1); + AudioBuffer test_output(1); - input_buffer->put(&test_input, sizeof(int)); - CPPUNIT_ASSERT(output_buffer->get(&test_output, sizeof(float), MainBuffer::DEFAULT_ID) == sizeof(float)); - CPPUNIT_ASSERT(test_input == test_output); + input_buffer->put(test_input); + CPPUNIT_ASSERT(output_buffer->get(test_output, MainBuffer::DEFAULT_ID) == 1); + CPPUNIT_ASSERT(test_sample == (*test_output.getChannel(0))[0]); } @@ -826,34 +833,38 @@ void MainBufferTest::testGetPutDataByID() mainbuffer_->bindCallID(test_id, MainBuffer::DEFAULT_ID); - int test_input1 = 12; - int test_input2 = 13; - int test_output = 0; + SFLAudioSample test_sample1 = 12; + SFLAudioSample test_sample2 = 13; + + AudioBuffer test_input1(&test_sample1, 1); + AudioBuffer test_input2(&test_sample2, 1); + AudioBuffer test_output(1); + AudioBuffer test_output_large(100); // put by MainBuffer::DEFAULT_ID get by test_id without preleminary put CPPUNIT_ASSERT(mainbuffer_->availableForGetByID(MainBuffer::DEFAULT_ID, test_id) == 0); - CPPUNIT_ASSERT(mainbuffer_->getDataByID(&test_output, sizeof(int), MainBuffer::DEFAULT_ID, test_id) == 0); + CPPUNIT_ASSERT(mainbuffer_->getDataByID(test_output, MainBuffer::DEFAULT_ID, test_id) == 0); // put by MainBuffer::DEFAULT_ID, get by test_id - mainbuffer_->putData(&test_input1, sizeof(int), MainBuffer::DEFAULT_ID); - CPPUNIT_ASSERT(mainbuffer_->availableForGetByID(MainBuffer::DEFAULT_ID, test_id) == sizeof(int)); + mainbuffer_->putData(test_input1, MainBuffer::DEFAULT_ID); + CPPUNIT_ASSERT(mainbuffer_->availableForGetByID(MainBuffer::DEFAULT_ID, test_id) == 1); // get by MainBuffer::DEFAULT_ID without preliminary input CPPUNIT_ASSERT(mainbuffer_->availableForGetByID(test_id, MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(mainbuffer_->getDataByID(&test_output, 100, test_id, MainBuffer::DEFAULT_ID) == 0); + CPPUNIT_ASSERT(mainbuffer_->getDataByID(test_output_large, test_id, MainBuffer::DEFAULT_ID) == 0); - // pu by test_id get by test_id - mainbuffer_->putData(&test_input2, sizeof(int), test_id); - CPPUNIT_ASSERT(mainbuffer_->availableForGetByID(test_id, MainBuffer::DEFAULT_ID) == sizeof(int)); - CPPUNIT_ASSERT(mainbuffer_->getDataByID(&test_output, 100, test_id, MainBuffer::DEFAULT_ID) == sizeof(int)); + // put by test_id get by test_id + mainbuffer_->putData(test_input2, test_id); + CPPUNIT_ASSERT(mainbuffer_->availableForGetByID(test_id, MainBuffer::DEFAULT_ID) == 1); + CPPUNIT_ASSERT(mainbuffer_->getDataByID(test_output_large, test_id, MainBuffer::DEFAULT_ID) == 1); CPPUNIT_ASSERT(mainbuffer_->availableForGetByID(test_id, MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(test_input2 == test_output); + CPPUNIT_ASSERT((*test_output_large.getChannel(0))[0] == test_sample2); // put/get by false id - mainbuffer_->putData(&test_input2, sizeof(int), false_id); - CPPUNIT_ASSERT(mainbuffer_->getDataByID(&test_input2, 100, false_id, false_id) == 0); - CPPUNIT_ASSERT(mainbuffer_->getDataByID(&test_input2, 100, MainBuffer::DEFAULT_ID, false_id) == 0); - CPPUNIT_ASSERT(mainbuffer_->getDataByID(&test_input2, 100, false_id, MainBuffer::DEFAULT_ID) == 0); + mainbuffer_->putData(test_input2, false_id); + CPPUNIT_ASSERT(mainbuffer_->getDataByID(test_output_large, false_id, false_id) == 0); + CPPUNIT_ASSERT(mainbuffer_->getDataByID(test_output_large, MainBuffer::DEFAULT_ID, false_id) == 0); + CPPUNIT_ASSERT(mainbuffer_->getDataByID(test_output_large, false_id, MainBuffer::DEFAULT_ID) == 0); mainbuffer_->unBindCallID(test_id, MainBuffer::DEFAULT_ID); } @@ -867,31 +878,34 @@ void MainBufferTest::testGetPutData() mainbuffer_->bindCallID(test_id, MainBuffer::DEFAULT_ID); - int test_input1 = 12; - int test_input2 = 13; - int test_output; + SFLAudioSample test_sample1 = 12; + SFLAudioSample test_sample2 = 13; + + AudioBuffer test_input1(&test_sample1, 1); + AudioBuffer test_input2(&test_sample2, 1); + AudioBuffer test_output(100); // get by test_id without preleminary put CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id) == 0); - CPPUNIT_ASSERT(mainbuffer_->getData(&test_output, 100, test_id) == 0); + CPPUNIT_ASSERT(mainbuffer_->getData(test_output, test_id) == 0); // put by MainBuffer::DEFAULT_ID, get by test_id - mainbuffer_->putData(&test_input1, sizeof(int), MainBuffer::DEFAULT_ID); - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id) == sizeof(int)); - CPPUNIT_ASSERT(mainbuffer_->getData(&test_output, 100, test_id) == sizeof(int)); + mainbuffer_->putData(test_input1, MainBuffer::DEFAULT_ID); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id) == 1); + CPPUNIT_ASSERT(mainbuffer_->getData(test_output, test_id) == 1); CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id) == 0); - CPPUNIT_ASSERT(test_input1 == test_output); + CPPUNIT_ASSERT(test_sample1 == (*test_output.getChannel(0))[0]); // get by MainBuffer::DEFAULT_ID without preleminary put CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(mainbuffer_->getData(&test_output, sizeof(int), MainBuffer::DEFAULT_ID) == 0); + CPPUNIT_ASSERT(mainbuffer_->getData(test_output, MainBuffer::DEFAULT_ID) == 0); // put by test_id, get by MainBuffer::DEFAULT_ID - mainbuffer_->putData(&test_input2, sizeof(int), test_id); - CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == sizeof(int)); - CPPUNIT_ASSERT(mainbuffer_->getData(&test_output, 100, MainBuffer::DEFAULT_ID) == sizeof(int)); + mainbuffer_->putData(test_input2, test_id); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == 1); + CPPUNIT_ASSERT(mainbuffer_->getData(test_output, MainBuffer::DEFAULT_ID) == 1); CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(test_input2 == test_output); + CPPUNIT_ASSERT(test_sample2 == (*test_output.getChannel(0))[0]); mainbuffer_->unBindCallID(test_id, MainBuffer::DEFAULT_ID); @@ -905,29 +919,28 @@ void MainBufferTest::testDiscardFlush() // mainbuffer_->createRingBuffer(test_id); mainbuffer_->bindCallID(test_id, MainBuffer::DEFAULT_ID); - int test_input1 = 12; - // int test_output_size; - // int init_size; + SFLAudioSample test_sample1 = 12; + AudioBuffer test_input1(&test_sample1, 1); - mainbuffer_->putData(&test_input1, sizeof(int), test_id); - CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == sizeof(int)); - mainbuffer_->discard(sizeof(int), MainBuffer::DEFAULT_ID); + mainbuffer_->putData(test_input1, test_id); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == 1); + mainbuffer_->discard(1, MainBuffer::DEFAULT_ID); CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == 0); CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id) == 0); - mainbuffer_->discard(sizeof(int), test_id); + mainbuffer_->discard(1, test_id); CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id) == 0); - CPPUNIT_ASSERT(mainbuffer_->getRingBuffer(test_id)->getReadPointer(MainBuffer::DEFAULT_ID) == sizeof(int)); + CPPUNIT_ASSERT(mainbuffer_->getRingBuffer(test_id)->getReadPointer(MainBuffer::DEFAULT_ID) == 1); CPPUNIT_ASSERT(mainbuffer_->getRingBuffer(test_id)->getReadPointer(test_id) == 0); CPPUNIT_ASSERT(mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID)->getReadPointer(test_id) == 0); - mainbuffer_->putData(&test_input1, 100, MainBuffer::DEFAULT_ID); + mainbuffer_->putData(test_input1, MainBuffer::DEFAULT_ID); CPPUNIT_ASSERT(mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID)->getReadPointer(test_id) == 0); - mainbuffer_->discard(sizeof(int), test_id); - CPPUNIT_ASSERT(mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID)->getReadPointer(test_id) == sizeof(int)); + mainbuffer_->discard(1, test_id); + CPPUNIT_ASSERT(mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID)->getReadPointer(test_id) == 1); mainbuffer_->unBindCallID(test_id, MainBuffer::DEFAULT_ID); } @@ -973,66 +986,70 @@ void MainBufferTest::testRingBufferSeveralPointers() test_ring_buffer->createReadPointer(test_pointer1); test_ring_buffer->createReadPointer(test_pointer2); - int testint1 = 12; - int testint2 = 13; - int testint3 = 14; - int testint4 = 15; - - int testoutput; - - test_ring_buffer->put(&testint1, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == sizeof(int)); - - test_ring_buffer->put(&testint2, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 2*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 2*sizeof(int)); - - test_ring_buffer->put(&testint3, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == 3*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == 3*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == 3*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 3*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 3*sizeof(int)); - - test_ring_buffer->put(&testint4, sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == 4*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == 4*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == 4*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 4*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 4*sizeof(int)); - - - CPPUNIT_ASSERT(test_ring_buffer->get(&testoutput, sizeof(int), test_pointer1) == sizeof(int)); - CPPUNIT_ASSERT(testoutput == testint1); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 3*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 4*sizeof(int)); - - CPPUNIT_ASSERT(test_ring_buffer->get(&testoutput, sizeof(int), test_pointer2) == sizeof(int)); - CPPUNIT_ASSERT(testoutput == testint1); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 3*sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 3*sizeof(int)); + SFLAudioSample testint1 = 12; + SFLAudioSample testint2 = 13; + SFLAudioSample testint3 = 14; + SFLAudioSample testint4 = 15; + AudioBuffer test_input1(&testint1, 1); + AudioBuffer test_input2(&testint2, 1); + AudioBuffer test_input3(&testint3, 1); + AudioBuffer test_input4(&testint4, 1); + + AudioBuffer test_output(1); + + test_ring_buffer->put(test_input1); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == 1); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 1); + + test_ring_buffer->put(test_input2); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 2); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == 2); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == 2); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 2); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 2); + + test_ring_buffer->put(test_input3); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 3); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == 3); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == 3); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 3); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 3); + + test_ring_buffer->put(test_input4); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 4); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer1) == 4); + CPPUNIT_ASSERT(test_ring_buffer->getLength(test_pointer2) == 4); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 4); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 4); + + + CPPUNIT_ASSERT(test_ring_buffer->get(test_output, test_pointer1) == 1); + CPPUNIT_ASSERT((*test_output.getChannel(0))[0] == testint1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 3); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 4); + + CPPUNIT_ASSERT(test_ring_buffer->get(test_output, test_pointer2) == 1); + CPPUNIT_ASSERT((*test_output.getChannel(0))[0] == testint1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer1) == 3); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_pointer2) == 3); // However, we should no be alowed to read in our own ring buffer - // if we are either an AudioLayer or and RTP session - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4*sizeof(int)); + // if we are either an AudioLayer or an RTP session + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4); // However, we should no be alowed to read in our own ring buffer - // if we are either an AudioLayer or and RTP session - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4*sizeof(int)); + // if we are either an AudioLayer or an RTP session + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4); // However, we should no be alowed to read in our own ring buffer - // if we are either an AudioLayer or and RTP session - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4*sizeof(int)); + // if we are either an AudioLayer or an RTP session + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 4); - CPPUNIT_ASSERT(test_ring_buffer->discard(sizeof(int), test_pointer1) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->discard(sizeof(int), test_pointer2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->discard(1, test_pointer1) == 1); + CPPUNIT_ASSERT(test_ring_buffer->discard(1, test_pointer2) == 1); test_ring_buffer->removeReadPointer(test_pointer1); test_ring_buffer->removeReadPointer(test_pointer2); @@ -1190,17 +1207,18 @@ void MainBufferTest::testConference() // test putData default - int testint = 12; + SFLAudioSample testint = 12; + AudioBuffer testbuf(&testint, 1); CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == 0); CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id1) == 0); CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == 0); // put data test ring buffers - mainbuffer_->putData(&testint, sizeof(int), MainBuffer::DEFAULT_ID); + mainbuffer_->putData(testbuf, MainBuffer::DEFAULT_ID); test_ring_buffer = mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == 1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id1); CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 0); @@ -1211,50 +1229,50 @@ void MainBufferTest::testConference() CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == 0); // test mainbuffer availforget (get data even if some participant missing) CPPUNIT_ASSERT(mainbuffer_->availableForGet(MainBuffer::DEFAULT_ID) == 0); - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id1) == sizeof(int)); - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id1) == 1); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == 1); //putdata test ring buffers - mainbuffer_->putData(&testint, 100, test_id1); + mainbuffer_->putData(testbuf, test_id1); test_ring_buffer = mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == 1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id2); CPPUNIT_ASSERT(test_ring_buffer->putLength() == 0); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(MainBuffer::DEFAULT_ID) == 0); CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == 0); - mainbuffer_->putData(&testint, 100, test_id2); + mainbuffer_->putData(testbuf, test_id2); test_ring_buffer = mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == 1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id2); // test mainbuffer availforget - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id1) == sizeof(int)); - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id1) == 1); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == 1); // test getData default id (audio layer) test_ring_buffer = mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id1) == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == 1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id2); // test mainbuffer availforget - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id1) == sizeof(int)); - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id1) == 1); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == 1); // test getData test_id1 (audio layer) test_ring_buffer = mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID); - CPPUNIT_ASSERT(test_ring_buffer->putLength() == sizeof(int)); - CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(test_ring_buffer->putLength() == 1); + CPPUNIT_ASSERT(test_ring_buffer->availableForGet(test_id2) == 1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id1); test_ring_buffer = mainbuffer_->getRingBuffer(test_id2); // test mainbuffer availforget - CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == sizeof(int)); + CPPUNIT_ASSERT(mainbuffer_->availableForGet(test_id2) == 1); // test getData test_id2 (audio layer) test_ring_buffer = mainbuffer_->getRingBuffer(MainBuffer::DEFAULT_ID); test_ring_buffer = mainbuffer_->getRingBuffer(test_id1); diff --git a/daemon/test/mainbuffertest.h b/daemon/test/mainbuffertest.h index 9b63fa7f08e6a206d936de6d92de8f713ee6ddb3..58b946ce6049d0d6e04a4bb2912ab531201eb80e 100644 --- a/daemon/test/mainbuffertest.h +++ b/daemon/test/mainbuffertest.h @@ -37,7 +37,7 @@ #include <cppunit/TestCase.h> #include <cppunit/TestSuite.h> -#include <tr1/memory> +#include <memory> class MainBuffer; /* @@ -56,7 +56,7 @@ class MainBufferTest : public CppUnit::TestCase { CPPUNIT_TEST(testCallIDSet); CPPUNIT_TEST(testRingBufferInt); CPPUNIT_TEST(testRingBufferNonDefaultID); - CPPUNIT_TEST(testRingBufferFloat); + //CPPUNIT_TEST(testRingBufferFloat); CPPUNIT_TEST(testTwoPointer); CPPUNIT_TEST(testBindUnbindBuffer); CPPUNIT_TEST(testGetPutDataByID); @@ -103,7 +103,7 @@ class MainBufferTest : public CppUnit::TestCase { private: - std::tr1::shared_ptr<MainBuffer> mainbuffer_; + std::unique_ptr<MainBuffer> mainbuffer_; }; /* Register our test module */ diff --git a/daemon/test/resamplertest.cpp b/daemon/test/resamplertest.cpp index 793335ee13350fd08f15492bcdaa2b799e525f88..2ba4fbb0ba80040395992dc2ef681440af12afb1 100644 --- a/daemon/test/resamplertest.cpp +++ b/daemon/test/resamplertest.cpp @@ -36,7 +36,7 @@ #include "resamplertest.h" ResamplerTest::ResamplerTest() : - CppUnit::TestCase("Resampler module test"), inputBuffer(), outputBuffer() + CppUnit::TestCase("Resampler module test"), inputBuffer(MAX_BUFFER_LENGTH), outputBuffer(MAX_BUFFER_LENGTH) {} void ResamplerTest::setUp() @@ -54,7 +54,7 @@ namespace { void print_buffer(T &buffer) { std::copy(buffer.begin(), buffer.end(), - std::ostream_iterator<SFLDataFormat>(std::cout, ", ")); + std::ostream_iterator<SFLAudioSample>(std::cout, ", ")); std::cout << std::endl; } } @@ -69,16 +69,16 @@ void ResamplerTest::testUpsamplingRamp() performUpsampling(converter); - LowSmplrBuffer tmpInputBuffer; - HighSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); + AudioBuffer tmpOutputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); - std::copy(inputBuffer.begin(), inputBuffer.begin() + tmpInputBuffer.size(), tmpInputBuffer.begin()); + tmpInputBuffer.copy(inputBuffer); std::cout << "Input Buffer" << std::endl; - print_buffer(tmpInputBuffer); + print_buffer(*tmpInputBuffer.getChannel(0)); - std::copy(outputBuffer.begin(), outputBuffer.begin() + tmpOutputBuffer.size(), tmpOutputBuffer.begin()); + tmpOutputBuffer.copy(outputBuffer); std::cout << "Output Buffer" << std::endl; - print_buffer(tmpOutputBuffer); + print_buffer(*tmpOutputBuffer.getChannel(0)); } void ResamplerTest::testDownsamplingRamp() @@ -90,16 +90,16 @@ void ResamplerTest::testDownsamplingRamp() performDownsampling(converter); - HighSmplrBuffer tmpInputBuffer; - LowSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); + AudioBuffer tmpOutputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); - std::copy(inputBuffer.begin(), inputBuffer.begin() + tmpInputBuffer.size(), tmpInputBuffer.begin()); + tmpInputBuffer.copy(inputBuffer); std::cout << "Input Buffer" << std::endl; - print_buffer(tmpInputBuffer); + print_buffer(*tmpInputBuffer.getChannel(0)); - std::copy(outputBuffer.begin(), outputBuffer.begin() + tmpOutputBuffer.size(), tmpOutputBuffer.begin()); + tmpOutputBuffer.copy(outputBuffer); std::cout << "Output Buffer" << std::endl; - print_buffer(tmpOutputBuffer); + print_buffer(*tmpOutputBuffer.getChannel(0)); } void ResamplerTest::testUpsamplingTriangle() @@ -111,16 +111,16 @@ void ResamplerTest::testUpsamplingTriangle() performUpsampling(converter); - LowSmplrBuffer tmpInputBuffer; - HighSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); + AudioBuffer tmpOutputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); - std::copy(inputBuffer.begin(), inputBuffer.begin() + tmpInputBuffer.size(), tmpInputBuffer.begin()); + tmpInputBuffer.copy(inputBuffer); std::cout << "Input Buffer" << std::endl; - print_buffer(tmpInputBuffer); + print_buffer(*tmpInputBuffer.getChannel(0)); - std::copy(outputBuffer.begin(), outputBuffer.begin() + tmpOutputBuffer.size(), tmpOutputBuffer.begin()); + tmpOutputBuffer.copy(outputBuffer); std::cout << "Output Buffer" << std::endl; - print_buffer(tmpOutputBuffer); + print_buffer(*tmpOutputBuffer.getChannel(0)); } void ResamplerTest::testDownsamplingTriangle() @@ -132,16 +132,16 @@ void ResamplerTest::testDownsamplingTriangle() performDownsampling(converter); - HighSmplrBuffer tmpInputBuffer; - LowSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); + AudioBuffer tmpOutputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); - std::copy(inputBuffer.begin(), inputBuffer.begin() + tmpInputBuffer.size(), tmpInputBuffer.begin()); + tmpInputBuffer.copy(inputBuffer); std::cout << "Input Buffer" << std::endl; - print_buffer(tmpInputBuffer); + print_buffer(*tmpInputBuffer.getChannel(0)); - std::copy(outputBuffer.begin(), outputBuffer.begin() + tmpOutputBuffer.size(), tmpOutputBuffer.begin()); + tmpOutputBuffer.copy(outputBuffer); std::cout << "Output Buffer" << std::endl; - print_buffer(tmpOutputBuffer); + print_buffer(*tmpOutputBuffer.getChannel(0)); } void ResamplerTest::testUpsamplingSine() { @@ -153,16 +153,16 @@ void ResamplerTest::testUpsamplingSine() performUpsampling(converter); - LowSmplrBuffer tmpInputBuffer; - HighSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); + AudioBuffer tmpOutputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); - std::copy(inputBuffer.begin(), inputBuffer.begin() + tmpInputBuffer.size(), tmpInputBuffer.begin()); + tmpInputBuffer.copy(inputBuffer); std::cout << "Input Buffer" << std::endl; - print_buffer(tmpInputBuffer); + print_buffer(*tmpInputBuffer.getChannel(0)); - std::copy(outputBuffer.begin(), outputBuffer.begin() + tmpOutputBuffer.size(), tmpOutputBuffer.begin()); + tmpOutputBuffer.copy(outputBuffer); std::cout << "Output Buffer" << std::endl; - print_buffer(tmpOutputBuffer); + print_buffer(*tmpOutputBuffer.getChannel(0)); } void ResamplerTest::testDownsamplingSine() @@ -175,56 +175,59 @@ void ResamplerTest::testDownsamplingSine() performDownsampling(converter); - HighSmplrBuffer tmpInputBuffer; - LowSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); + AudioBuffer tmpOutputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); - std::copy(inputBuffer.begin(), inputBuffer.begin() + tmpInputBuffer.size(), tmpInputBuffer.begin()); + tmpInputBuffer.copy(inputBuffer); std::cout << "Input Buffer" << std::endl; - print_buffer(tmpInputBuffer); + print_buffer(*tmpInputBuffer.getChannel(0)); - std::copy(outputBuffer.begin(), outputBuffer.begin() + tmpOutputBuffer.size(), tmpOutputBuffer.begin()); + tmpOutputBuffer.copy(outputBuffer); std::cout << "Output Buffer" << std::endl; - print_buffer(tmpOutputBuffer); + print_buffer(*tmpOutputBuffer.getChannel(0)); } void ResamplerTest::generateRamp() { - for (size_t i = 0; i < inputBuffer.size(); ++i) - inputBuffer[i] = i; + std::vector<SFLAudioSample>* buf = inputBuffer.getChannel(0); + for (size_t i = 0; i < buf->size(); ++i) + (*buf)[i] = i; } void ResamplerTest::generateTriangularSignal() { - for (size_t i = 0; i < inputBuffer.size(); ++i) - inputBuffer[i] = i * 10; + std::vector<SFLAudioSample>* buf = inputBuffer.getChannel(0); + for (size_t i = 0; i < buf->size(); ++i) + (*buf)[i] = i * 10; } void ResamplerTest::generateSineSignal() { - for (size_t i = 0; i < inputBuffer.size(); ++i) - inputBuffer[i] = (SFLDataFormat) (1000.0 * sin(i)); + std::vector<SFLAudioSample>* buf = inputBuffer.getChannel(0); + for (size_t i = 0; i < buf->size(); ++i) + (*buf)[i] = (SFLAudioSample) (1000.0 * sin(i)); } void ResamplerTest::performUpsampling(SamplerateConverter &converter) { - LowSmplrBuffer tmpInputBuffer; - HighSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); + AudioBuffer tmpOutputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); - for (size_t i = 0, j = 0; i < (inputBuffer.size() / 2); i += tmpInputBuffer.size(), j += tmpOutputBuffer.size()) { - std::copy(inputBuffer.begin() + i, inputBuffer.begin() + tmpInputBuffer.size() + i, tmpInputBuffer.begin()); - converter.resample(tmpInputBuffer.data(), tmpOutputBuffer.data(), tmpOutputBuffer.size(), 8000, 16000, tmpInputBuffer.size()); - std::copy(tmpOutputBuffer.begin(), tmpOutputBuffer.end(), outputBuffer.begin() + j); + for (size_t i = 0, j = 0; i < (inputBuffer.samples() / 2); i += tmpInputBuffer.samples(), j += tmpOutputBuffer.samples()) { + tmpInputBuffer.copy(inputBuffer, i); + converter.resample(tmpInputBuffer, tmpOutputBuffer); + outputBuffer.copy(tmpOutputBuffer, -1, 0, j); } } void ResamplerTest::performDownsampling(SamplerateConverter &converter) { - HighSmplrBuffer tmpInputBuffer; - LowSmplrBuffer tmpOutputBuffer; + AudioBuffer tmpInputBuffer(TMP_HIGHSMPLR_BUFFER_LENGTH, 1, 16000); + AudioBuffer tmpOutputBuffer(TMP_LOWSMPLR_BUFFER_LENGTH, 1, 8000); - for (size_t i = 0, j = 0; i < inputBuffer.size(); i += tmpInputBuffer.size(), j += tmpOutputBuffer.size()) { - std::copy(inputBuffer.begin() + i, inputBuffer.begin() + tmpInputBuffer.size() + i, tmpInputBuffer.begin()); - converter.resample(tmpInputBuffer.data(), tmpOutputBuffer.data(), tmpOutputBuffer.size(), 16000, 8000, tmpInputBuffer.size()); - std::copy(tmpOutputBuffer.begin(), tmpOutputBuffer.end(), outputBuffer.begin() + j); + for (size_t i = 0, j = 0; i < inputBuffer.samples(); i += tmpInputBuffer.samples(), j += tmpOutputBuffer.samples()) { + tmpInputBuffer.copy(inputBuffer, i); + converter.resample(tmpInputBuffer, tmpOutputBuffer); + outputBuffer.copy(tmpOutputBuffer, -1, 0, j); } } diff --git a/daemon/test/resamplertest.h b/daemon/test/resamplertest.h index ecd8b205bf3e8a81d57ab6927893da5ede303d99..a5fffc53b71dbebed83efe692aea48b843c6f690 100644 --- a/daemon/test/resamplertest.h +++ b/daemon/test/resamplertest.h @@ -45,8 +45,8 @@ #define TMP_LOWSMPLR_BUFFER_LENGTH 160 #define TMP_HIGHSMPLR_BUFFER_LENGTH 320 -typedef std::tr1::array<SFLDataFormat, TMP_LOWSMPLR_BUFFER_LENGTH> LowSmplrBuffer; -typedef std::tr1::array<SFLDataFormat, TMP_HIGHSMPLR_BUFFER_LENGTH> HighSmplrBuffer; +//typedef std::tr1::array<SFLDataFormat, TMP_LOWSMPLR_BUFFER_LENGTH> LowSmplrBuffer; +//typedef std::tr1::array<SFLDataFormat, TMP_HIGHSMPLR_BUFFER_LENGTH> HighSmplrBuffer; class ResamplerTest : public CppUnit::TestCase { @@ -138,12 +138,14 @@ private: /** * Used to store input samples */ - std::tr1::array<SFLDataFormat, MAX_BUFFER_LENGTH> inputBuffer; + //std::tr1::array<SFLDataFormat, MAX_BUFFER_LENGTH> inputBuffer; + AudioBuffer inputBuffer; /** * Used to receive output samples */ - std::tr1::array<SFLDataFormat, MAX_BUFFER_LENGTH> outputBuffer; + //std::tr1::array<SFLDataFormat, MAX_BUFFER_LENGTH> outputBuffer; + AudioBuffer outputBuffer; }; /* Register the test module */ diff --git a/daemon/test/sflphoned-sample.yml b/daemon/test/sflphoned-sample.yml index 7a268593312bd4d0af3994fbd93f1f27ecb917f8..faf60f63639091dc688426bdcc4f3d6d29ce4d7d 100644 --- a/daemon/test/sflphoned-sample.yml +++ b/daemon/test/sflphoned-sample.yml @@ -2,17 +2,19 @@ accounts: - alias: SFL test audioCodecs: 0/3/8/9/110/111/112/ + autoAnswer: false credential: - Account.password: 1234 - Account.realm: + Account.realm: Account.username: sfltest - displayName: + displayName: dtmfType: overrtp enable: false hostname: localhost id: Account:1334389473 interface: default - mailbox: + keepAlive: false + mailbox: port: 5060 publishAddr: 0.0.0.0 publishPort: 5060 @@ -20,55 +22,75 @@ accounts: ringtoneEnabled: true ringtonePath: /usr/share/sflphone/ringtones/konga.ul sameasLocal: true - serviceRoute: + serviceRoute: srtp: enable: false - keyExchange: + keyExchange: rtpFallback: false stunEnabled: false stunServer: stun.sflphone.org tls: - calist: - certificate: - ciphers: + calist: + certificate: + ciphers: enable: false method: TLSv1 - password: - privateKey: + password: + privateKey: requireCertif: true - server: + server: timeout: 2 tlsPort: 5061 verifyClient: true verifyServer: true type: SIP + useragent: SFLphone-test username: sfltest videoCodecs: + - bitrate: 400 + enabled: true + name: H263-2000 + parameters: + - bitrate: 400 + enabled: true + name: H264 + parameters: profile-level-id=428014 + - bitrate: 400 + enabled: true + name: MP4V-ES + parameters: + - bitrate: 400 + enabled: true + name: VP8 + parameters: zrtp: displaySas: true displaySasOnce: false helloHashEnabled: true notSuppWarning: true - alias: IP2IP - codecs: 0/ + audioCodecs: 0/3/8/9/110/111/112/ + autoAnswer: false credential: - - password: - realm: '*' - username: - displayName: + - Account.password: + Account.realm: + Account.username: + displayName: dtmfType: true enable: true - hostname: + hostname: id: IP2IP interface: default - mailbox: + keepAlive: false + mailbox: port: 5060 - publishAddr: + publishAddr: publishPort: 5060 + registrationexpire: 60 ringtoneEnabled: true ringtonePath: /usr/share/sflphone/ringtones/konga.ul sameasLocal: true - serviceRoute: + serviceRoute: srtp: enable: false keyExchange: sdes @@ -76,28 +98,39 @@ accounts: stunEnabled: false stunServer: stun.sflphone.org tls: - calist: - certificate: - ciphers: + calist: + certificate: + ciphers: enable: false method: TLSv1 - password: - privateKey: + password: + privateKey: requireCertif: true - server: + server: timeout: 2 tlsPort: 5061 verifyClient: true verifyServer: true type: SIP - username: + useragent: SFLphone-test + username: videoCodecs: - bitrate: 400 enabled: true name: H263-2000 + parameters: - bitrate: 400 enabled: true name: H264 + parameters: profile-level-id=428014 + - bitrate: 400 + enabled: true + name: MP4V-ES + parameters: + - bitrate: 400 + enabled: true + name: VP8 + parameters: zrtp: displaySas: true displaySasOnce: false @@ -107,9 +140,9 @@ preferences: historyLimit: 30 historyMaxCalls: 20 md5Hash: false - notifyMails: false - order: Account:1328115463/Account:1328115393/Account:1328115062/Account:1316122317/Account:1316122284/Account:1316121900/Account:1316121889/Account:1316121691/Account:1316121662/Account:1316121661/Account:1316121654/Account:1316121611/Account:1316121607/Account:1316121605/Account:1316121602/Account:1312584532/Account:1312398082/Account:1312398066/Account:1309188361/Account:1309187807/Account:1309187723/Account:1309187670/Account:1309187609/Account:1309187081/Account:1308839853/Account:1308839662/Account:1308839447/Account:1308839359/Account:1308839335/Account:1308838875/Account:1308838713/Account:1308838236/Account:1307975440/Account:1307975347/Account:1307974800/Account:1307974672/Account:1307974527/Account:1303487773/Account:1303247743/Account:1302895321/Account:1302892836/Account:1302891834/Account:1302882519/Account:1302207377/Account:1302207262/Account:1302204136/Account:1302204108/Account:1294850905/Account:1294850775/Account:1294850618/Account:1294849651/Account:1294849602/Account:1294849310/Account:1288964768/Account:1288964603/Account:1288964434/Account:1288964141/Account:1288964134/ + order: Account:1375906657/Account:1328115463/Account:1328115393/Account:1328115062/Account:1316122317/Account:1316122284/Account:1316121900/Account:1316121889/Account:1316121691/Account:1316121662/Account:1316121661/Account:1316121654/Account:1316121611/Account:1316121607/Account:1316121605/Account:1316121602/Account:1312584532/Account:1312398082/Account:1312398066/Account:1309188361/Account:1309187807/Account:1309187723/Account:1309187670/Account:1309187609/Account:1309187081/Account:1308839853/Account:1308839662/Account:1308839447/Account:1308839359/Account:1308839335/Account:1308838875/Account:1308838713/Account:1308838236/Account:1307975440/Account:1307975347/Account:1307974800/Account:1307974672/Account:1307974527/Account:1303487773/Account:1303247743/Account:1302895321/Account:1302892836/Account:1302891834/Account:1302882519/Account:1302207377/Account:1302207262/Account:1302204136/Account:1302204108/Account:1294850905/Account:1294850775/Account:1294850618/Account:1294849651/Account:1294849602/Account:1294849310/Account:1288964768/Account:1288964603/Account:1288964434/Account:1288964141/Account:1288964134/ portNum: 5060 + registrationexpire: 180 searchBarDisplay: true zeroConfenable: false zoneToneChoice: North America @@ -121,7 +154,7 @@ voipPreferences: zidFile: true hooks: iax2Enabled: false - numberAddPrefix: + numberAddPrefix: numberEnabled: false sipEnabled: false urlCommand: x-www-browser @@ -136,25 +169,23 @@ audio: alwaysRecording: false audioApi: pulseaudio echoCancel: false - echoDelayLength: 0 - echoTailLength: 100 noiseReduce: true pulse: devicePlayback: alsa_output.pci-0000_00_1b.0.analog-stereo deviceRecord: alsa_input.pci-0000_00_1b.0.analog-stereo deviceRingtone: alsa_output.pci-0000_00_1b.0.analog-stereo - recordPath: + recordPath: /home/tristan volumeMic: 100 volumeSpkr: 100 video: - v4l2Channel: - v4l2Dev: - v4l2Rate: - v4l2Size: + v4l2Channel: + v4l2Dev: + v4l2Rate: + v4l2Size: shortcuts: - hangUp: - pickUp: - popupWindow: - toggleHold: - togglePickupHangup: + hangUp: + pickUp: + popupWindow: + toggleHold: + togglePickupHangup: ... diff --git a/daemon/test/sflphonedrc-sample b/daemon/test/sflphonedrc-sample deleted file mode 100644 index 6d0064a7c50fc350fb1d55aa1faef4002c321427..0000000000000000000000000000000000000000 --- a/daemon/test/sflphonedrc-sample +++ /dev/null @@ -1,74 +0,0 @@ -[Account:1239059899] -Account.alias=1260@sip.sflphone.org -Account.enable=1 -Account.type=SIP -hostname=sflphone.org -password=NIPAgmLo -username=1260 - -[Account:1243544046] -Account.alias=Manu -Account.enable=1 -Account.mailbox=*97 -Account.type=SIP -hostname=192.168.50.3 -password=sfl-137pw -username=137 - -[Addressbook] -Addressbook.contact_photo=0 -Addressbook.enable=1 -Addressbook.list=1243608768.30329.0@emilou-desktop/1243456917.15690.23@emilou-desktop/ -Addressbook.max_results=25 -Addressbook.phone_business=1 -Addressbook.phone_home=0 -Addressbook.phone_mobile=0 - -[Audio] -Alsa.cardID_In=0 -Alsa.cardID_Out=0 -Alsa.framesize=20 -Alsa.plugin=default -Alsa.sampleRate=44100 -Record.path=/home/emilou -Rings.ringChoice=/usr/share/sflphone/ringtones/konga.ul -Volume.micro=100 -Volume.speakers=100 - -[Hooks] -Hooks.iax2_enabled=0 -Hooks.phone_number_add_prefix= -Hooks.phone_number_enabled=0 -Hooks.sip_enabled=0 -Hooks.url_command=x-www-browser -Hooks.url_sip_field=X-sflphone-url - -[Preferences] -Accounts.order=Account:1243544046/Account:1239138829/ -Audio.api=1 -Dialpad.display=0 -History.enabled=1 -History.limit=30 -History.maxCalls=20 -Notify.all=1 -Notify.mails=0 -Options.zoneToneChoice=North America -Pulseaudio.volumeCtrl=1 -Registration.expire=180 -Ringtones.enable=1 -SIP.portNum=5060 -Searchbar.display=1 -Start.hidden=0 -Volume.display=0 -Window.popup=0 -Zeroconf.enable=0 - -[VoIPLink] -DTMF.playDtmf=1 -DTMF.playTones=1 -DTMF.pulseLength=250 -DTMF.sendDTMFas=0 -STUN.enable=0 -STUN.server=stun.sflphone.org -VoIPLink.symmetric=1 - diff --git a/daemon/test/siptest.cpp b/daemon/test/siptest.cpp index b00ab8bae06fcccd83ae912fd5f29dbc956e8055..8c27304c4e8f4e3da17857ae1846fe2bb2314d69 100644 --- a/daemon/test/siptest.cpp +++ b/daemon/test/siptest.cpp @@ -28,8 +28,9 @@ * as that of the covered work. */ -#include <stdlib.h> -#include <stdio.h> +#include <unistd.h> +#include <cstdlib> +#include <cstdio> #include <iostream> #include <fstream> diff --git a/gnome/.cproject b/gnome/.cproject deleted file mode 100644 index 108d69e9da01af604c24174c2e40c1c0f4c0cc48..0000000000000000000000000000000000000000 --- a/gnome/.cproject +++ /dev/null @@ -1,628 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> -<?fileVersion 4.0.0?> - -<cproject> - <storageModule moduleId="org.eclipse.cdt.core.settings"> - <cconfiguration id="cdt.managedbuild.toolchain.gnu.base.666814495"> - <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.base.666814495" moduleId="org.eclipse.cdt.core.settings" name="Release"> - <externalSettings/> - <extensions> - <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> - <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> - </extensions> - </storageModule> - <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactName="sflphone-gtk" buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.base.666814495" name="Release" parent="org.eclipse.cdt.build.core.emptycfg"> - <folderInfo id="cdt.managedbuild.toolchain.gnu.base.666814495.1839755914" name="/" resourcePath=""> - <toolChain id="cdt.managedbuild.toolchain.gnu.base.1195789621" name="cdt.managedbuild.toolchain.gnu.base" superClass="cdt.managedbuild.toolchain.gnu.base"> - <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.1493285969" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/> - <builder id="cdt.managedbuild.target.gnu.builder.base.421214348" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="-1" superClass="cdt.managedbuild.target.gnu.builder.base"/> - <tool id="cdt.managedbuild.tool.gnu.archiver.base.1558364998" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> - <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.731757910" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base"/> - <tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1299938473" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base"> - <option id="gnu.c.compiler.option.include.paths.1303328171" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath"> - <listOptionValue builtIn="false" value="/usr/include/gtk-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/glib-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/dbus-1.0"/> - <listOptionValue builtIn="false" value="/usr/include/libgnome-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/libgnomeui-2.0"/> - <listOptionValue builtIn="false" value="/usr/include"/> - </option> - <option id="gnu.c.compiler.option.preprocessor.def.symbols.1676995808" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols"> - <listOptionValue builtIn="false" value=""ICONS_DIR="/usr/share/sflphone\""/> - <listOptionValue builtIn="false" value=""CODECS_DIR="/usr/lib/sflphone/codecs\""/> - <listOptionValue builtIn="false" value=""DATA_DIR="/usr/share/sflphone\""/> - </option> - <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1938301835" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> - </tool> - <tool id="cdt.managedbuild.tool.gnu.c.linker.base.981882139" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"> - <option id="gnu.c.link.option.paths.137448498" name="Library search path (-L)" superClass="gnu.c.link.option.paths" valueType="libPaths"> - <listOptionValue builtIn="false" value="/usr/include/gtk-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/glib-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/dbus-1.0"/> - <listOptionValue builtIn="false" value="/usr/include/libgnome-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/libgnomeui-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/libgnome-2.0/libgnome"/> - </option> - <inputType id="cdt.managedbuild.tool.gnu.c.linker.input.1274984809" superClass="cdt.managedbuild.tool.gnu.c.linker.input"> - <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> - <additionalInput kind="additionalinput" paths="$(LIBS)"/> - </inputType> - </tool> - <tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.963771621" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base"/> - <tool id="cdt.managedbuild.tool.gnu.assembler.base.1924201184" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base"> - <option id="gnu.both.asm.option.include.paths.1513412733" name="Include paths (-I)" superClass="gnu.both.asm.option.include.paths"/> - <inputType id="cdt.managedbuild.tool.gnu.assembler.input.938125330" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> - </tool> - </toolChain> - </folderInfo> - </configuration> - </storageModule> - <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> - <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/> - <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> - <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> - <storageModule moduleId="scannerConfiguration"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1995189473;cdt.managedbuild.config.gnu.exe.debug.1995189473.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.44474984;cdt.managedbuild.tool.gnu.c.compiler.input.1565605211"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.base.666814495;cdt.managedbuild.toolchain.gnu.base.666814495.1839755914;cdt.managedbuild.tool.gnu.c.compiler.base.1299938473;cdt.managedbuild.tool.gnu.c.compiler.input.1938301835"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - </storageModule> - </cconfiguration> - <cconfiguration id="cdt.managedbuild.config.gnu.exe.debug.1995189473"> - <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.exe.debug.1995189473" moduleId="org.eclipse.cdt.core.settings" name="Debug"> - <externalSettings/> - <extensions> - <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/> - <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> - <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> - </extensions> - </storageModule> - <storageModule moduleId="org.eclipse.cdt.core.language.mapping"/> - <storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/> - <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> - <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <configuration artifactName="gnome" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.debug.1995189473" name="Debug" parent="cdt.managedbuild.config.gnu.exe.debug"> - <folderInfo id="cdt.managedbuild.config.gnu.exe.debug.1995189473." name="/" resourcePath=""> - <toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.1423428378" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug"> - <targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.debug.285066138" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.debug"/> - <builder id="cdt.managedbuild.target.gnu.builder.exe.debug.100968868" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" parallelBuildOn="true" parallelizationNumber="-1" superClass="cdt.managedbuild.target.gnu.builder.exe.debug"/> - <tool id="cdt.managedbuild.tool.gnu.archiver.base.417731669" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/> - <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.187669799" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug"> - <option id="gnu.cpp.compiler.exe.debug.option.optimization.level.1648950260" name="Optimization Level" superClass="gnu.cpp.compiler.exe.debug.option.optimization.level" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/> - <option id="gnu.cpp.compiler.exe.debug.option.debugging.level.1642920658" name="Debug Level" superClass="gnu.cpp.compiler.exe.debug.option.debugging.level" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/> - </tool> - <tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.44474984" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug"> - <option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.exe.debug.option.optimization.level.228151721" name="Optimization Level" superClass="gnu.c.compiler.exe.debug.option.optimization.level" valueType="enumerated"/> - <option id="gnu.c.compiler.exe.debug.option.debugging.level.676359726" name="Debug Level" superClass="gnu.c.compiler.exe.debug.option.debugging.level" value="gnu.c.debugging.level.max" valueType="enumerated"/> - <option id="gnu.c.compiler.option.include.paths.1167204962" name="Include paths (-I)" superClass="gnu.c.compiler.option.include.paths" valueType="includePath"> - <listOptionValue builtIn="false" value="/usr/include"/> - <listOptionValue builtIn="false" value="/usr/include/glib-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/gtk-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/dbus-1.0"/> - <listOptionValue builtIn="false" value="/usr/include/libgnome-2.0"/> - <listOptionValue builtIn="false" value="/usr/include/libgnomeui-2.0"/> - </option> - <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1565605211" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> - </tool> - <tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1289604635" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug"> - <option id="gnu.c.link.option.paths.1262921055" name="Library search path (-L)" superClass="gnu.c.link.option.paths"/> - <inputType id="cdt.managedbuild.tool.gnu.c.linker.input.861769146" superClass="cdt.managedbuild.tool.gnu.c.linker.input"> - <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> - <additionalInput kind="additionalinput" paths="$(LIBS)"/> - </inputType> - </tool> - <tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.172868928" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug"/> - <tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.210816158" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug"> - <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1667826927" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> - </tool> - </toolChain> - </folderInfo> - </configuration> - </storageModule> - <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> - <storageModule moduleId="scannerConfiguration"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.1995189473;cdt.managedbuild.config.gnu.exe.debug.1995189473.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.44474984;cdt.managedbuild.tool.gnu.c.compiler.input.1565605211"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - <scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.base.666814495;cdt.managedbuild.toolchain.gnu.base.666814495.1839755914;cdt.managedbuild.tool.gnu.c.compiler.base.1299938473;cdt.managedbuild.tool.gnu.c.compiler.input.1938301835"> - <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="makefileGenerator"> - <runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - <profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC"> - <buildOutputProvider> - <openAction enabled="true" filePath=""/> - <parser enabled="true"/> - </buildOutputProvider> - <scannerInfoProvider id="specsFile"> - <runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/> - <parser enabled="true"/> - </scannerInfoProvider> - </profile> - </scannerConfigBuildInfo> - </storageModule> - </cconfiguration> - </storageModule> - <storageModule moduleId="cdtBuildSystem" version="4.0.0"> - <project id="sflphone-gtk.null.1710073778" name="sflphone-gtk"/> - </storageModule> -</cproject> diff --git a/gnome/.project b/gnome/.project deleted file mode 100644 index 0ca91571783f5c16eb2a2490ddacbc4cc482ac1e..0000000000000000000000000000000000000000 --- a/gnome/.project +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>gnome</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - <buildCommand> - <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> - <triggers>clean,full,incremental,</triggers> - <arguments> - <dictionary> - <key>?name?</key> - <value></value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.append_environment</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.autoBuildTarget</key> - <value>all</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.buildArguments</key> - <value>-j</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.buildCommand</key> - <value>make</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.cleanBuildTarget</key> - <value>clean</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.contents</key> - <value>org.eclipse.cdt.make.core.activeConfigSettings</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.enableAutoBuild</key> - <value>false</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.enableCleanBuild</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.enableFullBuild</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.fullBuildTarget</key> - <value>all</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.stopOnError</key> - <value>true</value> - </dictionary> - <dictionary> - <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key> - <value>true</value> - </dictionary> - </arguments> - </buildCommand> - <buildCommand> - <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> - <arguments> - </arguments> - </buildCommand> - </buildSpec> - <natures> - <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> - <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> - <nature>org.eclipse.cdt.core.cnature</nature> - </natures> -</projectDescription> diff --git a/gnome/src/actions.c b/gnome/src/actions.c index 35cd55a39c4f3fa2c262bd8917296a485226f880..a2df2ba573cccfb9917f7b7221e2518ceb632157 100644 --- a/gnome/src/actions.c +++ b/gnome/src/actions.c @@ -130,12 +130,17 @@ status_bar_display_account() account_t *acc = account_list_get_current(); status_tray_icon_online(acc != NULL); + static const char * const account_types[] = { + N_("(SIP)"), + N_("(IAX)") + }; + gchar* msg; if (acc) { - msg = g_markup_printf_escaped("%s %s (%s)" , - _("Using account"), + const guint type_idx = account_is_IAX(acc); + msg = g_markup_printf_escaped(_("Using account %s %s"), (gchar*) account_lookup(acc, CONFIG_ACCOUNT_ALIAS), - (gchar*) account_lookup(acc, CONFIG_ACCOUNT_TYPE)); + _(account_types[type_idx])); } else { msg = g_markup_printf_escaped(_("No registered accounts")); } diff --git a/gnome/src/codeclist.c b/gnome/src/codeclist.c index 9baf922c37c35d61db85684aa66f4fddd00252f7..ac4319a4c8d84fb91f3c196c2501983982182ff4 100644 --- a/gnome/src/codeclist.c +++ b/gnome/src/codeclist.c @@ -58,6 +58,7 @@ static codec_t *codec_create(gint payload, gchar **specs) codec->bitrate = g_strdup(specs[2]); codec->sample_rate = atoi(specs[1]); } + codec->channels = specs[3]?atoi(specs[3]):1; codec->is_active = TRUE; g_strfreev(specs); @@ -131,6 +132,7 @@ codec_t *codec_create_new_from_caps(codec_t *original) codec->name = g_strdup(original->name); codec->sample_rate = original->sample_rate; codec->bitrate = g_strdup(original->bitrate); + codec->channels = original->channels; } return codec; diff --git a/gnome/src/codeclist.h b/gnome/src/codeclist.h index 8a11335d05f5653c846a5e3ed75c595524f69b0d..c73addbd2f419f54a0584f55b7dddcc6b8a61950 100644 --- a/gnome/src/codeclist.h +++ b/gnome/src/codeclist.h @@ -47,6 +47,8 @@ typedef struct { gint sample_rate; /** Bitrate */ gchar * bitrate; + /** Channel number */ + gint channels; } codec_t; /** @struct codec_t diff --git a/gnome/src/config/accountconfigdialog.c b/gnome/src/config/accountconfigdialog.c index aa171bcb3a57fdb178f28bdd4ec6a1c7f9aa5c6d..c38e7a34bfe642150b48b0d6697f0a4f7668b838 100644 --- a/gnome/src/config/accountconfigdialog.c +++ b/gnome/src/config/accountconfigdialog.c @@ -56,6 +56,7 @@ #include "tlsadvanceddialog.h" #include "dbus/dbus.h" #include "utils.h" +#include "seekslider.h" /** * TODO: tidy this up @@ -95,6 +96,7 @@ static GtkWidget *file_chooser; static GtkWidget *security_tab; static GtkWidget *advanced_tab; static GtkWidget *overrtp; +static GtkWidget *ringtone_seekslider; typedef struct OptionsData { account_t *account; @@ -171,7 +173,6 @@ select_dtmf_type(void) static GPtrArray* get_new_credential(void) { - gint row_count = 0; GPtrArray *credential_array = g_ptr_array_new(); GtkTreeIter iter; @@ -188,8 +189,6 @@ static GPtrArray* get_new_credential(void) COLUMN_CREDENTIAL_PASSWORD, &password, -1); - g_debug("Row %d: %s %s %s", row_count++, username, password, realm); - GHashTable * new_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); g_hash_table_insert(new_table, g_strdup(CONFIG_ACCOUNT_REALM), realm); @@ -1063,6 +1062,18 @@ static void ringtone_enabled_cb(G_GNUC_UNUSED GtkWidget *widget, gpointer data, gtk_widget_set_sensitive(data, !gtk_widget_is_sensitive(data)); } +void update_ringtone_slider(guint position, guint size) +{ + if (ringtone_seekslider) + sfl_seekslider_update_scale(SFL_SEEKSLIDER(ringtone_seekslider), position, size); +} + +static void ringtone_changed_cb(GtkWidget *widget, gpointer data) +{ + GtkFileChooser *chooser = GTK_FILE_CHOOSER(widget); + SFLSeekSlider *seekslider = data; + g_object_set(seekslider, "file-path", gtk_file_chooser_get_filename(chooser), NULL); +} static GtkWidget* create_audiocodecs_configuration(const account_t *account) @@ -1112,24 +1123,36 @@ create_audiocodecs_configuration(const account_t *account) enable_tone = gtk_check_button_new_with_mnemonic(_("_Enable ringtones")); const gboolean ringtone_enabled = g_strcmp0(ptr, "true") == 0; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_tone), ringtone_enabled); - g_signal_connect(G_OBJECT(enable_tone) , "clicked", G_CALLBACK(ringtone_enabled_cb), file_chooser); + g_signal_connect(G_OBJECT(enable_tone), "clicked", G_CALLBACK(ringtone_enabled_cb), file_chooser); gtk_grid_attach(GTK_GRID(grid), enable_tone, 0, 0, 1, 1); // file chooser button - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser) , g_get_home_dir()); + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser), g_get_home_dir()); ptr = account_lookup(account, CONFIG_RINGTONE_PATH); - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser) , ptr); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser), ptr); gtk_widget_set_sensitive(file_chooser, ringtone_enabled); + // button to preview ringtones + ringtone_seekslider = GTK_WIDGET(sfl_seekslider_new()); + g_object_set(G_OBJECT(ringtone_seekslider), "file-path", ptr, NULL); + g_signal_connect(G_OBJECT(file_chooser), "selection-changed", G_CALLBACK(ringtone_changed_cb), ringtone_seekslider); + GtkFileFilter *filter = gtk_file_filter_new(); gtk_file_filter_set_name(filter, _("Audio Files")); gtk_file_filter_add_pattern(filter, "*.wav"); gtk_file_filter_add_pattern(filter, "*.ul"); gtk_file_filter_add_pattern(filter, "*.au"); + gtk_file_filter_add_pattern(filter, "*.flac"); + gtk_file_filter_add_pattern(filter, "*.ogg"); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_chooser), filter); gtk_grid_attach(GTK_GRID(grid), file_chooser, 0, 1, 1, 1); + GtkWidget *alignment = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 6, 6); + gtk_container_add(GTK_CONTAINER(alignment), ringtone_seekslider); + gtk_box_pack_start(GTK_BOX(vbox), alignment, FALSE, FALSE, 0); + gtk_widget_show_all(vbox); return vbox; @@ -1150,7 +1173,7 @@ create_videocodecs_configuration(const account_t *a) gtk_box_pack_start(GTK_BOX (vbox), videocodecs, FALSE, FALSE, 0); gtk_widget_set_size_request(GTK_WIDGET (videocodecs), -1, 200); gtk_widget_show(videocodecs); - gtk_container_add(GTK_CONTAINER (videocodecs) , box); + gtk_container_add(GTK_CONTAINER (videocodecs), box); gtk_widget_show_all(vbox); @@ -1208,9 +1231,6 @@ static void update_account_from_basic_tab(account_t *account) account_replace(account, CONFIG_ACCOUNT_ROUTESET, gtk_entry_get_text(GTK_ENTRY(entry_route_set))); - account_replace(account, CONFIG_ACCOUNT_USERAGENT, - gtk_entry_get_text(GTK_ENTRY(entry_user_agent))); - gboolean v = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(use_stun_check_box)); account_replace(account, CONFIG_STUN_ENABLE, bool_to_string(v)); @@ -1279,6 +1299,8 @@ static void update_account_from_basic_tab(account_t *account) gtk_entry_get_text(GTK_ENTRY(local_port_spin_box))); } + account_replace(account, CONFIG_ACCOUNT_USERAGENT, + gtk_entry_get_text(GTK_ENTRY(entry_user_agent))); account_replace(account, CONFIG_ACCOUNT_ALIAS, gtk_entry_get_text(GTK_ENTRY(entry_alias))); account_replace(account, CONFIG_ACCOUNT_TYPE, proto); account_replace(account, CONFIG_ACCOUNT_HOSTNAME, gtk_entry_get_text(GTK_ENTRY(entry_hostname))); diff --git a/gnome/src/config/accountconfigdialog.h b/gnome/src/config/accountconfigdialog.h index 79dbced498896369be13e007b5b432e09cac48c8..ff7ec1cacfedf0854c98cd1fe9c4d977b5a7b462 100644 --- a/gnome/src/config/accountconfigdialog.h +++ b/gnome/src/config/accountconfigdialog.h @@ -53,4 +53,10 @@ show_account_window(account_t *a, SFLPhoneClient *client, gboolean is_new); */ void update_account_from_dialog(GtkWidget *dialog, account_t *a); +/* + * @param position The position of the slider + * @param size The size of the slider + */ +void update_ringtone_slider(guint position, guint size); + #endif diff --git a/gnome/src/config/audioconf.c b/gnome/src/config/audioconf.c index 98f49d4187d36fb34f08a89f6dbe7a6ecfea9ffb..0793bb32d27fe4aca02345ab9ab2d4c2e8cf524b 100644 --- a/gnome/src/config/audioconf.c +++ b/gnome/src/config/audioconf.c @@ -57,6 +57,7 @@ enum { COLUMN_CODEC_NAME, COLUMN_CODEC_FREQUENCY, COLUMN_CODEC_BITRATE, + COLUMN_CODEC_CHANNELS, CODEC_COLUMN_COUNT }; @@ -91,12 +92,14 @@ fill_codec_list(const account_t *account) gtk_list_store_append(codecStore, &iter); gchar *samplerate = g_strdup_printf("%d " KHZ, (gint) (c->sample_rate * 0.001)); gchar *bitrate = g_strdup_printf("%s " KBPS, c->bitrate); + gchar *channels = g_strdup_printf("%d", c->channels); gtk_list_store_set(codecStore, &iter, COLUMN_CODEC_ACTIVE, c->is_active, COLUMN_CODEC_NAME, c->name, COLUMN_CODEC_FREQUENCY, samplerate, COLUMN_CODEC_BITRATE, bitrate, + COLUMN_CODEC_CHANNELS, channels, -1); g_free(samplerate); g_free(bitrate); @@ -511,6 +514,7 @@ audiocodecs_box(const account_t *account) G_TYPE_STRING, /* Name */ G_TYPE_STRING, /* Frequency */ G_TYPE_STRING, /* Bitrate */ + G_TYPE_STRING, /* Channels */ G_TYPE_STRING /* Bandwidth */); // Create codec tree view with list store @@ -548,6 +552,11 @@ audiocodecs_box(const account_t *account) treeViewColumn = gtk_tree_view_column_new_with_attributes(_("Bitrate"), renderer, "text", COLUMN_CODEC_BITRATE, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(codecTreeView), treeViewColumn); + // Channels column + renderer = gtk_cell_renderer_text_new(); + treeViewColumn = gtk_tree_view_column_new_with_attributes(_("Channels"), renderer, "text", COLUMN_CODEC_CHANNELS, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(codecTreeView), treeViewColumn); + gtk_container_add(GTK_CONTAINER(scrolledWindow), codecTreeView); // Create button box diff --git a/gnome/src/config/tlsadvanceddialog.c b/gnome/src/config/tlsadvanceddialog.c index d7f4148cb65f33ba27c35a244ad2e6dacee21e39..0a41f43d17cf2e057fa3cbc6783dc12cb0cc7cac 100644 --- a/gnome/src/config/tlsadvanceddialog.c +++ b/gnome/src/config/tlsadvanceddialog.c @@ -189,34 +189,27 @@ void show_advanced_tls_options(account_t *account, SFLPhoneClient *client) gtk_grid_attach(GTK_GRID(grid), privateKeyPasswordEntry, 1, 6, 1, 1); /* TLS protocol methods */ - GtkTreeIter iter; - GtkListStore * tlsProtocolMethodListStore = gtk_list_store_new(1, G_TYPE_STRING); label = gtk_label_new_with_mnemonic(_("TLS protocol method")); gtk_grid_attach(GTK_GRID(grid), label, 0, 7, 1, 1); gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5); + GtkWidget *tlsProtocolMethodCombo = gtk_combo_box_text_new(); gchar** supported_tls_method = dbus_get_supported_tls_method(); - GtkTreeIter supported_tls_method_iter; + gint supported_tls_method_idx = 0; + gint idx = 0; for (char **supported_tls_method_ptr = supported_tls_method; supported_tls_method_ptr && *supported_tls_method_ptr; supported_tls_method_ptr++) { - gtk_list_store_append(tlsProtocolMethodListStore, &iter); - gtk_list_store_set(tlsProtocolMethodListStore, &iter, 0, *supported_tls_method_ptr, -1); - + gtk_combo_box_text_append(GTK_COMBO_BOX_TEXT(tlsProtocolMethodCombo), NULL, *supported_tls_method_ptr); + /* make sure current TLS method from is active */ if (g_strcmp0(*supported_tls_method_ptr, tls_method) == 0) - supported_tls_method_iter = iter; + supported_tls_method_idx = idx; + ++idx; } + gtk_combo_box_set_active(GTK_COMBO_BOX(tlsProtocolMethodCombo), supported_tls_method_idx); - GtkWidget *tlsProtocolMethodCombo = gtk_combo_box_new_with_model(GTK_TREE_MODEL(tlsProtocolMethodListStore)); gtk_label_set_mnemonic_widget(GTK_LABEL(label), tlsProtocolMethodCombo); gtk_grid_attach(GTK_GRID(grid), tlsProtocolMethodCombo, 1, 7, 1, 1); - g_object_unref(G_OBJECT(tlsProtocolMethodListStore)); - - GtkCellRenderer *tlsProtocolMethodCellRenderer; - tlsProtocolMethodCellRenderer = gtk_cell_renderer_text_new(); - gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(tlsProtocolMethodCombo), tlsProtocolMethodCellRenderer, TRUE); - gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(tlsProtocolMethodCombo), tlsProtocolMethodCellRenderer, "text", 0, NULL); - gtk_combo_box_set_active_iter(GTK_COMBO_BOX(tlsProtocolMethodCombo), &supported_tls_method_iter); /* Cipher list */ GtkWidget * cipherListEntry; diff --git a/gnome/src/contacts/calltree.c b/gnome/src/contacts/calltree.c index 6de67257930656c3a8df6c72dce70e1dec644912..0adf6c0738312cd0d086fb102cb31b1962fa19aa 100644 --- a/gnome/src/contacts/calltree.c +++ b/gnome/src/contacts/calltree.c @@ -101,6 +101,12 @@ is_conference(GtkTreeModel *model, GtkTreeIter *iter) return result; } +static void +update_ringtone_seekslider_path(callable_obj_t *call) +{ + main_window_update_seekslider(call->_recordfile); +} + /* Call back when the user click on a call in the list */ static void call_selected_cb(GtkTreeSelection *sel, SFLPhoneClient *client) @@ -132,8 +138,11 @@ call_selected_cb(GtkTreeSelection *sel, SFLPhoneClient *client) callable_obj_t *selected_call = calllist_get_call(active_calltree_tab, id); g_free(id); - if (selected_call) + if (selected_call) { calltab_select_call(active_calltree_tab, selected_call); + if (calltab_has_name(active_calltree_tab, HISTORY)) + update_ringtone_seekslider_path(selected_call); + } } update_actions(client); diff --git a/gnome/src/dbus/callmanager-introspec.xml b/gnome/src/dbus/callmanager-introspec.xml index c86062e82a331a9f052063557685d6cb4fe8b64e..400cae60615b60c2240b0c7ab629eb1f9647d398 100644 --- a/gnome/src/dbus/callmanager-introspec.xml +++ b/gnome/src/dbus/callmanager-introspec.xml @@ -211,6 +211,11 @@ <arg type="as" name="participants" direction="in"/> </method> + <method name="isConferenceParticipant" tp:name-for-bindings="isConferenceParticipant"> + <arg type="s" name="callID" direction="in"/> + <arg type="b" name="isParticipant" direction="out"/> + </method> + <method name="addParticipant" tp:name-for-bindings="addParticipant"> <tp:added version="0.9.7"/> <tp:docstring> @@ -392,6 +397,7 @@ <signal name="updatePlaybackScale" tp:name-for-bindings="updatePlaybackScale"> <tp:docstring/> + <arg type="s" name="filepath" /> <arg type="i" name="position" /> <arg type="i" name="size" /> </signal> diff --git a/gnome/src/dbus/dbus.c b/gnome/src/dbus/dbus.c index 58edccabe9b12d27d527cfbb3b735410c2cb8756..f9218508aa7aa835138c8c8dc970d1223d716655 100644 --- a/gnome/src/dbus/dbus.c +++ b/gnome/src/dbus/dbus.c @@ -50,6 +50,7 @@ #include "assistant.h" #include "accountlist.h" #include "accountlistconfigdialog.h" +#include "accountconfigdialog.h" #include "messaging/message_tab.h" #include "sflphone_client.h" @@ -412,9 +413,11 @@ record_playback_stopped_cb(G_GNUC_UNUSED DBusGProxy *proxy, const gchar *filepat } static void -update_playback_scale_cb(G_GNUC_UNUSED DBusGProxy *proxy, guint position, guint size) +update_playback_scale_cb(G_GNUC_UNUSED DBusGProxy *proxy, + const gchar *file_path, guint position, guint size) { - main_window_update_playback_scale(position, size); + if (!main_window_update_playback_scale(file_path, position, size)) + update_ringtone_slider(position, size); } static void @@ -648,8 +651,6 @@ gboolean dbus_connect(GError **error, SFLPhoneClient *client) const char *configurationmanager_object_instance = "/org/sflphone/SFLphone/ConfigurationManager"; const char *configurationmanager_interface = "org.sflphone.SFLphone.ConfigurationManager"; - g_type_init(); - DBusGConnection *connection = dbus_g_bus_get(DBUS_BUS_SESSION, error); if (connection == NULL) { g_warning("could not establish connection with session bus"); @@ -810,7 +811,7 @@ gboolean dbus_connect(GError **error, SFLPhoneClient *client) dbus_g_proxy_connect_signal(call_proxy, "recordPlaybackStopped", G_CALLBACK(record_playback_stopped_cb), client, NULL); - dbus_g_proxy_add_signal(call_proxy, "updatePlaybackScale", G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_add_signal(call_proxy, "updatePlaybackScale", G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, G_TYPE_INVALID); dbus_g_proxy_connect_signal(call_proxy, "updatePlaybackScale", G_CALLBACK(update_playback_scale_cb), NULL, NULL); diff --git a/gnome/src/dbus/instance-introspec.xml b/gnome/src/dbus/instance-introspec.xml index f564d54cc1ed7bb941af0b35fb063928cd2a9f88..f3d1373a6409b7875a4d80db5bf0f815f285d637 100644 --- a/gnome/src/dbus/instance-introspec.xml +++ b/gnome/src/dbus/instance-introspec.xml @@ -29,5 +29,8 @@ </tp:docstring> </arg> </method> + <signal name="started" tp:name-for-bindings="started"> + <tp:docstring>Notify clients that daemon has started</tp:docstring> + </signal> </interface> </node> diff --git a/gnome/src/mainwindow.c b/gnome/src/mainwindow.c index 01acc808f8bd5d0b170037ceffbc22a507a03c2d..68d0a7555f86f5bff8a3ae962da82e55a15435a4 100644 --- a/gnome/src/mainwindow.c +++ b/gnome/src/mainwindow.c @@ -546,10 +546,14 @@ main_window_confirm_go_clear(callable_obj_t * c, SFLPhoneClient *client) add_error_dialog(GTK_WIDGET(mini_dialog)); } -void -main_window_update_playback_scale(guint current, guint size) +gboolean +main_window_update_playback_scale(const gchar *file_path, guint current, guint size) { - sfl_seekslider_update_scale(SFL_SEEKSLIDER(seekslider), current, size); + if (sfl_seekslider_has_path(SFL_SEEKSLIDER(seekslider), file_path)) { + sfl_seekslider_update_scale(SFL_SEEKSLIDER(seekslider), current, size); + return TRUE; + } + return FALSE; } void @@ -589,3 +593,9 @@ main_window_pause_keygrabber(gboolean value) { pause_grabber = value; } + +void +main_window_update_seekslider(const gchar *recordfile) +{ + g_object_set(G_OBJECT(seekslider), "file-path", recordfile, NULL); +} diff --git a/gnome/src/mainwindow.h b/gnome/src/mainwindow.h index 3e27fdbc10517d509a78e800815959eb61f69246..b183ca644da53fe135dbc4d92b340c298da0af19 100644 --- a/gnome/src/mainwindow.h +++ b/gnome/src/mainwindow.h @@ -107,7 +107,7 @@ void focus_on_searchbar_in(); * if the size is 0 or if the current value is larger than the size, the cursor position * is moved at the end of the scale. */ -void main_window_update_playback_scale(guint current, guint size); +gboolean main_window_update_playback_scale(const gchar *file_path, guint current, guint size); void main_window_set_playback_scale_sensitive(); @@ -131,4 +131,7 @@ void main_window_pause_keygrabber(gboolean value); void main_window_reset_playback_scale(); void main_window_bring_to_front(SFLPhoneClient *client, guint32 timestamp); + +void main_window_update_seekslider(const gchar *recordfile); + #endif diff --git a/gnome/src/seekslider.c b/gnome/src/seekslider.c index 2ebdc35f1a409bf4691139329ec066bca61ac9ed..23ebd4a00f947bb38254210ace9a6583250e88fb 100644 --- a/gnome/src/seekslider.c +++ b/gnome/src/seekslider.c @@ -36,7 +36,6 @@ #include <string.h> #include "seekslider.h" #include "dbus.h" -#include "calltab.h" /** * SECTION:sfl-seekslider @@ -89,13 +88,18 @@ struct SFLSeekSliderPrivate gboolean is_dragging; gboolean can_update_scale; gboolean is_playing; + gchar *file_path; }; enum { PROP_0, + PROP_FILE_PATH, + N_PROPERTIES }; +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + G_DEFINE_TYPE(SFLSeekSlider, sfl_seekslider, GTK_TYPE_HBOX) static void @@ -108,6 +112,10 @@ sfl_seekslider_class_init(SFLSeekSliderClass *klass) object_class->set_property = sfl_seekslider_set_property; object_class->get_property = sfl_seekslider_get_property; + obj_properties[PROP_FILE_PATH] = g_param_spec_string("file-path", "File path", + "Set file path for playback", "" /* default value */, G_PARAM_READWRITE); + + g_object_class_install_properties(object_class, N_PROPERTIES, obj_properties); g_type_class_add_private(klass, sizeof(SFLSeekSliderPrivate)); } @@ -186,6 +194,7 @@ sfl_seekslider_init(SFLSeekSlider *seekslider) seekslider->priv->current = 0; seekslider->priv->size = 0; seekslider->priv->is_playing = FALSE; + seekslider->priv->file_path = NULL; } static void @@ -199,6 +208,9 @@ sfl_seekslider_finalize(GObject *object) seekslider = SFL_SEEKSLIDER(object); g_return_if_fail(seekslider->priv != NULL); + /* Ensure that we've stopped playback */ + sfl_seekslider_stop_playback_record_cb(NULL, seekslider); + G_OBJECT_CLASS(sfl_seekslider_parent_class)->finalize(object); } @@ -206,15 +218,54 @@ sfl_seekslider_finalize(GObject *object) static void sfl_seekslider_set_property (GObject *object, guint prop_id, const GValue *value G_GNUC_UNUSED, GParamSpec *pspec) { - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + SFLSeekSlider *self = SFL_SEEKSLIDER(object); + + switch (prop_id) + { + case PROP_FILE_PATH: + /* no change */ + if (g_strcmp0(self->priv->file_path, g_value_get_string(value)) == 0) + break; + + /* cache is_playing as it will be modified */ + const gboolean resume_playing = self->priv->is_playing; + if (resume_playing) + sfl_seekslider_stop_playback_record_cb(NULL, self); + + g_free(self->priv->file_path); + self->priv->file_path = g_value_dup_string(value); + g_debug("filepath: %s\n", self->priv->file_path); + + if (resume_playing) + sfl_seekslider_play_playback_record_cb(NULL, self); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } } static void sfl_seekslider_get_property (GObject *object, guint prop_id, GValue *value G_GNUC_UNUSED, GParamSpec *pspec) { - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + SFLSeekSlider *self = SFL_SEEKSLIDER(object); + + switch (prop_id) + { + case PROP_FILE_PATH: + g_value_set_string(value, self->priv->file_path); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } } + /** * sfl_seekslider_new: * @shell_player: the #RBShellPlayer instance @@ -298,37 +349,30 @@ on_playback_scale_scrolled_cb(GtkWidget *widget G_GNUC_UNUSED, GdkEvent *event G static void sfl_seekslider_play_playback_record_cb (GtkButton *button G_GNUC_UNUSED, gpointer user_data) { - SFLSeekSlider *seekslider = SFL_SEEKSLIDER(user_data); + SFLSeekSlider *self = SFL_SEEKSLIDER(user_data); - callable_obj_t *selectedCall = calltab_get_selected_call(history_tab); - if (selectedCall == NULL) + if (self->priv->file_path == NULL || (*self->priv->file_path == 0)) return; - g_debug("Start selected call file playback %s", selectedCall->_recordfile); - seekslider->priv->is_playing = selectedCall->_record_is_playing = - dbus_start_recorded_file_playback(selectedCall->_recordfile); + g_debug("Start file playback %s", self->priv->file_path); + self->priv->is_playing = dbus_start_recorded_file_playback(self->priv->file_path); - if (seekslider->priv->is_playing) - sfl_seekslider_set_display(seekslider, SFL_SEEKSLIDER_DISPLAY_PAUSE); + if (self->priv->is_playing) + sfl_seekslider_set_display(self, SFL_SEEKSLIDER_DISPLAY_PAUSE); } static void sfl_seekslider_stop_playback_record_cb (GtkButton *button G_GNUC_UNUSED, gpointer user_data) { - SFLSeekSlider *seekslider = SFL_SEEKSLIDER(user_data); + SFLSeekSlider *self = SFL_SEEKSLIDER(user_data); - callable_obj_t *selectedCall = calltab_get_selected_call(history_tab); - if (selectedCall == NULL) + if (self->priv->file_path == NULL || (*self->priv->file_path == 0)) return; - if (selectedCall->_recordfile == NULL || - strlen(selectedCall->_recordfile) == 0) - return; - - dbus_stop_recorded_file_playback(selectedCall->_recordfile); - g_debug("Stop selected call file playback %s", selectedCall->_recordfile); - seekslider->priv->is_playing = selectedCall->_record_is_playing = FALSE; + dbus_stop_recorded_file_playback(self->priv->file_path); + g_debug("Stop file playback %s", self->priv->file_path); + self->priv->is_playing = FALSE; - sfl_seekslider_set_display(seekslider, SFL_SEEKSLIDER_DISPLAY_PLAY); + sfl_seekslider_set_display(self, SFL_SEEKSLIDER_DISPLAY_PLAY); } void sfl_seekslider_update_timelabel(SFLSeekSlider *seekslider, guint current, guint size) @@ -416,3 +460,9 @@ void sfl_seekslider_reset(SFLSeekSlider *seekslider) seekslider->priv->is_playing = FALSE; seekslider->priv->can_update_scale = TRUE; } + +gboolean +sfl_seekslider_has_path(SFLSeekSlider *seekslider, const gchar *file_path) +{ + return g_strcmp0(seekslider->priv->file_path, file_path) == 0; +} diff --git a/gnome/src/seekslider.h b/gnome/src/seekslider.h index 325084624305d467e6e814427bcc4611147be7bf..72082265622b7dc4ad399656751614fbfe845bd3 100644 --- a/gnome/src/seekslider.h +++ b/gnome/src/seekslider.h @@ -68,6 +68,8 @@ void sfl_seekslider_update_timelabel(SFLSeekSlider *seekslider, guint current, g void sfl_seekslider_set_display(SFLSeekSlider *seekslider, SFLSeekSliderDisplay display); +gboolean sfl_seekslider_has_path(SFLSeekSlider *seekslider, const gchar *file_path); + void sfl_seekslider_reset(SFLSeekSlider *seekslider); #endif /* __RB_SEEKSLIDER_H */ diff --git a/gnome/tests/check_dbus.c b/gnome/tests/check_dbus.c index 8bd3e0af8b67e5ccab44e9101f2b592d7468d3d6..5214aebc80798a6e262aaf51d0291ce3887e40f0 100644 --- a/gnome/tests/check_dbus.c +++ b/gnome/tests/check_dbus.c @@ -36,7 +36,6 @@ START_TEST(test_dbus_connect) { - g_type_init(); GError *error = NULL; SFLPhoneClient *client = sflphone_client_new(); fail_unless(dbus_connect(&error, client) == TRUE, "dbus_connect () returns FALSE"); diff --git a/hudson-sflphone-script.sh b/hudson-sflphone-script.sh index c19624d73e9b8e87e66532d385deb9c4e9e957d5..2b5d0360ea8465a704e6b7c85891da193c943423 100755 --- a/hudson-sflphone-script.sh +++ b/hudson-sflphone-script.sh @@ -42,22 +42,22 @@ CONFIGDIR=~/.config SFLCONFDIR=${CONFIGDIR}/sflphone function run_code_analysis { - # Check if cppcheck is installed on the system - if [ `which cppcheck &>/dev/null ; echo $?` -ne 1 ] ; then - pushd src - cppcheck . --enable=all --xml --inline-suppr 2> cppcheck-report.xml - popd - fi + # Check if cppcheck is installed on the system + if [ `which cppcheck &>/dev/null ; echo $?` -ne 1 ] ; then + pushd src + cppcheck . --enable=all --xml --inline-suppr 2> cppcheck-report.xml + popd + fi } function gen_doxygen { - # Check if doxygen is installed on the system - if [ `which doxygen &>/dev/null ; echo $?` -ne 1 ] ; then - pushd doc/doxygen - doxygen core-doc.cfg.in - popd - fi + # Check if doxygen is installed on the system + if [ `which doxygen &>/dev/null ; echo $?` -ne 1 ] ; then + pushd doc/doxygen + doxygen core-doc.cfg.in + popd + fi } function launch_functional_test_daemon { @@ -102,67 +102,64 @@ function launch_functional_test_daemon { function build_daemon { - # Compile the daemon - pushd daemon - # Run static analysis code tool - if [ $CODE_ANALYSIS == 1 ]; then - run_code_analysis - fi - make distclean - ./autogen.sh - # Compile pjproject first - pushd libs/pjproject-2.1.0 - ./autogen.sh - CFLAGS=-fPIC ./configure - make && make dep - popd - ./configure --prefix=/usr - make clean - # Compile src code - make -j - # Remove the previous XML test file - rm -rf $XML_RESULTS - # Compile unit tests - make check - popd + pushd daemon + # Run static analysis code tool + if [ $CODE_ANALYSIS == 1 ]; then + run_code_analysis + fi + make distclean + + ./autogen.sh || exit 1 + # Compile pjproject first + pushd libs + ./compile_pjsip.sh + popd + + # Compile the daemon + ./configure --prefix=/usr + make clean + make -j + # Remove the previous XML test file + rm -rf $XML_RESULTS + # Compile unit tests + make check + popd } function build_gnome { - # Compile the daemon - pushd daemon - killall sflphoned - make distclean - ./autogen.sh - # Compile pjproject first - pushd libs/pjproject-2.1.0 - ./autogen.sh - CFLAGS=-fPIC ./configure - make && make dep - popd - ./configure --prefix=/usr - make clean - # Compile src code - make -j - ./src/sflphoned& - popd - - # Compile the plugins - pushd plugins - make distclean - ./autogen.sh - ./configure --prefix=/usr - make -j - popd - - # Compile the client - pushd gnome - make distclean - ./autogen.sh - ./configure --prefix=/usr - make clean - make -j 1 - make check - popd + pushd daemon + killall sflphoned + make distclean + + # Compile pjproject first + pushd libs + ./compile_pjsip.sh + popd + + # Compile daemon + ./configure --prefix=/usr + make clean + make -j + ./src/sflphoned & + popd + + # Compile the plugins + pushd plugins + make distclean + ./autogen.sh || exit 1 + ./configure --prefix=/usr + make -j + popd + + # Compile the client + pushd gnome + make distclean + ./autogen.sh || exit 1 + ./configure --prefix=/usr + make clean + make -j 1 + make check + popd } function build_kde { @@ -177,41 +174,41 @@ function build_kde { if [ "$#" -eq 0 ]; then # Script needs at least one command-line argument. - echo "Usage $0 -b select which one to build: daemon or gnome - -t enable unit tests after build" - exit $E_OPTERR + echo "Usage $0 -b select which one to build: daemon or gnome + -t enable unit tests after build" + exit $E_OPTERR fi git clean -f -d -x while getopts ":b: t a d" opt; do - case $opt in - b) - echo "-b was triggered. Parameter: $OPTARG" >&2 - BUILD=$OPTARG - ;; - t) - echo "-t was triggered. Tests will be run" >&2 - TEST=1 - ;; - a) - echo "-a was triggered. Static code analysis will be run" >&2 - CODE_ANALYSIS=1 - ;; - d) - echo "-d was triggered. Doxygen documentation will be generated" >&2 - DOXYGEN=1 - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - exit 1 - ;; - :) - echo "Option -$OPTARG requires an argument." >&2 - exit 1 - ;; - esac + case $opt in + b) + echo "-b was triggered. Parameter: $OPTARG" >&2 + BUILD=$OPTARG + ;; + t) + echo "-t was triggered. Tests will be run" >&2 + TEST=1 + ;; + a) + echo "-a was triggered. Static code analysis will be run" >&2 + CODE_ANALYSIS=1 + ;; + d) + echo "-d was triggered. Doxygen documentation will be generated" >&2 + DOXYGEN=1 + ;; + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + :) + echo "Option -$OPTARG requires an argument." >&2 + exit 1 + ;; + esac done # Call appropriate build function, with parameters if needed diff --git a/tools/build-system/README.launchpad b/tools/build-system/README.launchpad new file mode 100644 index 0000000000000000000000000000000000000000..eabd74ef2b5c7ab8723276614fa23f15a46038b7 --- /dev/null +++ b/tools/build-system/README.launchpad @@ -0,0 +1,9 @@ +To push packages for a new Ubuntu distribution on launchpad, you'll need to +modify the following files: + +tools/build-system/launchpad/dput.conf +tools/build-system/setenv.sh + +See commit 1b19e3869aa5e4632b8b043f47024297218ed2c5 for an example. + +In addition, you'll have to modify the sflphone-package-manager job on Jenkins diff --git a/tools/build-system/launchpad/dput.conf b/tools/build-system/launchpad/dput.conf index 01af29933e620b9fbefc03f25de7429bb084d6e1..12f1c2b688c0c8c11ba84f441caf4fbf912f5b41 100644 --- a/tools/build-system/launchpad/dput.conf +++ b/tools/build-system/launchpad/dput.conf @@ -33,6 +33,13 @@ incoming = ~savoirfairelinux/ubuntu/raring login = anonymous allow_unsigned_uploads = 0 +[sflphone-saucy] +fqdn = ppa.launchpad.net +method = ftp +incoming = ~savoirfairelinux/ubuntu/saucy +login = anonymous +allow_unsigned_uploads = 0 + [sflphone-nightly-natty] fqdn = ppa.launchpad.net method = ftp @@ -61,6 +68,13 @@ incoming = ~savoirfairelinux/sflphone-nightly/ubuntu/raring login = anonymous allow_unsigned_uploads = 0 +[sflphone-nightly-saucy] +fqdn = ppa.launchpad.net +method = ftp +incoming = ~savoirfairelinux/sflphone-nightly/ubuntu/saucy +login = anonymous +allow_unsigned_uploads = 0 + [sflphone-testing-precise] fqdn = ppa.launchpad.net method = ftp diff --git a/tools/build-system/launchpad/sflphone-common-video/debian/control b/tools/build-system/launchpad/sflphone-common-video/debian/control index f8638f67a74dd80a981fbb187e77114e2f475d16..bf55d1aa11b33f6b819d7fae464acc77701c469c 100644 --- a/tools/build-system/launchpad/sflphone-common-video/debian/control +++ b/tools/build-system/launchpad/sflphone-common-video/debian/control @@ -2,7 +2,7 @@ Source: sflphone-common-video Maintainer: SavoirFaireLinux Inc <julien.bonjean@savoirfairelinux.com> Section: gnome Priority: optional -Build-Depends: debhelper (>= 7.0.50), libgcc1, autoconf, automake, libpulse-dev, libsamplerate0-dev, libcommoncpp2-dev, libccrtp-dev, libgsm1-dev, libspeex-dev, libtool, libdbus-1-dev, libasound2-dev, libspeexdsp-dev, uuid-dev, libexpat1-dev, libzrtpcpp-dev, libssl-dev, libpcre3-dev, libyaml-dev, libdbus-c++-dev, libavcodec-dev, libavformat-dev, libswscale-dev, libavdevice-dev, libavutil-dev, libudev-dev +Build-Depends: debhelper (>= 7.0.50), libgcc1, autoconf, automake, libpulse-dev, libsamplerate0-dev, libcommoncpp2-dev, libccrtp-dev, libgsm1-dev, libspeex-dev, libtool, libdbus-1-dev, libasound2-dev, libspeexdsp-dev, uuid-dev, libexpat1-dev, libzrtpcpp-dev, libssl-dev, libpcre3-dev, libyaml-dev, libdbus-c++-dev, libsndfile1-dev, libavcodec-dev, libavformat-dev, libswscale-dev, libavdevice-dev, libavutil-dev, libudev-dev Standards-Version: 3.7.3 Package: sflphone-common-video diff --git a/tools/build-system/launchpad/sflphone-common/debian/control b/tools/build-system/launchpad/sflphone-common/debian/control index 48ee9496116bb6b08d620a9ff51672c7fe80c1c9..5ba6ab5d4876643e164b1d208cd37c645ffa7e4a 100644 --- a/tools/build-system/launchpad/sflphone-common/debian/control +++ b/tools/build-system/launchpad/sflphone-common/debian/control @@ -2,7 +2,7 @@ Source: sflphone-common Maintainer: SavoirFaireLinux Inc <julien.bonjean@savoirfairelinux.com> Section: gnome Priority: optional -Build-Depends: debhelper (>= 7.0.50), libgcc1, autoconf, automake, libpulse-dev, libsamplerate0-dev, libcommoncpp2-dev, libccrtp-dev, libgsm1-dev, libspeex-dev, libtool, libdbus-1-dev, libasound2-dev, libspeexdsp-dev, uuid-dev, libexpat1-dev, libzrtpcpp-dev, libssl-dev, libpcre3-dev, libyaml-dev, libdbus-c++-dev +Build-Depends: debhelper (>= 7.0.50), libgcc1, autoconf, automake, libpulse-dev, libsamplerate0-dev, libcommoncpp2-dev, libccrtp-dev, libgsm1-dev, libspeex-dev, libtool, libdbus-1-dev, libasound2-dev, libspeexdsp-dev, uuid-dev, libexpat1-dev, libzrtpcpp-dev, libssl-dev, libpcre3-dev, libyaml-dev, libdbus-c++-dev, libsndfile1-dev Standards-Version: 3.7.3 Package: sflphone-common diff --git a/tools/build-system/rpm/sflphone.spec b/tools/build-system/rpm/sflphone.spec new file mode 100644 index 0000000000000000000000000000000000000000..c38d86010773c487baf126a0e5022509272c8bf3 --- /dev/null +++ b/tools/build-system/rpm/sflphone.spec @@ -0,0 +1,303 @@ +%bcond_with video +Name: sflphone +Version: 1.2.3 +Release: 1%{?dist} +Summary: SIP/IAX2 compatible enterprise-class software phone +Group: Applications/Internet +License: GPLv3 +URL: http://sflphone.org/ +Source0: https://projects.savoirfairelinux.com/attachments/download/6423/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +BuildRequires: gettext openssl-devel desktop-file-utils perl +BuildRequires: libyaml-devel alsa-lib-devel pulseaudio-libs-devel +BuildRequires: ccrtp-devel libzrtpcpp-devel dbus-c++-devel pcre-devel +BuildRequires: gsm-devel speex-devel expat-devel libsamplerate-devel +BuildRequires: gnome-doc-utils libtool libsexy-devel intltool yelp-tools +BuildRequires: libnotify-devel check-devel rarian-compat ilbc-devel +BuildRequires: evolution-data-server-devel gnome-common libsndfile-devel +# KDE requires +BuildRequires: cmake kdepimlibs-devel +%if 0%{?fedora} > 18 +BuildRequires: perl-podlators +%endif +%if %{with video} && 0%{?fedora} < 18 +BuildRequires: libudev-devel +%endif +%if %{with video} && 0%{?fedora} >= 18 +BuildRequires: systemd-devel +%endif + +%description +SFLphone is a robust standards-compliant enterprise software phone, +for desktop and embedded systems. It is designed to handle +several hundreds of calls a day. It supports both SIP and IAX2 +protocols. + +%prep +%setup -q + +%build +# Compile the daemon +pushd daemon +./autogen.sh +# Compile pjproject first +pushd libs +./compile_pjsip.sh +popd +# Compile daemon +%if %{with video} +%configure --enable-video +%else +%configure +%endif +make %{?_smp_mflags} +make doc +popd +pushd plugins +./autogen.sh +%configure +make %{?_smp_mflags} +popd +# Compile kde client (only without video) +%if ! %{with video} +pushd kde +sed -i '/^[^#]add_subdirectory.*test/s/^[^#]/#/' src/CMakeLists.txt +./config.sh --prefix=%{_prefix} +cd build +make %{?_smp_mflags} +popd +%endif +# Compile gnome client +pushd gnome +./autogen.sh +%if %{with video} +%configure --enable-video +%else +%configure +%endif +make %{?_smp_mflags} +popd + + +%if %{with video} +%package gnome-video +Summary: SIP/IAX2 compatible enterprise-class software phone +Group: Applications/Internet +Requires: %{name}-common-video +Conflicts: sflphone-gnome sflphone +BuildRequires: ffmpeg-devel clutter-gtk-devel +%description gnome-video +SFLphone is a robust standards-compliant enterprise software phone, +for desktop and embedded systems. It is designed to handle +several hundreds of calls a day. It supports both SIP and IAX2 +protocols. + +This package includes the Gnome client with videoconferencing ability + +%package common-video +Summary: SIP/IAX2 compatible enterprise-class software phone +Group: Applications/Internet +Conflicts: sflphone sflphone-daemon sflphone-common +%description common-video +SFLphone is a robust standards-compliant enterprise software phone, +for desktop and embedded systems. It is designed to handle +several hundreds of calls a day. It supports both SIP and IAX2 +protocols. + +This package includes the SFLPhone daemon with videoconferencing enabled +%else +%package common +Summary: SIP/IAX2 compatible enterprise-class software phone +Group: Applications/Internet +Conflicts: sflphone sflphone-daemon-video +%description common +SFLphone is a robust standards-compliant enterprise software phone, +for desktop and embedded systems. It is designed to handle +several hundreds of calls a day. It supports both SIP and IAX2 +protocols. + +This package includes the SFLPhone common + +%package gnome +Summary: Gnome interface for SFLphone +Group: Applications/Internet +Requires: %{name}-common +Obsoletes: sflphone < 1.2.2-2 +Conflicts: sflphone-video +%description gnome +SFLphone is a robust standards-compliant enterprise software phone, +for desktop and embedded systems. It is designed to handle +several hundreds of calls a day. It supports both SIP and IAX2 +protocols. + +This package includes the Gnome client + + +%package kde +Summary: KDE interface for SFLphone +Group: Applications/Internet +Requires: %{name}-common +%description kde +SFLphone is a robust standards-compliant enterprise software phone, +for desktop and embedded systems. It is designed to handle +several hundreds of calls a day. It supports both SIP and IAX2 +protocols. + +This package includes the KDE client +%endif + +%package plugins +Summary: Plugins (address book) for SFLphone +Group: Applications/Internet +Requires: %{name}-common +%description plugins +SFLphone is a robust standards-compliant enterprise software phone, +for desktop and embedded systems. It is designed to handle +several hundreds of calls a day. It supports both SIP and IAX2 +protocols. + +This package includes the address book plugin. + + +%install +rm -rf %{buildroot} +pushd daemon +make install DESTDIR=$RPM_BUILD_ROOT +popd +# Gnome install +pushd gnome +make install DESTDIR=$RPM_BUILD_ROOT +# Find Lang files +popd +# Plugins install +pushd plugins +make install DESTDIR=$RPM_BUILD_ROOT +popd +%find_lang sflphone --with-gnome +# Handling desktop file +desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop +%if ! %{with video} +# KDE install +pushd kde/build +make install DESTDIR=$RPM_BUILD_ROOT +popd +%endif + +%if %{with video} +%pre gnome-video +if [ "$1" -gt 1 ] ; then + glib-compile-schemas %{_datadir}/glib-2.0/schemas &>/dev/null +fi + +%post gnome-video + glib-compile-schemas %{_datadir}/glib-2.0/schemas &>/dev/null + +%preun gnome-video +if [ "$1" -eq 0 ] ; then + glib-compile-schemas %{_datadir}/glib-2.0/schemas &>/dev/null +fi +%else +%pre gnome +if [ "$1" -gt 1 ] ; then + glib-compile-schemas %{_datadir}/glib-2.0/schemas &>/dev/null +fi + +%post gnome + glib-compile-schemas %{_datadir}/glib-2.0/schemas &>/dev/null + +%preun gnome +if [ "$1" -eq 0 ] ; then + glib-compile-schemas %{_datadir}/glib-2.0/schemas &>/dev/null +fi +%endif + +%if %{with video} +%files common-video +%else +%files common +%endif +%defattr(-,root,root,-) +%doc AUTHORS COPYING NEWS README +%{_libdir}/%{name}/* +%{_datadir}/dbus-1/services/org.%{name}.SFLphone.service +%{_mandir}/man1/sflphoned.1.gz* +%{_datadir}/pixmaps/%{name}.svg +%{_datadir}/%{name}/* + +%if %{with video} +%files -f sflphone.lang gnome-video +%else +%files -f sflphone.lang gnome +%endif +%defattr(-,root,root,-) +%{_bindir}/sflphone +%{_bindir}/sflphone-client-gnome +%{_datadir}/glib-2.0/schemas/org.sflphone.SFLphone.gschema.xml +%{_datadir}/applications/%{name}.desktop +%{_mandir}/man1/sflphone.1.gz +%{_mandir}/man1/sflphone-client-gnome.1.gz +%{_datadir}/pixmaps/%{name}.svg +%{_datadir}/%{name}/* + +%files plugins +%{_libdir}/sflphone/plugins/libevladdrbook.so + +%if ! %{with video} +%files kde +%{_bindir}/sflphone-client-kde +%{_datadir}/kde4/apps/sflphone-client-kde +%{_datadir}/kde4/apps/plasma/plasmoids/ +%{_datadir}/kde4/apps/plasma/services/sflphone.operations +%{_datadir}/kde4/services +%{_datadir}/config.kcfg/sflphone-client-kde.kcfg +%{_datadir}/applications/kde4 +%doc %{_datadir}/doc/HTML/*/sflphone-client-kde +%doc %{_mandir}/man1/*kde* +%{_datadir}/icons/hicolor +%{_libdir}/libksflphone.so* +%{_libdir}/libqtsflphone.so* +%{_libdir}/kde4/plasma_engine_sflphone.so +%exclude %{_includedir}/kde4/ksflphone/*.h +%exclude %{_includedir}/kde4/qtsflphone/*.h +%endif + +%changelog +* Wed Jun 19 2013 Simon Piette <simonp@fedoraproject.org> - 1.2.3-1 +- Update to 1.2.3 +- Enable ilbc + +* Mon Feb 18 2013 Simon Piette <simonp@fedoraproject.org> - 1.2.2-6 +- Add sflphone-plugins + +* Mon Feb 18 2013 Simon Piette <simonp@fedoraproject.org> - 1.2.2-5 +- Renamed daemon to config + +* Mon Feb 18 2013 Simon Piette <simonp@fedoraproject.org> - 1.2.2-4 +- Video variant for gnome + +* Wed Feb 13 2013 Simon Piette <simonp@fedoraproject.org> - 1.2.2-3 +- split daemon and gnome packages + +* Wed Feb 13 2013 Simon Piette <simonp@fedoraproject.org> - 1.2.2-2 +- creates a kde client package + +* Tue Jan 15 2013 Simon Piette <simonp@fedoraproject.org> - 1.2.2-1 +- upgraded to 1.2.2 +- updated BuildRequires +- disabled ilbc +- replaced gconf with gsettings + +* Tue Sep 11 2012 Simon Piette <simonp@fedoraproject.org> - 1.2.0-1 +- upgraded to 1.2.0 (tested on f16) +- updated BuildRequires + +* Wed Apr 20 2011 Prabin Kumar Datta <prabindatta@fedoraproject.org> - 0.9.13-1 +- avoiding compling with Celt codec support to resolve build problem +- removed clean section since not required +- upgraded to 0.9.13 + +* Mon Apr 18 2011 Prabin Kumar Datta <prabindatta@fedoraproject.org> - 0.9.12-2 +- Fixed schema registration problem + +* Fri Mar 25 2011 Prabin Kumar Datta <prabindatta@fedoraproject.org> - 0.9.12-1 +- Initial build diff --git a/tools/build-system/setenv.sh b/tools/build-system/setenv.sh index b78df319f47a87a601e41c09836e2ee124b7ae26..f8bc9ec302ab112c9f7e6dd27fef6e247fcafeb5 100644 --- a/tools/build-system/setenv.sh +++ b/tools/build-system/setenv.sh @@ -22,5 +22,5 @@ export REFERENCE_REPOSITORY="${ROOT_DIR}/sflphone-source-repository" export WORKING_DIR="${ROOT_DIR}/sflphone-build-repository/tools/build-system" export LAUNCHPAD_DIR="${WORKING_DIR}/launchpad" -LAUNCHPAD_DISTRIBUTIONS=("oneiric" "precise" "quantal" "raring") +LAUNCHPAD_DISTRIBUTIONS=("oneiric" "precise" "quantal" "raring" "saucy") export LAUNCHPAD_DISTRIBUTIONS