mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-08-13 17:38:59 +00:00
[mod_portaudio, mod_portaudio_stream] Remove from tree
This commit is contained in:
6
src/mod/.gitignore
vendored
6
src/mod/.gitignore
vendored
@@ -33,9 +33,6 @@
|
||||
/codecs/mod_vp8/Makefile
|
||||
/dialplans/mod_dialplan_asterisk/Makefile
|
||||
/dialplans/mod_dialplan_xml/Makefile
|
||||
/endpoints/mod_portaudio/Makefile
|
||||
/endpoints/mod_portaudio/Makefile.in
|
||||
/endpoints/mod_portaudio/mod_portaudio.log
|
||||
/endpoints/mod_skinny/Makefile
|
||||
/endpoints/mod_skinny/Makefile.in
|
||||
/endpoints/mod_skinny/mod_skinny.log
|
||||
@@ -45,9 +42,6 @@
|
||||
/event_handlers/mod_erlang_event/Makefile
|
||||
/event_handlers/mod_event_socket/Makefile
|
||||
/formats/mod_native_file/Makefile
|
||||
/formats/mod_portaudio_stream/Makefile
|
||||
/formats/mod_portaudio_stream/Makefile.in
|
||||
/formats/mod_portaudio_stream/mod_portaudio_stream.log
|
||||
/formats/mod_tone_stream/Makefile
|
||||
/languages/mod_java/Makefile
|
||||
/languages/mod_java/classes/
|
||||
|
@@ -1,19 +0,0 @@
|
||||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_portaudio
|
||||
|
||||
if HAVE_PORTAUDIO
|
||||
mod_LTLIBRARIES = mod_portaudio.la
|
||||
mod_portaudio_la_SOURCES = mod_portaudio.c pablio.c pa_ringbuffer.c
|
||||
mod_portaudio_la_CFLAGS = $(AM_CFLAGS)
|
||||
mod_portaudio_la_CPPFLAGS = -I. $(PORTAUDIO_CFLAGS) $(AM_CPPFLAGS)
|
||||
mod_portaudio_la_LIBADD = $(PORTAUDIO_LIBS) $(switch_builddir)/libfreeswitch.la
|
||||
mod_portaudio_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
||||
if ISMAC
|
||||
mod_portaudio_la_LDFLAGS += -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon
|
||||
endif
|
||||
else
|
||||
install: error
|
||||
all: error
|
||||
error:
|
||||
$(error You must install portaudio19-dev to build $(MODNAME))
|
||||
endif
|
@@ -1,221 +0,0 @@
|
||||
<configuration name="portaudio.conf" description="Soundcard Endpoint">
|
||||
<settings>
|
||||
<!-- indev, outdev, ringdev:
|
||||
partial case sensitive string match on something in the name
|
||||
or the device number prefixed with # eg "#1" (or blank for default) -->
|
||||
|
||||
<!-- device to use for input -->
|
||||
<param name="indev" value=""/>
|
||||
<!-- device to use for output -->
|
||||
<param name="outdev" value=""/>
|
||||
|
||||
<!--device to use for inbound ring -->
|
||||
<!--<param name="ringdev" value=""/>-->
|
||||
<!--File to play as the ring sound -->
|
||||
<!--<param name="ring-file" value="/sounds/ring.wav"/>-->
|
||||
<!--Number of seconds to pause between rings -->
|
||||
<!--<param name="ring-interval" value="5"/>-->
|
||||
<!--Enable or Disable dual_streams-->
|
||||
<!--<param name="dual-streams" value="true"/>-->
|
||||
|
||||
<!--file to play when calls are on hold-->
|
||||
<param name="hold-file" value="$${hold_music}"/>
|
||||
<!--Timer to use for hold music (i'd leave this one commented)-->
|
||||
<!--<param name="timer-name" value="soft"/>-->
|
||||
|
||||
<!--Default dialplan and caller-id info -->
|
||||
<param name="dialplan" value="XML"/>
|
||||
<param name="cid-name" value="$${outbound_caller_name}"/>
|
||||
<param name="cid-num" value="$${outbound_caller_id}"/>
|
||||
|
||||
<!--audio sample rate and interval -->
|
||||
<param name="sample-rate" value="48000"/>
|
||||
<param name="codec-ms" value="20"/>
|
||||
|
||||
<!--uncomment the following line to make mod_portaudio fail to load if it fails to find a device-->
|
||||
<!-- <param name="unload-on-device-fail" value="true"/> -->
|
||||
</settings>
|
||||
|
||||
<!--
|
||||
mod_portaudio "streams"
|
||||
|
||||
The portaudio streams were introduced to support multiple devices and multiple channels in mod_portaudio.
|
||||
For example, if you have a sound card that supports multiple channels or have multiple sound cards and you
|
||||
want to use them at the same time, you can do it configuring streams and endpoints here.
|
||||
|
||||
A "stream" is just a logical container for some settings required by portaudio in order to stream audio and
|
||||
define a friendly name for that configuration. Streams in itself do not do anything else than contain configs.
|
||||
Once you have your streams defined you can proceed to define "endpoints". Go to the "<endpoints>" section
|
||||
for more information on endpoints.
|
||||
|
||||
You can use the command "pa shstreams" (portaudio shared streams) to show the configured streams.
|
||||
-->
|
||||
<streams>
|
||||
<!--
|
||||
In this example we define 2 streams, one for a usb audio device and another for the usual Mac defaults
|
||||
The name="" attribute in the <stream> tag must uniquely identify the stream configuration and can be
|
||||
later used when creating endpoints in the "instream" and "outstream" parameters of the endpoint.
|
||||
-->
|
||||
|
||||
<!-- This sample "usb1" configuration was tested with a USB Griffin iMic device -->
|
||||
<stream name="usb1">
|
||||
<!--
|
||||
Which device to use for input in this stream
|
||||
The value for this parameter must be either in the form '#devno',
|
||||
for example '#2' for device number 2, or 'device-name', like 'iMic USB audio system'
|
||||
The output of command "pa devlist" will show you device names and numbers as enumerated
|
||||
by portaudio.
|
||||
-->
|
||||
<param name="indev" value="#2" />
|
||||
|
||||
<!--
|
||||
Same as the indev but for output. In this case the device is capable of input and output
|
||||
Some devices are capable of input only or output only (see the default example)
|
||||
-->
|
||||
<param name="outdev" value="#2" />
|
||||
|
||||
<!-- The sample rate to use for this stream -->
|
||||
<param name="sample-rate" value="48000" />
|
||||
|
||||
<!--
|
||||
Size of the packets in milliseconds. The smaller the number the less latency you'll have
|
||||
The minimum value is 10ms
|
||||
-->
|
||||
<param name="codec-ms" value="10" />
|
||||
|
||||
<!--
|
||||
How many channels to open for this stream.
|
||||
If you're device is stereo, you can choose 2 here. However, bear in mind that then
|
||||
your left and right channels will be separated and when creating endpoints you will have
|
||||
to either choose the left or right channel. This may or may not be what you want. This separation
|
||||
means that you can have 2 separate FreeSWITCH calls, listening to one of them in your left channel
|
||||
and the other in the right chanel.
|
||||
-->
|
||||
<param name="channels" value="2" />
|
||||
</stream>
|
||||
|
||||
<!-- This default stream was tested using the default Macbook Pro input/output devices -->
|
||||
<stream name="default">
|
||||
<!-- The default system input device -->
|
||||
<param name="indev" value="#0" />
|
||||
<!-- The default system output device -->
|
||||
<param name="outdev" value="#1" />
|
||||
<!-- CD quality sampling rate ftw -->
|
||||
<param name="sample-rate" value="48000" />
|
||||
<!-- Low latency -->
|
||||
<param name="codec-ms" value="10" />
|
||||
<!-- Choosing 1 channel allows to hear in both left-right channel when using a headset -->
|
||||
<param name="channels" value="1" />
|
||||
</stream>
|
||||
</streams>
|
||||
|
||||
<!--
|
||||
mod_portaudio "endpoints"
|
||||
|
||||
Endpoints is a way to define the input and output that a given portaudio channel will use.
|
||||
There is a lot of flexibility. You can create endpoints which are "send-only", which means
|
||||
audio will be read from FreeSWITCH and sent down to the provided stream, but no audio will
|
||||
be read from that stream and only silence provided back to FreeSWITCH.
|
||||
|
||||
send-only endpoint:
|
||||
(FS CORE) ->-> audio ->-> sound-card-x
|
||||
|
||||
You can also create a read-only endpoint.
|
||||
|
||||
read-only-endpoint:
|
||||
(FS CORE) <-<- audio <-<- sound-card-x
|
||||
|
||||
And of course you can create a bidirectional endpoint:
|
||||
bidirectional-endpoint:
|
||||
(FS CORE) <-> audio <-> sound-card-x
|
||||
|
||||
You can also define a stream which uses only the left or only the right channel of a given device stream.
|
||||
This means you can have 2 SIP calls connected to the same device haring one call in your left ear and
|
||||
the other call to your right ear :-)
|
||||
|
||||
The name="parameter" of the endpoint allows you to use it in the FreeSWITCH dial plan to dial, ie:
|
||||
|
||||
<action application="bridge" data="portaudio/endpoint/usb1out-left" />
|
||||
|
||||
You can use the command "pa endpoints" to show the configured endpoints.
|
||||
-->
|
||||
<endpoints>
|
||||
|
||||
<!--
|
||||
An endpoint is a handle name to refer to a configuration that determines where to read media from
|
||||
and write media to. The endpoint can use any input/output stream combination for that purpose as
|
||||
long as the streams match the sampling rate and codec-ms (see <streams> XML tag).
|
||||
You can also omit the instream or the outstream parameter (but obviously not both).
|
||||
-->
|
||||
|
||||
<!--
|
||||
Configuration for a "default" bidirectional endpoint that uses the default stream defined previously in
|
||||
the <streams> section.
|
||||
-->
|
||||
<endpoint name="default">
|
||||
<!--
|
||||
The instream, outstream is the name of the stream and channel to use. The stream
|
||||
name is the same you configured in the <streams> section. This parameters follow
|
||||
the syntax <stream-name>:<channel index>. You can omit either the outstream
|
||||
or the instream, but not both! The channel index is zero-based and must be consistent
|
||||
with the number of channels available for that stream (as configured in the <stream> section).
|
||||
You cannot use index 1 if you chose channels=1 in the stream configuration.
|
||||
-->
|
||||
<param name="instream" value="default:0" />
|
||||
<param name="outstream" value="default:0" />
|
||||
</endpoint>
|
||||
|
||||
<!--
|
||||
This endpoint uses the USB stream defined previously in the <streams> section and
|
||||
is 'send-only' or 'output-only' and uses the channel index 0 (left channel in a stereo device)
|
||||
-->
|
||||
<endpoint name="usb1out-left">
|
||||
<param name="outstream" value="usb1:0" />
|
||||
</endpoint>
|
||||
|
||||
<!--
|
||||
This endpoint uses the USB stream defined previously in the <streams> section and
|
||||
is 'send-only' or 'output-only' and uses the channel index 1 (right channel in a stereo device)
|
||||
-->
|
||||
<endpoint name="usb1out-right">
|
||||
<param name="outstream" value="usb1:1" />
|
||||
</endpoint>
|
||||
|
||||
<!--
|
||||
This endpoint uses the USB stream defined previously in the <streams> section and
|
||||
is 'receive-only' or 'input-only' and uses the channel index 0 (left channel in a stereo device)
|
||||
-->
|
||||
<endpoint name="usb1in-left">
|
||||
<param name="instream" value="usb1:0" />
|
||||
</endpoint>
|
||||
|
||||
<!--
|
||||
This endpoint uses the USB stream defined previously in the <streams> section and
|
||||
is 'receive-only' or 'input-only' and uses the channel index 1 (right channel in a stereo device)
|
||||
-->
|
||||
<endpoint name="usb1in-right">
|
||||
<param name="instream" value="usb1:1" />
|
||||
</endpoint>
|
||||
|
||||
<!--
|
||||
This endpoint uses the USB stream defined previously in the <streams> section and
|
||||
is 'bidirectional' or 'send-receive' and uses the channel index 0 (left channel in a stereo device)
|
||||
-->
|
||||
<endpoint name="usb1-left">
|
||||
<param name="instream" value="usb1:0" />
|
||||
<param name="outstream" value="usb1:0" />
|
||||
</endpoint>
|
||||
|
||||
<!--
|
||||
This endpoint uses the USB stream defined previously in the <streams> section and
|
||||
is 'bidirectional' or 'send-receive' and uses the channel index 1 (right channel in a stereo device)
|
||||
-->
|
||||
<endpoint name="usb1-right">
|
||||
<param name="instream" value="usb1:1" />
|
||||
<param name="outstream" value="usb1:1" />
|
||||
</endpoint>
|
||||
|
||||
</endpoints>
|
||||
|
||||
</configuration>
|
||||
|
@@ -1,195 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectName>mod_PortAudio</ProjectName>
|
||||
<ProjectGuid>{5FD31A25-5D83-4794-8BEE-904DAD84CE71}</ProjectGuid>
|
||||
<RootNamespace>mod_PortAudio</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_release.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\..\..\w32\module_debug.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<CodeAnalysisRuleSet>NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<CodeAnalysisRuleSet>NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<CodeAnalysisRuleSet>NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<CodeAnalysisRuleSet>NativeMinimumRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\portaudio\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;ALLOW_SMP_DANGERS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<DisableSpecificWarnings>4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>/NODEFAULTLIB:LIMBCTD %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>ksuser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\..\libs\portaudio\winvc\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\portaudio\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;ALLOW_SMP_DANGERS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<DisableSpecificWarnings>4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>/NODEFAULTLIB:LIMBCTD %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>ksuser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\..\libs\portaudio\winvc\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\portaudio\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>ALLOW_SMP_DANGERS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<DisableSpecificWarnings>4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ksuser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\..\libs\portaudio\winvc\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Midl>
|
||||
<TargetEnvironment>X64</TargetEnvironment>
|
||||
</Midl>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(RootDir)%(Directory)..\..\..\..\libs\portaudio\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>ALLOW_SMP_DANGERS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<DisableSpecificWarnings>4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>ksuser.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\..\libs\portaudio\winvc\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<DataExecutionPrevention>
|
||||
</DataExecutionPrevention>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_PortAudio.c">
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">6011;4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">6011;4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">6011;4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">6011;4100;4101;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pa_ringbuffer.c" />
|
||||
<ClCompile Include="pablio.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pa_ringbuffer.h" />
|
||||
<ClInclude Include="pablio.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\libs\win32\apr\libapr.2017.vcxproj">
|
||||
<Project>{f6c55d93-b927-4483-bb69-15aef3dd2dff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\libs\win32\portaudio\portaudio.2017.vcxproj">
|
||||
<Project>{0a18a071-125e-442f-aff7-a3f68abecf99}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\..\w32\Library\FreeSwitchCore.2017.vcxproj">
|
||||
<Project>{202d7a4e-760d-4d0e-afa1-d7459ced30ff}</Project>
|
||||
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
File diff suppressed because it is too large
Load Diff
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
* $Id: pa_ringbuffer.c 1164 2006-12-21 15:34:50Z bjornroche $
|
||||
* Portable Audio I/O Library
|
||||
* Ring Buffer utility.
|
||||
*
|
||||
* Author: Phil Burk, http://www.softsynth.com
|
||||
* modified for SMP safety on Mac OS X by Bjorn Roche
|
||||
* modified for SMP safety on Linux by Leland Lucius
|
||||
* also, allowed for const where possible
|
||||
* Note that this is safe only for a single-thread reader and a
|
||||
* single-thread writer.
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The text above constitutes the entire PortAudio license; however,
|
||||
* the PortAudio community also makes the following non-binding requests:
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version. It is also
|
||||
* requested that these non-binding requests be included along with the
|
||||
* license above.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
@ingroup common_src
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "pa_ringbuffer.h"
|
||||
|
||||
/****************
|
||||
* First, we'll define some memory barrier primitives based on the system.
|
||||
* right now only OS X, FreeBSD, and Linux are supported. In addition to providing
|
||||
* memory barriers, these functions should ensure that data cached in registers
|
||||
* is written out to cache where it can be snooped by other CPUs. (ie, the volatile
|
||||
* keyword should not be required)
|
||||
*
|
||||
* the primitives that must be defined are:
|
||||
*
|
||||
* PaUtil_FullMemoryBarrier()
|
||||
* PaUtil_ReadMemoryBarrier()
|
||||
* PaUtil_WriteMemoryBarrier()
|
||||
*
|
||||
****************/
|
||||
#define __VIA_HACK__
|
||||
#if defined(__VIA_HACK__)
|
||||
#define NO_BARRIER
|
||||
#endif
|
||||
|
||||
#if defined(NO_BARRIER)
|
||||
# define PaUtil_FullMemoryBarrier()
|
||||
# define PaUtil_ReadMemoryBarrier()
|
||||
# define PaUtil_WriteMemoryBarrier()
|
||||
#else
|
||||
|
||||
#if defined(__APPLE__) //|| defined(__FreeBSD__)
|
||||
# include <libkern/OSAtomic.h>
|
||||
/* Here are the memory barrier functions. Mac OS X and FreeBSD only provide
|
||||
full memory barriers, so the three types of barriers are the same. */
|
||||
# define PaUtil_FullMemoryBarrier() OSMemoryBarrier()
|
||||
# define PaUtil_ReadMemoryBarrier() OSMemoryBarrier()
|
||||
# define PaUtil_WriteMemoryBarrier() OSMemoryBarrier()
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
/* GCC understands volatile asm and "memory" to mean it
|
||||
* should not reorder memory read/writes */
|
||||
# if defined( __PPC__ )
|
||||
# define PaUtil_FullMemoryBarrier() __asm__ volatile("sync":::"memory")
|
||||
# define PaUtil_ReadMemoryBarrier() __asm__ volatile("sync":::"memory")
|
||||
# define PaUtil_WriteMemoryBarrier() __asm__ volatile("sync":::"memory")
|
||||
# elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || defined( __i686__ ) || defined(__x86_64__)
|
||||
# define PaUtil_FullMemoryBarrier() __asm__ volatile("mfence":::"memory")
|
||||
# define PaUtil_ReadMemoryBarrier() __asm__ volatile("lfence":::"memory")
|
||||
# define PaUtil_WriteMemoryBarrier() __asm__ volatile("sfence":::"memory")
|
||||
# else
|
||||
# define PaUtil_FullMemoryBarrier()
|
||||
# define PaUtil_ReadMemoryBarrier()
|
||||
# define PaUtil_WriteMemoryBarrier()
|
||||
# endif
|
||||
#elif defined(_MSC_VER)
|
||||
# include <intrin.h>
|
||||
# pragma intrinsic(_ReadWriteBarrier)
|
||||
# pragma intrinsic(_ReadBarrier)
|
||||
# pragma intrinsic(_WriteBarrier)
|
||||
# define PaUtil_FullMemoryBarrier() _ReadWriteBarrier()
|
||||
# define PaUtil_ReadMemoryBarrier() _ReadBarrier()
|
||||
# define PaUtil_WriteMemoryBarrier() _WriteBarrier()
|
||||
#else
|
||||
# define PaUtil_FullMemoryBarrier()
|
||||
# define PaUtil_ReadMemoryBarrier()
|
||||
# define PaUtil_WriteMemoryBarrier()
|
||||
#endif
|
||||
#endif
|
||||
/***************************************************************************
|
||||
* Initialize FIFO.
|
||||
* numBytes must be power of 2, returns -1 if not.
|
||||
*/
|
||||
long PaUtil_InitializeRingBuffer(PaUtilRingBuffer * rbuf, long numBytes, void *dataPtr)
|
||||
{
|
||||
if (((numBytes - 1) & numBytes) != 0)
|
||||
return -1; /* Not Power of two. */
|
||||
rbuf->bufferSize = numBytes;
|
||||
rbuf->buffer = (char *) dataPtr;
|
||||
PaUtil_FlushRingBuffer(rbuf);
|
||||
rbuf->bigMask = (numBytes * 2) - 1;
|
||||
rbuf->smallMask = (numBytes) - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Return number of bytes available for reading. */
|
||||
long PaUtil_GetRingBufferReadAvailable(PaUtilRingBuffer * rbuf)
|
||||
{
|
||||
PaUtil_ReadMemoryBarrier();
|
||||
return ((rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Return number of bytes available for writing. */
|
||||
long PaUtil_GetRingBufferWriteAvailable(PaUtilRingBuffer * rbuf)
|
||||
{
|
||||
/* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */
|
||||
return (rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf));
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Clear buffer. Should only be called when buffer is NOT being read. */
|
||||
void PaUtil_FlushRingBuffer(PaUtilRingBuffer * rbuf)
|
||||
{
|
||||
rbuf->writeIndex = rbuf->readIndex = 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Get address of region(s) to which we can write data.
|
||||
** If the region is contiguous, size2 will be zero.
|
||||
** If non-contiguous, size2 will be the size of second region.
|
||||
** Returns room available to be written or numBytes, whichever is smaller.
|
||||
*/
|
||||
long PaUtil_GetRingBufferWriteRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2)
|
||||
{
|
||||
long index;
|
||||
long available = PaUtil_GetRingBufferWriteAvailable(rbuf);
|
||||
if (numBytes > available)
|
||||
numBytes = available;
|
||||
/* Check to see if write is not contiguous. */
|
||||
index = rbuf->writeIndex & rbuf->smallMask;
|
||||
if ((index + numBytes) > rbuf->bufferSize) {
|
||||
/* Write data in two blocks that wrap the buffer. */
|
||||
long firstHalf = rbuf->bufferSize - index;
|
||||
*dataPtr1 = &rbuf->buffer[index];
|
||||
*sizePtr1 = firstHalf;
|
||||
*dataPtr2 = &rbuf->buffer[0];
|
||||
*sizePtr2 = numBytes - firstHalf;
|
||||
} else {
|
||||
*dataPtr1 = &rbuf->buffer[index];
|
||||
*sizePtr1 = numBytes;
|
||||
*dataPtr2 = NULL;
|
||||
*sizePtr2 = 0;
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
*/
|
||||
long PaUtil_AdvanceRingBufferWriteIndex(PaUtilRingBuffer * rbuf, long numBytes)
|
||||
{
|
||||
/* we need to ensure that previous writes are seen before we update the write index */
|
||||
PaUtil_WriteMemoryBarrier();
|
||||
return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Get address of region(s) from which we can read data.
|
||||
** If the region is contiguous, size2 will be zero.
|
||||
** If non-contiguous, size2 will be the size of second region.
|
||||
** Returns room available to be written or numBytes, whichever is smaller.
|
||||
*/
|
||||
long PaUtil_GetRingBufferReadRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2)
|
||||
{
|
||||
long index;
|
||||
long available = PaUtil_GetRingBufferReadAvailable(rbuf);
|
||||
if (numBytes > available)
|
||||
numBytes = available;
|
||||
/* Check to see if read is not contiguous. */
|
||||
index = rbuf->readIndex & rbuf->smallMask;
|
||||
if ((index + numBytes) > rbuf->bufferSize) {
|
||||
/* Write data in two blocks that wrap the buffer. */
|
||||
long firstHalf = rbuf->bufferSize - index;
|
||||
*dataPtr1 = &rbuf->buffer[index];
|
||||
*sizePtr1 = firstHalf;
|
||||
*dataPtr2 = &rbuf->buffer[0];
|
||||
*sizePtr2 = numBytes - firstHalf;
|
||||
} else {
|
||||
*dataPtr1 = &rbuf->buffer[index];
|
||||
*sizePtr1 = numBytes;
|
||||
*dataPtr2 = NULL;
|
||||
*sizePtr2 = 0;
|
||||
}
|
||||
return numBytes;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*/
|
||||
long PaUtil_AdvanceRingBufferReadIndex(PaUtilRingBuffer * rbuf, long numBytes)
|
||||
{
|
||||
/* we need to ensure that previous writes are always seen before updating the index. */
|
||||
PaUtil_WriteMemoryBarrier();
|
||||
return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Return bytes written. */
|
||||
long PaUtil_WriteRingBuffer(PaUtilRingBuffer * rbuf, const void *data, long numBytes)
|
||||
{
|
||||
long size1, size2, numWritten;
|
||||
void *data1, *data2;
|
||||
numWritten = PaUtil_GetRingBufferWriteRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
|
||||
if (size2 > 0) {
|
||||
|
||||
memcpy(data1, data, size1);
|
||||
data = ((char *) data) + size1;
|
||||
memcpy(data2, data, size2);
|
||||
} else {
|
||||
memcpy(data1, data, size1);
|
||||
}
|
||||
PaUtil_AdvanceRingBufferWriteIndex(rbuf, numWritten);
|
||||
return numWritten;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
** Return bytes read. */
|
||||
long PaUtil_ReadRingBuffer(PaUtilRingBuffer * rbuf, void *data, long numBytes)
|
||||
{
|
||||
long size1, size2, numRead;
|
||||
void *data1, *data2;
|
||||
numRead = PaUtil_GetRingBufferReadRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
|
||||
if (size2 > 0) {
|
||||
memcpy(data, data1, size1);
|
||||
data = ((char *) data) + size1;
|
||||
memcpy(data, data2, size2);
|
||||
} else {
|
||||
memcpy(data, data1, size1);
|
||||
}
|
||||
PaUtil_AdvanceRingBufferReadIndex(rbuf, numRead);
|
||||
return numRead;
|
||||
}
|
@@ -1,192 +0,0 @@
|
||||
#ifndef PA_RINGBUFFER_H
|
||||
#define PA_RINGBUFFER_H
|
||||
/*
|
||||
* $Id: pa_ringbuffer.h 1151 2006-11-29 02:11:16Z leland_lucius $
|
||||
* Portable Audio I/O Library
|
||||
* Ring Buffer utility.
|
||||
*
|
||||
* Author: Phil Burk, http://www.softsynth.com
|
||||
* modified for SMP safety on OS X by Bjorn Roche.
|
||||
* also allowed for const where possible.
|
||||
* Note that this is safe only for a single-thread reader
|
||||
* and a single-thread writer.
|
||||
*
|
||||
* This program is distributed with the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The text above constitutes the entire PortAudio license; however,
|
||||
* the PortAudio community also makes the following non-binding requests:
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version. It is also
|
||||
* requested that these non-binding requests be included along with the
|
||||
* license above.
|
||||
*/
|
||||
|
||||
/** @file
|
||||
@ingroup common_src
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct PaUtilRingBuffer {
|
||||
long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */
|
||||
long writeIndex; /* Index of next writable byte. Set by PaUtil_AdvanceRingBufferWriteIndex. */
|
||||
long readIndex; /* Index of next readable byte. Set by PaUtil_AdvanceRingBufferReadIndex. */
|
||||
long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
|
||||
long smallMask; /* Used for fitting indices to buffer. */
|
||||
char *buffer;
|
||||
} PaUtilRingBuffer;
|
||||
|
||||
/** Initialize Ring Buffer.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@param numBytes The number of bytes in the buffer and must be power of 2.
|
||||
|
||||
@param dataPtr A pointer to a previously allocated area where the data
|
||||
will be maintained. It must be numBytes long.
|
||||
|
||||
@return -1 if numBytes is not a power of 2, otherwise 0.
|
||||
*/
|
||||
long PaUtil_InitializeRingBuffer(PaUtilRingBuffer * rbuf, long numBytes, void *dataPtr);
|
||||
|
||||
/** Clear buffer. Should only be called when buffer is NOT being read.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
*/
|
||||
void PaUtil_FlushRingBuffer(PaUtilRingBuffer * rbuf);
|
||||
|
||||
/** Retrieve the number of bytes available in the ring buffer for writing.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@return The number of bytes available for writing.
|
||||
*/
|
||||
long PaUtil_GetRingBufferWriteAvailable(PaUtilRingBuffer * rbuf);
|
||||
|
||||
/** Retrieve the number of bytes available in the ring buffer for reading.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@return The number of bytes available for reading.
|
||||
*/
|
||||
long PaUtil_GetRingBufferReadAvailable(PaUtilRingBuffer * rbuf);
|
||||
|
||||
/** Write data to the ring buffer.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@param data The address of new data to write to the buffer.
|
||||
|
||||
@param numBytes The number of bytes to be written.
|
||||
|
||||
@return The number of bytes written.
|
||||
*/
|
||||
long PaUtil_WriteRingBuffer(PaUtilRingBuffer * rbuf, const void *data, long numBytes);
|
||||
|
||||
/** Read data from the ring buffer.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@param data The address where the data should be stored.
|
||||
|
||||
@param numBytes The number of bytes to be read.
|
||||
|
||||
@return The number of bytes read.
|
||||
*/
|
||||
long PaUtil_ReadRingBuffer(PaUtilRingBuffer * rbuf, void *data, long numBytes);
|
||||
|
||||
/** Get address of region(s) to which we can write data.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@param numBytes The number of bytes desired.
|
||||
|
||||
@param dataPtr1 The address where the first (or only) region pointer will be
|
||||
stored.
|
||||
|
||||
@param sizePtr1 The address where the first (or only) region length will be
|
||||
stored.
|
||||
|
||||
@param dataPtr2 The address where the second region pointer will be stored if
|
||||
the first region is too small to satisfy numBytes.
|
||||
|
||||
@param sizePtr2 The address where the second region length will be stored if
|
||||
the first region is too small to satisfy numBytes.
|
||||
|
||||
@return The room available to be written or numBytes, whichever is smaller.
|
||||
*/
|
||||
long PaUtil_GetRingBufferWriteRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2);
|
||||
|
||||
/** Advance the write index to the next location to be written.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@param numBytes The number of bytes to advance.
|
||||
|
||||
@return The new position.
|
||||
*/
|
||||
long PaUtil_AdvanceRingBufferWriteIndex(PaUtilRingBuffer * rbuf, long numBytes);
|
||||
|
||||
/** Get address of region(s) from which we can write data.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@param numBytes The number of bytes desired.
|
||||
|
||||
@param dataPtr1 The address where the first (or only) region pointer will be
|
||||
stored.
|
||||
|
||||
@param sizePtr1 The address where the first (or only) region length will be
|
||||
stored.
|
||||
|
||||
@param dataPtr2 The address where the second region pointer will be stored if
|
||||
the first region is too small to satisfy numBytes.
|
||||
|
||||
@param sizePtr2 The address where the second region length will be stored if
|
||||
the first region is too small to satisfy numBytes.
|
||||
|
||||
@return The number of bytes available for reading.
|
||||
*/
|
||||
long PaUtil_GetRingBufferReadRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2);
|
||||
|
||||
/** Advance the read index to the next location to be read.
|
||||
|
||||
@param rbuf The ring buffer.
|
||||
|
||||
@param numBytes The number of bytes to advance.
|
||||
|
||||
@return The new position.
|
||||
*/
|
||||
long PaUtil_AdvanceRingBufferReadIndex(PaUtilRingBuffer * rbuf, long numBytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* PA_RINGBUFFER_H */
|
@@ -1,442 +0,0 @@
|
||||
/*
|
||||
* $Id: pablio.c 1151 2006-11-29 02:11:16Z leland_lucius $
|
||||
* pablio.c
|
||||
* Portable Audio Blocking Input/Output utility.
|
||||
*
|
||||
* Author: Phil Burk, http://www.softsynth.com
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The text above constitutes the entire PortAudio license; however,
|
||||
* the PortAudio community also makes the following non-binding requests:
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version. It is also
|
||||
* requested that these non-binding requests be included along with the
|
||||
* license above.
|
||||
*/
|
||||
|
||||
#include <switch.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <portaudio.h>
|
||||
#include "pa_ringbuffer.h"
|
||||
#include "pablio.h"
|
||||
|
||||
/************************************************************************/
|
||||
/******** Prototypes ****************************************************/
|
||||
/************************************************************************/
|
||||
|
||||
static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags,
|
||||
void *userData);
|
||||
static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo,
|
||||
PaStreamCallbackFlags statusFlags, void *userData);
|
||||
|
||||
static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags,
|
||||
void *userData);
|
||||
|
||||
static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame);
|
||||
static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf);
|
||||
|
||||
/************************************************************************/
|
||||
/******** Functions *****************************************************/
|
||||
/************************************************************************/
|
||||
|
||||
/* Called from PortAudio.
|
||||
* Read and write data
|
||||
*/
|
||||
static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
|
||||
{
|
||||
int c = 0, i = 0, j = 0;
|
||||
PABLIO_Stream *data = (PABLIO_Stream *) userData;
|
||||
long numBytes = data->bytesPerFrame * framesPerBuffer;
|
||||
const int16_t *inputSamples = inputBuffer;
|
||||
int16_t *chanSamples = (int16_t*)data->iobuff;
|
||||
|
||||
/* This may get called with NULL inputBuffer during initial setup. */
|
||||
if (inputBuffer != NULL) {
|
||||
/* retrieve the data for each channel and put it in the ring buffer */
|
||||
for (c = 0; c < data->channelCount; c++) {
|
||||
for (i = 0, j = c; i < (int)framesPerBuffer; j += data->channelCount, i++) {
|
||||
chanSamples[i] = inputSamples[j];
|
||||
}
|
||||
if (PaUtil_WriteRingBuffer(&data->inFIFOs[c], chanSamples, numBytes) != numBytes) {
|
||||
PaUtil_FlushRingBuffer(&data->inFIFOs[c]);
|
||||
PaUtil_WriteRingBuffer(&data->inFIFOs[c], chanSamples, numBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
|
||||
{
|
||||
PABLIO_Stream *data = (PABLIO_Stream *) userData;
|
||||
long numBytes = data->bytesPerFrame * framesPerBuffer;
|
||||
int16_t *outputSamples = outputBuffer;
|
||||
int16_t *chanSamples = (short *)data->iobuff;
|
||||
int c = 0, i = 0, j = 0;
|
||||
|
||||
if (outputBuffer != NULL) {
|
||||
for (c = 0; c < data->channelCount; c++) {
|
||||
int numRead = PaUtil_ReadRingBuffer(&data->outFIFOs[c], chanSamples, numBytes);
|
||||
numRead = numRead / sizeof(int16_t);
|
||||
for (i = 0, j = c; i < (int)framesPerBuffer; j += data->channelCount, i++) {
|
||||
if (i < numRead) {
|
||||
outputSamples[j] = chanSamples[i];
|
||||
} else {
|
||||
outputSamples[j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags,
|
||||
void *userData)
|
||||
{
|
||||
iblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
|
||||
oblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate buffer. */
|
||||
static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame)
|
||||
{
|
||||
long numBytes = numFrames * bytesPerFrame;
|
||||
char *buffer = (char *) malloc(numBytes);
|
||||
if (buffer == NULL)
|
||||
return paInsufficientMemory;
|
||||
memset(buffer, 0, numBytes);
|
||||
return (PaError) PaUtil_InitializeRingBuffer(rbuf, numBytes, buffer);
|
||||
}
|
||||
|
||||
/* Free buffer. */
|
||||
static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf)
|
||||
{
|
||||
if (rbuf->buffer)
|
||||
free(rbuf->buffer);
|
||||
rbuf->buffer = NULL;
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Write data to ring buffer.
|
||||
* Will not return until all the data has been written.
|
||||
*/
|
||||
long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, switch_timer_t *timer)
|
||||
{
|
||||
long bytesWritten;
|
||||
char *p = (char *) data;
|
||||
long numBytes = aStream->bytesPerFrame * numFrames;
|
||||
|
||||
switch_core_timer_next(timer);
|
||||
|
||||
bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFOs[chan], p, numBytes);
|
||||
numBytes -= bytesWritten;
|
||||
|
||||
if (numBytes > 0) {
|
||||
PaUtil_FlushRingBuffer(&aStream->outFIFOs[chan]);
|
||||
return 0;
|
||||
}
|
||||
return numFrames;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Read data from ring buffer.
|
||||
* Will not return until all the data has been read.
|
||||
*/
|
||||
long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, switch_timer_t *timer)
|
||||
{
|
||||
long bytesRead = 0;
|
||||
char *p = (char *) data;
|
||||
long avail, totalBytes = 0, neededBytes = aStream->bytesPerFrame * numFrames;
|
||||
int max = 5000;
|
||||
|
||||
switch_core_timer_next(timer);
|
||||
|
||||
while (totalBytes < neededBytes && --max > 0) {
|
||||
|
||||
avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[chan]);
|
||||
//printf("AVAILABLE BYTES %ld pass %d\n", avail, 5000 - max);
|
||||
if (avail >= neededBytes * 6) {
|
||||
PaUtil_FlushRingBuffer(&aStream->inFIFOs[chan]);
|
||||
} else {
|
||||
|
||||
bytesRead = 0;
|
||||
|
||||
if (totalBytes < neededBytes && avail >= neededBytes) {
|
||||
bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFOs[chan], p, neededBytes);
|
||||
totalBytes += bytesRead;
|
||||
}
|
||||
|
||||
if (bytesRead) {
|
||||
p += bytesRead;
|
||||
} else {
|
||||
switch_cond_next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return totalBytes / aStream->bytesPerFrame;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Return the number of frames that could be written to the stream without
|
||||
* having to wait.
|
||||
*/
|
||||
long GetAudioStreamWriteable(PABLIO_Stream * aStream, int chan)
|
||||
{
|
||||
int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[chan]);
|
||||
return bytesEmpty / aStream->bytesPerFrame;
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Return the number of frames that are available to be read from the
|
||||
* stream without having to wait.
|
||||
*/
|
||||
long GetAudioStreamReadable(PABLIO_Stream * aStream, int chan)
|
||||
{
|
||||
int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFOs[chan]);
|
||||
return bytesFull / aStream->bytesPerFrame;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
static unsigned long RoundUpToNextPowerOf2(unsigned long n)
|
||||
{
|
||||
long numBits = 0;
|
||||
if (((n - 1) & n) == 0)
|
||||
return n;
|
||||
while (n > 0) {
|
||||
n = n >> 1;
|
||||
numBits++;
|
||||
}
|
||||
return (1 << numBits);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/************************************************************
|
||||
* Opens a PortAudio stream with default characteristics.
|
||||
* Allocates PABLIO_Stream structure.
|
||||
*
|
||||
*/
|
||||
PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
|
||||
const PaStreamParameters * inputParameters,
|
||||
const PaStreamParameters * outputParameters, double sampleRate, PaStreamFlags streamFlags, long samples_per_packet, int do_dual)
|
||||
{
|
||||
long bytesPerSample = 2;
|
||||
PaError err;
|
||||
PABLIO_Stream *aStream;
|
||||
long numFrames;
|
||||
//long numBytes;
|
||||
int c = 0;
|
||||
int channels = 1;
|
||||
|
||||
if (!(inputParameters || outputParameters)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate PABLIO_Stream structure for caller. */
|
||||
aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
|
||||
switch_assert(aStream);
|
||||
memset(aStream, 0, sizeof(PABLIO_Stream));
|
||||
|
||||
if (inputParameters) {
|
||||
channels = inputParameters->channelCount;
|
||||
} else if (outputParameters) {
|
||||
channels = outputParameters->channelCount;
|
||||
}
|
||||
|
||||
numFrames = RoundUpToNextPowerOf2(samples_per_packet * 5);
|
||||
aStream->bytesPerFrame = bytesPerSample;
|
||||
aStream->channelCount = channels;
|
||||
|
||||
/* Initialize Ring Buffers */
|
||||
|
||||
if (inputParameters) {
|
||||
for (c = 0; c < channels; c++) {
|
||||
err = PABLIO_InitFIFO(&aStream->inFIFOs[c], numFrames, aStream->bytesPerFrame);
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
aStream->has_in = 1;
|
||||
}
|
||||
|
||||
if (outputParameters) {
|
||||
for (c = 0; c < channels; c++) {
|
||||
err = PABLIO_InitFIFO(&aStream->outFIFOs[c], numFrames, aStream->bytesPerFrame);
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
aStream->has_out = 1;
|
||||
}
|
||||
|
||||
/* Open a PortAudio stream that we will use to communicate with the underlying
|
||||
* audio drivers. */
|
||||
|
||||
aStream->do_dual = do_dual;
|
||||
|
||||
if (aStream->do_dual) {
|
||||
err = Pa_OpenStream(&aStream->istream, inputParameters, NULL, sampleRate, samples_per_packet, streamFlags, iblockingIOCallback, aStream);
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
err = Pa_OpenStream(&aStream->ostream, NULL, outputParameters, sampleRate, samples_per_packet, streamFlags, oblockingIOCallback, aStream);
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
err =
|
||||
Pa_OpenStream(&aStream->iostream, inputParameters, outputParameters, sampleRate, samples_per_packet, streamFlags, ioblockingIOCallback,
|
||||
aStream);
|
||||
}
|
||||
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (aStream->do_dual) {
|
||||
err = Pa_StartStream(aStream->istream);
|
||||
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = Pa_StartStream(aStream->ostream);
|
||||
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
} else {
|
||||
err = Pa_StartStream(aStream->iostream);
|
||||
}
|
||||
|
||||
if (err != paNoError) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
*rwblPtr = aStream;
|
||||
|
||||
switch_yield(500000);
|
||||
|
||||
return paNoError;
|
||||
|
||||
error:
|
||||
|
||||
CloseAudioStream(aStream);
|
||||
|
||||
*rwblPtr = NULL;
|
||||
return err;
|
||||
}
|
||||
|
||||
/************************************************************/
|
||||
PaError CloseAudioStream(PABLIO_Stream * aStream)
|
||||
{
|
||||
int bytesEmpty;
|
||||
int byteSize;
|
||||
int c = 0;
|
||||
|
||||
|
||||
if (aStream->has_out) {
|
||||
|
||||
for (c = 0; c < aStream->channelCount; c++) {
|
||||
byteSize = aStream->outFIFOs[c].bufferSize;
|
||||
|
||||
/* If we are writing data, make sure we play everything written. */
|
||||
if (byteSize > 0) {
|
||||
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[c]);
|
||||
while (bytesEmpty < byteSize) {
|
||||
Pa_Sleep(10);
|
||||
bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFOs[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (aStream->do_dual) {
|
||||
if (aStream->has_in && aStream->istream) {
|
||||
if (Pa_IsStreamActive(aStream->istream)) {
|
||||
Pa_StopStream(aStream->istream);
|
||||
}
|
||||
|
||||
Pa_CloseStream(aStream->istream);
|
||||
aStream->istream = NULL;
|
||||
}
|
||||
|
||||
if (aStream->has_out && aStream->ostream) {
|
||||
if (Pa_IsStreamActive(aStream->ostream)) {
|
||||
Pa_StopStream(aStream->ostream);
|
||||
}
|
||||
|
||||
Pa_CloseStream(aStream->ostream);
|
||||
aStream->ostream = NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (aStream->iostream) {
|
||||
if (Pa_IsStreamActive(aStream->iostream)) {
|
||||
Pa_StopStream(aStream->iostream);
|
||||
}
|
||||
|
||||
Pa_CloseStream(aStream->iostream);
|
||||
aStream->iostream = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (aStream->has_in) {
|
||||
for (c = 0; c < aStream->channelCount; c++) {
|
||||
PABLIO_TermFIFO(&aStream->inFIFOs[c]);
|
||||
}
|
||||
}
|
||||
|
||||
if (aStream->has_out) {
|
||||
for (c = 0; c < aStream->channelCount; c++) {
|
||||
PABLIO_TermFIFO(&aStream->outFIFOs[c]);
|
||||
}
|
||||
}
|
||||
|
||||
free(aStream);
|
||||
switch_yield(500000);
|
||||
|
||||
return paNoError;
|
||||
}
|
||||
|
@@ -1,132 +0,0 @@
|
||||
#ifndef PORTAUDIO_PABLIO_H
|
||||
#define PORTAUDIO_PABLIO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* $Id: pablio.h 1083 2006-08-23 07:30:49Z rossb $
|
||||
* PABLIO.h
|
||||
* Portable Audio Blocking read/write utility.
|
||||
*
|
||||
* Author: Phil Burk, http://www.softsynth.com/portaudio/
|
||||
*
|
||||
* Include file for PABLIO, the Portable Audio Blocking I/O Library.
|
||||
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The text above constitutes the entire PortAudio license; however,
|
||||
* the PortAudio community also makes the following non-binding requests:
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version. It is also
|
||||
* requested that these non-binding requests be included along with the
|
||||
* license above.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <portaudio.h>
|
||||
#include "pa_ringbuffer.h"
|
||||
|
||||
/*! Maximum number of channels per stream */
|
||||
#define MAX_IO_CHANNELS 2
|
||||
|
||||
/*! Maximum numer of milliseconds per packet */
|
||||
#define MAX_IO_MS 100
|
||||
|
||||
/*! Maximum sampling rate (48Khz) */
|
||||
#define MAX_SAMPLING_RATE 48000
|
||||
|
||||
/* Maximum size of a read */
|
||||
#define MAX_IO_BUFFER (((MAX_IO_MS * MAX_SAMPLING_RATE)/1000)*sizeof(int16_t))
|
||||
typedef struct {
|
||||
PaStream *istream;
|
||||
PaStream *ostream;
|
||||
PaStream *iostream;
|
||||
int bytesPerFrame;
|
||||
int do_dual;
|
||||
int has_in;
|
||||
int has_out;
|
||||
PaUtilRingBuffer inFIFOs[MAX_IO_CHANNELS];
|
||||
PaUtilRingBuffer outFIFOs[MAX_IO_CHANNELS];
|
||||
int channelCount;
|
||||
char iobuff[MAX_IO_BUFFER];
|
||||
} PABLIO_Stream;
|
||||
|
||||
/* Values for flags for OpenAudioStream(). */
|
||||
#define PABLIO_READ (1<<0)
|
||||
#define PABLIO_WRITE (1<<1)
|
||||
#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
|
||||
#define PABLIO_MONO (1<<2)
|
||||
#define PABLIO_STEREO (1<<3)
|
||||
|
||||
/************************************************************
|
||||
* Write data to ring buffer.
|
||||
* Will not return until all the data has been written.
|
||||
*/
|
||||
long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, switch_timer_t *timer);
|
||||
|
||||
/************************************************************
|
||||
* Read data from ring buffer.
|
||||
* Will not return until all the data has been read.
|
||||
*/
|
||||
long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, int chan, switch_timer_t *timer);
|
||||
|
||||
/************************************************************
|
||||
* Return the number of frames that could be written to the stream without
|
||||
* having to wait.
|
||||
*/
|
||||
long GetAudioStreamWriteable(PABLIO_Stream * aStream, int chan);
|
||||
|
||||
/************************************************************
|
||||
* Return the number of frames that are available to be read from the
|
||||
* stream without having to wait.
|
||||
*/
|
||||
long GetAudioStreamReadable(PABLIO_Stream * aStream, int chan);
|
||||
|
||||
/************************************************************
|
||||
* Opens a PortAudio stream with default characteristics.
|
||||
* Allocates PABLIO_Stream structure.
|
||||
*
|
||||
* flags parameter can be an ORed combination of:
|
||||
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
|
||||
* and either PABLIO_MONO or PABLIO_STEREO
|
||||
*/
|
||||
PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
|
||||
const PaStreamParameters * inputParameters,
|
||||
const PaStreamParameters * outputParameters,
|
||||
double sampleRate, PaStreamCallbackFlags statusFlags, long samples_per_packet, int do_dual);
|
||||
|
||||
PaError CloseAudioStream(PABLIO_Stream * aStream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* _PABLIO_H */
|
@@ -1,20 +0,0 @@
|
||||
include $(top_srcdir)/build/modmake.rulesam
|
||||
MODNAME=mod_portaudio_stream
|
||||
MODPA_DIR=$(switch_srcdir)/src/mod/endpoints/mod_portaudio
|
||||
|
||||
if HAVE_PORTAUDIO
|
||||
mod_LTLIBRARIES = mod_portaudio_stream.la
|
||||
mod_portaudio_stream_la_SOURCES = mod_portaudio_stream.c ../../endpoints/mod_portaudio/pablio.c ../../endpoints/mod_portaudio/pa_ringbuffer.c
|
||||
mod_portaudio_stream_la_CFLAGS = $(AM_CFLAGS)
|
||||
mod_portaudio_stream_la_CPPFLAGS = -I. -I$(MODPA_DIR) $(PORTAUDIO_CFLAGS) $(AM_CPPFLAGS)
|
||||
mod_portaudio_stream_la_LIBADD = $(PORTAUDIO_LIBS) $(switch_builddir)/libfreeswitch.la
|
||||
mod_portaudio_stream_la_LDFLAGS = -avoid-version -module -no-undefined -shared
|
||||
if ISMAC
|
||||
mod_portaudio_stream_la_LDFLAGS += -framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon
|
||||
endif
|
||||
else
|
||||
install: error
|
||||
all: error
|
||||
error:
|
||||
$(error You must install portaudio19-dev to build $(MODNAME))
|
||||
endif
|
@@ -1,615 +0,0 @@
|
||||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthm@freeswitch.org>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* mod_portaudio_stream.c -- Portaudio Streaming interface Audio
|
||||
*
|
||||
*/
|
||||
#include "switch.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "pablio.h"
|
||||
|
||||
#define DEFAULT_PREBUFFER_SIZE 1024 * 64
|
||||
#define SAMPLE_TYPE paInt16
|
||||
#define PREFERRED_RATE 8000
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_stream_load);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_stream_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_portaudio_stream, mod_portaudio_stream_load, mod_portaudio_stream_shutdown, NULL);
|
||||
static switch_memory_pool_t *module_pool = NULL;
|
||||
|
||||
struct portaudio_stream_source;
|
||||
|
||||
static struct {
|
||||
int running;
|
||||
int threads;
|
||||
switch_mutex_t *mutex;
|
||||
switch_hash_t *source_hash;
|
||||
|
||||
} globals;
|
||||
|
||||
|
||||
struct portaudio_stream_context {
|
||||
struct portaudio_stream_source *source;
|
||||
switch_mutex_t *audio_mutex;
|
||||
switch_buffer_t *audio_buffer;
|
||||
int err;
|
||||
const char *func;
|
||||
const char *file;
|
||||
int line;
|
||||
switch_file_handle_t *handle;
|
||||
struct portaudio_stream_context *next;
|
||||
};
|
||||
|
||||
typedef struct portaudio_stream_context portaudio_stream_context_t;
|
||||
|
||||
struct portaudio_stream_source {
|
||||
char *sourcename;
|
||||
int sourcedev;
|
||||
int rate;
|
||||
int interval;
|
||||
char *timer_name;
|
||||
int total;
|
||||
int ready;
|
||||
int stopped;
|
||||
uint8_t channels;
|
||||
switch_size_t samples;
|
||||
uint32_t prebuf;
|
||||
portaudio_stream_context_t *context_list;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
switch_thread_rwlock_t *rwlock;
|
||||
PABLIO_Stream *audio_stream;
|
||||
switch_frame_t read_frame;
|
||||
switch_timer_t timer;
|
||||
switch_codec_t read_codec;
|
||||
switch_codec_t write_codec;
|
||||
switch_mutex_t *device_lock;
|
||||
unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
|
||||
};
|
||||
|
||||
typedef struct portaudio_stream_source portaudio_stream_source_t;
|
||||
|
||||
|
||||
|
||||
static int get_dev_by_number(char *numstr, int in)
|
||||
{
|
||||
int numDevices = Pa_GetDeviceCount();
|
||||
const PaDeviceInfo *pdi;
|
||||
char *end_ptr;
|
||||
int number;
|
||||
|
||||
number = (int) strtol(numstr, &end_ptr, 10);
|
||||
|
||||
if (end_ptr == numstr || number < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (number > -1 && number < numDevices && (pdi = Pa_GetDeviceInfo(number))) {
|
||||
if (in && pdi->maxInputChannels) {
|
||||
return number;
|
||||
} else if (!in && pdi->maxOutputChannels) {
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_dev_by_name(char *name, int in)
|
||||
{
|
||||
int i;
|
||||
int numDevices;
|
||||
const PaDeviceInfo *pdi;
|
||||
numDevices = Pa_GetDeviceCount();
|
||||
|
||||
if (numDevices < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices);
|
||||
return -2;
|
||||
}
|
||||
|
||||
for (i = 0; i < numDevices; i++) {
|
||||
int match = 0;
|
||||
pdi = Pa_GetDeviceInfo(i);
|
||||
|
||||
if (zstr(name)) {
|
||||
match = 1;
|
||||
} else if (pdi && pdi->name && strstr(pdi->name, name)) {
|
||||
match = 1;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
if (in && pdi->maxInputChannels) {
|
||||
return i;
|
||||
} else if (!in && pdi->maxOutputChannels) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static switch_status_t engage_device(portaudio_stream_source_t *source, int restart)
|
||||
{
|
||||
PaStreamParameters inputParameters, outputParameters;
|
||||
PaError err;
|
||||
int sample_rate = source->rate;
|
||||
int codec_ms = source->interval;
|
||||
|
||||
switch_mutex_init(&source->device_lock, SWITCH_MUTEX_NESTED, module_pool);
|
||||
|
||||
if (source->timer.timer_interface) {
|
||||
switch_core_timer_sync(&source->timer);
|
||||
}
|
||||
|
||||
if (source->audio_stream) {
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!switch_core_codec_ready(&source->read_codec)) {
|
||||
if (switch_core_codec_init(&source->read_codec,
|
||||
"L16",
|
||||
NULL, NULL, sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
|
||||
NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
switch_assert(source->read_codec.implementation);
|
||||
|
||||
if (!switch_core_codec_ready(&source->write_codec)) {
|
||||
if (switch_core_codec_init(&source->write_codec,
|
||||
"L16",
|
||||
NULL, NULL,
|
||||
sample_rate, codec_ms, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
|
||||
switch_core_codec_destroy(&source->read_codec);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!source->timer.timer_interface) {
|
||||
if (switch_core_timer_init(&source->timer,
|
||||
source->timer_name, codec_ms, source->read_codec.implementation->samples_per_packet,
|
||||
module_pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "setup timer failed!\n");
|
||||
switch_core_codec_destroy(&source->read_codec);
|
||||
switch_core_codec_destroy(&source->write_codec);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
source->read_frame.rate = sample_rate;
|
||||
source->read_frame.codec = &source->read_codec;
|
||||
|
||||
switch_mutex_lock(source->device_lock);
|
||||
/* LOCKED ************************************************************************************************** */
|
||||
inputParameters.device = source->sourcedev;
|
||||
inputParameters.channelCount = 1;
|
||||
inputParameters.sampleFormat = SAMPLE_TYPE;
|
||||
inputParameters.suggestedLatency = Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency;
|
||||
inputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
outputParameters.device = source->sourcedev;
|
||||
outputParameters.channelCount = 1;
|
||||
outputParameters.sampleFormat = SAMPLE_TYPE;
|
||||
outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency;
|
||||
outputParameters.hostApiSpecificStreamInfo = NULL;
|
||||
|
||||
|
||||
err = OpenAudioStream(&source->audio_stream, &inputParameters, NULL, sample_rate, paClipOff, source->read_codec.implementation->samples_per_packet, 0);
|
||||
/* UNLOCKED ************************************************************************************************* */
|
||||
if (err != paNoError) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening audio device retrying\n");
|
||||
switch_yield(1000000);
|
||||
err = OpenAudioStream(&source->audio_stream, &inputParameters, &outputParameters, sample_rate, paClipOff,
|
||||
source->read_codec.implementation->samples_per_packet, 0);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(source->device_lock);
|
||||
if (err != paNoError) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open audio device\n");
|
||||
switch_core_codec_destroy(&source->read_codec);
|
||||
switch_core_timer_destroy(&source->timer);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
portaudio_stream_source_t *source = obj;
|
||||
portaudio_stream_context_t *cp;
|
||||
int samples;
|
||||
int bused, bytesToWrite;
|
||||
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.threads++;
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
if (!source->prebuf) {
|
||||
source->prebuf = DEFAULT_PREBUFFER_SIZE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
switch_core_hash_insert(globals.source_hash, source->sourcename, source);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
|
||||
switch_thread_rwlock_create(&source->rwlock, source->pool);
|
||||
|
||||
if (engage_device(source, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, " Dev %d cant be engaged !\n", (int) source->sourcedev);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " Dev %d engaged at %d rate!\n", (int) source->sourcedev, (int) source->rate);
|
||||
if (globals.running && !source->stopped) {
|
||||
source->ready = 1;
|
||||
|
||||
if (!source->audio_stream) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Audio Stream wops!\n");
|
||||
source->stopped = 0;
|
||||
source->ready = 0;
|
||||
} else {
|
||||
while (globals.running && !source->stopped) {
|
||||
switch_mutex_lock(source->device_lock);
|
||||
samples = ReadAudioStream(source->audio_stream, source->databuf,
|
||||
source->read_codec.implementation->samples_per_packet, 0, &source->timer);
|
||||
switch_mutex_unlock(source->device_lock);
|
||||
|
||||
|
||||
if (samples) {
|
||||
bytesToWrite = source->samples;
|
||||
if (samples < bytesToWrite) {
|
||||
bytesToWrite = samples;
|
||||
}
|
||||
bytesToWrite *= source->audio_stream->bytesPerFrame;
|
||||
|
||||
if (source->total) {
|
||||
|
||||
switch_mutex_lock(source->mutex);
|
||||
for (cp = source->context_list; cp; cp = cp->next) {
|
||||
|
||||
switch_mutex_lock(cp->audio_mutex);
|
||||
|
||||
bused = switch_buffer_inuse(cp->audio_buffer);
|
||||
if (bused > source->samples * 768) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Leaking stream handle! [%s() %s:%d] %d used %d max\n",
|
||||
cp->func, cp->file, cp->line, (int) bused, (int) (source->samples * 768));
|
||||
switch_buffer_zero(cp->audio_buffer);
|
||||
} else {
|
||||
switch_buffer_write(cp->audio_buffer, source->databuf, bytesToWrite);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(cp->audio_mutex);
|
||||
}
|
||||
switch_mutex_unlock(source->mutex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
source->ready = 0;
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
switch_core_hash_delete(globals.source_hash, source->sourcename);
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_thread_rwlock_wrlock(source->rwlock);
|
||||
switch_thread_rwlock_unlock(source->rwlock);
|
||||
|
||||
|
||||
switch_mutex_lock(source->device_lock);
|
||||
CloseAudioStream(source->audio_stream);
|
||||
if (switch_core_codec_ready(&source->read_codec)) {
|
||||
switch_core_codec_destroy(&source->read_codec);
|
||||
switch_core_codec_destroy(&source->write_codec);
|
||||
}
|
||||
if (switch_core_codec_ready(&source->write_codec)) {
|
||||
switch_core_codec_destroy(&source->write_codec);
|
||||
}
|
||||
switch_mutex_unlock(source->device_lock);
|
||||
|
||||
|
||||
switch_core_destroy_memory_pool(&source->pool);
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
globals.threads--;
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " thread ending succesfully !\n");
|
||||
switch_thread_exit(thread, SWITCH_STATUS_SUCCESS);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t portaudio_stream_file_open(switch_file_handle_t *handle, const char *path)
|
||||
{
|
||||
portaudio_stream_context_t *context;
|
||||
portaudio_stream_source_t *source;
|
||||
switch_memory_pool_t *pool;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_thread_t *thread;
|
||||
switch_threadattr_t *thd_attr = NULL;
|
||||
uint32_t rate = PREFERRED_RATE;
|
||||
char *npath;
|
||||
int devNumber;
|
||||
int tmp;
|
||||
|
||||
handle->pre_buffer_datalen = 0;
|
||||
|
||||
if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing! (yet)\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
npath = switch_core_strdup(module_pool, path);
|
||||
|
||||
tmp = handle->samplerate;
|
||||
if (tmp == 8000 || tmp == 16000 || tmp == 32000 || tmp == 48000) {
|
||||
rate = tmp;
|
||||
}
|
||||
|
||||
if (*path == '#') {
|
||||
devNumber = get_dev_by_number(npath + 1, 1);
|
||||
} else {
|
||||
devNumber = get_dev_by_name(npath, 1);
|
||||
}
|
||||
npath = switch_mprintf("device-%d at %d", devNumber, rate);
|
||||
|
||||
switch_mutex_lock(globals.mutex);
|
||||
source = switch_core_hash_find(globals.source_hash, npath);
|
||||
|
||||
/* dev isnt there, try to start thread */
|
||||
if (!source) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " source isnt Created, create and start thread!\n");
|
||||
|
||||
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, " :S no pool\n");
|
||||
} else {
|
||||
source = switch_core_alloc(pool, sizeof(*source));
|
||||
if (source != NULL) {
|
||||
source->pool = pool;
|
||||
source->sourcedev = devNumber;
|
||||
source->sourcename = switch_core_strdup(source->pool, npath);
|
||||
source->rate = rate;
|
||||
source->interval = 20;
|
||||
source->channels = 1;
|
||||
source->timer_name = "soft";
|
||||
source->prebuf = DEFAULT_PREBUFFER_SIZE;
|
||||
source->stopped = 0;
|
||||
source->ready = 0;
|
||||
source->samples = switch_samples_per_packet(source->rate, source->interval);
|
||||
|
||||
switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool);
|
||||
|
||||
switch_threadattr_create(&thd_attr, source->pool);
|
||||
switch_threadattr_detach_set(thd_attr, 1);
|
||||
|
||||
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
|
||||
switch_thread_create(&thread, thd_attr, read_stream_thread, source, source->pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.mutex);
|
||||
switch_yield(1000000);
|
||||
/* dev already engaged */
|
||||
if (source) {
|
||||
|
||||
/*wait for source to be ready */
|
||||
while (source->ready == 0) {
|
||||
switch_yield(100000);
|
||||
}
|
||||
|
||||
if (switch_thread_rwlock_tryrdlock(source->rwlock) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " error rwlock !\n");
|
||||
source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (source) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, " error allocating context!\n");
|
||||
status = SWITCH_STATUS_MEMERR;
|
||||
} else {
|
||||
/* everything goes fine at this point */
|
||||
handle->samples = 0;
|
||||
handle->samplerate = source->rate;
|
||||
handle->channels = 1;
|
||||
handle->format = 0;
|
||||
handle->sections = 0;
|
||||
handle->seekable = 0;
|
||||
handle->speed = 0;
|
||||
handle->private_info = context;
|
||||
handle->interval = source->interval;
|
||||
|
||||
switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, handle->memory_pool);
|
||||
if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
|
||||
status = SWITCH_STATUS_MEMERR;
|
||||
} else {
|
||||
/* context created... then continue */
|
||||
context->source = source;
|
||||
context->file = handle->file;
|
||||
context->func = handle->func;
|
||||
context->line = handle->line;
|
||||
context->handle = handle;
|
||||
switch_mutex_lock(source->mutex);
|
||||
context->next = source->context_list;
|
||||
source->context_list = context;
|
||||
source->total++;
|
||||
switch_mutex_unlock(source->mutex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown source %s\n", path);
|
||||
status = SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t portaudio_stream_file_close(switch_file_handle_t *handle)
|
||||
{
|
||||
portaudio_stream_context_t *cp, *last = NULL, *context = handle->private_info;
|
||||
|
||||
|
||||
switch_mutex_lock(context->source->mutex);
|
||||
for (cp = context->source->context_list; cp; cp = cp->next) {
|
||||
if (cp == context) {
|
||||
if (last) {
|
||||
last->next = cp->next;
|
||||
} else {
|
||||
context->source->context_list = cp->next;
|
||||
}
|
||||
break;
|
||||
}
|
||||
last = cp;
|
||||
}
|
||||
context->source->total--;
|
||||
switch_mutex_unlock(context->source->mutex);
|
||||
switch_buffer_destroy(&context->audio_buffer);
|
||||
switch_thread_rwlock_unlock(context->source->rwlock);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static switch_status_t portaudio_stream_file_read(switch_file_handle_t *handle, void *data, size_t *len)
|
||||
{
|
||||
portaudio_stream_context_t *context = handle->private_info;
|
||||
switch_size_t bytes = 0;
|
||||
int bytesPerSample = context->source->audio_stream->bytesPerFrame;
|
||||
size_t need = *len * bytesPerSample;
|
||||
|
||||
if (!context->source->ready) {
|
||||
*len = 0;
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_mutex_lock(context->audio_mutex);
|
||||
if ((bytes = switch_buffer_read(context->audio_buffer, data, need))) {
|
||||
*len = bytes / bytesPerSample;
|
||||
} else {
|
||||
if (need > 2560) {
|
||||
need = 2560;
|
||||
}
|
||||
memset(data, 255, need);
|
||||
*len = need / bytesPerSample;
|
||||
}
|
||||
switch_mutex_unlock(context->audio_mutex);
|
||||
|
||||
|
||||
|
||||
handle->sample_count += *len;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Registration */
|
||||
|
||||
static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
|
||||
|
||||
static void shutdown_event_handler(switch_event_t *event)
|
||||
{
|
||||
globals.running = 0;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_portaudio_stream_load)
|
||||
{
|
||||
switch_file_interface_t *file_interface;
|
||||
supported_formats[0] = "portaudio_stream";
|
||||
|
||||
module_pool = pool;
|
||||
|
||||
Pa_Initialize();
|
||||
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
|
||||
file_interface->interface_name = modname;
|
||||
file_interface->extens = supported_formats;
|
||||
file_interface->file_open = portaudio_stream_file_open;
|
||||
file_interface->file_close = portaudio_stream_file_close;
|
||||
file_interface->file_read = portaudio_stream_file_read;
|
||||
|
||||
if (switch_event_bind(modname, SWITCH_EVENT_SHUTDOWN, SWITCH_EVENT_SUBCLASS_ANY, shutdown_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind shutdown event handler!\n");
|
||||
}
|
||||
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
globals.running = 1;
|
||||
globals.threads = 0;
|
||||
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, module_pool);
|
||||
switch_core_hash_init(&globals.source_hash);
|
||||
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_portaudio_stream_shutdown)
|
||||
{
|
||||
globals.running = 0;
|
||||
switch_event_unbind_callback(shutdown_event_handler);
|
||||
|
||||
while (globals.threads > 0) {
|
||||
switch_yield(100000);
|
||||
}
|
||||
|
||||
Pa_Terminate();
|
||||
|
||||
switch_core_hash_destroy(&globals.source_hash);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* indent-tabs-mode:t
|
||||
* tab-width:4
|
||||
* c-basic-offset:4
|
||||
* End:
|
||||
* For VIM:
|
||||
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
||||
*/
|
Reference in New Issue
Block a user