summaryrefslogtreecommitdiff
path: root/pjmedia/src/pjmedia/portaudio
diff options
context:
space:
mode:
Diffstat (limited to 'pjmedia/src/pjmedia/portaudio')
-rw-r--r--pjmedia/src/pjmedia/portaudio/LICENSE.txt65
-rw-r--r--pjmedia/src/pjmedia/portaudio/README.txt81
-rw-r--r--pjmedia/src/pjmedia/portaudio/V19-devel-readme.txt222
-rw-r--r--pjmedia/src/pjmedia/portaudio/dsound_wrapper.c621
-rw-r--r--pjmedia/src/pjmedia/portaudio/dsound_wrapper.h130
-rw-r--r--pjmedia/src/pjmedia/portaudio/notes.txt145
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_allocation.c234
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_allocation.h95
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_converters.c1928
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_converters.h254
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_cpuload.c96
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_cpuload.h63
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_dither.c204
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_dither.h91
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_endianness.h122
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_front.c1976
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_hostapi.h244
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_lib.c831
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c3272
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h64
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core.c2042
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core.h118
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.c564
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.h133
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core_internal.h162
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core_old.c914
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.c612
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.h215
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_mac_hostapis.c87
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_process.c1756
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_process.h741
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_skeleton.c807
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_stream.c141
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_stream.h196
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_trace.c88
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_trace.h70
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_types.h65
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c64
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_unix_oss.c1918
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_unix_util.c173
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_unix_util.h73
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_util.h167
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_win_ds.c1835
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c86
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_win_util.c137
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_win_wmme.c3633
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_win_wmme.h160
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c1167
-rw-r--r--pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h19
-rw-r--r--pjmedia/src/pjmedia/portaudio/portaudio.h1122
-rw-r--r--pjmedia/src/pjmedia/portaudio/ringbuffer.c270
-rw-r--r--pjmedia/src/pjmedia/portaudio/ringbuffer.h117
52 files changed, 0 insertions, 30390 deletions
diff --git a/pjmedia/src/pjmedia/portaudio/LICENSE.txt b/pjmedia/src/pjmedia/portaudio/LICENSE.txt
deleted file mode 100644
index 105da3f7..00000000
--- a/pjmedia/src/pjmedia/portaudio/LICENSE.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-Portable header file to contain:
-/*
- * PortAudio Portable Real-Time Audio Library
- * PortAudio API Header File
- * Latest version available at: http://www.audiomulch.com/portaudio/
- *
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */
-
-
-Implementation files to contain:
-/*
- * PortAudio Portable Real-Time Audio Library
- * Latest version at: http://www.audiomulch.com/portaudio/
- * <platform> Implementation
- * Copyright (c) 1999-2000 <author(s)>
- *
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */ \ No newline at end of file
diff --git a/pjmedia/src/pjmedia/portaudio/README.txt b/pjmedia/src/pjmedia/portaudio/README.txt
deleted file mode 100644
index 4cfc6166..00000000
--- a/pjmedia/src/pjmedia/portaudio/README.txt
+++ /dev/null
@@ -1,81 +0,0 @@
-README for PortAudio
-Implementations for PC DirectSound and Mac SoundManager
-
-/*
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com//
- *
- * Copyright (c) 1999-2000 Phil Burk and Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */
-
-PortAudio is a portable audio I/O library designed for cross-platform
-support of audio. It uses a callback mechanism to request audio processing.
-Audio can be generated in various formats, including 32 bit floating point,
-and will be converted to the native format internally.
-
-Documentation:
- See "pa_common/portaudio.h" for API spec.
- See docs folder for a tutorial.
- Also see http://www.portaudio.com/docs/
- And see "pa_tests/patest_saw.c" for an example.
-
-For information on compiling programs with PortAudio, please see the
-tutorial at:
-
- http://www.portaudio.com/docs/pa_tutorial.html
-
-Important Files and Folders:
- pa_common/ = platform independant code
- pa_common/portaudio.h = header file for PortAudio API. Specifies API.
- pa_common/pa_lib.c = host independant code for all implementations.
-
- pablio = simple blocking read/write interface
-
-Platform Implementations
- pa_asio = ASIO for Windows and Macintosh
- pa_beos = BeOS
- pa_mac_sm = Macintosh Sound Manager for OS 8,9 and Carbon
- pa_mac_core = Macintosh Core Audio for OS X
- pa_sgi = Silicon Graphics AL
- pa_unix_oss = OSS implementation for various Unixes
- pa_win_ds = Windows Direct Sound
- pa_win_wmme = Windows MME (most widely supported)
-
-Test Programs
- pa_tests/pa_fuzz.c = guitar fuzz box
- pa_tests/pa_devs.c = print a list of available devices
- pa_tests/pa_minlat.c = determine minimum latency for your machine
- pa_tests/paqa_devs.c = self test that opens all devices
- pa_tests/paqa_errs.c = test error detection and reporting
- pa_tests/patest_clip.c = hear a sine wave clipped and unclipped
- pa_tests/patest_dither.c = hear effects of dithering (extremely subtle)
- pa_tests/patest_pink.c = fun with pink noise
- pa_tests/patest_record.c = record and playback some audio
- pa_tests/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad().
- pa_tests/patest_sine.c = output a sine wave in a simple PA app
- pa_tests/patest_sync.c = test syncronization of audio and video
- pa_tests/patest_wire.c = pass input to output, wire simulator
diff --git a/pjmedia/src/pjmedia/portaudio/V19-devel-readme.txt b/pjmedia/src/pjmedia/portaudio/V19-devel-readme.txt
deleted file mode 100644
index ae5570eb..00000000
--- a/pjmedia/src/pjmedia/portaudio/V19-devel-readme.txt
+++ /dev/null
@@ -1,222 +0,0 @@
-STATUS:
-
-MME, DirectSound and ASIO versions are more-or-less working. See FIXMEs @todos
-and the proposals matrix at portaudio.com for further status.
-
-The pa_tests directory contains tests. pa_tests/README.txt notes which tests
-currently build.
-
-The PaUtil support code is finished enough for other implementations to be
-ported. No changes are expected to be made to the definition of the PaUtil
-functions.
-
-Note that it's not yet 100% clear how the current support functions
-will interact with blocking read/write streams.
-
-BUILD INSTRUCTIONS
-
-to build tests/patest_sine.c you will need to compile and link the following
-files (MME)
-pa_common\pa_process.c
-pa_common\pa_skeleton.c
-pa_common\pa_stream.c
-pa_common\pa_trace.c
-pa_common\pa_converters.c
-pa_common\pa_cpuload.c
-pa_common\pa_dither.c
-pa_common\pa_front.c
-pa_common\pa_allocation.h
-pa_win\pa_win_util.c
-pa_win\pa_win_hostapis.c
-pa_win_wmme\pa_win_wmme.c
-
-see below for a description of these files.
-
-
-FILES:
-
-portaudio.h
- public api header file
-
-pa_front.c
- implements the interface defined in portaudio.h. manages multiple host apis.
- validates function parameters before calling through to host apis. tracks
- open streams and closes them at Pa_Terminate().
-
-pa_util.h
- declares utility functions for use my implementations. including utility
- functions which must be implemented separately for each platform.
-
-pa_hostapi.h
- hostapi representation structure used to interface between pa_front.c
- and implementations
-
-pa_stream.c/h
- stream interface and representation structures and helper functions
- used to interface between pa_front.c and implementations
-
-pa_cpuload.c/h
- source and header for cpu load calculation facility
-
-pa_trace.c/h
- source and header for debug trace log facility
-
-pa_converters.c/h
- sample buffer conversion facility
-
-pa_dither.c/h
- dither noise generator
-
-pa_process.c/h
- callback buffer processing facility including interleave and block adaption
-
-pa_allocation.c/h
- allocation context for tracking groups of allocations
-
-pa_skeleton.c
- an skeleton implementation showing how the common code can be used.
-
-pa_win_util.c
- Win32 implementation of platform specific PaUtil functions (memory allocation,
- usec clock, Pa_Sleep().) The file will be used with all Win32 host APIs.
-
-pa_win_hostapis.c
- contains the paHostApiInitializers array and an implementation of
- Pa_GetDefaultHostApi() for win32 builds.
-
-pa_win_wmme.c
- Win32 host api implementation for the windows multimedia extensions audio API.
-
-pa_win_wmme.h
- public header file containing interfaces to mme-specific functions and the
- deviceInfo data structure.
-
-
-CODING GUIDELINES:
-
-naming conventions:
- #defines begin with PA_
- #defines local to a file end with _
- global utility variables begin with paUtil
- global utility types begin with PaUtil (including function types)
- global utility functions begin with PaUtil_
- static variables end with _
- static constants begin with const and end with _
- static funtions have no special prefix/suffix
-
-In general, implementations should declare all of their members static,
-except for their initializer which should be exported. All exported names
-should be preceeded by Pa<MN>_ where MN is the module name, for example
-the windows mme initializer should be named PaWinWmme_Initialize().
-
-Every host api should define an initializer which returns an error code
-and a PaHostApiInterface*. The initializer should only return an error other
-than paNoError if it encounters an unexpected and fatal error (memory allocation
-error for example). In general, there may be conditions under which it returns
-a NULL interface pointer and also returns paNoError. For example, if the ASIO
-implementation detects that ASIO is not installed, it should return a
-NULL interface, and paNoError.
-
-Platform-specific shared functions should begin with Pa<PN>_ where PN is the
-platform name. eg. PaWin_ for windows, PaUnix_ for unix.
-
-The above two conventions should also be followed whenever it is necessary to
-share functions accross multiple source files.
-
-Two utilities for debug messages are provided. The PA_DEBUG macro defined in
-pa_implementation.h provides a simple way to print debug messages to stderr.
-Due to real-time performance issues, PA_DEBUG may not be suitable for use
-within the portaudio processing callback, or in other threads. In such cases
-the event tracing facility provided in pa_trace.h may be more appropriate.
-
-If PA_LOG_API_CALLS is defined, all calls to the public PortAudio API
-will be logged to stderr along with parameter and return values.
-
-
-TODO:
- (this list is totally out of date)
-
- finish coding converter functions in pa_converters.c (anyone?)
-
- implement block adaption in pa_process.c (phil?)
-
- fix all current tests to work with new code. this should mostly involve
- changing PortAudioStream to PaStream, and GetDefaultDeviceID to GetDefaultDevice etc.
-
- write some new tests to exercise the multi-api functions
-
- write (doxygen) documentation for pa_trace (phil?)
-
- remove unused typeids from PaHostAPITypeID
-
- create a global configuration file which documents which PA_ defines can be
- used for configuration
-
- need a coding standard for comment formatting
-
- migrate directx (phil)
-
- migrate asio (ross?, stephane?)
-
- see top of pa_win_wmme.c for MME todo items (ross)
-
- write style guide document (ross)
-
-
-DESIGN ISSUES:
- (this list is totally out of date)
-
- consider removing Pa_ConvertHostApiDeviceIndexToGlobalDeviceIndex() from the API
-
- switch to new latency parameter mechanism now (?)
-
- question: if input or outputDriverInfo structures are passed for a different
- hostApi from the one being called, do we return an error or just ignore
- them? (i think return error)
-
- consider renaming PortAudioCallback to PaStreamCallback
-
- consider renaming PaError, PaResult
-
-
-ASSORTED DISORGANISED NOTES:
-
- NOTE:
- pa_lib.c performs the following validations for Pa_OpenStream() which we do not currently do:
- - checks the device info to make sure that the device supports the requested sample rate,
- it may also change the sample rate to the "closest available" sample rate if it
- is within a particular error margin
-
- rationale for breaking up internalPortAudioStream:
- each implementation has its own requirements and behavior, and should be
- able to choose the best way to operate without being limited by the
- constraints imposed by a common infrastructure. in other words the
- implementations should be able to pick and choose services from the
- common infrastructure. currently identified services include:
-
- - cpu load tracking
- - buffering and conversion service (same code works for input and output)
- - should support buffer multiplexing (non-integer length input and output buffers)
- - in-place conversion where possible (only for callback, read/write always copies)
- - should manage allocation of temporary buffers if necessary
- - instrumentation (should be able to be disabled): callback count, framesProcessed
- - common data: magic, streamInterface, callback, userdata
-
-
-- conversion functions:
- - should handle temp buffer allocation
- - dithering (random number state per-stream)
- - buffer size mismatches
- - with new buffer slip rules, temp buffers may always be needed
- - we should aim for in-place conversion wherever possible
- - does phil's code support in-place conversion? (yes)
-
-- dicuss relationship between user and host buffer sizes
- - completely independent.. individual implementations may constrain
- host buffer sizes if necessary
-
-
-- discuss device capabilities:
- - i'd like to be able to request certain information:
- - channel count for example
-
diff --git a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.c b/pjmedia/src/pjmedia/portaudio/dsound_wrapper.c
deleted file mode 100644
index 93ccee00..00000000
--- a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.c
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * $Id: dsound_wrapper.c,v 1.1.1.1.2.11 2003/09/07 13:04:53 rossbencina Exp $
- * Simplified DirectSound interface.
- *
- * Author: Phil Burk & Robert Marsanyi
- *
- * PortAudio Portable Real-Time Audio Library
- * For more information see: http://www.softsynth.com/portaudio/
- * DirectSound Implementation
- * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
- *
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "dsound_wrapper.h"
-#include "pa_trace.h"
-
-/*
- Rather than linking with dxguid.a or using "#define INITGUID" to force a
- header file to instantiate the required GUID(s), we define them directly
- below.
-*/
-#include <initguid.h> // needed for the DEFINE_GUID macro
-DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16);
-
-
-/************************************************************************************/
-DSoundEntryPoints dswDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 };
-/************************************************************************************/
-static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
-{
- (void)lpcGuidDevice; /* unused parameter */
- (void)ppDS; /* unused parameter */
- (void)pUnkOuter; /* unused parameter */
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext)
-{
- (void)lpDSEnumCallback; /* unused parameter */
- (void)lpContext; /* unused parameter */
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext)
-{
- (void)lpDSEnumCallback; /* unused parameter */
- (void)lpContext; /* unused parameter */
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter)
-{
- (void)lpcGUID; /* unused parameter */
- (void)lplpDSC; /* unused parameter */
- (void)pUnkOuter; /* unused parameter */
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext)
-{
- (void)lpDSCEnumCallback; /* unused parameter */
- (void)lpContext; /* unused parameter */
- return E_NOTIMPL;
-}
-
-static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext)
-{
- (void)lpDSCEnumCallback; /* unused parameter */
- (void)lpContext; /* unused parameter */
- return E_NOTIMPL;
-}
-
-#ifndef _T
-# define _T(s) s
-#endif
-
-/************************************************************************************/
-void DSW_InitializeDSoundEntryPoints(void)
-{
- dswDSoundEntryPoints.hInstance_ = LoadLibrary(_T("dsound.dll"));
- if( dswDSoundEntryPoints.hInstance_ != NULL )
- {
- dswDSoundEntryPoints.DirectSoundCreate =
- (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
- GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCreate") );
- if( dswDSoundEntryPoints.DirectSoundCreate == NULL )
- dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
-
- dswDSoundEntryPoints.DirectSoundEnumerateW =
- (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
- GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundEnumerateW") );
- if( dswDSoundEntryPoints.DirectSoundEnumerateW == NULL )
- dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
-
- dswDSoundEntryPoints.DirectSoundEnumerateA =
- (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
- GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundEnumerateA") );
- if( dswDSoundEntryPoints.DirectSoundEnumerateA == NULL )
- dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
-
- dswDSoundEntryPoints.DirectSoundCaptureCreate =
- (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
- GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCaptureCreate") );
- if( dswDSoundEntryPoints.DirectSoundCaptureCreate == NULL )
- dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
-
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateW =
- (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
- GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCaptureEnumerateW") );
- if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL )
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
-
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateA =
- (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
- GetProcAddress( dswDSoundEntryPoints.hInstance_, _T("DirectSoundCaptureEnumerateA") );
- if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL )
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
- }
- else
- {
- /* initialize with dummy entry points to make live easy when ds isn't present */
- dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
- dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
- dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
- dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
- }
-}
-/************************************************************************************/
-void DSW_TerminateDSoundEntryPoints(void)
-{
- if( dswDSoundEntryPoints.hInstance_ != NULL )
- {
- FreeLibrary( dswDSoundEntryPoints.hInstance_ );
- dswDSoundEntryPoints.hInstance_ = NULL;
- /* ensure that we crash reliably if the entry points arent initialised */
- dswDSoundEntryPoints.DirectSoundCreate = 0;
- dswDSoundEntryPoints.DirectSoundEnumerateW = 0;
- dswDSoundEntryPoints.DirectSoundEnumerateA = 0;
- dswDSoundEntryPoints.DirectSoundCaptureCreate = 0;
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0;
- dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0;
- }
-}
-/************************************************************************************/
-void DSW_Term( DSoundWrapper *dsw )
-{
- // Cleanup the sound buffers
- if (dsw->dsw_OutputBuffer)
- {
- IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
- IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer );
- dsw->dsw_OutputBuffer = NULL;
- }
-
- if (dsw->dsw_InputBuffer)
- {
- IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
- IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer );
- dsw->dsw_InputBuffer = NULL;
- }
-
- if (dsw->dsw_pDirectSoundCapture)
- {
- IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture );
- dsw->dsw_pDirectSoundCapture = NULL;
- }
-
- if (dsw->dsw_pDirectSound)
- {
- IDirectSound_Release( dsw->dsw_pDirectSound );
- dsw->dsw_pDirectSound = NULL;
- }
-}
-/************************************************************************************/
-HRESULT DSW_Init( DSoundWrapper *dsw )
-{
- memset( dsw, 0, sizeof(DSoundWrapper) );
- return 0;
-}
-/************************************************************************************/
-HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
-{
- // Create the DS object
- HRESULT hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL );
- if( hr != DS_OK ) return hr;
- return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )
-{
- DWORD dwDataLen;
- DWORD playCursor;
- HRESULT result;
- LPDIRECTSOUNDBUFFER pPrimaryBuffer;
- HWND hWnd;
- HRESULT hr;
- WAVEFORMATEX wfFormat;
- DSBUFFERDESC primaryDesc;
- DSBUFFERDESC secondaryDesc;
- unsigned char* pDSBuffData;
- LARGE_INTEGER counterFrequency;
-
- dsw->dsw_OutputSize = bytesPerBuffer;
- dsw->dsw_OutputRunning = FALSE;
- dsw->dsw_OutputUnderflows = 0;
- dsw->dsw_FramesWritten = 0;
- dsw->dsw_BytesPerOutputFrame = nChannels * sizeof(short);
-
- // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the
- // applications's window. Also if that window is closed before the Buffer is closed
- // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.)
- // So we will use GetDesktopWindow() which was suggested by Miller Puckette.
- // hWnd = GetForegroundWindow();
- //
- // FIXME: The example code I have on the net creates a hidden window that
- // is managed by our code - I think we should do that - one hidden
- // window for the whole of Pa_DS
- //
- hWnd = GetDesktopWindow();
-
- // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz.
- // Exclusize also prevents unexpected sounds from other apps during a performance.
- if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound,
- hWnd, DSSCL_EXCLUSIVE)) != DS_OK)
- {
- return hr;
- }
-
- // -----------------------------------------------------------------------
- // Create primary buffer and set format just so we can specify our custom format.
- // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz.
- // Setup the primary buffer description
- ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
- primaryDesc.dwSize = sizeof(DSBUFFERDESC);
- primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth
- primaryDesc.dwBufferBytes = 0;
- primaryDesc.lpwfxFormat = NULL;
- // Create the buffer
- if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
- &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result;
- // Define the buffer format
- wfFormat.wFormatTag = WAVE_FORMAT_PCM;
- wfFormat.nChannels = nChannels;
- wfFormat.nSamplesPerSec = nFrameRate;
- wfFormat.wBitsPerSample = 8 * sizeof(short);
- wfFormat.nBlockAlign = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
- wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
- wfFormat.cbSize = 0; /* No extended format info. */
- // Set the primary buffer's format
- if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result;
-
- // ----------------------------------------------------------------------
- // Setup the secondary buffer description
- ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
- secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
- secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
- secondaryDesc.dwBufferBytes = bytesPerBuffer;
- secondaryDesc.lpwfxFormat = &wfFormat;
- // Create the secondary buffer
- if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
- &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result;
- // Lock the DS buffer
- if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData,
- &dwDataLen, NULL, 0, 0)) != DS_OK) return result;
- // Zero the DS buffer
- ZeroMemory(pDSBuffData, dwDataLen);
- // Unlock the DS buffer
- if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result;
- if( QueryPerformanceFrequency( &counterFrequency ) )
- {
- int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short));
- dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate;
- }
- else
- {
- dsw->dsw_CounterTicksPerBuffer.QuadPart = 0;
- }
- // Let DSound set the starting write position because if we set it to zero, it looks like the
- // buffer is full to begin with. This causes a long pause before sound starts when using large buffers.
- hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset );
- if( hr != DS_OK )
- {
- return hr;
- }
- dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerOutputFrame;
- /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */
- return DS_OK;
-}
-
-/************************************************************************************/
-HRESULT DSW_StartOutput( DSoundWrapper *dsw )
-{
- HRESULT hr;
- QueryPerformanceCounter( &dsw->dsw_LastPlayTime );
- dsw->dsw_LastPlayCursor = 0;
- dsw->dsw_FramesPlayed = 0;
- hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 );
- if( hr != DS_OK )
- {
- return hr;
- }
- // Start the buffer playback in a loop.
- if( dsw->dsw_OutputBuffer != NULL )
- {
- hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING );
- if( hr != DS_OK )
- {
- return hr;
- }
- dsw->dsw_OutputRunning = TRUE;
- }
-
- return 0;
-}
-/************************************************************************************/
-HRESULT DSW_StopOutput( DSoundWrapper *dsw )
-{
- // Stop the buffer playback
- if( dsw->dsw_OutputBuffer != NULL )
- {
- dsw->dsw_OutputRunning = FALSE;
- return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
- }
- else return 0;
-}
-
-/************************************************************************************/
-HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilledPtr )
-{
- HRESULT hr;
- DWORD playCursor;
- DWORD writeCursor;
- long bytesFilled;
- // Query to see where play position is.
- // We don't need the writeCursor but sometimes DirectSound doesn't handle NULLS correctly
- // so let's pass a pointer just to be safe.
- hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
- if( hr != DS_OK )
- {
- return hr;
- }
- bytesFilled = dsw->dsw_WriteOffset - playCursor;
- if( bytesFilled < 0 ) bytesFilled += dsw->dsw_OutputSize; // unwrap offset
- *bytesFilledPtr = bytesFilled;
- return hr;
-}
-
-/************************************************************************************
- * Determine how much space can be safely written to in DS buffer.
- * Detect underflows and overflows.
- * Does not allow writing into safety gap maintained by DirectSound.
- */
-HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty )
-{
- HRESULT hr;
- DWORD playCursor;
- DWORD writeCursor;
- long numBytesEmpty;
- long playWriteGap;
- // Query to see how much room is in buffer.
- hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
- if( hr != DS_OK )
- {
- return hr;
- }
- // Determine size of gap between playIndex and WriteIndex that we cannot write into.
- playWriteGap = writeCursor - playCursor;
- if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap
- /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */
- /* Attempt to detect playCursor wrap-around and correct it. */
- if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) )
- {
- /* How much time has elapsed since last check. */
- LARGE_INTEGER currentTime;
- LARGE_INTEGER elapsedTime;
- long bytesPlayed;
- long bytesExpected;
- long buffersWrapped;
- QueryPerformanceCounter( &currentTime );
- elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart;
- dsw->dsw_LastPlayTime = currentTime;
- /* How many bytes does DirectSound say have been played. */
- bytesPlayed = playCursor - dsw->dsw_LastPlayCursor;
- if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap
- dsw->dsw_LastPlayCursor = playCursor;
- /* Calculate how many bytes we would have expected to been played by now. */
- bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart);
- buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize;
- if( buffersWrapped > 0 )
- {
- playCursor += (buffersWrapped * dsw->dsw_OutputSize);
- bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize);
- }
- /* Maintain frame output cursor. */
- dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerOutputFrame);
- }
- numBytesEmpty = playCursor - dsw->dsw_WriteOffset;
- if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset
- /* Have we underflowed? */
- if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) )
- {
- if( dsw->dsw_OutputRunning )
- {
- dsw->dsw_OutputUnderflows += 1;
- }
- dsw->dsw_WriteOffset = writeCursor;
- numBytesEmpty = dsw->dsw_OutputSize - playWriteGap;
- }
- *bytesEmpty = numBytesEmpty;
- return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw )
-{
- HRESULT hr;
- LPBYTE lpbuf1 = NULL;
- LPBYTE lpbuf2 = NULL;
- DWORD dwsize1 = 0;
- DWORD dwsize2 = 0;
- long bytesEmpty;
- hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed
- if (hr != DS_OK) return hr;
- if( bytesEmpty == 0 ) return DS_OK;
- // Lock free space in the DS
- hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1,
- (void **) &lpbuf2, &dwsize2, 0);
- if (hr == DS_OK)
- {
- // Copy the buffer into the DS
- ZeroMemory(lpbuf1, dwsize1);
- if(lpbuf2 != NULL)
- {
- ZeroMemory(lpbuf2, dwsize2);
- }
- // Update our buffer offset and unlock sound buffer
- dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
- IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
- dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerOutputFrame;
- }
- return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes )
-{
- HRESULT hr;
- LPBYTE lpbuf1 = NULL;
- LPBYTE lpbuf2 = NULL;
- DWORD dwsize1 = 0;
- DWORD dwsize2 = 0;
- // Lock free space in the DS
- hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1,
- (void **) &lpbuf2, &dwsize2, 0);
- if (hr == DS_OK)
- {
- // Copy the buffer into the DS
- CopyMemory(lpbuf1, buf, dwsize1);
- if(lpbuf2 != NULL)
- {
- CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
- }
- // Update our buffer offset and unlock sound buffer
- dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
- IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
- dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerOutputFrame;
- }
- return hr;
-}
-
-/************************************************************************************/
-DWORD DSW_GetOutputStatus( DSoundWrapper *dsw )
-{
- DWORD status;
- if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK)
- return( DSERR_INVALIDPARAM );
- else
- return( status );
-}
-
-/* These routines are used to support audio input.
- * Do NOT compile these calls when using NT4 because it does
- * not support the entry points.
- */
-/************************************************************************************/
-HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
-{
- HRESULT hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
- if( hr != DS_OK ) return hr;
- return hr;
-}
-/************************************************************************************/
-HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, WORD nChannels, int bytesPerBuffer )
-{
- DSCBUFFERDESC captureDesc;
- WAVEFORMATEX wfFormat;
- HRESULT result;
-
- dsw->dsw_BytesPerInputFrame = nChannels * sizeof(short);
-
- // Define the buffer format
- wfFormat.wFormatTag = WAVE_FORMAT_PCM;
- wfFormat.nChannels = nChannels;
- wfFormat.nSamplesPerSec = nFrameRate;
- wfFormat.wBitsPerSample = 8 * sizeof(short);
- wfFormat.nBlockAlign = (WORD)(wfFormat.nChannels * (wfFormat.wBitsPerSample / 8));
- wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
- wfFormat.cbSize = 0; /* No extended format info. */
- dsw->dsw_InputSize = bytesPerBuffer;
- // ----------------------------------------------------------------------
- // Setup the secondary buffer description
- ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
- captureDesc.dwSize = sizeof(DSCBUFFERDESC);
- captureDesc.dwFlags = 0;
- captureDesc.dwBufferBytes = bytesPerBuffer;
- captureDesc.lpwfxFormat = &wfFormat;
- // Create the capture buffer
- if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture,
- &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result;
- dsw->dsw_ReadOffset = 0; // reset last read position to start of buffer
- return DS_OK;
-}
-
-/************************************************************************************/
-HRESULT DSW_StartInput( DSoundWrapper *dsw )
-{
- // Start the buffer playback
- if( dsw->dsw_InputBuffer != NULL )
- {
- return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING );
- }
- else return 0;
-}
-
-/************************************************************************************/
-HRESULT DSW_StopInput( DSoundWrapper *dsw )
-{
- // Stop the buffer playback
- if( dsw->dsw_InputBuffer != NULL )
- {
- return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
- }
- else return 0;
-}
-
-/************************************************************************************/
-HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )
-{
- HRESULT hr;
- DWORD capturePos;
- DWORD readPos;
- long filled;
- // Query to see how much data is in buffer.
- // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly
- // so let's pass a pointer just to be safe.
- hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );
- if( hr != DS_OK )
- {
- return hr;
- }
- filled = readPos - dsw->dsw_ReadOffset;
- if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset
- *bytesFilled = filled;
- return hr;
-}
-
-/************************************************************************************/
-HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )
-{
- HRESULT hr;
- LPBYTE lpbuf1 = NULL;
- LPBYTE lpbuf2 = NULL;
- DWORD dwsize1 = 0;
- DWORD dwsize2 = 0;
- // Lock free space in the DS
- hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,
- (void **) &lpbuf2, &dwsize2, 0);
- if (hr == DS_OK)
- {
- // Copy from DS to the buffer
- CopyMemory( buf, lpbuf1, dwsize1);
- if(lpbuf2 != NULL)
- {
- CopyMemory( buf+dwsize1, lpbuf2, dwsize2);
- }
- // Update our buffer offset and unlock sound buffer
- dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;
- IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
- }
- return hr;
-}
-
diff --git a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.h b/pjmedia/src/pjmedia/portaudio/dsound_wrapper.h
deleted file mode 100644
index 9e3f565f..00000000
--- a/pjmedia/src/pjmedia/portaudio/dsound_wrapper.h
+++ /dev/null
@@ -1,130 +0,0 @@
-#ifndef __DSOUND_WRAPPER_H
-#define __DSOUND_WRAPPER_H
-/*
- * $Id: dsound_wrapper.h,v 1.1.1.1.2.8 2005/01/16 20:48:37 rossbencina Exp $
- * Simplified DirectSound interface.
- *
- * Author: Phil Burk & Robert Marsanyi
- *
- * For PortAudio Portable Real-Time Audio Library
- * For more information see: http://www.softsynth.com/portaudio/
- * DirectSound Implementation
- * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
- *
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */
-
-/* on Borland compilers, WIN32 doesn't seem to be defined by default, which
- breaks DSound.h. Adding the define here fixes the problem. - rossb. */
-#ifdef __BORLANDC__
-#if !defined(WIN32)
-#define WIN32
-#endif
-#endif
-
-/*
- We are only using DX3 in here, no need to polute the namespace - davidv
-*/
-#define DIRECTSOUND_VERSION 0x0300
-
-#include <DSound.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-typedef struct
-{
- HINSTANCE hInstance_;
-
- HRESULT (WINAPI *DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
- HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
- HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
-
- HRESULT (WINAPI *DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);
- HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
- HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
-}DSoundEntryPoints;
-
-extern DSoundEntryPoints dswDSoundEntryPoints;
-
-void DSW_InitializeDSoundEntryPoints(void);
-void DSW_TerminateDSoundEntryPoints(void);
-
-#define DSW_NUM_POSITIONS (4)
-#define DSW_NUM_EVENTS (5)
-#define DSW_TERMINATION_EVENT (DSW_NUM_POSITIONS)
-
-typedef struct
-{
-/* Output */
- LPDIRECTSOUND dsw_pDirectSound;
- LPDIRECTSOUNDBUFFER dsw_OutputBuffer;
- DWORD dsw_WriteOffset; /* last write position */
- INT dsw_OutputSize;
- INT dsw_BytesPerOutputFrame;
- /* Try to detect play buffer underflows. */
- LARGE_INTEGER dsw_CounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */
- LARGE_INTEGER dsw_LastPlayTime;
- UINT dsw_LastPlayCursor;
- UINT dsw_OutputUnderflows;
- BOOL dsw_OutputRunning;
- /* use double which lets us can play for several thousand years with enough precision */
- double dsw_FramesWritten;
- double dsw_FramesPlayed;
-/* Input */
- INT dsw_BytesPerInputFrame;
- LPDIRECTSOUNDCAPTURE dsw_pDirectSoundCapture;
- LPDIRECTSOUNDCAPTUREBUFFER dsw_InputBuffer;
- UINT dsw_ReadOffset; /* last read position */
- UINT dsw_InputSize;
-} DSoundWrapper;
-
-HRESULT DSW_Init( DSoundWrapper *dsw );
-void DSW_Term( DSoundWrapper *dsw );
-HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
- WORD nChannels, int bufSize );
-HRESULT DSW_StartOutput( DSoundWrapper *dsw );
-HRESULT DSW_StopOutput( DSoundWrapper *dsw );
-DWORD DSW_GetOutputStatus( DSoundWrapper *dsw );
-HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes );
-HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw );
-HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty );
-HRESULT DSW_Enumerate( DSoundWrapper *dsw );
-
-HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
- WORD nChannels, int bufSize );
-HRESULT DSW_StartInput( DSoundWrapper *dsw );
-HRESULT DSW_StopInput( DSoundWrapper *dsw );
-HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes );
-HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled );
-HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilled );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* __DSOUND_WRAPPER_H */
diff --git a/pjmedia/src/pjmedia/portaudio/notes.txt b/pjmedia/src/pjmedia/portaudio/notes.txt
deleted file mode 100644
index ad66f358..00000000
--- a/pjmedia/src/pjmedia/portaudio/notes.txt
+++ /dev/null
@@ -1,145 +0,0 @@
-Notes on status of CoreAudio Implementation of PortAudio
-
-Document Last Updated December 9, 2005
-
-There are currently two implementations of PortAudio for Mac Core Audio.
-
-The original is in pa_mac_core_old.c, and the newer, default implementation
-is in pa_mac_core.c.
-Only pa_mac_core.c is currently developed and supported as it uses apple's
-current core audio technology. To select use the old implementation, replace
-pa_mac_core.c with pa_mac_core_old.c (eg. "cp pa_mac_core_auhal.c
-pa_mac_core.c"), then run configure and make as usual.
-
-----------------------------------------
-
-Notes on Original implementation:
-
-by Phil Burk and Darren Gibbs
-
-Last updated March 20, 2002
-
-WHAT WORKS
-
-Output with very low latency, <10 msec.
-Half duplex input or output.
-Full duplex on the same CoreAudio device.
-The paFLoat32, paInt16, paInt8, paUInt8 sample formats.
-Pa_GetCPULoad()
-Pa_StreamTime()
-
-KNOWN BUGS OR LIMITATIONS
-
-We do not yet support simultaneous input and output on different
-devices. Note that some CoreAudio devices like the Roland UH30 look
-like one device but are actually two different CoreAudio devices. The
-Built-In audio is typically one CoreAudio device.
-
-Mono doesn't work.
-
-DEVICE MAPPING
-
-CoreAudio devices can support both input and output. But the sample
-rates supported may be different. So we have map one or two PortAudio
-device to each CoreAudio device depending on whether it supports
-input, output or both.
-
-When we query devices, we first get a list of CoreAudio devices. Then
-we scan the list and add a PortAudio device for each CoreAudio device
-that supports input. Then we make a scan for output devices.
-
--------------------------------------------
-
-Notes on Newer/Default AUHAL implementation:
-
-by Bjorn Roche
-
-Last Updated December 9, 2005
-
-Principle of Operation:
-
-This implementation uses AUHAL for audio I/O. To some extent, it also
-operates at the "HAL" Layer, though this behavior can be limited by
-platform specific flags (see pa_mac_core.h for details). The default
-settings should be reasonable: they don't change the SR of the device and
-don't cause interruptions if other devices are using the device.
-
-Major Software Elements Used: Apple's HAL AUs provide output SR
-conversion transparently, however, only on output, so this
-implementation uses AudioConverters to convert the sample rate on input.
-A PortAudio ring buffer is used to buffer input when sample rate
-conversion is required or when separate audio units are used for duplex
-IO. Finally, a PortAudio buffer processor is used to convert formats and
-provide additional buffers if needed. Internally, interleaved floating
-point data streams are used exclusively - the audio unit converts from
-the audio hardware's native format to interleaved float PCM and
-PortAudio's Buffer processor is used for conversion to user formats.
-
-Simplex Input: Simplex input uses a single callback. If sample rate
-conversion is required, a ring buffer and AudioConverter are used as
-well.
-
-Simplex output: Simplex output uses a single callback. No ring buffer or
-audio converter is used because AUHAL does its own output SR conversion.
-
-Duplex, one device (no SR conversion): When one device is used, a single
-callback is used. This achieves very low latency.
-
-Duplex, separate devices or SR conversion: When SR conversion is
-required, data must be buffered before it is converted and data is not
-always available at the same times on input and output, so SR conversion
-requires the same treatment as separate devices. The input callback
-reads data and puts it in the ring buffer. The output callback reads the
-data off the ring buffer, into an audio converter and finally to the
-buffer processor.
-
-Platform Specific Options:
-
-By using the flags in pa_mac_core.h, the user may specify several options.
-For example, the user can specify the sample-rate conversion quality, and
-the extent to which PA will attempt to "play nice" and to what extent it
-will interrupt other apps to improve performance. For example, if 44100 Hz
-sample rate is requested but the device is set at 48000 Hz, PA can either
-change the device for optimal playback ("Pro" mode), which may interrupt
-other programs playing back audio, or simple use a sample-rate coversion,
-which allows for friendlier sharing of the device ("Play Nice" mode).
-
-
-Known issues:
-
-- Latency: Latency settings are ignored in most cases. Exceptions are when
-doing I/O between different devices and as a hint for selecting a realtively
-low or relatively high latency in conjunction with
-paHostFramesPerBufferUnspecified. Latency settings are always automatically
-bound to "safe" values, however, so setting extreme values here should not be
-an issue.
-
-- Buffer Size: paHostFramesPerBufferUnspecified and specific host buffer sizes
-are supported. paHostFramesPerBufferUnspecified works best in "pro" mode,
-where the buffer size and sample rate of the audio device is most likely
-to match the expected values.
-
-- Timing info. It reports on stream time, but I'm probably doing something
-wrong since patest_sine_time often reports negative latency numbers.
-
-- xrun detection: The only xrun detection performed is when reading
-and writing the ring buffer. There is probably more that can be done.
-
-- abort/stop issues: stopping a stream is always a complete operation,
-but latency should be low enough to make the lack of a separate abort
-unnecessary. Apple clarifies its AudioOutputUnitStop() call here:
-http://lists.apple.com/archives/coreaudio-api/2005/Dec/msg00055.html
-
-- blocking interface: Not implemented.
-
-- multichannel: It has been tested successfully on multichannel hardware
-from MOTU: traveler and 896HD.
-
-- sample rate conversion quality: By default, SR conversion is the maximum
-available. This can be tweaked using flags pa_mac_core.h. Note that the AU
-render quyality property is used to set the sample rat conversion quality
-as "documented" here:
-http://lists.apple.com/archives/coreaudio-api/2004/Jan/msg00141.html
-
-- x86: I haven't tested it on an x86 Mac myself, but users have reported
-being able to comiple and run it.
diff --git a/pjmedia/src/pjmedia/portaudio/pa_allocation.c b/pjmedia/src/pjmedia/portaudio/pa_allocation.c
deleted file mode 100644
index 035b4d0b..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_allocation.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * $Id: pa_allocation.c,v 1.1.2.6 2004/12/20 12:07:51 rossbencina Exp $
- * Portable Audio I/O Library allocation group implementation
- * memory allocation group for tracking allocation groups
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Allocation Group implementation.
-*/
-
-
-#include "pa_allocation.h"
-#include "pa_util.h"
-
-
-/*
- Maintain 3 singly linked lists...
- linkBlocks: the buffers used to allocate the links
- spareLinks: links available for use in the allocations list
- allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory()
-
- Link block size is doubled every time new links are allocated.
-*/
-
-
-#define PA_INITIAL_LINK_COUNT_ 16
-
-struct PaUtilAllocationGroupLink
-{
- struct PaUtilAllocationGroupLink *next;
- void *buffer;
-};
-
-/*
- Allocate a block of links. The first link will have it's buffer member
- pointing to the block, and it's next member set to <nextBlock>. The remaining
- links will have NULL buffer members, and each link will point to
- the next link except the last, which will point to <nextSpare>
-*/
-static struct PaUtilAllocationGroupLink *AllocateLinks( long count,
- struct PaUtilAllocationGroupLink *nextBlock,
- struct PaUtilAllocationGroupLink *nextSpare )
-{
- struct PaUtilAllocationGroupLink *result;
- int i;
-
- result = (struct PaUtilAllocationGroupLink *)PaUtil_AllocateMemory(
- sizeof(struct PaUtilAllocationGroupLink) * count );
- if( result )
- {
- /* the block link */
- result[0].buffer = result;
- result[0].next = nextBlock;
-
- /* the spare links */
- for( i=1; i<count; ++i )
- {
- result[i].buffer = 0;
- result[i].next = &result[i+1];
- }
- result[count-1].next = nextSpare;
- }
-
- return result;
-}
-
-
-PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void )
-{
- PaUtilAllocationGroup* result = 0;
- struct PaUtilAllocationGroupLink *links;
-
-
- links = AllocateLinks( PA_INITIAL_LINK_COUNT_, 0, 0 );
- if( links != 0 )
- {
- result = (PaUtilAllocationGroup*)PaUtil_AllocateMemory( sizeof(PaUtilAllocationGroup) );
- if( result )
- {
- result->linkCount = PA_INITIAL_LINK_COUNT_;
- result->linkBlocks = &links[0];
- result->spareLinks = &links[1];
- result->allocations = 0;
- }
- else
- {
- PaUtil_FreeMemory( links );
- }
- }
-
- return result;
-}
-
-
-void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group )
-{
- struct PaUtilAllocationGroupLink *current = group->linkBlocks;
- struct PaUtilAllocationGroupLink *next;
-
- while( current )
- {
- next = current->next;
- PaUtil_FreeMemory( current->buffer );
- current = next;
- }
-
- PaUtil_FreeMemory( group );
-}
-
-
-void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size )
-{
- struct PaUtilAllocationGroupLink *links, *link;
- void *result = 0;
-
- /* allocate more links if necessary */
- if( !group->spareLinks )
- {
- /* double the link count on each block allocation */
- links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks );
- if( links )
- {
- group->linkCount += group->linkCount;
- group->linkBlocks = &links[0];
- group->spareLinks = &links[1];
- }
- }
-
- if( group->spareLinks )
- {
- result = PaUtil_AllocateMemory( size );
- if( result )
- {
- link = group->spareLinks;
- group->spareLinks = link->next;
-
- link->buffer = result;
- link->next = group->allocations;
-
- group->allocations = link;
- }
- }
-
- return result;
-}
-
-
-void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer )
-{
- struct PaUtilAllocationGroupLink *current = group->allocations;
- struct PaUtilAllocationGroupLink *previous = 0;
-
- if( buffer == 0 )
- return;
-
- /* find the right link and remove it */
- while( current )
- {
- if( current->buffer == buffer )
- {
- if( previous )
- {
- previous->next = current->next;
- }
- else
- {
- group->allocations = current->next;
- }
-
- current->buffer = 0;
- current->next = group->spareLinks;
- group->spareLinks = current;
-
- break;
- }
-
- previous = current;
- current = current->next;
- }
-
- PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */
-}
-
-
-void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group )
-{
- struct PaUtilAllocationGroupLink *current = group->allocations;
- struct PaUtilAllocationGroupLink *previous = 0;
-
- /* free all buffers in the allocations list */
- while( current )
- {
- PaUtil_FreeMemory( current->buffer );
- current->buffer = 0;
-
- previous = current;
- current = current->next;
- }
-
- /* link the former allocations list onto the front of the spareLinks list */
- if( previous )
- {
- previous->next = group->spareLinks;
- group->spareLinks = group->allocations;
- group->allocations = 0;
- }
-}
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_allocation.h b/pjmedia/src/pjmedia/portaudio/pa_allocation.h
deleted file mode 100644
index fb9321a0..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_allocation.h
+++ /dev/null
@@ -1,95 +0,0 @@
-#ifndef PA_ALLOCATION_H
-#define PA_ALLOCATION_H
-/*
- * $Id: pa_allocation.h,v 1.1.2.4 2003/09/20 21:04:44 rossbencina Exp $
- * Portable Audio I/O Library allocation context header
- * memory allocation context for tracking allocation groups
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Allocation Group prototypes. An Allocation Group makes it easy to
- allocate multiple blocks of memory and free them all simultanously.
-
- An allocation group is useful for keeping track of multiple blocks
- of memory which are allocated at the same time (such as during initialization)
- and need to be deallocated at the same time. The allocation group maintains
- a list of allocated blocks, and can deallocate them all simultaneously which
- can be usefull for cleaning up after a partially initialized object fails.
-
- The allocation group implementation is built on top of the lower
- level allocation functions defined in pa_util.h
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-typedef struct
-{
- long linkCount;
- struct PaUtilAllocationGroupLink *linkBlocks;
- struct PaUtilAllocationGroupLink *spareLinks;
- struct PaUtilAllocationGroupLink *allocations;
-}PaUtilAllocationGroup;
-
-
-
-/** Create an allocation group.
-*/
-PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void );
-
-/** Destroy an allocation group, but not the memory allocated through the group.
-*/
-void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group );
-
-/** Allocate a block of memory though an allocation group.
-*/
-void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size );
-
-/** Free a block of memory that was previously allocated though an allocation
- group. Calling this function is a relatively time consuming operation.
- Under normal circumstances clients should call PaUtil_FreeAllAllocations to
- free all allocated blocks simultaneously.
- @see PaUtil_FreeAllAllocations
-*/
-void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer );
-
-/** Free all blocks of memory which have been allocated through the allocation
- group. This function doesn't destroy the group itself.
-*/
-void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_ALLOCATION_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_converters.c b/pjmedia/src/pjmedia/portaudio/pa_converters.c
deleted file mode 100644
index fa5e5d41..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_converters.c
+++ /dev/null
@@ -1,1928 +0,0 @@
-/*
- * $Id: pa_converters.c,v 1.1.2.26 2004/12/11 16:32:38 aknudsen Exp $
- * Portable Audio I/O Library sample conversion mechanism
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Conversion functions implementations.
-
- If the C9x function lrintf() is available, define PA_USE_C99_LRINTF to use it
-
- @todo Consider whether functions which dither but don't clip should exist,
- V18 automatically enabled clipping whenever dithering was selected. Perhaps
- we should do the same.
-
- @todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither,
- Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24_Dither,
- Int32_To_UInt8_Dither, Int24_To_Int16_Dither, Int24_To_Int8_Dither,
- Int24_To_UInt8_Dither, Int16_To_Int8_Dither, Int16_To_UInt8_Dither,
-
- @todo review the converters marked REVIEW: Float32_To_Int32,
- Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip,
- Int32_To_Int16_Dither, Int32_To_Int8_Dither, Int16_To_Int32
-*/
-
-
-#include "pa_converters.h"
-#include "pa_dither.h"
-#include "pa_endianness.h"
-#include "pa_types.h"
-
-
-PaSampleFormat PaUtil_SelectClosestAvailableFormat(
- PaSampleFormat availableFormats, PaSampleFormat format )
-{
- PaSampleFormat result;
-
- format &= ~paNonInterleaved;
- availableFormats &= ~paNonInterleaved;
-
- if( (format & availableFormats) == 0 )
- {
- /* NOTE: this code depends on the sample format constants being in
- descending order of quality - ie best quality is 0
- FIXME: should write an assert which checks that all of the
- known constants conform to that requirement.
- */
-
- if( format != 0x01 )
- {
- /* scan for better formats */
- result = format;
- do
- {
- result >>= 1;
- }
- while( (result & availableFormats) == 0 && result != 0 );
- }
- else
- {
- result = 0;
- }
-
- if( result == 0 ){
- /* scan for worse formats */
- result = format;
- do
- {
- result <<= 1;
- }
- while( (result & availableFormats) == 0 && result != paCustomFormat );
-
- if( (result & availableFormats) == 0 )
- result = paSampleFormatNotSupported;
- }
-
- }else{
- result = format;
- }
-
- return result;
-}
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \
- switch( format & ~paNonInterleaved ){ \
- case paFloat32: \
- float32 \
- case paInt32: \
- int32 \
- case paInt24: \
- int24 \
- case paInt16: \
- int16 \
- case paInt8: \
- int8 \
- case paUInt8: \
- uint8 \
- default: return 0; \
- }
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination ) \
- if( flags & paClipOff ){ /* no clip */ \
- if( flags & paDitherOff ){ /* no dither */ \
- return paConverters. source ## _To_ ## destination; \
- }else{ /* dither */ \
- return paConverters. source ## _To_ ## destination ## _Dither; \
- } \
- }else{ /* clip */ \
- if( flags & paDitherOff ){ /* no dither */ \
- return paConverters. source ## _To_ ## destination ## _Clip; \
- }else{ /* dither */ \
- return paConverters. source ## _To_ ## destination ## _DitherClip; \
- } \
- }
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_SELECT_CONVERTER_DITHER_( flags, source, destination ) \
- if( flags & paDitherOff ){ /* no dither */ \
- return paConverters. source ## _To_ ## destination; \
- }else{ /* dither */ \
- return paConverters. source ## _To_ ## destination ## _Dither; \
- }
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_USE_CONVERTER_( source, destination )\
- return paConverters. source ## _To_ ## destination;
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_UNITY_CONVERSION_( wordlength )\
- return paConverters. Copy_ ## wordlength ## _To_ ## wordlength;
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
- PaSampleFormat destinationFormat, PaStreamFlags flags )
-{
- PA_SELECT_FORMAT_( sourceFormat,
- /* paFloat32: */
- PA_SELECT_FORMAT_( destinationFormat,
- /* paFloat32: */ PA_UNITY_CONVERSION_( 32 ),
- /* paInt32: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ),
- /* paInt24: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ),
- /* paInt16: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ),
- /* paInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ),
- /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 )
- ),
- /* paInt32: */
- PA_SELECT_FORMAT_( destinationFormat,
- /* paFloat32: */ PA_USE_CONVERTER_( Int32, Float32 ),
- /* paInt32: */ PA_UNITY_CONVERSION_( 32 ),
- /* paInt24: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ),
- /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ),
- /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ),
- /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 )
- ),
- /* paInt24: */
- PA_SELECT_FORMAT_( destinationFormat,
- /* paFloat32: */ PA_USE_CONVERTER_( Int24, Float32 ),
- /* paInt32: */ PA_USE_CONVERTER_( Int24, Int32 ),
- /* paInt24: */ PA_UNITY_CONVERSION_( 24 ),
- /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ),
- /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ),
- /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 )
- ),
- /* paInt16: */
- PA_SELECT_FORMAT_( destinationFormat,
- /* paFloat32: */ PA_USE_CONVERTER_( Int16, Float32 ),
- /* paInt32: */ PA_USE_CONVERTER_( Int16, Int32 ),
- /* paInt24: */ PA_USE_CONVERTER_( Int16, Int24 ),
- /* paInt16: */ PA_UNITY_CONVERSION_( 16 ),
- /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ),
- /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 )
- ),
- /* paInt8: */
- PA_SELECT_FORMAT_( destinationFormat,
- /* paFloat32: */ PA_USE_CONVERTER_( Int8, Float32 ),
- /* paInt32: */ PA_USE_CONVERTER_( Int8, Int32 ),
- /* paInt24: */ PA_USE_CONVERTER_( Int8, Int24 ),
- /* paInt16: */ PA_USE_CONVERTER_( Int8, Int16 ),
- /* paInt8: */ PA_UNITY_CONVERSION_( 8 ),
- /* paUInt8: */ PA_USE_CONVERTER_( Int8, UInt8 )
- ),
- /* paUInt8: */
- PA_SELECT_FORMAT_( destinationFormat,
- /* paFloat32: */ PA_USE_CONVERTER_( UInt8, Float32 ),
- /* paInt32: */ PA_USE_CONVERTER_( UInt8, Int32 ),
- /* paInt24: */ PA_USE_CONVERTER_( UInt8, Int24 ),
- /* paInt16: */ PA_USE_CONVERTER_( UInt8, Int16 ),
- /* paInt8: */ PA_USE_CONVERTER_( UInt8, Int8 ),
- /* paUInt8: */ PA_UNITY_CONVERSION_( 8 )
- )
- )
-}
-
-/* -------------------------------------------------------------------------- */
-
-#ifdef PA_NO_STANDARD_CONVERTERS
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilConverterTable paConverters = {
- 0, /* PaUtilConverter *Float32_To_Int32; */
- 0, /* PaUtilConverter *Float32_To_Int32_Dither; */
- 0, /* PaUtilConverter *Float32_To_Int32_Clip; */
- 0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */
-
- 0, /* PaUtilConverter *Float32_To_Int24; */
- 0, /* PaUtilConverter *Float32_To_Int24_Dither; */
- 0, /* PaUtilConverter *Float32_To_Int24_Clip; */
- 0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */
-
- 0, /* PaUtilConverter *Float32_To_Int16; */
- 0, /* PaUtilConverter *Float32_To_Int16_Dither; */
- 0, /* PaUtilConverter *Float32_To_Int16_Clip; */
- 0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */
-
- 0, /* PaUtilConverter *Float32_To_Int8; */
- 0, /* PaUtilConverter *Float32_To_Int8_Dither; */
- 0, /* PaUtilConverter *Float32_To_Int8_Clip; */
- 0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */
-
- 0, /* PaUtilConverter *Float32_To_UInt8; */
- 0, /* PaUtilConverter *Float32_To_UInt8_Dither; */
- 0, /* PaUtilConverter *Float32_To_UInt8_Clip; */
- 0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
-
- 0, /* PaUtilConverter *Int32_To_Float32; */
- 0, /* PaUtilConverter *Int32_To_Int24; */
- 0, /* PaUtilConverter *Int32_To_Int24_Dither; */
- 0, /* PaUtilConverter *Int32_To_Int16; */
- 0, /* PaUtilConverter *Int32_To_Int16_Dither; */
- 0, /* PaUtilConverter *Int32_To_Int8; */
- 0, /* PaUtilConverter *Int32_To_Int8_Dither; */
- 0, /* PaUtilConverter *Int32_To_UInt8; */
- 0, /* PaUtilConverter *Int32_To_UInt8_Dither; */
-
- 0, /* PaUtilConverter *Int24_To_Float32; */
- 0, /* PaUtilConverter *Int24_To_Int32; */
- 0, /* PaUtilConverter *Int24_To_Int16; */
- 0, /* PaUtilConverter *Int24_To_Int16_Dither; */
- 0, /* PaUtilConverter *Int24_To_Int8; */
- 0, /* PaUtilConverter *Int24_To_Int8_Dither; */
- 0, /* PaUtilConverter *Int24_To_UInt8; */
- 0, /* PaUtilConverter *Int24_To_UInt8_Dither; */
-
- 0, /* PaUtilConverter *Int16_To_Float32; */
- 0, /* PaUtilConverter *Int16_To_Int32; */
- 0, /* PaUtilConverter *Int16_To_Int24; */
- 0, /* PaUtilConverter *Int16_To_Int8; */
- 0, /* PaUtilConverter *Int16_To_Int8_Dither; */
- 0, /* PaUtilConverter *Int16_To_UInt8; */
- 0, /* PaUtilConverter *Int16_To_UInt8_Dither; */
-
- 0, /* PaUtilConverter *Int8_To_Float32; */
- 0, /* PaUtilConverter *Int8_To_Int32; */
- 0, /* PaUtilConverter *Int8_To_Int24 */
- 0, /* PaUtilConverter *Int8_To_Int16; */
- 0, /* PaUtilConverter *Int8_To_UInt8; */
-
- 0, /* PaUtilConverter *UInt8_To_Float32; */
- 0, /* PaUtilConverter *UInt8_To_Int32; */
- 0, /* PaUtilConverter *UInt8_To_Int24; */
- 0, /* PaUtilConverter *UInt8_To_Int16; */
- 0, /* PaUtilConverter *UInt8_To_Int8; */
-
- 0, /* PaUtilConverter *Copy_8_To_8; */
- 0, /* PaUtilConverter *Copy_16_To_16; */
- 0, /* PaUtilConverter *Copy_24_To_24; */
- 0 /* PaUtilConverter *Copy_32_To_32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#else /* PA_NO_STANDARD_CONVERTERS is not defined */
-
-/* -------------------------------------------------------------------------- */
-
-#define PA_CLIP_( val, min, max )\
- { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
-
-
-static const float const_1_div_128_ = 1.0f / 128.0f; /* 8 bit multiplier */
-
-static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */
-
-static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
- float scaled = *src * 0x7FFFFFFF;
- *dest = lrintf(scaled-0.5f);
-#else
- double scaled = *src * 0x7FFFFFFF;
- *dest = (signed long) scaled;
-#endif
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
-
- while( count-- )
- {
- /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
- float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- float dithered = ((float)*src * (2147483646.0f)) + dither;
- *dest = lrintf(dithered - 0.5f);
-#else
- double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- double dithered = ((double)*src * (2147483646.0)) + dither;
- *dest = (signed long) dithered;
-#endif
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
- float scaled = *src * 0x7FFFFFFF;
- PA_CLIP_( scaled, -2147483648.f, 2147483647.f );
- *dest = lrintf(scaled-0.5f);
-#else
- double scaled = *src * 0x7FFFFFFF;
- PA_CLIP_( scaled, -2147483648., 2147483647. );
- *dest = (signed long) scaled;
-#endif
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
-
- while( count-- )
- {
- /* REVIEW */
-#ifdef PA_USE_C99_LRINTF
- float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- float dithered = ((float)*src * (2147483646.0f)) + dither;
- PA_CLIP_( dithered, -2147483648.f, 2147483647.f );
- *dest = lrintf(dithered-0.5f);
-#else
- double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- double dithered = ((double)*src * (2147483646.0)) + dither;
- PA_CLIP_( dithered, -2147483648., 2147483647. );
- *dest = (signed long) dithered;
-#endif
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* convert to 32 bit and drop the low 8 bits */
- double scaled = *src * 0x7FFFFFFF;
- temp = (signed long) scaled;
-
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (unsigned char)(temp >> 24);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 8);
-#endif
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
-
- while( count-- )
- {
- /* convert to 32 bit and drop the low 8 bits */
-
- double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- double dithered = ((double)*src * (2147483646.0)) + dither;
-
- temp = (signed long) dithered;
-
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (unsigned char)(temp >> 24);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 8);
-#endif
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* convert to 32 bit and drop the low 8 bits */
- double scaled = *src * 0x7FFFFFFF;
- PA_CLIP_( scaled, -2147483648., 2147483647. );
- temp = (signed long) scaled;
-
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (unsigned char)(temp >> 24);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 8);
-#endif
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
-
- while( count-- )
- {
- /* convert to 32 bit and drop the low 8 bits */
-
- double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- double dithered = ((double)*src * (2147483646.0)) + dither;
- PA_CLIP_( dithered, -2147483648., 2147483647. );
-
- temp = (signed long) dithered;
-
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 24);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (unsigned char)(temp >> 24);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 8);
-#endif
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-#ifdef PA_USE_C99_LRINTF
- float tempf = (*src * (32767.0f)) ;
- *dest = lrintf(tempf-0.5f);
-#else
- short samp = (short) (*src * (32767.0f));
- *dest = samp;
-#endif
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
-
- while( count-- )
- {
-
- float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- float dithered = (*src * (32766.0f)) + dither;
-
-#ifdef PA_USE_C99_LRINTF
- *dest = lrintf(dithered-0.5f);
-#else
- *dest = (signed short) dithered;
-#endif
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-#ifdef PA_USE_C99_LRINTF
- long samp = lrintf((*src * (32767.0f)) -0.5f);
-#else
- long samp = (signed long) (*src * (32767.0f));
-#endif
- PA_CLIP_( samp, -0x8000, 0x7FFF );
- *dest = (signed short) samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-
- float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- float dithered = (*src * (32766.0f)) + dither;
- signed long samp = (signed long) dithered;
- PA_CLIP_( samp, -0x8000, 0x7FFF );
-#ifdef PA_USE_C99_LRINTF
- *dest = lrintf(samp-0.5f);
-#else
- *dest = (signed short) samp;
-#endif
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- signed char samp = (signed char) (*src * (127.0f));
- *dest = samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- float dithered = (*src * (126.0f)) + dither;
- signed long samp = (signed long) dithered;
- *dest = (signed char) samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- signed long samp = (signed long)(*src * (127.0f));
- PA_CLIP_( samp, -0x80, 0x7F );
- *dest = (signed char) samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int8_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- /* use smaller scaler to prevent overflow when we add the dither */
- float dithered = (*src * (126.0f)) + dither;
- signed long samp = (signed long) dithered;
- PA_CLIP_( samp, -0x80, 0x7F );
- *dest = (signed char) samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f))));
- *dest = samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* IMPLEMENT ME */
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* IMPLEMENT ME */
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_UInt8_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* IMPLEMENT ME */
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Float32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- float *dest = (float*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- *dest = (float) ((double)*src * const_1_div_2147483648_);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int24(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* REVIEW */
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = (unsigned char)(*src >> 8);
- dest[1] = (unsigned char)(*src >> 16);
- dest[2] = (unsigned char)(*src >> 24);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (unsigned char)(*src >> 24);
- dest[1] = (unsigned char)(*src >> 16);
- dest[2] = (unsigned char)(*src >> 8);
-#endif
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int24_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- (void) destinationBuffer; /* unused parameters */
- (void) destinationStride; /* unused parameters */
- (void) sourceBuffer; /* unused parameters */
- (void) sourceStride; /* unused parameters */
- (void) count; /* unused parameters */
- (void) ditherGenerator; /* unused parameters */
- /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int16(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- *dest = (signed short) ((*src) >> 16);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int16_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- signed long dither;
-
- while( count-- )
- {
- /* REVIEW */
- dither = PaUtil_Generate16BitTriangularDither( ditherGenerator );
- *dest = (signed short) ((((*src)>>1) + dither) >> 15);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- *dest = (signed char) ((*src) >> 24);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_Int8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- signed long dither;
-
- while( count-- )
- {
- /* REVIEW */
- dither = PaUtil_Generate16BitTriangularDither( ditherGenerator );
- *dest = (signed char) ((((*src)>>1) + dither) >> 23);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_UInt8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (unsigned char)(((*src) >> 24) + 128);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int32_To_UInt8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed long *src = (signed long*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* IMPLEMENT ME */
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Float32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- float *dest = (float*)destinationBuffer;
- signed long temp;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-
-#if defined(PA_LITTLE_ENDIAN)
- temp = (((long)src[0]) << 8);
- temp = temp | (((long)src[1]) << 16);
- temp = temp | (((long)src[2]) << 24);
-#elif defined(PA_BIG_ENDIAN)
- temp = (((long)src[0]) << 24);
- temp = temp | (((long)src[1]) << 16);
- temp = temp | (((long)src[2]) << 8);
-#endif
-
- *dest = (float) ((double)temp * const_1_div_2147483648_);
-
- src += sourceStride * 3;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- signed long *dest = (signed long*) destinationBuffer;
- signed long temp;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-
-#if defined(PA_LITTLE_ENDIAN)
- temp = (((long)src[0]) << 8);
- temp = temp | (((long)src[1]) << 16);
- temp = temp | (((long)src[2]) << 24);
-#elif defined(PA_BIG_ENDIAN)
- temp = (((long)src[0]) << 24);
- temp = temp | (((long)src[1]) << 16);
- temp = temp | (((long)src[2]) << 8);
-#endif
-
- *dest = temp;
-
- src += sourceStride * 3;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int16(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
-
- signed short temp;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-
-#if defined(PA_LITTLE_ENDIAN)
- /* src[0] is discarded */
- temp = (((signed short)src[1]));
- temp = temp | (signed short)(((signed short)src[2]) << 8);
-#elif defined(PA_BIG_ENDIAN)
- /* src[2] is discarded */
- temp = (signed short)(((signed short)src[0]) << 8);
- temp = temp | (((signed short)src[1]));
-#endif
-
- *dest = temp;
-
- src += sourceStride * 3;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int16_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- (void) destinationBuffer; /* unused parameters */
- (void) destinationStride; /* unused parameters */
- (void) sourceBuffer; /* unused parameters */
- (void) sourceStride; /* unused parameters */
- (void) count; /* unused parameters */
- (void) ditherGenerator; /* unused parameters */
- /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-
-#if defined(PA_LITTLE_ENDIAN)
- /* src[0] is discarded */
- /* src[1] is discarded */
- *dest = src[2];
-#elif defined(PA_BIG_ENDIAN)
- /* src[2] is discarded */
- /* src[1] is discarded */
- *dest = src[0];
-#endif
-
- src += sourceStride * 3;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_Int8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- (void) destinationBuffer; /* unused parameters */
- (void) destinationStride; /* unused parameters */
- (void) sourceBuffer; /* unused parameters */
- (void) sourceStride; /* unused parameters */
- (void) count; /* unused parameters */
- (void) ditherGenerator; /* unused parameters */
- /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_UInt8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-
-#if defined(PA_LITTLE_ENDIAN)
- /* src[0] is discarded */
- /* src[1] is discarded */
- *dest = (unsigned char)(src[2] + 128);
-#elif defined(PA_BIG_ENDIAN)
- *dest = (unsigned char)(src[0] + 128);
- /* src[1] is discarded */
- /* src[2] is discarded */
-#endif
-
- src += sourceStride * 3;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int24_To_UInt8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- (void) destinationBuffer; /* unused parameters */
- (void) destinationStride; /* unused parameters */
- (void) sourceBuffer; /* unused parameters */
- (void) sourceStride; /* unused parameters */
- (void) count; /* unused parameters */
- (void) ditherGenerator; /* unused parameters */
- /* IMPLEMENT ME */
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Float32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed short *src = (signed short*)sourceBuffer;
- float *dest = (float*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */
- *dest = samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed short *src = (signed short*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* REVIEW: we should consider something like
- (*src << 16) | (*src & 0xFFFF)
- */
-
- *dest = *src << 16;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int24(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed short *src = (signed short*) sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed short temp;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- temp = *src;
-
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = 0;
- dest[1] = (unsigned char)(temp);
- dest[2] = (unsigned char)(temp >> 8);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp);
- dest[2] = 0;
-#endif
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed short *src = (signed short*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (signed char)((*src) >> 8);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_Int8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed short *src = (signed short*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* IMPLEMENT ME */
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_UInt8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed short *src = (signed short*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (unsigned char)(((*src) >> 8) + 128);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int16_To_UInt8_Dither(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed short *src = (signed short*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- /* IMPLEMENT ME */
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Float32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed char *src = (signed char*)sourceBuffer;
- float *dest = (float*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- float samp = *src * const_1_div_128_;
- *dest = samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Int32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed char *src = (signed char*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (*src) << 24;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Int24(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed char *src = (signed char*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
-
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = 0;
- dest[1] = 0;
- dest[2] = (*src);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (*src);
- dest[1] = 0;
- dest[2] = 0;
-#endif
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_Int16(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed char *src = (signed char*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (signed short)((*src) << 8);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Int8_To_UInt8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- signed char *src = (signed char*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (unsigned char)(*src + 128);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Float32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- float *dest = (float*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- float samp = (*src - 128) * const_1_div_128_;
- *dest = samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (*src - 128) << 24;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int24(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- (void) ditherGenerator; /* unused parameters */
-
- while( count-- )
- {
-
-#if defined(PA_LITTLE_ENDIAN)
- dest[0] = 0;
- dest[1] = 0;
- dest[2] = (unsigned char)(*src - 128);
-#elif defined(PA_BIG_ENDIAN)
- dest[0] = (unsigned char)(*src - 128);
- dest[1] = 0;
- dest[2] = 0;
-#endif
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int16(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (signed short)((*src - 128) << 8);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void UInt8_To_Int8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- signed char *dest = (signed char*)destinationBuffer;
- (void)ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- (*dest) = (signed char)(*src - 128);
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_8_To_8(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- *dest = *src;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_16_To_16(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- PaUint16 *src = (PaUint16 *)sourceBuffer;
- PaUint16 *dest = (PaUint16 *)destinationBuffer;
-
- if (dest==NULL) return;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- *dest = *src;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_24_To_24(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- unsigned char *src = (unsigned char*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- dest[0] = src[0];
- dest[1] = src[1];
- dest[2] = src[2];
-
- src += sourceStride * 3;
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Copy_32_To_32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- PaUint32 *dest = (PaUint32 *)destinationBuffer;
- PaUint32 *src = (PaUint32 *)sourceBuffer;
-
- (void) ditherGenerator; /* unused parameter */
-
- while( count-- )
- {
- *dest = *src;
-
- src += sourceStride;
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilConverterTable paConverters = {
- Float32_To_Int32, /* PaUtilConverter *Float32_To_Int32; */
- Float32_To_Int32_Dither, /* PaUtilConverter *Float32_To_Int32_Dither; */
- Float32_To_Int32_Clip, /* PaUtilConverter *Float32_To_Int32_Clip; */
- Float32_To_Int32_DitherClip, /* PaUtilConverter *Float32_To_Int32_DitherClip; */
-
- Float32_To_Int24, /* PaUtilConverter *Float32_To_Int24; */
- Float32_To_Int24_Dither, /* PaUtilConverter *Float32_To_Int24_Dither; */
- Float32_To_Int24_Clip, /* PaUtilConverter *Float32_To_Int24_Clip; */
- Float32_To_Int24_DitherClip, /* PaUtilConverter *Float32_To_Int24_DitherClip; */
-
- Float32_To_Int16, /* PaUtilConverter *Float32_To_Int16; */
- Float32_To_Int16_Dither, /* PaUtilConverter *Float32_To_Int16_Dither; */
- Float32_To_Int16_Clip, /* PaUtilConverter *Float32_To_Int16_Clip; */
- Float32_To_Int16_DitherClip, /* PaUtilConverter *Float32_To_Int16_DitherClip; */
-
- Float32_To_Int8, /* PaUtilConverter *Float32_To_Int8; */
- Float32_To_Int8_Dither, /* PaUtilConverter *Float32_To_Int8_Dither; */
- Float32_To_Int8_Clip, /* PaUtilConverter *Float32_To_Int8_Clip; */
- Float32_To_Int8_DitherClip, /* PaUtilConverter *Float32_To_Int8_DitherClip; */
-
- Float32_To_UInt8, /* PaUtilConverter *Float32_To_UInt8; */
- Float32_To_UInt8_Dither, /* PaUtilConverter *Float32_To_UInt8_Dither; */
- Float32_To_UInt8_Clip, /* PaUtilConverter *Float32_To_UInt8_Clip; */
- Float32_To_UInt8_DitherClip, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
-
- Int32_To_Float32, /* PaUtilConverter *Int32_To_Float32; */
- Int32_To_Int24, /* PaUtilConverter *Int32_To_Int24; */
- Int32_To_Int24_Dither, /* PaUtilConverter *Int32_To_Int24_Dither; */
- Int32_To_Int16, /* PaUtilConverter *Int32_To_Int16; */
- Int32_To_Int16_Dither, /* PaUtilConverter *Int32_To_Int16_Dither; */
- Int32_To_Int8, /* PaUtilConverter *Int32_To_Int8; */
- Int32_To_Int8_Dither, /* PaUtilConverter *Int32_To_Int8_Dither; */
- Int32_To_UInt8, /* PaUtilConverter *Int32_To_UInt8; */
- Int32_To_UInt8_Dither, /* PaUtilConverter *Int32_To_UInt8_Dither; */
-
- Int24_To_Float32, /* PaUtilConverter *Int24_To_Float32; */
- Int24_To_Int32, /* PaUtilConverter *Int24_To_Int32; */
- Int24_To_Int16, /* PaUtilConverter *Int24_To_Int16; */
- Int24_To_Int16_Dither, /* PaUtilConverter *Int24_To_Int16_Dither; */
- Int24_To_Int8, /* PaUtilConverter *Int24_To_Int8; */
- Int24_To_Int8_Dither, /* PaUtilConverter *Int24_To_Int8_Dither; */
- Int24_To_UInt8, /* PaUtilConverter *Int24_To_UInt8; */
- Int24_To_UInt8_Dither, /* PaUtilConverter *Int24_To_UInt8_Dither; */
-
- Int16_To_Float32, /* PaUtilConverter *Int16_To_Float32; */
- Int16_To_Int32, /* PaUtilConverter *Int16_To_Int32; */
- Int16_To_Int24, /* PaUtilConverter *Int16_To_Int24; */
- Int16_To_Int8, /* PaUtilConverter *Int16_To_Int8; */
- Int16_To_Int8_Dither, /* PaUtilConverter *Int16_To_Int8_Dither; */
- Int16_To_UInt8, /* PaUtilConverter *Int16_To_UInt8; */
- Int16_To_UInt8_Dither, /* PaUtilConverter *Int16_To_UInt8_Dither; */
-
- Int8_To_Float32, /* PaUtilConverter *Int8_To_Float32; */
- Int8_To_Int32, /* PaUtilConverter *Int8_To_Int32; */
- Int8_To_Int24, /* PaUtilConverter *Int8_To_Int24 */
- Int8_To_Int16, /* PaUtilConverter *Int8_To_Int16; */
- Int8_To_UInt8, /* PaUtilConverter *Int8_To_UInt8; */
-
- UInt8_To_Float32, /* PaUtilConverter *UInt8_To_Float32; */
- UInt8_To_Int32, /* PaUtilConverter *UInt8_To_Int32; */
- UInt8_To_Int24, /* PaUtilConverter *UInt8_To_Int24; */
- UInt8_To_Int16, /* PaUtilConverter *UInt8_To_Int16; */
- UInt8_To_Int8, /* PaUtilConverter *UInt8_To_Int8; */
-
- Copy_8_To_8, /* PaUtilConverter *Copy_8_To_8; */
- Copy_16_To_16, /* PaUtilConverter *Copy_16_To_16; */
- Copy_24_To_24, /* PaUtilConverter *Copy_24_To_24; */
- Copy_32_To_32 /* PaUtilConverter *Copy_32_To_32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#endif /* PA_NO_STANDARD_CONVERTERS */
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat )
-{
- switch( destinationFormat & ~paNonInterleaved ){
- case paFloat32:
- return paZeroers.Zero32;
- case paInt32:
- return paZeroers.Zero32;
- case paInt24:
- return paZeroers.Zero24;
- case paInt16:
- return paZeroers.Zero16;
- case paInt8:
- return paZeroers.Zero8;
- case paUInt8:
- return paZeroers.ZeroU8;
- default: return 0;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-#ifdef PA_NO_STANDARD_ZEROERS
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilZeroerTable paZeroers = {
- 0, /* PaUtilZeroer *ZeroU8; */
- 0, /* PaUtilZeroer *Zero8; */
- 0, /* PaUtilZeroer *Zero16; */
- 0, /* PaUtilZeroer *Zero24; */
- 0, /* PaUtilZeroer *Zero32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#else /* PA_NO_STANDARD_ZEROERS is not defined */
-
-/* -------------------------------------------------------------------------- */
-
-static void ZeroU8( void *destinationBuffer, signed int destinationStride,
- unsigned int count )
-{
- unsigned char *dest = (unsigned char*)destinationBuffer;
-
- while( count-- )
- {
- *dest = 128;
-
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero8( void *destinationBuffer, signed int destinationStride,
- unsigned int count )
-{
- unsigned char *dest = (unsigned char*)destinationBuffer;
-
- while( count-- )
- {
- *dest = 0;
-
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero16( void *destinationBuffer, signed int destinationStride,
- unsigned int count )
-{
- PaUint16 *dest = (PaUint16 *)destinationBuffer;
-
- while( count-- )
- {
- *dest = 0;
-
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero24( void *destinationBuffer, signed int destinationStride,
- unsigned int count )
-{
- unsigned char *dest = (unsigned char*)destinationBuffer;
-
- while( count-- )
- {
- dest[0] = 0;
- dest[1] = 0;
- dest[2] = 0;
-
- dest += destinationStride * 3;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Zero32( void *destinationBuffer, signed int destinationStride,
- unsigned int count )
-{
- PaUint32 *dest = (PaUint32 *)destinationBuffer;
-
- while( count-- )
- {
- *dest = 0;
-
- dest += destinationStride;
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-PaUtilZeroerTable paZeroers = {
- ZeroU8, /* PaUtilZeroer *ZeroU8; */
- Zero8, /* PaUtilZeroer *Zero8; */
- Zero16, /* PaUtilZeroer *Zero16; */
- Zero24, /* PaUtilZeroer *Zero24; */
- Zero32, /* PaUtilZeroer *Zero32; */
-};
-
-/* -------------------------------------------------------------------------- */
-
-#endif /* PA_NO_STANDARD_ZEROERS */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_converters.h b/pjmedia/src/pjmedia/portaudio/pa_converters.h
deleted file mode 100644
index 831c9c64..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_converters.h
+++ /dev/null
@@ -1,254 +0,0 @@
-#ifndef PA_CONVERTERS_H
-#define PA_CONVERTERS_H
-/*
- * $Id: pa_converters.h,v 1.1.2.9 2003/09/20 21:05:14 rossbencina Exp $
- * Portable Audio I/O Library sample conversion mechanism
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Conversion functions used to convert buffers of samples from one
- format to another.
-*/
-
-
-#include "portaudio.h" /* for PaSampleFormat */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-struct PaUtilTriangularDitherGenerator;
-
-
-/** Choose an available sample format which is most appropriate for
- representing the requested format. If the requested format is not available
- higher quality formats are considered before lower quality formates.
- @param availableFormats A variable containing the logical OR of all available
- formats.
- @param format The desired format.
- @return The most appropriate available format for representing the requested
- format.
-*/
-PaSampleFormat PaUtil_SelectClosestAvailableFormat(
- PaSampleFormat availableFormats, PaSampleFormat format );
-
-
-/* high level conversions functions for use by implementations */
-
-
-/** The generic sample converter prototype. Sample converters convert count
- samples from sourceBuffer to destinationBuffer. The actual type of the data
- pointed to by these parameters varys for different converter functions.
- @param destinationBuffer A pointer to the first sample of the destination.
- @param destinationStride An offset between successive destination samples
- expressed in samples (not bytes.) It may be negative.
- @param sourceBuffer A pointer to the first sample of the source.
- @param sourceStride An offset between successive source samples
- expressed in samples (not bytes.) It may be negative.
- @param count The number of samples to convert.
- @param ditherState State information used to calculate dither. Converters
- that do not perform dithering will ignore this parameter, in which case
- NULL or invalid dither state may be passed.
-*/
-typedef void PaUtilConverter(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator );
-
-
-/** Find a sample converter function for the given source and destinations
- formats and flags (clip and dither.)
- @return
- A pointer to a PaUtilConverter which will perform the requested
- conversion, or NULL if the given format conversion is not supported.
- For conversions where clipping or dithering is not necessary, the
- clip and dither flags are ignored and a non-clipping or dithering
- version is returned.
- If the source and destination formats are the same, a function which
- copies data of the appropriate size will be returned.
-*/
-PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
- PaSampleFormat destinationFormat, PaStreamFlags flags );
-
-
-/** The generic buffer zeroer prototype. Buffer zeroers copy count zeros to
- destinationBuffer. The actual type of the data pointed to varys for
- different zeroer functions.
- @param destinationBuffer A pointer to the first sample of the destination.
- @param destinationStride An offset between successive destination samples
- expressed in samples (not bytes.) It may be negative.
- @param count The number of samples to zero.
-*/
-typedef void PaUtilZeroer(
- void *destinationBuffer, signed int destinationStride, unsigned int count );
-
-
-/** Find a buffer zeroer function for the given destination format.
- @return
- A pointer to a PaUtilZeroer which will perform the requested
- zeroing.
-*/
-PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat );
-
-/*----------------------------------------------------------------------------*/
-/* low level functions and data structures which may be used for
- substituting conversion functions */
-
-
-/** The type used to store all sample conversion functions.
- @see paConverters;
-*/
-typedef struct{
- PaUtilConverter *Float32_To_Int32;
- PaUtilConverter *Float32_To_Int32_Dither;
- PaUtilConverter *Float32_To_Int32_Clip;
- PaUtilConverter *Float32_To_Int32_DitherClip;
-
- PaUtilConverter *Float32_To_Int24;
- PaUtilConverter *Float32_To_Int24_Dither;
- PaUtilConverter *Float32_To_Int24_Clip;
- PaUtilConverter *Float32_To_Int24_DitherClip;
-
- PaUtilConverter *Float32_To_Int16;
- PaUtilConverter *Float32_To_Int16_Dither;
- PaUtilConverter *Float32_To_Int16_Clip;
- PaUtilConverter *Float32_To_Int16_DitherClip;
-
- PaUtilConverter *Float32_To_Int8;
- PaUtilConverter *Float32_To_Int8_Dither;
- PaUtilConverter *Float32_To_Int8_Clip;
- PaUtilConverter *Float32_To_Int8_DitherClip;
-
- PaUtilConverter *Float32_To_UInt8;
- PaUtilConverter *Float32_To_UInt8_Dither;
- PaUtilConverter *Float32_To_UInt8_Clip;
- PaUtilConverter *Float32_To_UInt8_DitherClip;
-
- PaUtilConverter *Int32_To_Float32;
- PaUtilConverter *Int32_To_Int24;
- PaUtilConverter *Int32_To_Int24_Dither;
- PaUtilConverter *Int32_To_Int16;
- PaUtilConverter *Int32_To_Int16_Dither;
- PaUtilConverter *Int32_To_Int8;
- PaUtilConverter *Int32_To_Int8_Dither;
- PaUtilConverter *Int32_To_UInt8;
- PaUtilConverter *Int32_To_UInt8_Dither;
-
- PaUtilConverter *Int24_To_Float32;
- PaUtilConverter *Int24_To_Int32;
- PaUtilConverter *Int24_To_Int16;
- PaUtilConverter *Int24_To_Int16_Dither;
- PaUtilConverter *Int24_To_Int8;
- PaUtilConverter *Int24_To_Int8_Dither;
- PaUtilConverter *Int24_To_UInt8;
- PaUtilConverter *Int24_To_UInt8_Dither;
-
- PaUtilConverter *Int16_To_Float32;
- PaUtilConverter *Int16_To_Int32;
- PaUtilConverter *Int16_To_Int24;
- PaUtilConverter *Int16_To_Int8;
- PaUtilConverter *Int16_To_Int8_Dither;
- PaUtilConverter *Int16_To_UInt8;
- PaUtilConverter *Int16_To_UInt8_Dither;
-
- PaUtilConverter *Int8_To_Float32;
- PaUtilConverter *Int8_To_Int32;
- PaUtilConverter *Int8_To_Int24;
- PaUtilConverter *Int8_To_Int16;
- PaUtilConverter *Int8_To_UInt8;
-
- PaUtilConverter *UInt8_To_Float32;
- PaUtilConverter *UInt8_To_Int32;
- PaUtilConverter *UInt8_To_Int24;
- PaUtilConverter *UInt8_To_Int16;
- PaUtilConverter *UInt8_To_Int8;
-
- PaUtilConverter *Copy_8_To_8; /* copy without any conversion */
- PaUtilConverter *Copy_16_To_16; /* copy without any conversion */
- PaUtilConverter *Copy_24_To_24; /* copy without any conversion */
- PaUtilConverter *Copy_32_To_32; /* copy without any conversion */
-} PaUtilConverterTable;
-
-
-/** A table of pointers to all required converter functions.
- PaUtil_SelectConverter() uses this table to lookup the appropriate
- conversion functions. The fields of this structure are initialized
- with default conversion functions. Fields may be NULL, indicating that
- no conversion function is available. User code may substitue optimised
- conversion functions by assigning different function pointers to
- these fields.
-
- @note
- If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined,
- PortAudio's standard converters will not be compiled, and all fields
- of this structure will be initialized to NULL. In such cases, users
- should supply their own conversion functions if the require PortAudio
- to open a stream that requires sample conversion.
-
- @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter
-*/
-extern PaUtilConverterTable paConverters;
-
-
-/** The type used to store all buffer zeroing functions.
- @see paZeroers;
-*/
-typedef struct{
- PaUtilZeroer *ZeroU8; /* unsigned 8 bit, zero == 128 */
- PaUtilZeroer *Zero8;
- PaUtilZeroer *Zero16;
- PaUtilZeroer *Zero24;
- PaUtilZeroer *Zero32;
-} PaUtilZeroerTable;
-
-
-/** A table of pointers to all required zeroer functions.
- PaUtil_SelectZeroer() uses this table to lookup the appropriate
- conversion functions. The fields of this structure are initialized
- with default conversion functions. User code may substitue optimised
- conversion functions by assigning different function pointers to
- these fields.
-
- @note
- If the PA_NO_STANDARD_ZEROERS preprocessor variable is defined,
- PortAudio's standard zeroers will not be compiled, and all fields
- of this structure will be initialized to NULL. In such cases, users
- should supply their own zeroing functions for the sample sizes which
- they intend to use.
-
- @see PaUtilZeroerTable, PaUtilZeroer, PaUtil_SelectZeroer
-*/
-extern PaUtilZeroerTable paZeroers;
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_CONVERTERS_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_cpuload.c b/pjmedia/src/pjmedia/portaudio/pa_cpuload.c
deleted file mode 100644
index e70fbf4e..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_cpuload.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * $Id: pa_cpuload.c,v 1.1.2.14 2004/01/08 22:01:12 rossbencina Exp $
- * Portable Audio I/O Library CPU Load measurement functions
- * Portable CPU load measurement facility.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2002 Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Functions to assist in measuring the CPU utilization of a callback
- stream. Used to implement the Pa_GetStreamCpuLoad() function.
-
- @todo Dynamically calculate the coefficients used to smooth the CPU Load
- Measurements over time to provide a uniform characterisation of CPU Load
- independent of rate at which PaUtil_BeginCpuLoadMeasurement /
- PaUtil_EndCpuLoadMeasurement are called.
-*/
-
-
-#include "pa_cpuload.h"
-
-#include <assert.h>
-
-#include "pa_util.h" /* for PaUtil_GetTime() */
-
-
-void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate )
-{
- assert( sampleRate > 0 );
-
- measurer->samplingPeriod = 1. / sampleRate;
- measurer->averageLoad = 0.;
-}
-
-void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer )
-{
- measurer->averageLoad = 0.;
-}
-
-void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer )
-{
- measurer->measurementStartTime = PaUtil_GetTime();
-}
-
-
-void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed )
-{
- double measurementEndTime, secondsFor100Percent, measuredLoad;
-
- if( framesProcessed > 0 ){
- measurementEndTime = PaUtil_GetTime();
-
- assert( framesProcessed > 0 );
- secondsFor100Percent = framesProcessed * measurer->samplingPeriod;
-
- measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent;
-
- /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */
- /** FIXME @todo these coefficients shouldn't be hardwired */
-#define LOWPASS_COEFFICIENT_0 (0.9)
-#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
-
- measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) +
- (LOWPASS_COEFFICIENT_1 * measuredLoad);
- }
-}
-
-
-double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer )
-{
- return measurer->averageLoad;
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_cpuload.h b/pjmedia/src/pjmedia/portaudio/pa_cpuload.h
deleted file mode 100644
index f77d9199..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_cpuload.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef PA_CPULOAD_H
-#define PA_CPULOAD_H
-/*
- * $Id: pa_cpuload.h,v 1.1.2.10 2004/01/08 22:01:12 rossbencina Exp $
- * Portable Audio I/O Library CPU Load measurement functions
- * Portable CPU load measurement facility.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2002 Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Functions to assist in measuring the CPU utilization of a callback
- stream. Used to implement the Pa_GetStreamCpuLoad() function.
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-typedef struct {
- double samplingPeriod;
- double measurementStartTime;
- double averageLoad;
-} PaUtilCpuLoadMeasurer; /**< @todo need better name than measurer */
-
-void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate );
-void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer );
-void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed );
-void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer );
-double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_CPULOAD_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_dither.c b/pjmedia/src/pjmedia/portaudio/pa_dither.c
deleted file mode 100644
index 0600db62..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_dither.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * $Id: pa_dither.c,v 1.1.2.6 2005/05/28 22:49:02 rossbencina Exp $
- * Portable Audio I/O Library triangular dither generator
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Functions for generating dither noise
-*/
-
-
-#include "pa_dither.h"
-#include "pa_types.h"
-
-#define PA_DITHER_BITS_ (15)
-
-
-void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state )
-{
- state->previous = 0;
- state->randSeed1 = 22222;
- state->randSeed2 = 5555555;
-}
-
-
-signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state )
-{
- signed long current, highPass;
-
- /* Generate two random numbers. */
- state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
- state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
-
- /* Generate triangular distribution about 0.
- * Shift before adding to prevent overflow which would skew the distribution.
- * Also shift an extra bit for the high pass filter.
- */
-#define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
- current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
- (((signed long)state->randSeed2)>>DITHER_SHIFT_);
-
- /* High pass filter to reduce audibility. */
- highPass = current - state->previous;
- state->previous = current;
- return highPass;
-}
-
-
-/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
-#define PA_FLOAT_DITHER_SCALE_ (1.0f / ((1<<PA_DITHER_BITS_)-1))
-static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;
-
-float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *state )
-{
- signed long current, highPass;
-
- /* Generate two random numbers. */
- state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
- state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
-
- /* Generate triangular distribution about 0.
- * Shift before adding to prevent overflow which would skew the distribution.
- * Also shift an extra bit for the high pass filter.
- */
-#define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
- current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
- (((signed long)state->randSeed2)>>DITHER_SHIFT_);
-
- /* High pass filter to reduce audibility. */
- highPass = current - state->previous;
- state->previous = current;
- return ((float)highPass) * const_float_dither_scale_;
-}
-
-
-/*
-The following alternate dither algorithms (from musicdsp.org) could be
-considered
-*/
-
-/*Noise shaped dither (March 2000)
--------------------
-
-This is a simple implementation of highpass triangular-PDF dither with
-2nd-order noise shaping, for use when truncating floating point audio
-data to fixed point.
-
-The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz
-sample rate) compared to triangular-PDF dither. The code below assumes
-input data is in the range +1 to -1 and doesn't check for overloads!
-
-To save time when generating dither for multiple channels you can do
-things like this: r3=(r1 & 0x7F)<<8; instead of calling rand() again.
-
-
-
- int r1, r2; //rectangular-PDF random numbers
- float s1, s2; //error feedback buffers
- float s = 0.5f; //set to 0.0f for no noise shaping
- float w = pow(2.0,bits-1); //word length (usually bits=16)
- float wi= 1.0f/w;
- float d = wi / RAND_MAX; //dither amplitude (2 lsb)
- float o = wi * 0.5f; //remove dc offset
- float in, tmp;
- int out;
-
-
-//for each sample...
-
- r2=r1; //can make HP-TRI dither by
- r1=rand(); //subtracting previous rand()
-
- in += s * (s1 + s1 - s2); //error feedback
- tmp = in + o + d * (float)(r1 - r2); //dc offset and dither
-
- out = (int)(w * tmp); //truncate downwards
- if(tmp<0.0f) out--; //this is faster than floor()
-
- s2 = s1;
- s1 = in - wi * (float)out; //error
-
-
-
---
-paul.kellett@maxim.abel.co.uk
-http://www.maxim.abel.co.uk
-*/
-
-
-/*
-16-to-8-bit first-order dither
-
-Type : First order error feedforward dithering code
-References : Posted by Jon Watte
-
-Notes :
-This is about as simple a dithering algorithm as you can implement, but it's
-likely to sound better than just truncating to N bits.
-
-Note that you might not want to carry forward the full difference for infinity.
-It's probably likely that the worst performance hit comes from the saturation
-conditionals, which can be avoided with appropriate instructions on many DSPs
-and integer SIMD type instructions, or CMOV.
-
-Last, if sound quality is paramount (such as when going from > 16 bits to 16
-bits) you probably want to use a higher-order dither function found elsewhere
-on this site.
-
-
-Code :
-// This code will down-convert and dither a 16-bit signed short
-// mono signal into an 8-bit unsigned char signal, using a first
-// order forward-feeding error term dither.
-
-#define uchar unsigned char
-
-void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory )
-{
- int m = *memory;
- while( count-- > 0 ) {
- int i = *input++;
- i += m;
- int j = i + 32768 - 128;
- uchar o;
- if( j < 0 ) {
- o = 0;
- }
- else if( j > 65535 ) {
- o = 255;
- }
- else {
- o = (uchar)((j>>8)&0xff);
- }
- m = ((j-32768+128)-i);
- *output++ = o;
- }
- *memory = m;
-}
-*/
diff --git a/pjmedia/src/pjmedia/portaudio/pa_dither.h b/pjmedia/src/pjmedia/portaudio/pa_dither.h
deleted file mode 100644
index 70369e18..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_dither.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef PA_DITHER_H
-#define PA_DITHER_H
-/*
- * $Id: pa_dither.h,v 1.1.2.4 2003/09/20 21:06:19 rossbencina Exp $
- * Portable Audio I/O Library triangular dither generator
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Functions for generating dither noise
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** @brief State needed to generate a dither signal */
-typedef struct PaUtilTriangularDitherGenerator{
- unsigned long previous;
- unsigned long randSeed1;
- unsigned long randSeed2;
-} PaUtilTriangularDitherGenerator;
-
-
-/** @brief Initialize dither state */
-void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState );
-
-
-/**
- @brief Calculate 2 LSB dither signal with a triangular distribution.
- Ranged for adding to a 1 bit right-shifted 32 bit integer
- prior to >>15. eg:
-<pre>
- signed long in = *
- signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );
- signed short out = (signed short)(((in>>1) + dither) >> 15);
-</pre>
- @return
- A signed long with a range of +32767 to -32768
-*/
-signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
-
-
-/**
- @brief Calculate 2 LSB dither signal with a triangular distribution.
- Ranged for adding to a pre-scaled float.
-<pre>
- float in = *
- float dither = PaUtil_GenerateFloatTriangularDither( ditherState );
- // use smaller scaler to prevent overflow when we add the dither
- signed short out = (signed short)(in*(32766.0f) + dither );
-</pre>
- @return
- A float with a range of -2.0 to +1.99999.
-*/
-float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_DITHER_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_endianness.h b/pjmedia/src/pjmedia/portaudio/pa_endianness.h
deleted file mode 100644
index 38932438..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_endianness.h
+++ /dev/null
@@ -1,122 +0,0 @@
-#ifndef PA_ENDIANNESS_H
-#define PA_ENDIANNESS_H
-/*
- * $Id: pa_endianness.h,v 1.1.2.3 2003/09/20 21:06:19 rossbencina Exp $
- * Portable Audio I/O Library current platform endianness macros
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Configure endianness symbols for the target processor.
-
- Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols
- to be defined. The one that is defined reflects the endianness of the target
- platform and may be used to implement conditional compilation of byte-order
- dependent code.
-
- If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt
- is made to override that setting. This may be useful if you have a better way
- of determining the platform's endianness. The autoconf mechanism uses this for
- example.
-
- A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time
- and runtime endiannes and raise an assertion if they don't match.
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-#include <pj/config.h>
-
-#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
-# define PA_BIG_ENDIAN 1
-#elif defined(PJ_IS_LITTLE_ENDIAN) && PJ_IS_LITTLE_ENDIAN!=0
-# define PA_LITTLE_ENDIAN 1
-#else
-# error "Unable to detect PJLIB's endianness"
-#endif
-
-
-
-#if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN)
- /* endianness define has been set externally, such as by autoconf */
-
- #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN)
- #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please
- #endif
-
-#else
- /* endianness define has not been set externally */
-
- /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */
-
- #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
-
- #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */
-
- #else
-
-#endif
-
- #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN)
- /*
- If the following error is raised, you either need to modify the code above
- to automatically determine the endianness from other symbols defined on your
- platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally.
- */
- #error pa_endianness.h was unable to automatically determine the endianness of the target platform
- #endif
-
-#endif
-
-/* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness,
- and raises an assertion if they don't match. <assert.h> must be included in
- the context in which this macro is used.
-*/
-#if defined(PA_LITTLE_ENDIAN)
- #define PA_VALIDATE_ENDIANNESS \
- { \
- const long nativeOne = 1; \
- assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \
- }
-#elif defined(PA_BIG_ENDIAN)
- #define PA_VALIDATE_ENDIANNESS \
- { \
- const long nativeOne = 1; \
- assert( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \
- }
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_ENDIANNESS_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_front.c b/pjmedia/src/pjmedia/portaudio/pa_front.c
deleted file mode 100644
index 3a267bbc..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_front.c
+++ /dev/null
@@ -1,1976 +0,0 @@
-/*
- * $Id: pa_front.c,v 1.1.2.51 2005/02/05 15:52:12 rossbencina Exp $
- * Portable Audio I/O Library Multi-Host API front end
- * Validate function parameters and manage multiple host APIs.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/* doxygen index page */
-/** @mainpage
-
-PortAudio is an open-source cross-platform †CË library for audio input
-and output. It is designed to simplify the porting of audio applications
-between various platforms, and also to simplify the development of audio
-software in general by hiding the complexities of device interfacing.
-
-See the PortAudio website for further information http://www.portaudio.com/
-
-This documentation pertains to PortAudio V19, API version 2.0 which is
-currently under development. API version 2.0 differs in a number of ways from
-previous versions, please consult the enhancement proposals for further details:
-http://www.portaudio.com/docs/proposals/index.html
-
-This documentation is under construction. Things you might be interested in
-include:
-
-- The PortAudio API 2.0, as documented in portaudio.h
-
-- The <a href="todo.html">TODO List</a>
-
-Feel free to pick an item off TODO list and fix/implement it. You may want to
-enquire about status on the PortAudio mailing list first.
-*/
-
-
-/** @file
- @brief Implements public PortAudio API, checks some errors, forwards to
- host API implementations.
-
- Implements the functions defined in the PortAudio API, checks for
- some parameter and state inconsistencies and forwards API requests to
- specific Host API implementations (via the interface declared in
- pa_hostapi.h), and Streams (via the interface declared in pa_stream.h).
-
- This file handles initialization and termination of Host API
- implementations via initializers stored in the paHostApiInitializers
- global variable.
-
- Some utility functions declared in pa_util.h are implemented in this file.
-
- All PortAudio API functions can be conditionally compiled with logging code.
- To compile with logging, define the PA_LOG_API_CALLS precompiler symbol.
-
- @todo Consider adding host API specific error text in Pa_GetErrorText() for
- paUnanticipatedHostError
-
- @todo Consider adding a new error code for when (inputParameters == NULL)
- && (outputParameters == NULL)
-
- @todo review whether Pa_CloseStream() should call the interface's
- CloseStream function if aborting the stream returns an error code.
-
- @todo Create new error codes if a NULL buffer pointer, or a
- zero frame count is passed to Pa_ReadStream or Pa_WriteStream.
-*/
-
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <memory.h>
-#include <string.h>
-#include <assert.h> /* needed by PA_VALIDATE_ENDIANNESS */
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_endianness.h"
-#include "pa_types.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-
-#include "pa_trace.h"
-
-
-#define PA_VERSION_ 1899
-#define PA_VERSION_TEXT_ "PortAudio V19-devel"
-
-
-
-/* #define PA_LOG_API_CALLS */
-
-/*
- The basic format for log messages is described below. If you need to
- add any log messages, please follow this format.
-
- Function entry (void function):
-
- "FunctionName called.\n"
-
- Function entry (non void function):
-
- "FunctionName called:\n"
- "\tParam1Type param1: param1Value\n"
- "\tParam2Type param2: param2Value\n" (etc...)
-
-
- Function exit (no return value):
-
- "FunctionName returned.\n"
-
- Function exit (simple return value):
-
- "FunctionName returned:\n"
- "\tReturnType: returnValue\n\n"
-
- If the return type is an error code, the error text is displayed in ()
-
- If the return type is not an error code, but has taken a special value
- because an error occurred, then the reason for the error is shown in []
-
- If the return type is a struct ptr, the struct is dumped.
-
- See the code below for examples
-*/
-
-
-int Pa_GetVersion( void )
-{
- return PA_VERSION_;
-}
-
-
-const char* Pa_GetVersionText( void )
-{
- return PA_VERSION_TEXT_;
-}
-
-
-
-#define PA_LAST_HOST_ERROR_TEXT_LENGTH_ 1024
-
-static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0};
-
-static PaHostErrorInfo lastHostErrorInfo_ = { (PaHostApiTypeId)-1, 0, lastHostErrorText_ };
-
-
-void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
- const char *errorText )
-{
- lastHostErrorInfo_.hostApiType = hostApiType;
- lastHostErrorInfo_.errorCode = errorCode;
-
- strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ );
-}
-
-
-void PaUtil_DebugPrint( const char *format, ... )
-{
- va_list ap;
-
- va_start( ap, format );
- vfprintf( stderr, format, ap );
- va_end( ap );
-
- fflush( stderr );
-}
-
-
-static PaUtilHostApiRepresentation **hostApis_ = 0;
-static int hostApisCount_ = 0;
-static int initializationCount_ = 0;
-static int deviceCount_ = 0;
-
-PaUtilStreamRepresentation *firstOpenStream_ = NULL;
-
-
-#define PA_IS_INITIALISED_ (initializationCount_ != 0)
-
-
-static int CountHostApiInitializers( void )
-{
- int result = 0;
-
- while( paHostApiInitializers[ result ] != 0 )
- ++result;
- return result;
-}
-
-
-static void TerminateHostApis( void )
-{
- /* terminate in reverse order from initialization */
-
- while( hostApisCount_ > 0 )
- {
- --hostApisCount_;
- hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] );
- }
- hostApisCount_ = 0;
- deviceCount_ = 0;
-
- if( hostApis_ != 0 )
- PaUtil_FreeMemory( hostApis_ );
- hostApis_ = 0;
-}
-
-
-static PaError InitializeHostApis( void )
-{
- PaError result = paNoError;
- int i, initializerCount, baseDeviceIndex;
-
- initializerCount = CountHostApiInitializers();
-
- hostApis_ = (PaUtilHostApiRepresentation**)PaUtil_AllocateMemory(
- sizeof(PaUtilHostApiRepresentation*) * initializerCount );
- if( !hostApis_ )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- hostApisCount_ = 0;
- deviceCount_ = 0;
- baseDeviceIndex = 0;
-
- for( i=0; i< initializerCount; ++i )
- {
- hostApis_[hostApisCount_] = NULL;
- result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ );
- if( result != paNoError )
- goto error;
-
- if( hostApis_[hostApisCount_] )
- {
-
- hostApis_[hostApisCount_]->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
-
- if( hostApis_[hostApisCount_]->info.defaultInputDevice != paNoDevice )
- hostApis_[hostApisCount_]->info.defaultInputDevice += baseDeviceIndex;
-
- if( hostApis_[hostApisCount_]->info.defaultOutputDevice != paNoDevice )
- hostApis_[hostApisCount_]->info.defaultOutputDevice += baseDeviceIndex;
-
- baseDeviceIndex += hostApis_[hostApisCount_]->info.deviceCount;
- deviceCount_ += hostApis_[hostApisCount_]->info.deviceCount;
-
- ++hostApisCount_;
- }
- }
-
- return result;
-
-error:
- TerminateHostApis();
- return result;
-}
-
-
-/*
- FindHostApi() finds the index of the host api to which
- <device> belongs and returns it. if <hostSpecificDeviceIndex> is
- non-null, the host specific device index is returned in it.
- returns -1 if <device> is out of range.
-
-*/
-static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex )
-{
- int i=0;
-
- if( !PA_IS_INITIALISED_ )
- return -1;
-
- if( device < 0 )
- return -1;
-
- while( i < hostApisCount_
- && device >= hostApis_[i]->info.deviceCount )
- {
-
- device -= hostApis_[i]->info.deviceCount;
- ++i;
- }
-
- if( i >= hostApisCount_ )
- return -1;
-
- if( hostSpecificDeviceIndex )
- *hostSpecificDeviceIndex = device;
-
- return i;
-}
-
-
-static void AddOpenStream( PaStream* stream )
-{
- ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_;
- firstOpenStream_ = (PaUtilStreamRepresentation*)stream;
-}
-
-
-static void RemoveOpenStream( PaStream* stream )
-{
- PaUtilStreamRepresentation *previous = NULL;
- PaUtilStreamRepresentation *current = firstOpenStream_;
-
- while( current != NULL )
- {
- if( ((PaStream*)current) == stream )
- {
- if( previous == NULL )
- {
- firstOpenStream_ = current->nextOpenStream;
- }
- else
- {
- previous->nextOpenStream = current->nextOpenStream;
- }
- return;
- }
- else
- {
- previous = current;
- current = current->nextOpenStream;
- }
- }
-}
-
-
-static void CloseOpenStreams( void )
-{
- /* we call Pa_CloseStream() here to ensure that the same destruction
- logic is used for automatically closed streams */
-
- while( firstOpenStream_ != NULL )
- Pa_CloseStream( firstOpenStream_ );
-}
-
-
-PaError Pa_Initialize( void )
-{
- PaError result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint( "Pa_Initialize called.\n" );
-#endif
-
- if( PA_IS_INITIALISED_ )
- {
- ++initializationCount_;
- result = paNoError;
- }
- else
- {
- PA_VALIDATE_TYPE_SIZES;
- PA_VALIDATE_ENDIANNESS;
-
- PaUtil_InitializeClock();
- PaUtil_ResetTraceMessages();
-
- result = InitializeHostApis();
- if( result == paNoError )
- ++initializationCount_;
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint( "Pa_Initialize returned:\n" );
- PaUtil_DebugPrint( "\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_Terminate( void )
-{
- PaError result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_Terminate called.\n" );
-#endif
-
- if( PA_IS_INITIALISED_ )
- {
- if( --initializationCount_ == 0 )
- {
- CloseOpenStreams();
-
- TerminateHostApis();
-
- PaUtil_DumpTraceMessages();
- }
- result = paNoError;
- }
- else
- {
- result= paNotInitialized;
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_Terminate returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void )
-{
- return &lastHostErrorInfo_;
-}
-
-
-const char *Pa_GetErrorText( PaError errorCode )
-{
- const char *result;
-
- switch( errorCode )
- {
- case paNoError: result = "Success"; break;
- case paNotInitialized: result = "PortAudio not initialized"; break;
- /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */
- case paUnanticipatedHostError: result = "Unanticipated host error"; break;
- case paInvalidChannelCount: result = "Invalid number of channels"; break;
- case paInvalidSampleRate: result = "Invalid sample rate"; break;
- case paInvalidDevice: result = "Invalid device"; break;
- case paInvalidFlag: result = "Invalid flag"; break;
- case paSampleFormatNotSupported: result = "Sample format not supported"; break;
- case paBadIODeviceCombination: result = "Illegal combination of I/O devices"; break;
- case paInsufficientMemory: result = "Insufficient memory"; break;
- case paBufferTooBig: result = "Buffer too big"; break;
- case paBufferTooSmall: result = "Buffer too small"; break;
- case paNullCallback: result = "No callback routine specified"; break;
- case paBadStreamPtr: result = "Invalid stream pointer"; break;
- case paTimedOut: result = "Wait timed out"; break;
- case paInternalError: result = "Internal PortAudio error"; break;
- case paDeviceUnavailable: result = "Device unavailable"; break;
- case paIncompatibleHostApiSpecificStreamInfo: result = "Incompatible host API specific stream info"; break;
- case paStreamIsStopped: result = "Stream is stopped"; break;
- case paStreamIsNotStopped: result = "Stream is not stopped"; break;
- case paInputOverflowed: result = "Input overflowed"; break;
- case paOutputUnderflowed: result = "Output underflowed"; break;
- case paHostApiNotFound: result = "Host API not found"; break;
- case paInvalidHostApi: result = "Invalid host API"; break;
- case paCanNotReadFromACallbackStream: result = "Can't read from a callback stream"; break;
- case paCanNotWriteToACallbackStream: result = "Can't write to a callback stream"; break;
- case paCanNotReadFromAnOutputOnlyStream: result = "Can't read from an output only stream"; break;
- case paCanNotWriteToAnInputOnlyStream: result = "Can't write to an input only stream"; break;
- default: result = "Illegal error number"; break;
- }
- return result;
-}
-
-
-PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )
-{
- PaHostApiIndex result;
- int i;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex called:\n" );
- PaUtil_DebugPrint("\tPaHostApiTypeId type: %d\n", type );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
- }
- else
- {
- result = paHostApiNotFound;
-
- for( i=0; i < hostApisCount_; ++i )
- {
- if( hostApis_[i]->info.type == type )
- {
- result = i;
- break;
- }
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" );
- if( result < 0 )
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
- else
- PaUtil_DebugPrint("\tPaHostApiIndex: %d\n\n", result );
-#endif
-
- return result;
-}
-
-
-PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
- PaHostApiTypeId type )
-{
- PaError result;
- int i;
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
- }
- else
- {
- result = paHostApiNotFound;
-
- for( i=0; i < hostApisCount_; ++i )
- {
- if( hostApis_[i]->info.type == type )
- {
- *hostApi = hostApis_[i];
- result = paNoError;
- break;
- }
- }
- }
-
- return result;
-}
-
-
-PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
- PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi )
-{
- PaError result;
- PaDeviceIndex x;
-
- x = device - hostApi->privatePaFrontInfo.baseDeviceIndex;
-
- if( x < 0 || x >= hostApi->info.deviceCount )
- {
- result = paInvalidDevice;
- }
- else
- {
- *hostApiDevice = x;
- result = paNoError;
- }
-
- return result;
-}
-
-
-PaHostApiIndex Pa_GetHostApiCount( void )
-{
- int result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetHostApiCount called.\n" );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
- }
- else
- {
- result = hostApisCount_;
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetHostApiCount returned:\n" );
- if( result < 0 )
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
- else
- PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );
-#endif
-
- return result;
-}
-
-
-PaHostApiIndex Pa_GetDefaultHostApi( void )
-{
- int result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDefaultHostApi called.\n" );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
- }
- else
- {
- result = paDefaultHostApiIndex;
-
- /* internal consistency check: make sure that the default host api
- index is within range */
-
- if( result < 0 || result >= hostApisCount_ )
- {
- result = paInternalError;
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
- if( result < 0 )
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
- else
- PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );
-#endif
-
- return result;
-}
-
-
-const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi )
-{
- PaHostApiInfo *info;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetHostApiInfo called:\n" );
- PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- info = NULL;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
- PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n\n" );
-#endif
-
- }
- else if( hostApi < 0 || hostApi >= hostApisCount_ )
- {
- info = NULL;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
- PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n\n" );
-#endif
-
- }
- else
- {
- info = &hostApis_[hostApi]->info;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
- PaUtil_DebugPrint("\tPaHostApiInfo*: 0x%p\n", info );
- PaUtil_DebugPrint("\t{" );
- PaUtil_DebugPrint("\t\tint structVersion: %d\n", info->structVersion );
- PaUtil_DebugPrint("\t\tPaHostApiTypeId type: %d\n", info->type );
- PaUtil_DebugPrint("\t\tconst char *name: %s\n\n", info->name );
- PaUtil_DebugPrint("\t}\n\n" );
-#endif
-
- }
-
- return info;
-}
-
-
-PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex )
-{
- PaDeviceIndex result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex called:\n" );
- PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
- PaUtil_DebugPrint("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
- }
- else
- {
- if( hostApi < 0 || hostApi >= hostApisCount_ )
- {
- result = paInvalidHostApi;
- }
- else
- {
- if( hostApiDeviceIndex < 0 ||
- hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount )
- {
- result = paInvalidDevice;
- }
- else
- {
- result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex;
- }
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
- if( result < 0 )
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
- else
- PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
- return result;
-}
-
-
-PaDeviceIndex Pa_GetDeviceCount( void )
-{
- PaDeviceIndex result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDeviceCount called.\n" );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
- }
- else
- {
- result = deviceCount_;
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDeviceCount returned:\n" );
- if( result < 0 )
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
- else
- PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
- return result;
-}
-
-
-PaDeviceIndex Pa_GetDefaultInputDevice( void )
-{
- PaHostApiIndex hostApi;
- PaDeviceIndex result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDefaultInputDevice called.\n" );
-#endif
-
- hostApi = Pa_GetDefaultHostApi();
- if( hostApi < 0 )
- {
- result = paNoDevice;
- }
- else
- {
- result = hostApis_[hostApi]->info.defaultInputDevice;
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDefaultInputDevice returned:\n" );
- PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
- return result;
-}
-
-
-PaDeviceIndex Pa_GetDefaultOutputDevice( void )
-{
- PaHostApiIndex hostApi;
- PaDeviceIndex result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDefaultOutputDevice called.\n" );
-#endif
-
- hostApi = Pa_GetDefaultHostApi();
- if( hostApi < 0 )
- {
- result = paNoDevice;
- }
- else
- {
- result = hostApis_[hostApi]->info.defaultOutputDevice;
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDefaultOutputDevice returned:\n" );
- PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
-#endif
-
- return result;
-}
-
-
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
-{
- int hostSpecificDeviceIndex;
- int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex );
- PaDeviceInfo *result;
-
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDeviceInfo called:\n" );
- PaUtil_DebugPrint("\tPaDeviceIndex device: %d\n", device );
-#endif
-
- if( hostApiIndex < 0 )
- {
- result = NULL;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
- PaUtil_DebugPrint("\tPaDeviceInfo* NULL [ invalid device index ]\n\n" );
-#endif
-
- }
- else
- {
- result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ];
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
- PaUtil_DebugPrint("\tPaDeviceInfo*: 0x%p:\n", result );
- PaUtil_DebugPrint("\t{\n" );
-
- PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
- PaUtil_DebugPrint("\t\tconst char *name: %s\n", result->name );
- PaUtil_DebugPrint("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi );
- PaUtil_DebugPrint("\t\tint maxInputChannels: %d\n", result->maxInputChannels );
- PaUtil_DebugPrint("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels );
- PaUtil_DebugPrint("\t}\n\n" );
-#endif
-
- }
-
- return result;
-}
-
-
-/*
- SampleFormatIsValid() returns 1 if sampleFormat is a sample format
- defined in portaudio.h, or 0 otherwise.
-*/
-static int SampleFormatIsValid( PaSampleFormat format )
-{
- switch( format & ~paNonInterleaved )
- {
- case paFloat32: return 1;
- case paInt16: return 1;
- case paInt32: return 1;
- case paInt24: return 1;
- case paInt8: return 1;
- case paUInt8: return 1;
- case paCustomFormat: return 1;
- default: return 0;
- }
-}
-
-/*
- NOTE: make sure this validation list is kept syncronised with the one in
- pa_hostapi.h
-
- ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream()
- conform to the expected values as described below. This function is
- also designed to be used with the proposed Pa_IsFormatSupported() function.
-
- There are basically two types of validation that could be performed:
- Generic conformance validation, and device capability mismatch
- validation. This function performs only generic conformance validation.
- Validation that would require knowledge of device capabilities is
- not performed because of potentially complex relationships between
- combinations of parameters - for example, even if the sampleRate
- seems ok, it might not be for a duplex stream - we have no way of
- checking this in an API-neutral way, so we don't try.
-
- On success the function returns PaNoError and fills in hostApi,
- hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure
- the function returns an error code indicating the first encountered
- parameter error.
-
-
- If ValidateOpenStreamParameters() returns paNoError, the following
- assertions are guaranteed to be true.
-
- - at least one of inputParameters & outputParmeters is valid (not NULL)
-
- - if inputParameters & outputParmeters are both valid, that
- inputParameters->device & outputParmeters->device both use the same host api
-
- PaDeviceIndex inputParameters->device
- - is within range (0 to Pa_GetDeviceCount-1) Or:
- - is paUseHostApiSpecificDeviceSpecification and
- inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
- to a valid host api
-
- int inputParameters->channelCount
- - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0
- - upper bound is NOT validated against device capabilities
-
- PaSampleFormat inputParameters->sampleFormat
- - is one of the sample formats defined in portaudio.h
-
- void *inputParameters->hostApiSpecificStreamInfo
- - if supplied its hostApi field matches the input device's host Api
-
- PaDeviceIndex outputParmeters->device
- - is within range (0 to Pa_GetDeviceCount-1)
-
- int outputParmeters->channelCount
- - if inputDevice is valid, channelCount is > 0
- - upper bound is NOT validated against device capabilities
-
- PaSampleFormat outputParmeters->sampleFormat
- - is one of the sample formats defined in portaudio.h
-
- void *outputParmeters->hostApiSpecificStreamInfo
- - if supplied its hostApi field matches the output device's host Api
-
- double sampleRate
- - is not an 'absurd' rate (less than 1000. or greater than 200000.)
- - sampleRate is NOT validated against device capabilities
-
- PaStreamFlags streamFlags
- - unused platform neutral flags are zero
- - paNeverDropInput is only used for full-duplex callback streams with
- variable buffer size (paFramesPerBufferUnspecified)
-*/
-static PaError ValidateOpenStreamParameters(
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- PaUtilHostApiRepresentation **hostApi,
- PaDeviceIndex *hostApiInputDevice,
- PaDeviceIndex *hostApiOutputDevice )
-{
- int inputHostApiIndex = -1, /* Surpress uninitialised var warnings: compiler does */
- outputHostApiIndex = -1; /* not see that if inputParameters and outputParame- */
- /* ters are both nonzero, these indices are set. */
-
- if( (inputParameters == NULL) && (outputParameters == NULL) )
- {
- return paInvalidDevice; /** @todo should be a new error code "invalid device parameters" or something */
- }
- else
- {
- if( inputParameters == NULL )
- {
- *hostApiInputDevice = paNoDevice;
- }
- else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- if( inputParameters->hostApiSpecificStreamInfo )
- {
- inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
- ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType );
-
- if( inputHostApiIndex != -1 )
- {
- *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification;
- *hostApi = hostApis_[inputHostApiIndex];
- }
- else
- {
- return paInvalidDevice;
- }
- }
- else
- {
- return paInvalidDevice;
- }
- }
- else
- {
- if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ )
- return paInvalidDevice;
-
- inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice );
- if( inputHostApiIndex < 0 )
- return paInternalError;
-
- *hostApi = hostApis_[inputHostApiIndex];
-
- if( inputParameters->channelCount <= 0 )
- return paInvalidChannelCount;
-
- if( !SampleFormatIsValid( inputParameters->sampleFormat ) )
- return paSampleFormatNotSupported;
-
- if( inputParameters->hostApiSpecificStreamInfo != NULL )
- {
- if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType
- != (*hostApi)->info.type )
- return paIncompatibleHostApiSpecificStreamInfo;
- }
- }
-
- if( outputParameters == NULL )
- {
- *hostApiOutputDevice = paNoDevice;
- }
- else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- if( outputParameters->hostApiSpecificStreamInfo )
- {
- outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
- ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType );
-
- if( outputHostApiIndex != -1 )
- {
- *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification;
- *hostApi = hostApis_[outputHostApiIndex];
- }
- else
- {
- return paInvalidDevice;
- }
- }
- else
- {
- return paInvalidDevice;
- }
- }
- else
- {
- if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ )
- return paInvalidDevice;
-
- outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice );
- if( outputHostApiIndex < 0 )
- return paInternalError;
-
- *hostApi = hostApis_[outputHostApiIndex];
-
- if( outputParameters->channelCount <= 0 )
- return paInvalidChannelCount;
-
- if( !SampleFormatIsValid( outputParameters->sampleFormat ) )
- return paSampleFormatNotSupported;
-
- if( outputParameters->hostApiSpecificStreamInfo != NULL )
- {
- if( ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType
- != (*hostApi)->info.type )
- return paIncompatibleHostApiSpecificStreamInfo;
- }
- }
-
- if( (inputParameters != NULL) && (outputParameters != NULL) )
- {
- /* ensure that both devices use the same API */
- if( inputHostApiIndex != outputHostApiIndex )
- return paBadIODeviceCombination;
- }
- }
-
-
- /* Check for absurd sample rates. */
- if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
- return paInvalidSampleRate;
-
- if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 )
- return paInvalidFlag;
-
- if( streamFlags & paNeverDropInput )
- {
- /* must be a callback stream */
- if( !streamCallback )
- return paInvalidFlag;
-
- /* must be a full duplex stream */
- if( (inputParameters == NULL) || (outputParameters == NULL) )
- return paInvalidFlag;
-
- /* must use paFramesPerBufferUnspecified */
- if( framesPerBuffer != paFramesPerBufferUnspecified )
- return paInvalidFlag;
- }
-
- return paNoError;
-}
-
-
-PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaError result;
- PaUtilHostApiRepresentation *hostApi;
- PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
- PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
- PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
-
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_IsFormatSupported called:\n" );
-
- if( inputParameters == NULL ){
- PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: NULL\n" );
- }else{
- PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters );
- PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
- PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
- PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
- PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
- PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
- }
-
- if( outputParameters == NULL ){
- PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: NULL\n" );
- }else{
- PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters );
- PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
- PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
- PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
- PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
- PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
- }
-
- PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
- return result;
- }
-
- result = ValidateOpenStreamParameters( inputParameters,
- outputParameters,
- sampleRate, 0, paNoFlag, 0,
- &hostApi,
- &hostApiInputDevice,
- &hostApiOutputDevice );
- if( result != paNoError )
- {
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
- return result;
- }
-
-
- if( inputParameters )
- {
- hostApiInputParameters.device = hostApiInputDevice;
- hostApiInputParameters.channelCount = inputParameters->channelCount;
- hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
- hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
- hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
- hostApiInputParametersPtr = &hostApiInputParameters;
- }
- else
- {
- hostApiInputParametersPtr = NULL;
- }
-
- if( outputParameters )
- {
- hostApiOutputParameters.device = hostApiOutputDevice;
- hostApiOutputParameters.channelCount = outputParameters->channelCount;
- hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
- hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
- hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
- hostApiOutputParametersPtr = &hostApiOutputParameters;
- }
- else
- {
- hostApiOutputParametersPtr = NULL;
- }
-
- result = hostApi->IsFormatSupported( hostApi,
- hostApiInputParametersPtr, hostApiOutputParametersPtr,
- sampleRate );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
- if( result == paFormatIsSupported )
- PaUtil_DebugPrint("\tPaError: 0 [ paFormatIsSupported ]\n\n" );
- else
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_OpenStream( PaStream** stream,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result;
- PaUtilHostApiRepresentation *hostApi;
- PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
- PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
- PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
-
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenStream called:\n" );
- PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
-
- if( inputParameters == NULL ){
- PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: NULL\n" );
- }else{
- PaUtil_DebugPrint("\tPaStreamParameters *inputParameters: 0x%p\n", inputParameters );
- PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
- PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
- PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
- PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
- PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
- }
-
- if( outputParameters == NULL ){
- PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: NULL\n" );
- }else{
- PaUtil_DebugPrint("\tPaStreamParameters *outputParameters: 0x%p\n", outputParameters );
- PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
- PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
- PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
- PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
- PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
- }
-
- PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
- PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
- PaUtil_DebugPrint("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags );
- PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
- PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
-#endif
-
- if( !PA_IS_INITIALISED_ )
- {
- result = paNotInitialized;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
- PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
- return result;
- }
-
- /* Check for parameter errors.
- NOTE: make sure this validation list is kept syncronised with the one
- in pa_hostapi.h
- */
-
- if( stream == NULL )
- {
- result = paBadStreamPtr;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
- PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
- return result;
- }
-
- result = ValidateOpenStreamParameters( inputParameters,
- outputParameters,
- sampleRate, framesPerBuffer,
- streamFlags, streamCallback,
- &hostApi,
- &hostApiInputDevice,
- &hostApiOutputDevice );
- if( result != paNoError )
- {
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
- PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
- return result;
- }
-
-
- if( inputParameters )
- {
- hostApiInputParameters.device = hostApiInputDevice;
- hostApiInputParameters.channelCount = inputParameters->channelCount;
- hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
- hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
- hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
- hostApiInputParametersPtr = &hostApiInputParameters;
- }
- else
- {
- hostApiInputParametersPtr = NULL;
- }
-
- if( outputParameters )
- {
- hostApiOutputParameters.device = hostApiOutputDevice;
- hostApiOutputParameters.channelCount = outputParameters->channelCount;
- hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
- hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
- hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
- hostApiOutputParametersPtr = &hostApiOutputParameters;
- }
- else
- {
- hostApiOutputParametersPtr = NULL;
- }
-
- result = hostApi->OpenStream( hostApi, stream,
- hostApiInputParametersPtr, hostApiOutputParametersPtr,
- sampleRate, framesPerBuffer, streamFlags, streamCallback, userData );
-
- if( result == paNoError )
- AddOpenStream( *stream );
-
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
- PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p\n", *stream );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_OpenDefaultStream( PaStream** stream,
- int inputChannelCount,
- int outputChannelCount,
- PaSampleFormat sampleFormat,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result;
- PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
- PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenDefaultStream called:\n" );
- PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
- PaUtil_DebugPrint("\tint inputChannelCount: %d\n", inputChannelCount );
- PaUtil_DebugPrint("\tint outputChannelCount: %d\n", outputChannelCount );
- PaUtil_DebugPrint("\tPaSampleFormat sampleFormat: %d\n", sampleFormat );
- PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
- PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
- PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
- PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
-#endif
-
-
- if( inputChannelCount > 0 )
- {
- hostApiInputParameters.device = Pa_GetDefaultInputDevice();
- hostApiInputParameters.channelCount = inputChannelCount;
- hostApiInputParameters.sampleFormat = sampleFormat;
- /* defaultHighInputLatency is used below instead of
- defaultLowInputLatency because it is more important for the default
- stream to work reliably than it is for it to work with the lowest
- latency.
- */
- hostApiInputParameters.suggestedLatency =
- Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;
- hostApiInputParameters.hostApiSpecificStreamInfo = NULL;
- hostApiInputParametersPtr = &hostApiInputParameters;
- }
- else
- {
- hostApiInputParametersPtr = NULL;
- }
-
- if( outputChannelCount > 0 )
- {
- hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();
- hostApiOutputParameters.channelCount = outputChannelCount;
- hostApiOutputParameters.sampleFormat = sampleFormat;
- /* defaultHighOutputLatency is used below instead of
- defaultLowOutputLatency because it is more important for the default
- stream to work reliably than it is for it to work with the lowest
- latency.
- */
- hostApiOutputParameters.suggestedLatency =
- Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
- hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;
- hostApiOutputParametersPtr = &hostApiOutputParameters;
- }
- else
- {
- hostApiOutputParametersPtr = NULL;
- }
-
-
- result = Pa_OpenStream(
- stream, hostApiInputParametersPtr, hostApiOutputParametersPtr,
- sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_OpenDefaultStream returned:\n" );
- PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p", *stream );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError PaUtil_ValidateStreamPointer( PaStream* stream )
-{
- if( !PA_IS_INITIALISED_ ) return paNotInitialized;
-
- if( stream == NULL ) return paBadStreamPtr;
-
- if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC )
- return paBadStreamPtr;
-
- return paNoError;
-}
-
-
-PaError Pa_CloseStream( PaStream* stream )
-{
- PaUtilStreamInterface *interface;
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_CloseStream called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- /* always remove the open stream from our list, even if this function
- eventually returns an error. Otherwise CloseOpenStreams() will
- get stuck in an infinite loop */
- RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */
-
- if( result == paNoError )
- {
- interface = PA_STREAM_INTERFACE(stream);
-
- /* abort the stream if it isn't stopped */
- result = interface->IsStopped( stream );
- if( result == 1 )
- result = paNoError;
- else if( result == 0 )
- result = interface->Abort( stream );
-
- if( result == paNoError ) /** @todo REVIEW: shouldn't we close anyway? */
- result = interface->Close( stream );
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_CloseStream returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_SetStreamFinishedCallback called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
- PaUtil_DebugPrint("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback );
-#endif
-
- if( result == paNoError )
- {
- result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
- if( result == 0 )
- {
- result = paStreamIsNotStopped ;
- }
- if( result == 1 )
- {
- PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback;
- result = paNoError;
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_SetStreamFinishedCallback returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-
-}
-
-
-PaError Pa_StartStream( PaStream *stream )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_StartStream called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( result == paNoError )
- {
- result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
- if( result == 0 )
- {
- result = paStreamIsNotStopped ;
- }
- else if( result == 1 )
- {
- result = PA_STREAM_INTERFACE(stream)->Start( stream );
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_StartStream returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_StopStream( PaStream *stream )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_StopStream called\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( result == paNoError )
- {
- result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
- if( result == 0 )
- {
- result = PA_STREAM_INTERFACE(stream)->Stop( stream );
- }
- else if( result == 1 )
- {
- result = paStreamIsStopped;
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_StopStream returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_AbortStream( PaStream *stream )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_AbortStream called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( result == paNoError )
- {
- result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
- if( result == 0 )
- {
- result = PA_STREAM_INTERFACE(stream)->Abort( stream );
- }
- else if( result == 1 )
- {
- result = paStreamIsStopped;
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_AbortStream returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_IsStreamStopped( PaStream *stream )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_IsStreamStopped called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( result == paNoError )
- result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_IsStreamStopped returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_IsStreamActive( PaStream *stream )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_IsStreamActive called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( result == paNoError )
- result = PA_STREAM_INTERFACE(stream)->IsActive( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_IsStreamActive returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream )
-{
- PaError error = PaUtil_ValidateStreamPointer( stream );
- const PaStreamInfo *result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamInfo called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( error != paNoError )
- {
- result = 0;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
- PaUtil_DebugPrint("\tconst PaStreamInfo*: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
-#endif
-
- }
- else
- {
- result = &PA_STREAM_REP( stream )->streamInfo;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
- PaUtil_DebugPrint("\tconst PaStreamInfo*: 0x%p:\n", result );
- PaUtil_DebugPrint("\t{" );
-
- PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
- PaUtil_DebugPrint("\t\tPaTime inputLatency: %f\n", result->inputLatency );
- PaUtil_DebugPrint("\t\tPaTime outputLatency: %f\n", result->outputLatency );
- PaUtil_DebugPrint("\t\tdouble sampleRate: %f\n", result->sampleRate );
- PaUtil_DebugPrint("\t}\n\n" );
-#endif
-
- }
-
- return result;
-}
-
-
-PaTime Pa_GetStreamTime( PaStream *stream )
-{
- PaError error = PaUtil_ValidateStreamPointer( stream );
- PaTime result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamTime called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( error != paNoError )
- {
- result = 0;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
- PaUtil_DebugPrint("\tPaTime: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
-#endif
-
- }
- else
- {
- result = PA_STREAM_INTERFACE(stream)->GetTime( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
- PaUtil_DebugPrint("\tPaTime: %g\n\n", result );
-#endif
-
- }
-
- return result;
-}
-
-
-double Pa_GetStreamCpuLoad( PaStream* stream )
-{
- PaError error = PaUtil_ValidateStreamPointer( stream );
- double result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamCpuLoad called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( error != paNoError )
- {
-
- result = 0.0;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
- PaUtil_DebugPrint("\tdouble: 0.0 [PaError error: %d ( %s )]\n\n", error, Pa_GetErrorText( error ) );
-#endif
-
- }
- else
- {
- result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
- PaUtil_DebugPrint("\tdouble: %g\n\n", result );
-#endif
-
- }
-
- return result;
-}
-
-
-PaError Pa_ReadStream( PaStream* stream,
- void *buffer,
- unsigned long frames )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_ReadStream called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( result == paNoError )
- {
- if( frames == 0 )
- {
- result = paInternalError; /** @todo should return a different error code */
- }
- else if( buffer == 0 )
- {
- result = paInternalError; /** @todo should return a different error code */
- }
- else
- {
- result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
- if( result == 0 )
- {
- result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames );
- }
- else if( result == 1 )
- {
- result = paStreamIsStopped;
- }
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_ReadStream returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-
-PaError Pa_WriteStream( PaStream* stream,
- const void *buffer,
- unsigned long frames )
-{
- PaError result = PaUtil_ValidateStreamPointer( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_WriteStream called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( result == paNoError )
- {
- if( frames == 0 )
- {
- result = paInternalError; /** @todo should return a different error code */
- }
- else if( buffer == 0 )
- {
- result = paInternalError; /** @todo should return a different error code */
- }
- else
- {
- result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
- if( result == 0 )
- {
- result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames );
- }
- else if( result == 1 )
- {
- result = paStreamIsStopped;
- }
- }
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_WriteStream returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return result;
-}
-
-signed long Pa_GetStreamReadAvailable( PaStream* stream )
-{
- PaError error = PaUtil_ValidateStreamPointer( stream );
- signed long result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamReadAvailable called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( error != paNoError )
- {
- result = 0;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
- PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
-#endif
-
- }
- else
- {
- result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- }
-
- return result;
-}
-
-
-signed long Pa_GetStreamWriteAvailable( PaStream* stream )
-{
- PaError error = PaUtil_ValidateStreamPointer( stream );
- signed long result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamWriteAvailable called:\n" );
- PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
-#endif
-
- if( error != paNoError )
- {
- result = 0;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
- PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
-#endif
-
- }
- else
- {
- result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream );
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- }
-
- return result;
-}
-
-
-PaError Pa_GetSampleSize( PaSampleFormat format )
-{
- int result;
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetSampleSize called:\n" );
- PaUtil_DebugPrint("\tPaSampleFormat format: %d\n", format );
-#endif
-
- switch( format & ~paNonInterleaved )
- {
-
- case paUInt8:
- case paInt8:
- result = 1;
- break;
-
- case paInt16:
- result = 2;
- break;
-
- case paInt24:
- result = 3;
- break;
-
- case paFloat32:
- case paInt32:
- result = 4;
- break;
-
- default:
- result = paSampleFormatNotSupported;
- break;
- }
-
-#ifdef PA_LOG_API_CALLS
- PaUtil_DebugPrint("Pa_GetSampleSize returned:\n" );
- if( result > 0 )
- PaUtil_DebugPrint("\tint: %d\n\n", result );
- else
- PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
-#endif
-
- return (PaError) result;
-}
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_hostapi.h b/pjmedia/src/pjmedia/portaudio/pa_hostapi.h
deleted file mode 100644
index d0550706..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_hostapi.h
+++ /dev/null
@@ -1,244 +0,0 @@
-#ifndef PA_HOSTAPI_H
-#define PA_HOSTAPI_H
-/*
- * $Id: pa_hostapi.h,v 1.1.2.14 2004/01/08 22:01:12 rossbencina Exp $
- * Portable Audio I/O Library
- * host api representation
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Interface used by pa_front to virtualize functions which operate on
- host APIs.
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** **FOR THE USE OF pa_front.c ONLY**
- Do NOT use fields in this structure, they my change at any time.
- Use functions defined in pa_util.h if you think you need functionality
- which can be derived from here.
-*/
-typedef struct PaUtilPrivatePaFrontHostApiInfo {
-
-
- unsigned long baseDeviceIndex;
-}PaUtilPrivatePaFrontHostApiInfo;
-
-
-/** The common header for all data structures whose pointers are passed through
- the hostApiSpecificStreamInfo field of the PaStreamParameters structure.
- Note that in order to keep the public PortAudio interface clean, this structure
- is not used explicitly when declaring hostApiSpecificStreamInfo data structures.
- However, some code in pa_front depends on the first 3 members being equivalent
- with this structure.
- @see PaStreamParameters
-*/
-typedef struct PaUtilHostApiSpecificStreamInfoHeader
-{
- unsigned long size; /**< size of whole structure including this header */
- PaHostApiTypeId hostApiType; /**< host API for which this data is intended */
- unsigned long version; /**< structure version */
-} PaUtilHostApiSpecificStreamInfoHeader;
-
-
-
-/** A structure representing the interface to a host API. Contains both
- concrete data and pointers to functions which implement the interface.
-*/
-typedef struct PaUtilHostApiRepresentation {
- PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo;
-
- /** The host api implementation should populate the info field. In the
- case of info.defaultInputDevice and info.defaultOutputDevice the
- values stored should be 0 based indices within the host api's own
- device index range (0 to deviceCount). These values will be converted
- to global device indices by pa_front after PaUtilHostApiInitializer()
- returns.
- */
- PaHostApiInfo info;
-
- PaDeviceInfo** deviceInfos;
-
- /**
- (*Terminate)() is guaranteed to be called with a valid <hostApi>
- parameter, which was previously returned from the same implementation's
- initializer.
- */
- void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi );
-
- /**
- The inputParameters and outputParameters pointers should not be saved
- as they will not remain valid after OpenStream is called.
-
-
- The following guarantees are made about parameters to (*OpenStream)():
-
- [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be
- kept in sync with the one for ValidateOpenStreamParameters and
- Pa_OpenStream in pa_front.c]
-
- PaHostApiRepresentation *hostApi
- - is valid for this implementation
-
- PaStream** stream
- - is non-null
-
- - at least one of inputParameters & outputParmeters is valid (not NULL)
-
- - if inputParameters & outputParmeters are both valid, that
- inputParameters->device & outputParmeters->device both use the same host api
-
- PaDeviceIndex inputParameters->device
- - is within range (0 to Pa_CountDevices-1) Or:
- - is paUseHostApiSpecificDeviceSpecification and
- inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
- to a valid host api
-
- int inputParameters->numChannels
- - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0
- - upper bound is NOT validated against device capabilities
-
- PaSampleFormat inputParameters->sampleFormat
- - is one of the sample formats defined in portaudio.h
-
- void *inputParameters->hostApiSpecificStreamInfo
- - if supplied its hostApi field matches the input device's host Api
-
- PaDeviceIndex outputParmeters->device
- - is within range (0 to Pa_CountDevices-1)
-
- int outputParmeters->numChannels
- - if inputDevice is valid, numInputChannels is > 0
- - upper bound is NOT validated against device capabilities
-
- PaSampleFormat outputParmeters->sampleFormat
- - is one of the sample formats defined in portaudio.h
-
- void *outputParmeters->hostApiSpecificStreamInfo
- - if supplied its hostApi field matches the output device's host Api
-
- double sampleRate
- - is not an 'absurd' rate (less than 1000. or greater than 200000.)
- - sampleRate is NOT validated against device capabilities
-
- PaStreamFlags streamFlags
- - unused platform neutral flags are zero
- - paNeverDropInput is only used for full-duplex callback streams
- with variable buffer size (paFramesPerBufferUnspecified)
-
- [*END PA FRONT VALIDATIONS*]
-
-
- The following validations MUST be performed by (*OpenStream)():
-
- - check that input device can support numInputChannels
-
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - if inputStreamInfo is supplied, validate its contents,
- or return an error if no inputStreamInfo is expected
-
- - check that output device can support numOutputChannels
-
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - if outputStreamInfo is supplied, validate its contents,
- or return an error if no outputStreamInfo is expected
-
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported
-
- - check that the device supports sampleRate
-
- - alter sampleRate to a close allowable rate if necessary
-
- - validate inputLatency and outputLatency
-
- - validate any platform specific flags, if flags are supplied they
- must be valid.
- */
- PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** stream,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerCallback,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-
-
- PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-} PaUtilHostApiRepresentation;
-
-
-/** Prototype for the initialization function which must be implemented by every
- host API.
-
- @see paHostApiInitializers
-*/
-typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex );
-
-
-/** paHostApiInitializers is a NULL-terminated array of host API initialization
- functions. These functions are called by pa_front to initialize the host APIs
- when the client calls Pa_Initialize().
-
- There is a platform specific file which defines paHostApiInitializers for that
- platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example.
-*/
-extern PaUtilHostApiInitializer *paHostApiInitializers[];
-
-
-/** The index of the default host API in the paHostApiInitializers array.
-
- There is a platform specific file which defines paDefaultHostApiIndex for that
- platform, see pa_win/pa_win_hostapis.c for example.
-*/
-extern int paDefaultHostApiIndex;
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_HOSTAPI_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_lib.c b/pjmedia/src/pjmedia/portaudio/pa_lib.c
deleted file mode 100644
index 8dfdb590..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_lib.c
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- * Portable Audio I/O Library
- * Host Independant Layer
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 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.
- *
- * 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.
- *
- * 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.
- *
- */
-
-/* Modification History:
- PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
-#ifdef _WIN32
-#ifndef __MWERKS__
-#include <memory.h>
-#endif /* __MWERKS__ */
-#else /* !_WIN32 */
-#include <memory.h>
-#endif /* _WIN32 */
-
-#include "portaudio.h"
-//#include "pa_host.h"
-#include "pa_trace.h"
-
-typedef PaDeviceIndex PaDeviceID;
-typedef PaStream PortAudioStream;
-#define DLL_API
-
-/* The reason we might NOT want to validate the rate before opening the stream
- * is because many DirectSound drivers lie about the rates they actually support.
- */
-#define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */
-
-/*
-O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
-*/
-
-#ifndef FALSE
- #define FALSE (0)
- #define TRUE (!FALSE)
-#endif
-
-#define PRINT(x) { printf x; fflush(stdout); }
-#define ERR_RPT(x) PRINT(x)
-#define DBUG(x) /* PRINT(x) */
-#define DBUGX(x) /* PRINT(x) */
-
-static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
-
-static PaError Pa_KillStream( PortAudioStream *stream, int abort );
-
-/***********************************************************************/
-int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate )
-{
- double err, minErr = allowableError;
- int i, bestFit = -1;
-
- for( i=0; i<numRates; i++ )
- {
- err = fabs( frameRate - rateTable[i] );
- if( err < minErr )
- {
- minErr = err;
- bestFit = i;
- }
- }
- return bestFit;
-}
-
-/**************************************************************************
-** Make sure sample rate is legal and also convert to enumeration for driver.
-*/
-PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
- double *closestFrameRatePtr )
-{
- long bestRateIndex;
- const PaDeviceInfo *pdi;
- pdi = Pa_GetDeviceInfo( id );
- if( pdi == NULL ) return paInvalidDeviceId;
-
- if( pdi->numSampleRates == -1 )
- {
- /* Is it out of range? */
- if( (requestedFrameRate < pdi->sampleRates[0]) ||
- (requestedFrameRate > pdi->sampleRates[1]) )
- {
- return paInvalidSampleRate;
- }
-
- *closestFrameRatePtr = requestedFrameRate;
- }
- else
- {
- bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
- if( bestRateIndex < 0 ) return paInvalidSampleRate;
- *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
- }
- return paNoError;
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_OpenStream(
- PortAudioStream** streamPtrPtr,
- PaDeviceID inputDeviceID,
- int numInputChannels,
- PaSampleFormat inputSampleFormat,
- void *inputDriverInfo,
- PaDeviceID outputDeviceID,
- int numOutputChannels,
- PaSampleFormat outputSampleFormat,
- void *outputDriverInfo,
- double sampleRate,
- unsigned long framesPerBuffer,
- unsigned long numberOfBuffers,
- unsigned long streamFlags,
- PortAudioCallback *callback,
- void *userData )
-{
- internalPortAudioStream *past = NULL;
- PaError result = paNoError;
- int bitsPerInputSample;
- int bitsPerOutputSample;
- /* Print passed parameters. */
- DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
- streamPtrPtr, inputDeviceID, numInputChannels,
- inputSampleFormat, inputDriverInfo ));
- DBUG((" %d, %d, %d, %p, /* output */\n",
- outputDeviceID, numOutputChannels,
- outputSampleFormat, outputDriverInfo ));
- DBUG((" %g, %d, %d, 0x%x, , %p )\n",
- sampleRate, framesPerBuffer, numberOfBuffers,
- streamFlags, userData ));
-
- /* Check for parameter errors. */
- if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
- if( streamPtrPtr == NULL ) return paBadStreamPtr;
- if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
- if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
- if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
- if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) ) return paInvalidDeviceId;
- if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
-
-#if SUPPORT_AUDIO_CAPTURE
- if( inputDeviceID >= 0 )
- {
- PaError size = Pa_GetSampleSize( inputSampleFormat );
- if( size < 0 ) return size;
- bitsPerInputSample = 8 * size;
- if( (numInputChannels <= 0) ) return paInvalidChannelCount;
- }
-#else
- if( inputDeviceID >= 0 )
- {
- return paInvalidChannelCount;
- }
-#endif /* SUPPORT_AUDIO_CAPTURE */
- else
- {
- if( numInputChannels > 0 ) return paInvalidChannelCount;
- bitsPerInputSample = 0;
- }
-
- if( outputDeviceID >= 0 )
- {
- PaError size = Pa_GetSampleSize( outputSampleFormat );
- if( size < 0 ) return size;
- bitsPerOutputSample = 8 * size;
- if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
- }
- else
- {
- if( numOutputChannels > 0 ) return paInvalidChannelCount;
- bitsPerOutputSample = 0;
- }
-
- if( callback == NULL ) return paNullCallback;
-
- /* Allocate and clear stream structure. */
- past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
- if( past == NULL ) return paInsufficientMemory;
- memset( past, 0, sizeof(internalPortAudioStream) );
- AddTraceMessage("Pa_OpenStream: past", (long) past );
-
- past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
- past->past_FramesPerUserBuffer = framesPerBuffer;
- past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */
- past->past_Callback = callback;
- past->past_UserData = userData;
- past->past_OutputSampleFormat = outputSampleFormat;
- past->past_InputSampleFormat = inputSampleFormat;
- past->past_OutputDeviceID = outputDeviceID;
- past->past_InputDeviceID = inputDeviceID;
- past->past_NumInputChannels = numInputChannels;
- past->past_NumOutputChannels = numOutputChannels;
- past->past_Flags = streamFlags;
-
- /* Check for absurd sample rates. */
- if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
- {
- result = paInvalidSampleRate;
- goto cleanup;
- }
-
- /* Allocate buffers that may be used for format conversion from user to native buffers. */
- if( numInputChannels > 0 )
- {
-
-#if PA_VALIDATE_RATE
- result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
- if( result < 0 )
- {
- goto cleanup;
- }
-#else
- past->past_SampleRate = sampleRate;
-#endif
- /* Allocate single Input buffer. */
- past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
- past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
- if( past->past_InputBuffer == NULL )
- {
- result = paInsufficientMemory;
- goto cleanup;
- }
- }
- else
- {
- past->past_InputBuffer = NULL;
- }
-
- /* Allocate single Output buffer. */
- if( numOutputChannels > 0 )
- {
-#if PA_VALIDATE_RATE
- result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
- if( result < 0 )
- {
- goto cleanup;
- }
-#else
- past->past_SampleRate = sampleRate;
-#endif
- past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
- past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
- if( past->past_OutputBuffer == NULL )
- {
- result = paInsufficientMemory;
- goto cleanup;
- }
- }
- else
- {
- past->past_OutputBuffer = NULL;
- }
-
- result = PaHost_OpenStream( past );
- if( result < 0 ) goto cleanup;
-
- *streamPtrPtr = (void *) past;
-
- return result;
-
-cleanup:
- if( past != NULL ) Pa_CloseStream( past );
- *streamPtrPtr = NULL;
- return result;
-}
-
-
-/*************************************************************************/
-DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream,
- int numInputChannels,
- int numOutputChannels,
- PaSampleFormat sampleFormat,
- double sampleRate,
- unsigned long framesPerBuffer,
- unsigned long numberOfBuffers,
- PortAudioCallback *callback,
- void *userData )
-{
- return Pa_OpenStream(
- stream,
- ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
- numInputChannels, sampleFormat, NULL,
- ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
- numOutputChannels, sampleFormat, NULL,
- sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_CloseStream( PortAudioStream* stream)
-{
- PaError result;
- internalPortAudioStream *past;
-
- DBUG(("Pa_CloseStream()\n"));
- if( stream == NULL ) return paBadStreamPtr;
- past = (internalPortAudioStream *) stream;
-
- Pa_AbortStream( past );
- result = PaHost_CloseStream( past );
-
- if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
- if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
- PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
-
- return result;
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_StartStream( PortAudioStream *stream )
-{
- PaError result = paHostError;
- internalPortAudioStream *past;
-
- if( stream == NULL ) return paBadStreamPtr;
- past = (internalPortAudioStream *) stream;
-
- past->past_FrameCount = 0.0;
-
- if( past->past_NumInputChannels > 0 )
- {
- result = PaHost_StartInput( past );
- DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
- if( result < 0 ) goto error;
- }
-
- if( past->past_NumOutputChannels > 0 )
- {
- result = PaHost_StartOutput( past );
- DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
- if( result < 0 ) goto error;
- }
-
- result = PaHost_StartEngine( past );
- DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
- if( result < 0 ) goto error;
-
- return paNoError;
-
-error:
- return result;
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_StopStream( PortAudioStream *stream )
-{
- return Pa_KillStream( stream, 0 );
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_AbortStream( PortAudioStream *stream )
-{
- return Pa_KillStream( stream, 1 );
-}
-
-/*************************************************************************/
-static PaError Pa_KillStream( PortAudioStream *stream, int abort )
-{
- PaError result = paNoError;
- internalPortAudioStream *past;
-
- DBUG(("Pa_StopStream().\n"));
- if( stream == NULL ) return paBadStreamPtr;
- past = (internalPortAudioStream *) stream;
-
- if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
- {
- result = PaHost_StopEngine( past, abort );
- DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
- if( result < 0 ) goto error;
- }
-
- if( past->past_NumInputChannels > 0 )
- {
- result = PaHost_StopInput( past, abort );
- DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
- if( result != paNoError ) goto error;
- }
-
- if( past->past_NumOutputChannels > 0 )
- {
- result = PaHost_StopOutput( past, abort );
- DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
- if( result != paNoError ) goto error;
- }
-
-error:
- past->past_Usage = 0;
- past->past_IfLastExitValid = 0;
-
- return result;
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_StreamActive( PortAudioStream *stream )
-{
- internalPortAudioStream *past;
- if( stream == NULL ) return paBadStreamPtr;
- past = (internalPortAudioStream *) stream;
- return PaHost_StreamActive( past );
-}
-
-/*************************************************************************/
-DLL_API const char *Pa_GetErrorText( PaError errnum )
-{
- const char *msg;
-
- switch(errnum)
- {
- case paNoError: msg = "Success"; break;
- case paHostError: msg = "Host error."; break;
- case paInvalidChannelCount: msg = "Invalid number of channels."; break;
- case paInvalidSampleRate: msg = "Invalid sample rate."; break;
- case paInvalidDeviceId: msg = "Invalid device ID."; break;
- case paInvalidFlag: msg = "Invalid flag."; break;
- case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
- case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break;
- case paInsufficientMemory: msg = "Insufficient memory."; break;
- case paBufferTooBig: msg = "Buffer too big."; break;
- case paBufferTooSmall: msg = "Buffer too small."; break;
- case paNullCallback: msg = "No callback routine specified."; break;
- case paBadStreamPtr: msg = "Invalid stream pointer."; break;
- case paTimedOut : msg = "Wait Timed Out."; break;
- case paInternalError: msg = "Internal PortAudio Error."; break;
- default: msg = "Illegal error number."; break;
- }
- return msg;
-}
-
-/*
- Get CPU Load as a fraction of total CPU time.
- A value of 0.5 would imply that PortAudio and the sound generating
- callback was consuming roughly 50% of the available CPU time.
- The amount may vary depending on CPU load.
- This function may be called from the callback function.
-*/
-DLL_API double Pa_GetCPULoad( PortAudioStream* stream)
-{
- internalPortAudioStream *past;
- if( stream == NULL ) return (double) paBadStreamPtr;
- past = (internalPortAudioStream *) stream;
- return past->past_Usage;
-}
-
-/*************************************************************
-** Calculate 2 LSB dither signal with a triangular distribution.
-** Ranged properly for adding to a 32 bit integer prior to >>15.
-*/
-#define DITHER_BITS (15)
-#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
-static long Pa_TriangularDither( void )
-{
- static unsigned long previous = 0;
- static unsigned long randSeed1 = 22222;
- static unsigned long randSeed2 = 5555555;
- long current, highPass;
- /* Generate two random numbers. */
- randSeed1 = (randSeed1 * 196314165) + 907633515;
- randSeed2 = (randSeed2 * 196314165) + 907633515;
- /* Generate triangular distribution about 0. */
- current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
- /* High pass filter to reduce audibility. */
- highPass = current - previous;
- previous = current;
- return highPass;
-}
-
-/*************************************************************************
-** Called by host code.
-** Convert input from Int16, call user code, then convert output
-** to Int16 format for native use.
-** Assumes host native format is paInt16.
-** Returns result from user callback.
-*/
-long Pa_CallConvertInt16( internalPortAudioStream *past,
- short *nativeInputBuffer,
- short *nativeOutputBuffer )
-{
- long temp;
- long bytesEmpty = 0;
- long bytesFilled = 0;
- int userResult;
- unsigned int i;
- void *inputBuffer = NULL;
- void *outputBuffer = NULL;
-
-#if SUPPORT_AUDIO_CAPTURE
- /* Get native data from DirectSound. */
- if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
- {
- /* Convert from native format to PA format. */
- unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
- switch(past->past_InputSampleFormat)
- {
-
- case paFloat32:
- {
- float *inBufPtr = (float *) past->past_InputBuffer;
- inputBuffer = past->past_InputBuffer;
- for( i=0; i<samplesPerBuffer; i++ )
- {
- inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
- }
- break;
- }
-
- case paInt32:
- {
- /* Convert 16 bit data to 32 bit integers */
- int *inBufPtr = (int *) past->past_InputBuffer;
- inputBuffer = past->past_InputBuffer;
- for( i=0; i<samplesPerBuffer; i++ )
- {
- inBufPtr[i] = nativeInputBuffer[i] << 16;
- }
- break;
- }
-
- case paInt16:
- {
- /* Already in correct format so don't copy. */
- inputBuffer = nativeInputBuffer;
- break;
- }
-
- case paInt8:
- {
- /* Convert 16 bit data to 8 bit chars */
- char *inBufPtr = (char *) past->past_InputBuffer;
- inputBuffer = past->past_InputBuffer;
- if( past->past_Flags & paDitherOff )
- {
- for( i=0; i<samplesPerBuffer; i++ )
- {
- inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
- }
- }
- else
- {
- for( i=0; i<samplesPerBuffer; i++ )
- {
- temp = nativeInputBuffer[i];
- temp += Pa_TriangularDither() >> 7;
- temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
- inBufPtr[i] = (char)(temp >> 8);
- }
- }
- break;
- }
-
- case paUInt8:
- {
- /* Convert 16 bit data to 8 bit unsigned chars */
- unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
- inputBuffer = past->past_InputBuffer;
- if( past->past_Flags & paDitherOff )
- {
- for( i=0; i<samplesPerBuffer; i++ )
- {
- inBufPtr[i] = ((unsigned char)(nativeInputBuffer[i] >> 8)) + 0x80;
- }
- }
- else
- {
- /* If you dither then you have to clip because dithering could push the signal out of range! */
- for( i=0; i<samplesPerBuffer; i++ )
- {
- temp = nativeInputBuffer[i];
- temp += Pa_TriangularDither() >> 7;
- temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
- inBufPtr[i] = (unsigned char)(temp + 0x80);
- }
- }
- break;
- }
-
- default:
- break;
- }
- }
-#endif /* SUPPORT_AUDIO_CAPTURE */
-
- /* Are we doing output time? */
- if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
- {
- /* May already be in native format so just write directly to native buffer. */
- outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
- nativeOutputBuffer : past->past_OutputBuffer;
- }
- /*
- AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
- AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
- */
- /* Call user callback routine. */
- userResult = past->past_Callback(
- inputBuffer,
- outputBuffer,
- past->past_FramesPerUserBuffer,
- past->past_FrameCount,
- past->past_UserData );
-
- past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
-
- /* Convert to native format if necessary. */
- if( outputBuffer != NULL )
- {
- unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
- switch(past->past_OutputSampleFormat)
- {
- case paFloat32:
- {
- float *outBufPtr = (float *) past->past_OutputBuffer;
- if( past->past_Flags & paDitherOff )
- {
- if( past->past_Flags & paClipOff ) /* NOTHING */
- {
- for( i=0; i<samplesPerBuffer; i++ )
- {
- *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
- }
- }
- else /* CLIP */
- {
- for( i=0; i<samplesPerBuffer; i++ )
- {
- temp = (long)(outBufPtr[i] * 32767.0f);
- *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
- }
- }
- }
- else
- {
- /* If you dither then you have to clip because dithering could push the signal out of range! */
- for( i=0; i<samplesPerBuffer; i++ )
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- float dithered = (outBufPtr[i] * (32767.0f)) + dither;
- temp = (long) (dithered);
- *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
- }
- }
- break;
- }
-
- case paInt32:
- {
- int *outBufPtr = (int *) past->past_OutputBuffer;
- if( past->past_Flags & paDitherOff )
- {
- for( i=0; i<samplesPerBuffer; i++ )
- {
- *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
- }
- }
- else
- {
- for( i=0; i<samplesPerBuffer; i++ )
- {
- /* Shift one bit down before dithering so that we have room for overflow from add. */
- temp = (outBufPtr[i] >> 1) + Pa_TriangularDither();
- temp = temp >> 15;
- *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
- }
- }
- break;
- }
-
- case paInt8:
- {
- char *outBufPtr = (char *) past->past_OutputBuffer;
- for( i=0; i<samplesPerBuffer; i++ )
- {
- *nativeOutputBuffer++ = ((short)outBufPtr[i]) << 8;
- }
- break;
- }
-
- case paUInt8:
- {
- unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
- for( i=0; i<samplesPerBuffer; i++ )
- {
- *nativeOutputBuffer++ = ((short)(outBufPtr[i] - 0x80)) << 8;
- }
- break;
- }
-
- default:
- break;
- }
-
- }
-
- return userResult;
-}
-
-/*************************************************************************
-** Called by host code.
-** Convert input from Float32, call user code, then convert output
-** to Float32 format for native use.
-** Assumes host native format is Float32.
-** Returns result from user callback.
-** FIXME - Unimplemented for formats other than paFloat32!!!!
-*/
-long Pa_CallConvertFloat32( internalPortAudioStream *past,
- float *nativeInputBuffer,
- float *nativeOutputBuffer )
-{
- long bytesEmpty = 0;
- long bytesFilled = 0;
- int userResult;
- void *inputBuffer = NULL;
- void *outputBuffer = NULL;
-
- /* Get native data from DirectSound. */
- if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
- {
- inputBuffer = nativeInputBuffer; // FIXME
- }
-
- /* Are we doing output time? */
- if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
- {
- /* May already be in native format so just write directly to native buffer. */
- outputBuffer = (past->past_OutputSampleFormat == paFloat32) ?
- nativeOutputBuffer : past->past_OutputBuffer;
- }
- /*
- AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
- AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
- */
- /* Call user callback routine. */
- userResult = past->past_Callback(
- inputBuffer,
- outputBuffer,
- past->past_FramesPerUserBuffer,
- past->past_FrameCount,
- past->past_UserData );
-
- past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
-
- /* Convert to native format if necessary. */ // FIXME
- return userResult;
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_Initialize( void )
-{
- if( gInitCount++ > 0 ) return paNoError;
- ResetTraceMessages();
- return PaHost_Init();
-}
-
-DLL_API PaError Pa_Terminate( void )
-{
- PaError result = paNoError;
-
- if( gInitCount == 0 ) return paNoError;
- else if( --gInitCount == 0 )
- {
- result = PaHost_Term();
- DumpTraceMessages();
- }
- return result;
-}
-
-/*************************************************************************/
-DLL_API PaError Pa_GetSampleSize( PaSampleFormat format )
-{
- int size;
- switch(format )
- {
-
- case paUInt8:
- case paInt8:
- size = 1;
- break;
-
- case paInt16:
- size = 2;
- break;
-
- case paPackedInt24:
- size = 3;
- break;
-
- case paFloat32:
- case paInt32:
- case paInt24:
- size = 4;
- break;
-
- default:
- size = paSampleFormatNotSupported;
- break;
- }
- return (PaError) size;
-}
-
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c b/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c
deleted file mode 100644
index 0214ddaa..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.c
+++ /dev/null
@@ -1,3272 +0,0 @@
-/*
- * $Id: pa_linux_alsa.c,v 1.1.2.71 2005/04/15 18:20:18 aknudsen Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * ALSA implementation by Joshua Haberman and Arve Knudsen
- *
- * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
- * Copyright (c) 2005 Arve Knudsen <aknuds-1@broadpark.no>
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-#define ALSA_PCM_NEW_HW_PARAMS_API
-#define ALSA_PCM_NEW_SW_PARAMS_API
-#include <alsa/asoundlib.h>
-#undef ALSA_PCM_NEW_HW_PARAMS_API
-#undef ALSA_PCM_NEW_SW_PARAMS_API
-
-#include <sys/poll.h>
-#include <string.h> /* strlen() */
-#include <limits.h>
-#include <math.h>
-#include <pthread.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/mman.h>
-#include <signal.h> /* For sig_atomic_t */
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_unix_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-#include "pa_linux_alsa.h"
-
-/* Check return value of ALSA function, and map it to PaError */
-#define ENSURE_(expr, code) \
- do { \
- if( UNLIKELY( (aErr_ = (expr)) < 0 ) ) \
- { \
- /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
- if( (code) == paUnanticipatedHostError && pthread_self() != callbackThread_ ) \
- { \
- PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \
- } \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
- result = (code); \
- goto error; \
- } \
- } while( 0 );
-
-#define ASSERT_CALL_(expr, success) \
- aErr_ = (expr); \
- assert( aErr_ == success );
-
-static int aErr_; /* Used with ENSURE_ */
-static pthread_t callbackThread_;
-
-typedef enum
-{
- StreamDirection_In,
- StreamDirection_Out
-} StreamDirection;
-
-/* Threading utility struct */
-typedef struct PaAlsaThreading
-{
- pthread_t watchdogThread;
- pthread_t callbackThread;
- int watchdogRunning;
- int rtSched;
- int rtPrio;
- int useWatchdog;
- unsigned long throttledSleepTime;
- volatile PaTime callbackTime;
- volatile PaTime callbackCpuTime;
- PaUtilCpuLoadMeasurer *cpuLoadMeasurer;
-} PaAlsaThreading;
-
-typedef struct
-{
- PaSampleFormat hostSampleFormat;
- unsigned long framesPerBuffer;
- int numUserChannels, numHostChannels;
- int userInterleaved, hostInterleaved;
-
- snd_pcm_t *pcm;
- snd_pcm_uframes_t bufferSize;
- snd_pcm_format_t nativeFormat;
- unsigned int nfds;
- int ready; /* Marked ready from poll */
- void **userBuffers;
- snd_pcm_uframes_t offset;
- StreamDirection streamDir;
-
- snd_pcm_channel_area_t *channelAreas; /* Needed for channel adaption */
-} PaAlsaStreamComponent;
-
-/* Implementation specific stream structure */
-typedef struct PaAlsaStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
- PaAlsaThreading threading;
-
- unsigned long framesPerUserBuffer;
-
- int primeBuffers;
- int callbackMode; /* bool: are we running in callback mode? */
- int pcmsSynced; /* Have we successfully synced pcms */
-
- /* the callback thread uses these to poll the sound device(s), waiting
- * for data to be ready/available */
- struct pollfd *pfds;
- int pollTimeout;
-
- /* Used in communication between threads */
- volatile sig_atomic_t callback_finished; /* bool: are we in the "callback finished" state? */
- volatile sig_atomic_t callbackAbort; /* Drop frames? */
- volatile sig_atomic_t callbackStop; /* Signal a stop */
- volatile sig_atomic_t isActive; /* Is stream in active state? (Between StartStream and StopStream || !paContinue) */
- pthread_mutex_t stateMtx; /* Used to synchronize access to stream state */
- pthread_mutex_t startMtx; /* Used to synchronize stream start in callback mode */
- pthread_cond_t startCond; /* Wait untill audio is started in callback thread */
-
- int neverDropInput;
-
- PaTime underrun;
- PaTime overrun;
-
- PaAlsaStreamComponent capture, playback;
-}
-PaAlsaStream;
-
-/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct PaAlsaHostApiRepresentation
-{
- PaUtilHostApiRepresentation commonHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- PaHostApiIndex hostApiIndex;
-}
-PaAlsaHostApiRepresentation;
-
-typedef struct PaAlsaDeviceInfo
-{
- PaDeviceInfo commonDeviceInfo;
- char *alsaName;
- int isPlug;
- int minInputChannels;
- int minOutputChannels;
-}
-PaAlsaDeviceInfo;
-
-/* Threading utilities */
-
-static void InitializeThreading( PaAlsaThreading *th, PaUtilCpuLoadMeasurer *clm )
-{
- th->watchdogRunning = 0;
- th->rtSched = 0;
- th->callbackTime = 0;
- th->callbackCpuTime = 0;
- th->useWatchdog = 1;
- th->throttledSleepTime = 0;
- th->cpuLoadMeasurer = clm;
-
- th->rtPrio = (sched_get_priority_max( SCHED_FIFO ) - sched_get_priority_min( SCHED_FIFO )) / 2
- + sched_get_priority_min( SCHED_FIFO );
-}
-
-static PaError KillCallbackThread( PaAlsaThreading *th, int wait, PaError *exitResult, PaError *watchdogExitResult )
-{
- PaError result = paNoError;
- void *pret;
-
- if( exitResult )
- *exitResult = paNoError;
- if( watchdogExitResult )
- *watchdogExitResult = paNoError;
-
- if( th->watchdogRunning )
- {
- pthread_cancel( th->watchdogThread );
- ASSERT_CALL_( pthread_join( th->watchdogThread, &pret ), 0 );
-
- if( pret && pret != PTHREAD_CANCELED )
- {
- if( watchdogExitResult )
- *watchdogExitResult = *(PaError *) pret;
- free( pret );
- }
- }
-
- /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
- /* TODO: Make join time out */
- if( !wait )
- pthread_cancel( th->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
- ASSERT_CALL_( pthread_join( th->callbackThread, &pret ), 0 );
-
- if( pret && pret != PTHREAD_CANCELED )
- {
- if( exitResult )
- *exitResult = *(PaError *) pret;
- free( pret );
- }
-
- return result;
-}
-
-static void OnWatchdogExit( void *userData )
-{
- PaAlsaThreading *th = (PaAlsaThreading *) userData;
- struct sched_param spm = { 0 };
- assert( th );
-
- ASSERT_CALL_( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */
- PA_DEBUG(( "Watchdog exiting\n" ));
-}
-
-static PaError BoostPriority( PaAlsaThreading *th )
-{
- PaError result = paNoError;
- struct sched_param spm = { 0 };
- spm.sched_priority = th->rtPrio;
-
- assert( th );
-
- if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
- {
- PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */
- PA_DEBUG(( "Failed bumping priority\n" ));
- result = 0;
- }
- else
- result = 1; /* Success */
-error:
- return result;
-}
-
-static void *WatchdogFunc( void *userData )
-{
- PaError result = paNoError, *pres = NULL;
- int err;
- PaAlsaThreading *th = (PaAlsaThreading *) userData;
- unsigned intervalMsec = 500;
- const PaTime maxSeconds = 3.; /* Max seconds between callbacks */
- PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed;
- double cpuLoad, avgCpuLoad = 0.;
- int throttled = 0;
-
- assert( th );
-
- pthread_cleanup_push( &OnWatchdogExit, th ); /* Execute OnWatchdogExit when exiting */
-
- /* Boost priority of callback thread */
- PA_ENSURE( result = BoostPriority( th ) );
- if( !result )
- {
- pthread_exit( NULL ); /* Boost failed, might as well exit */
- }
-
- cpuTimeThen = th->callbackCpuTime;
- {
- int policy;
- struct sched_param spm = { 0 };
- pthread_getschedparam( pthread_self(), &policy, &spm );
- PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority ));
- }
-
- while( 1 )
- {
- double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff;
-
- /* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */
- pthread_testcancel();
- Pa_Sleep( intervalMsec );
- pthread_testcancel();
-
- if( PaUtil_GetTime() - th->callbackTime > maxSeconds )
- {
- PA_DEBUG(( "Watchdog: Terminating callback thread\n" ));
- /* Tell thread to terminate */
- err = pthread_kill( th->callbackThread, SIGKILL );
- pthread_exit( NULL );
- }
-
- PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) ));
-
- /* Check if we should throttle, or unthrottle :P */
- cpuTimeNow = th->callbackCpuTime;
- cpuTimeElapsed = cpuTimeNow - cpuTimeThen;
- cpuTimeThen = cpuTimeNow;
-
- timeNow = PaUtil_GetTime();
- timeElapsed = timeNow - timeThen;
- timeThen = timeNow;
- cpuLoad = cpuTimeElapsed / timeElapsed;
- avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1;
- /*
- if( throttled )
- PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed ));
- */
- if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 )
- {
- static int policy;
- static struct sched_param spm = { 0 };
- static const struct sched_param defaultSpm = { 0 };
- PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));
-
- pthread_getschedparam( th->callbackThread, &policy, &spm );
- if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )
- {
- throttled = 1;
- }
- else
- PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));
-
- /* Give other processes a go, before raising priority again */
- PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));
- Pa_Sleep( th->throttledSleepTime );
-
- /* Reset callback priority */
- if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
- {
- PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));
- }
-
- if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )
- intervalMsec = 50;
- else
- intervalMsec = 100;
-
- /*
- lowpassCoeff = .97;
- lowpassCoeff1 = .99999 - lowpassCoeff;
- */
- }
- else if( throttled && avgCpuLoad < .8 )
- {
- intervalMsec = 500;
- throttled = 0;
-
- /*
- lowpassCoeff = .9;
- lowpassCoeff1 = .99999 - lowpassCoeff;
- */
- }
- }
-
- pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */
-
-error:
- /* Shouldn't get here in the normal case */
-
- /* Pass on error code */
- pres = malloc( sizeof (PaError) );
- *pres = result;
-
- pthread_exit( pres );
-}
-
-static PaError CreateCallbackThread( PaAlsaThreading *th, void *(*callbackThreadFunc)( void * ), PaStream *s )
-{
- PaError result = paNoError;
- pthread_attr_t attr;
- int started = 0;
-
-#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
- if( th->rtSched )
- {
- if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )
- {
- int savedErrno = errno; /* In case errno gets overwritten */
- assert( savedErrno != EINVAL ); /* Most likely a programmer error */
- PA_UNLESS( (savedErrno == EPERM), paInternalError );
- PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));
- }
- else
- PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));
- }
-#endif
-
- PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
- /* Priority relative to other processes */
- PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
-
- PA_UNLESS( !pthread_create( &th->callbackThread, &attr, callbackThreadFunc, s ), paInternalError );
- started = 1;
-
- if( th->rtSched )
- {
- if( th->useWatchdog )
- {
- int err;
- struct sched_param wdSpm = { 0 };
- /* Launch watchdog, watchdog sets callback thread priority */
- int prio = PA_MIN( th->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );
- wdSpm.sched_priority = prio;
-
- PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
- PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );
- PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
- PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );
- PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );
- if( (err = pthread_create( &th->watchdogThread, &attr, &WatchdogFunc, th )) )
- {
- PA_UNLESS( err == EPERM, paInternalError );
- /* Permission error, go on without realtime privileges */
- PA_DEBUG(( "Failed bumping priority\n" ));
- }
- else
- {
- int policy;
- th->watchdogRunning = 1;
- ASSERT_CALL_( pthread_getschedparam( th->watchdogThread, &policy, &wdSpm ), 0 );
- /* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
- if( wdSpm.sched_priority != prio )
- {
- PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));
- PA_ENSURE( paInternalError );
- }
- }
- }
- else
- PA_ENSURE( BoostPriority( th ) );
- }
-
-end:
- return result;
-error:
- if( started )
- KillCallbackThread( th, 0, NULL, NULL );
-
- goto end;
-}
-
-static void CallbackUpdate( PaAlsaThreading *th )
-{
- th->callbackTime = PaUtil_GetTime();
- th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );
-}
-
-/* prototypes for functions declared in this file */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *callback,
- void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
-static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate );
-static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate );
-
-/* Callback prototypes */
-static void *CallbackThreadFunc( void *userData );
-
-/* Blocking prototypes */
-static signed long GetStreamReadAvailable( PaStream* s );
-static signed long GetStreamWriteAvailable( PaStream* s );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-
-
-static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation *hostApi, int device )
-{
- return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];
-}
-
-PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- PaAlsaHostApiRepresentation *alsaHostApi = NULL;
-
- PA_UNLESS( alsaHostApi = (PaAlsaHostApiRepresentation*) PaUtil_AllocateMemory(
- sizeof(PaAlsaHostApiRepresentation) ), paInsufficientMemory );
- PA_UNLESS( alsaHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
- alsaHostApi->hostApiIndex = hostApiIndex;
-
- *hostApi = (PaUtilHostApiRepresentation*)alsaHostApi;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paALSA;
- (*hostApi)->info.name = "ALSA";
-
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PA_ENSURE( BuildDeviceList( alsaHostApi ) );
-
- PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,
- CloseStream, StartStream,
- StopStream, AbortStream,
- IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable,
- PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &alsaHostApi->blockingStreamInterface,
- CloseStream, StartStream,
- StopStream, AbortStream,
- IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream,
- GetStreamReadAvailable,
- GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( alsaHostApi )
- {
- if( alsaHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( alsaHostApi->allocations );
- PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
- }
-
- PaUtil_FreeMemory( alsaHostApi );
- }
-
- return result;
-}
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
-
- assert( hostApi );
-
- if( alsaHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( alsaHostApi->allocations );
- PaUtil_DestroyAllocationGroup( alsaHostApi->allocations );
- }
-
- PaUtil_FreeMemory( alsaHostApi );
- snd_config_update_free_global();
-}
-
-/*! Determine max channels and default latencies.
- *
- * This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for
- * traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,
- * and a suitable result returned. The device is closed before returning.
- */
-static PaError GropeDevice( snd_pcm_t *pcm, int *minChannels, int *maxChannels, double *defaultLowLatency,
- double *defaultHighLatency, double *defaultSampleRate, int isPlug )
-{
- PaError result = paNoError;
- snd_pcm_hw_params_t *hwParams;
- snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;
- unsigned int minChans, maxChans;
- double defaultSr = *defaultSampleRate;
-
- assert( pcm );
-
- ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );
-
- snd_pcm_hw_params_alloca( &hwParams );
- snd_pcm_hw_params_any( pcm, hwParams );
-
- if( defaultSr >= 0 )
- {
- /* Could be that the device opened in one mode supports samplerates that the other mode wont have,
- * so try again .. */
- if( SetApproximateSampleRate( pcm, hwParams, defaultSr ) < 0 )
- {
- defaultSr = -1.;
- PA_DEBUG(( "%s: Original default samplerate failed, trying again ..\n", __FUNCTION__ ));
- }
- }
-
- if( defaultSr < 0. ) /* Default sample rate not set */
- {
- unsigned int sampleRate = 44100; /* Will contain approximate rate returned by alsa-lib */
- ENSURE_( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ), paUnanticipatedHostError );
- ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );
- }
-
- ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );
- assert( maxChans <= INT_MAX );
- assert( maxChans > 0 ); /* Weird linking issue could cause wrong version of ALSA symbols to be called,
- resulting in zeroed values */
-
- /* XXX: Limit to sensible number (ALSA plugins accept a crazy amount of channels)? */
- if( isPlug && maxChans > 128 )
- {
- maxChans = 128;
- PA_DEBUG(( "%s: Limiting number of plugin channels to %u\n", __FUNCTION__, maxChans ));
- }
-
- /* TWEAKME:
- *
- * Giving values for default min and max latency is not
- * straightforward. Here are our objectives:
- *
- * * for low latency, we want to give the lowest value
- * that will work reliably. This varies based on the
- * sound card, kernel, CPU, etc. I think it is better
- * to give sub-optimal latency than to give a number
- * too low and cause dropouts. My conservative
- * estimate at this point is to base it on 4096-sample
- * latency at 44.1 kHz, which gives a latency of 23ms.
- * * for high latency we want to give a large enough
- * value that dropouts are basically impossible. This
- * doesn't really require as much tweaking, since
- * providing too large a number will just cause us to
- * select the nearest setting that will work at stream
- * config time.
- */
- ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &lowLatency ), paUnanticipatedHostError );
-
- /* Have to reset hwParams, to set new buffer size */
- ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &highLatency ), paUnanticipatedHostError );
-
- *minChannels = (int)minChans;
- *maxChannels = (int)maxChans;
- *defaultSampleRate = defaultSr;
- *defaultLowLatency = (double) lowLatency / *defaultSampleRate;
- *defaultHighLatency = (double) highLatency / *defaultSampleRate;
-
-end:
- snd_pcm_close( pcm );
- return result;
-
-error:
- goto end;
-}
-
-/* Initialize device info with invalid values (maxInputChannels and maxOutputChannels are set to zero since these indicate
- * wether input/output is available) */
-static void InitializeDeviceInfo( PaDeviceInfo *deviceInfo )
-{
- deviceInfo->structVersion = -1;
- deviceInfo->name = NULL;
- deviceInfo->hostApi = -1;
- deviceInfo->maxInputChannels = 0;
- deviceInfo->maxOutputChannels = 0;
- deviceInfo->defaultLowInputLatency = -1.;
- deviceInfo->defaultLowOutputLatency = -1.;
- deviceInfo->defaultHighInputLatency = -1.;
- deviceInfo->defaultHighOutputLatency = -1.;
- deviceInfo->defaultSampleRate = -1.;
-}
-
-/* Helper struct */
-typedef struct
-{
- char *alsaName;
- char *name;
- int isPlug;
- int hasPlayback;
- int hasCapture;
-} DeviceNames;
-
-static PaError PaAlsa_StrDup( PaAlsaHostApiRepresentation *alsaApi,
- char **dst,
- const char *src)
-{
- PaError result = paNoError;
- int len = strlen( src ) + 1;
-
- /* PA_DEBUG(("PaStrDup %s %d\n", src, len)); */
-
- PA_UNLESS( *dst = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
- paInsufficientMemory );
- strncpy( *dst, src, len );
-
-error:
- return result;
-}
-
-/* Disregard standard plugins
- * XXX: Might want to make the "default" plugin available, if we can make it work
- */
-static int IgnorePlugin( const char *pluginId )
-{
-#define numIgnored 10
- static const char *ignoredPlugins[numIgnored] = {"hw", "plughw", "plug", "default", "dsnoop", "dmix", "tee",
- "file", "null", "shm"};
- int i;
-
- for( i = 0; i < numIgnored; ++i )
- {
- if( !strcmp( pluginId, ignoredPlugins[i] ) )
- {
- return 1;
- }
- }
-
- return 0;
-}
-
-/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
-static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
-{
- PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep;
- PaAlsaDeviceInfo *deviceInfoArray;
- int cardIdx = -1, devIdx = 0;
- snd_ctl_card_info_t *cardInfo;
- PaError result = paNoError;
- size_t numDeviceNames = 0, maxDeviceNames = 1, i;
- DeviceNames *deviceNames = NULL;
- snd_config_t *topNode = NULL;
- snd_pcm_info_t *pcmInfo;
- int res;
- int blocking = SND_PCM_NONBLOCK;
- char alsaCardName[50];
- if( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) && atoi( getenv( "PA_ALSA_INITIALIZE_BLOCK" ) ) )
- blocking = 0;
-
- /* These two will be set to the first working input and output device, respectively */
- commonApi->info.defaultInputDevice = paNoDevice;
- commonApi->info.defaultOutputDevice = paNoDevice;
-
- /* count the devices by enumerating all the card numbers */
-
- /* snd_card_next() modifies the integer passed to it to be:
- * the index of the first card if the parameter is -1
- * the index of the next card if the parameter is the index of a card
- * -1 if there are no more cards
- *
- * The function itself returns 0 if it succeeded. */
- cardIdx = -1;
- snd_ctl_card_info_alloca( &cardInfo );
- snd_pcm_info_alloca( &pcmInfo );
- while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 )
- {
- char *cardName;
- int devIdx = -1;
- snd_ctl_t *ctl;
- char buf[50];
-
- snprintf( alsaCardName, sizeof (alsaCardName), "hw:%d", cardIdx );
-
- /* Acquire name of card */
- if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 )
- continue; /* Unable to open card :( */
- snd_ctl_card_info( ctl, cardInfo );
-
- PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) );
-
- while( snd_ctl_pcm_next_device( ctl, &devIdx ) == 0 && devIdx >= 0 )
- {
- char *alsaDeviceName, *deviceName;
- size_t len;
- int hasPlayback = 0, hasCapture = 0;
- snprintf( buf, sizeof (buf), "%s:%d,%d", "hw", cardIdx, devIdx );
-
- /* Obtain info about this particular device */
- snd_pcm_info_set_device( pcmInfo, devIdx );
- snd_pcm_info_set_subdevice( pcmInfo, 0 );
- snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE );
- if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
- hasCapture = 1;
-
- snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK );
- if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
- hasPlayback = 1;
-
- if( !hasPlayback && !hasCapture )
- {
- continue; /* Error */
- }
-
- /* The length of the string written by snprintf plus terminating 0 */
- len = snprintf( NULL, 0, "%s: %s (%s)", cardName, snd_pcm_info_get_name( pcmInfo ), buf ) + 1;
- PA_UNLESS( deviceName = (char *)PaUtil_GroupAllocateMemory( alsaApi->allocations, len ),
- paInsufficientMemory );
- snprintf( deviceName, len, "%s: %s (%s)", cardName,
- snd_pcm_info_get_name( pcmInfo ), buf );
-
- ++numDeviceNames;
- if( !deviceNames || numDeviceNames > maxDeviceNames )
- {
- maxDeviceNames *= 2;
- PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),
- paInsufficientMemory );
- }
-
- PA_ENSURE( PaAlsa_StrDup( alsaApi, &alsaDeviceName, buf ) );
-
- deviceNames[ numDeviceNames - 1 ].alsaName = alsaDeviceName;
- deviceNames[ numDeviceNames - 1 ].name = deviceName;
- deviceNames[ numDeviceNames - 1 ].isPlug = 0;
- deviceNames[ numDeviceNames - 1 ].hasPlayback = hasPlayback;
- deviceNames[ numDeviceNames - 1 ].hasCapture = hasCapture;
- }
- snd_ctl_close( ctl );
- }
-
- /* Iterate over plugin devices */
- snd_config_update();
- if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 )
- {
- snd_config_iterator_t i, next;
-
- snd_config_for_each( i, next, topNode )
- {
- const char *tpStr = NULL, *idStr = NULL;
- char *alsaDeviceName, *deviceName;
- snd_config_t *n = snd_config_iterator_entry( i ), *tp = NULL;
- if( snd_config_get_type( n ) != SND_CONFIG_TYPE_COMPOUND )
- continue;
-
- ENSURE_( snd_config_search( n, "type", &tp ), paUnanticipatedHostError );
- ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );
-
- ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError );
- if( IgnorePlugin( idStr ) )
- {
- PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr ));
- continue;
- }
-
- PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr ));
-
- PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
- strlen(idStr) + 6 ), paInsufficientMemory );
- strcpy( alsaDeviceName, idStr );
- PA_UNLESS( deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
- strlen(idStr) + 1 ), paInsufficientMemory );
- strcpy( deviceName, idStr );
-
- ++numDeviceNames;
- if( !deviceNames || numDeviceNames > maxDeviceNames )
- {
- maxDeviceNames *= 2;
- PA_UNLESS( deviceNames = (DeviceNames *) realloc( deviceNames, maxDeviceNames * sizeof (DeviceNames) ),
- paInsufficientMemory );
- }
-
- deviceNames[numDeviceNames - 1].alsaName = alsaDeviceName;
- deviceNames[numDeviceNames - 1].name = deviceName;
- deviceNames[numDeviceNames - 1].isPlug = 1;
- deviceNames[numDeviceNames - 1].hasPlayback = 1;
- deviceNames[numDeviceNames - 1].hasCapture = 1;
- }
- }
- else
- PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) ));
-
- /* allocate deviceInfo memory based on the number of devices */
- PA_UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );
-
- /* allocate all device info structs in a contiguous block */
- PA_UNLESS( deviceInfoArray = (PaAlsaDeviceInfo*)PaUtil_GroupAllocateMemory(
- alsaApi->allocations, sizeof(PaAlsaDeviceInfo) * numDeviceNames ), paInsufficientMemory );
-
- /* Loop over list of cards, filling in info, if a device is deemed unavailable (can't get name),
- * it's ignored.
- */
- /* while( snd_card_next( &cardIdx ) == 0 && cardIdx >= 0 ) */
- for( i = 0, devIdx = 0; i < numDeviceNames; ++i )
- {
- snd_pcm_t *pcm;
- PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx];
- PaDeviceInfo *commonDeviceInfo = &deviceInfo->commonDeviceInfo;
-
- /* Zero fields */
- InitializeDeviceInfo( commonDeviceInfo );
-
- /* to determine device capabilities, we must open the device and query the
- * hardware parameter configuration space */
-
- /* Query capture */
- if( deviceNames[i].hasCapture &&
- snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 )
- {
- if( GropeDevice( pcm, &deviceInfo->minInputChannels, &commonDeviceInfo->maxInputChannels,
- &commonDeviceInfo->defaultLowInputLatency, &commonDeviceInfo->defaultHighInputLatency,
- &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )
- continue; /* Error */
- }
-
- /* Query playback */
- if( deviceNames[i].hasPlayback &&
- snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 )
- {
- if( GropeDevice( pcm, &deviceInfo->minOutputChannels, &commonDeviceInfo->maxOutputChannels,
- &commonDeviceInfo->defaultLowOutputLatency, &commonDeviceInfo->defaultHighOutputLatency,
- &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )
- continue; /* Error */
- }
-
- commonDeviceInfo->structVersion = 2;
- commonDeviceInfo->hostApi = alsaApi->hostApiIndex;
- commonDeviceInfo->name = deviceNames[i].name;
- deviceInfo->alsaName = deviceNames[i].alsaName;
- deviceInfo->isPlug = deviceNames[i].isPlug;
-
- /* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
- * Should now be safe to add device info, unless the device supports neither capture nor playback
- */
- if( commonDeviceInfo->maxInputChannels > 0 || commonDeviceInfo->maxOutputChannels > 0 )
- {
- if( commonApi->info.defaultInputDevice == paNoDevice && commonDeviceInfo->maxInputChannels > 0 )
- commonApi->info.defaultInputDevice = devIdx;
- if( commonApi->info.defaultOutputDevice == paNoDevice && commonDeviceInfo->maxOutputChannels > 0 )
- commonApi->info.defaultOutputDevice = devIdx;
-
- commonApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo;
- }
- }
- free( deviceNames );
-
- commonApi->info.deviceCount = devIdx; /* Number of successfully queried devices */
-
-end:
- return result;
-
-error:
- goto end; /* No particular action */
-}
-
-/* Check against known device capabilities */
-static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilHostApiRepresentation *hostApi, StreamDirection mode )
-{
- PaError result = paNoError;
- int maxChans;
- const PaAlsaDeviceInfo *deviceInfo = NULL;
- assert( parameters );
-
- if( parameters->device != paUseHostApiSpecificDeviceSpecification )
- {
- assert( parameters->device < hostApi->info.deviceCount );
- PA_UNLESS( parameters->hostApiSpecificStreamInfo == NULL, paBadIODeviceCombination );
- deviceInfo = GetDeviceInfo( hostApi, parameters->device );
- }
- else
- {
- const PaAlsaStreamInfo *streamInfo = parameters->hostApiSpecificStreamInfo;
-
- PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice );
- PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1,
- paIncompatibleHostApiSpecificStreamInfo );
-
- return paNoError; /* Skip further checking */
- }
-
- assert( deviceInfo );
- assert( parameters->hostApiSpecificStreamInfo == NULL );
- maxChans = (StreamDirection_In == mode ? deviceInfo->commonDeviceInfo.maxInputChannels :
- deviceInfo->commonDeviceInfo.maxOutputChannels);
- PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );
-
-error:
- return result;
-}
-
-/* Given an open stream, what sample formats are available? */
-
-static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )
-{
- PaSampleFormat available = 0;
- snd_pcm_hw_params_t *hwParams;
- snd_pcm_hw_params_alloca( &hwParams );
-
- snd_pcm_hw_params_any( pcm, hwParams );
-
- if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_FLOAT ) >= 0)
- available |= paFloat32;
-
- if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S32 ) >= 0)
- available |= paInt32;
-
- if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S24 ) >= 0)
- available |= paInt24;
-
- if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S16 ) >= 0)
- available |= paInt16;
-
- if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_U8 ) >= 0)
- available |= paUInt8;
-
- if( snd_pcm_hw_params_test_format( pcm, hwParams, SND_PCM_FORMAT_S8 ) >= 0)
- available |= paInt8;
-
- return available;
-}
-
-static snd_pcm_format_t Pa2AlsaFormat( PaSampleFormat paFormat )
-{
- switch( paFormat )
- {
- case paFloat32:
- return SND_PCM_FORMAT_FLOAT;
-
- case paInt16:
- return SND_PCM_FORMAT_S16;
-
- case paInt24:
- return SND_PCM_FORMAT_S24;
-
- case paInt32:
- return SND_PCM_FORMAT_S32;
-
- case paInt8:
- return SND_PCM_FORMAT_S8;
-
- case paUInt8:
- return SND_PCM_FORMAT_U8;
-
- default:
- return SND_PCM_FORMAT_UNKNOWN;
- }
-}
-
-/** Open an ALSA pcm handle.
- *
- * The device to be open can be specified in a custom PaAlsaStreamInfo struct, or it will be a device number. In case of a
- * device number, it maybe specified through an env variable (PA_ALSA_PLUGHW) that we should open the corresponding plugin
- * device.
- */
-static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *params, StreamDirection
- streamDir, snd_pcm_t **pcm )
-{
- PaError result = paNoError;
- int ret;
- const char *deviceName = alloca( 50 );
- const PaAlsaDeviceInfo *deviceInfo = NULL;
- PaAlsaStreamInfo *streamInfo = (PaAlsaStreamInfo *)params->hostApiSpecificStreamInfo;
-
- if( !streamInfo )
- {
- int usePlug = 0;
- deviceInfo = GetDeviceInfo( hostApi, params->device );
-
- /* If device name starts with hw: and PA_ALSA_PLUGHW is 1, we open the plughw device instead */
- if( !strncmp( "hw:", deviceInfo->alsaName, 3 ) && getenv( "PA_ALSA_PLUGHW" ) )
- usePlug = atoi( getenv( "PA_ALSA_PLUGHW" ) );
- if( usePlug )
- snprintf( (char *) deviceName, 50, "plug%s", deviceInfo->alsaName );
- else
- deviceName = deviceInfo->alsaName;
- }
- else
- deviceName = streamInfo->deviceString;
-
- if( (ret = snd_pcm_open( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK )) < 0 )
- {
- *pcm = NULL; /* Not to be closed */
- ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paBadIODeviceCombination );
- }
- ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
-
-end:
- return result;
-
-error:
- goto end;
-}
-
-static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters,
- double sampleRate, StreamDirection streamDir )
-{
- PaError result = paNoError;
- snd_pcm_t *pcm = NULL;
- PaSampleFormat availableFormats;
- /* We are able to adapt to a number of channels less than what the device supports */
- unsigned int numHostChannels;
- PaSampleFormat hostFormat;
- snd_pcm_hw_params_t *hwParams;
- snd_pcm_hw_params_alloca( &hwParams );
-
- if( !parameters->hostApiSpecificStreamInfo )
- {
- const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, parameters->device );
- numHostChannels = PA_MAX( parameters->channelCount, StreamDirection_In == streamDir ?
- devInfo->minInputChannels : devInfo->minOutputChannels );
- }
- else
- numHostChannels = parameters->channelCount;
-
- PA_ENSURE( AlsaOpen( hostApi, parameters, streamDir, &pcm ) );
-
- snd_pcm_hw_params_any( pcm, hwParams );
-
- if( SetApproximateSampleRate( pcm, hwParams, sampleRate ) < 0 )
- {
- result = paInvalidSampleRate;
- goto error;
- }
-
- if( snd_pcm_hw_params_set_channels( pcm, hwParams, numHostChannels ) < 0 )
- {
- result = paInvalidChannelCount;
- goto error;
- }
-
- /* See if we can find a best possible match */
- availableFormats = GetAvailableFormats( pcm );
- PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );
- ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );
-
- ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );
-
-end:
- if( pcm )
- snd_pcm_close( pcm );
- return result;
-
-error:
- goto end;
-}
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- int inputChannelCount = 0, outputChannelCount = 0;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaError result = paFormatIsSupported;
-
- if( inputParameters )
- {
- PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
-
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- }
-
- if( outputParameters )
- {
- PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
-
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- }
-
- if( inputChannelCount )
- {
- if( (result = TestParameters( hostApi, inputParameters, sampleRate, StreamDirection_In ))
- != paNoError )
- goto error;
- }
- if ( outputChannelCount )
- {
- if( (result = TestParameters( hostApi, outputParameters, sampleRate, StreamDirection_Out ))
- != paNoError )
- goto error;
- }
-
- return paFormatIsSupported;
-
-error:
- return result;
-}
-
-static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, PaAlsaHostApiRepresentation *alsaApi,
- const PaStreamParameters *params, StreamDirection streamDir, int callbackMode )
-{
- PaError result = paNoError;
- PaSampleFormat userSampleFormat = params->sampleFormat, hostSampleFormat;
- assert( params->channelCount > 0 );
-
- /* Make sure things have an initial value */
- memset( self, 0, sizeof (PaAlsaStreamComponent) );
-
- if( NULL == params->hostApiSpecificStreamInfo )
- {
- const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->commonHostApiRep, params->device );
- self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels
- : devInfo->minOutputChannels );
- }
- else
- {
- /* We're blissfully unaware of the minimum channelCount */
- self->numHostChannels = params->channelCount;
- }
-
- PA_ENSURE( AlsaOpen( &alsaApi->commonHostApiRep, params, streamDir, &self->pcm ) );
- self->nfds = snd_pcm_poll_descriptors_count( self->pcm );
- hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );
-
- self->hostSampleFormat = hostSampleFormat;
- self->nativeFormat = Pa2AlsaFormat( hostSampleFormat );
- self->hostInterleaved = self->userInterleaved = !(userSampleFormat & paNonInterleaved);
- self->numUserChannels = params->channelCount;
- self->streamDir = streamDir;
-
- if( !callbackMode && !self->userInterleaved )
- {
- /* Pre-allocate non-interleaved user provided buffers */
- PA_UNLESS( self->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * self->numUserChannels ),
- paInsufficientMemory );
- }
-
-error:
- return result;
-}
-
-static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
-{
- snd_pcm_close( self->pcm );
- if( self->userBuffers )
- PaUtil_FreeMemory( self->userBuffers );
-}
-
-/** Configure the associated ALSA pcm.
- *
- */
-static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, const PaStreamParameters *params, unsigned long
- framesPerHostBuffer, int primeBuffers, int callbackMode, double *sampleRate, PaTime *returnedLatency )
-{
- /*
- int numPeriods;
-
- if( getenv("PA_NUMPERIODS") != NULL )
- numPeriods = atoi( getenv("PA_NUMPERIODS") );
- else
- numPeriods = ( (latency * sampleRate) / *framesPerBuffer ) + 1;
-
- PA_DEBUG(( "latency: %f, rate: %f, framesPerBuffer: %d\n", latency, sampleRate, *framesPerBuffer ));
- if( numPeriods <= 1 )
- numPeriods = 2;
- */
-
- /* Configuration consists of setting all of ALSA's parameters.
- * These parameters come in two flavors: hardware parameters
- * and software paramters. Hardware parameters will affect
- * the way the device is initialized, software parameters
- * affect the way ALSA interacts with me, the user-level client.
- */
-
- snd_pcm_hw_params_t *hwParams;
- snd_pcm_sw_params_t *swParams;
- PaError result = paNoError;
- snd_pcm_access_t accessMode, alternateAccessMode;
- unsigned int numPeriods, minPeriods = 2;
- int dir = 0;
- snd_pcm_t *pcm = self->pcm;
- PaTime latency = params->suggestedLatency;
- double sr = *sampleRate;
- *returnedLatency = -1.;
-
- snd_pcm_hw_params_alloca( &hwParams );
- snd_pcm_sw_params_alloca( &swParams );
-
- self->framesPerBuffer = framesPerHostBuffer;
-
- /* ... fill up the configuration space with all possibile
- * combinations of parameters this device will accept */
- ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
-
- ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );
-
- if( self->userInterleaved )
- {
- accessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
- alternateAccessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
- }
- else
- {
- accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
- alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
- }
-
- /* If requested access mode fails, try alternate mode */
- if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
- {
- ENSURE_( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ), paUnanticipatedHostError );
- /* Flip mode */
- self->hostInterleaved = !self->userInterleaved;
- }
-
- ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, self->nativeFormat ), paUnanticipatedHostError );
-
- ENSURE_( SetApproximateSampleRate( pcm, hwParams, sr ), paInvalidSampleRate );
- ENSURE_( GetExactSampleRate( hwParams, &sr ), paUnanticipatedHostError );
- /* reject if there's no sample rate within 1% of the one requested */
- if( (fabs( *sampleRate - sr ) / *sampleRate) > 0.01 )
- {
- PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));
- PA_ENSURE( paInvalidSampleRate );
- }
-
- ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );
-
- /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */
- dir = 0;
- ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
- dir = 0;
- ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &self->framesPerBuffer, &dir ), paUnanticipatedHostError );
-
- /* Find an acceptable number of periods */
- numPeriods = (latency * sr) / self->framesPerBuffer + 1;
- dir = 0;
- ENSURE_( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, &dir ), paUnanticipatedHostError );
- /* Minimum of periods should already be 2 */
- PA_UNLESS( numPeriods >= 2, paInternalError );
-
- /* Set the parameters! */
- ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );
-
- /* Latency in seconds, one period is not counted as latency */
- latency = (numPeriods - 1) * self->framesPerBuffer / sr;
-
- /* Now software parameters... */
- ENSURE_( snd_pcm_sw_params_current( pcm, swParams ), paUnanticipatedHostError );
-
- ENSURE_( snd_pcm_sw_params_set_start_threshold( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_stop_threshold( pcm, swParams, self->bufferSize ), paUnanticipatedHostError );
-
- /* Silence buffer in the case of underrun */
- if( !primeBuffers ) /* XXX: Make sense? */
- {
- snd_pcm_uframes_t boundary;
- ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_silence_threshold( pcm, swParams, 0 ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_silence_size( pcm, swParams, boundary ), paUnanticipatedHostError );
- }
-
- ENSURE_( snd_pcm_sw_params_set_avail_min( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_xfer_align( pcm, swParams, 1 ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_tstamp_mode( pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );
-
- /* Set the parameters! */
- ENSURE_( snd_pcm_sw_params( pcm, swParams ), paUnanticipatedHostError );
-
- *sampleRate = sr;
- *returnedLatency = latency;
-
-end:
- return result;
-
-error:
- goto end; /* No particular action */
-}
-
-static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,
- const PaStreamParameters *outParams, double sampleRate, unsigned long framesPerUserBuffer, PaStreamCallback callback,
- PaStreamFlags streamFlags, void *userData )
-{
- PaError result = paNoError;
- assert( self );
-
- memset( self, 0, sizeof (PaAlsaStream) );
-
- if( NULL != callback )
- {
- PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
- &alsaApi->callbackStreamInterface,
- callback, userData );
- self->callbackMode = 1;
- }
- else
- {
- PaUtil_InitializeStreamRepresentation( &self->streamRepresentation,
- &alsaApi->blockingStreamInterface,
- NULL, userData );
- }
-
- self->framesPerUserBuffer = framesPerUserBuffer;
- self->neverDropInput = streamFlags & paNeverDropInput;
- /* XXX: Ignore paPrimeOutputBuffersUsingStreamCallback untill buffer priming is fully supported in pa_process.c */
- /*
- if( outParams & streamFlags & paPrimeOutputBuffersUsingStreamCallback )
- self->primeBuffers = 1;
- */
- memset( &self->capture, 0, sizeof (PaAlsaStreamComponent) );
- memset( &self->playback, 0, sizeof (PaAlsaStreamComponent) );
- if( inParams )
- PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->capture, alsaApi, inParams, StreamDirection_In, NULL != callback ) );
- if( outParams )
- PA_ENSURE( PaAlsaStreamComponent_Initialize( &self->playback, alsaApi, outParams, StreamDirection_Out, NULL != callback ) );
-
- assert( self->capture.nfds || self->playback.nfds );
-
- PA_UNLESS( self->pfds = (struct pollfd*)PaUtil_AllocateMemory( (self->capture.nfds +
- self->playback.nfds) * sizeof (struct pollfd) ), paInsufficientMemory );
-
- PaUtil_InitializeCpuLoadMeasurer( &self->cpuLoadMeasurer, sampleRate );
- InitializeThreading( &self->threading, &self->cpuLoadMeasurer );
- ASSERT_CALL_( pthread_mutex_init( &self->stateMtx, NULL ), 0 );
- ASSERT_CALL_( pthread_mutex_init( &self->startMtx, NULL ), 0 );
- ASSERT_CALL_( pthread_cond_init( &self->startCond, NULL ), 0 );
-
-error:
- return result;
-}
-
-/** Free resources associated with stream, and eventually stream itself.
- *
- * Frees allocated memory, and terminates individual StreamComponents.
- */
-static void PaAlsaStream_Terminate( PaAlsaStream *self )
-{
- assert( self );
-
- if( self->capture.pcm )
- {
- PaAlsaStreamComponent_Terminate( &self->capture );
- }
- if( self->playback.pcm )
- {
- PaAlsaStreamComponent_Terminate( &self->playback );
- }
-
- PaUtil_FreeMemory( self->pfds );
- ASSERT_CALL_( pthread_mutex_destroy( &self->stateMtx ), 0 );
- ASSERT_CALL_( pthread_mutex_destroy( &self->startMtx ), 0 );
- ASSERT_CALL_( pthread_cond_destroy( &self->startCond ), 0 );
-
- PaUtil_FreeMemory( self );
-}
-
-/** Calculate polling timeout
- *
- * @param frames Time to wait
- * @return Polling timeout in milliseconds
- */
-static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frames )
-{
- assert( stream->streamRepresentation.streamInfo.sampleRate > 0.0 );
- /* Period in msecs, rounded up */
- return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );
-}
-
-/** Set up ALSA stream parameters.
- *
- */
-static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters
- *outParams, double sampleRate, unsigned long framesPerHostBuffer, double *inputLatency, double *outputLatency,
- unsigned long *maxHostBufferSize )
-{
- PaError result = paNoError;
- double realSr = sampleRate;
-
- if( self->capture.pcm )
- PA_ENSURE( PaAlsaStreamComponent_Configure( &self->capture, inParams, framesPerHostBuffer, self->primeBuffers,
- self->callbackMode, &realSr, inputLatency ) );
- if( self->playback.pcm )
- PA_ENSURE( PaAlsaStreamComponent_Configure( &self->playback, outParams, framesPerHostBuffer, self->primeBuffers,
- self->callbackMode, &realSr, outputLatency ) );
-
- /* Should be exact now */
- self->streamRepresentation.streamInfo.sampleRate = realSr;
-
- /* this will cause the two streams to automatically start/stop/prepare in sync.
- * We only need to execute these operations on one of the pair.
- * A: We don't want to do this on a blocking stream.
- */
- if( self->callbackMode && self->capture.pcm && self->playback.pcm )
- {
- int err = snd_pcm_link( self->capture.pcm, self->playback.pcm );
- if( err >= 0 )
- self->pcmsSynced = 1;
- else
- PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) ));
- }
-
- /* Frames per host buffer for the stream is set as a compromise between the two directions */
- framesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,
- self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );
- self->pollTimeout = CalculatePollTimeout( self, framesPerHostBuffer ); /* Period in msecs, rounded up */
-
- *maxHostBufferSize = PA_MAX( self->capture.pcm ? self->capture.bufferSize : 0,
- self->playback.pcm ? self->playback.bufferSize : 0 );
-
- /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
- self->threading.throttledSleepTime = (unsigned long) (framesPerHostBuffer / sampleRate / 4 * 1000);
-
- if( self->callbackMode )
- {
- /* If the user expects a certain number of frames per callback we will either have to rely on block adaption
- * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number
- * of host buffer frames with what the user specified */
- if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
- {
- /* self->alignFrames = 1; */
-
- /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
- * on block adaption */
- /*
- if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&
- self->capture.framesPerBuffer != self->playback.framesPerBuffer) )
- self->useBlockAdaption = 1;
- else
- self->alignFrames = 1;
- */
- }
- }
-
-error:
- return result;
-}
-
-/* We need to determine how many frames per host buffer to use. Our
- * goals are to provide the best possible performance, but also to
- * most closely honor the requested latency settings. Therefore this
- * decision is based on:
- *
- * - the period sizes that playback and/or capture support. The
- * host buffer size has to be one of these.
- * - the number of periods that playback and/or capture support.
- *
- * We want to make period_size*(num_periods-1) to be as close as possible
- * to latency*rate for both playback and capture.
- *
- * This is one of those blocks of code that will just take a lot of
- * refinement to be any good.
- *
- * In the full-duplex case it is possible that the routine was unable
- * to find a number of frames per buffer acceptable to both devices
- * TODO: Implement an algorithm to find the value closest to acceptance
- * by both devices, to minimize difference between period sizes?
- */
-static PaError DetermineFramesPerBuffer( const PaAlsaStream *stream, double sampleRate, const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters, unsigned long *determinedFrames, const PaUtilHostApiRepresentation *hostApi )
-{
- PaError result = paNoError;
- unsigned long framesPerBuffer = 0;
- int numHostInputChannels = 0, numHostOutputChannels = 0;
-
- /* XXX: Clean this up */
- if( stream->capture.pcm )
- {
- const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, inputParameters->device );
- numHostInputChannels = PA_MAX( inputParameters->channelCount, devInfo->minInputChannels );
- }
- if( stream->playback.pcm )
- {
- const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, outputParameters->device );
- numHostOutputChannels = PA_MAX( outputParameters->channelCount, devInfo->minOutputChannels );
- }
-
- if( stream->capture.pcm && stream->playback.pcm )
- {
- snd_pcm_uframes_t desiredLatency, e;
- snd_pcm_uframes_t minPeriodSize, minPlayback, minCapture, maxPeriodSize, maxPlayback, maxCapture,
- optimalPeriodSize, periodSize;
- int dir = 0;
- unsigned int minPeriods = 2;
-
- snd_pcm_t *pcm;
- snd_pcm_hw_params_t *hwParamsPlayback, *hwParamsCapture;
-
- snd_pcm_hw_params_alloca( &hwParamsPlayback );
- snd_pcm_hw_params_alloca( &hwParamsCapture );
-
- /* Come up with a common desired latency */
- pcm = stream->playback.pcm;
- snd_pcm_hw_params_any( pcm, hwParamsPlayback );
- ENSURE_( SetApproximateSampleRate( pcm, hwParamsPlayback, sampleRate ), paInvalidSampleRate );
- ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsPlayback, numHostOutputChannels ),
- paBadIODeviceCombination );
-
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsPlayback, &minPeriods, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );
-
- pcm = stream->capture.pcm;
- ENSURE_( snd_pcm_hw_params_any( pcm, hwParamsCapture ), paUnanticipatedHostError );
- ENSURE_( SetApproximateSampleRate( pcm, hwParamsCapture, sampleRate ), paBadIODeviceCombination );
- ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsCapture, numHostInputChannels ),
- paBadIODeviceCombination );
-
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsCapture, &minPeriods, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );
-
- minPeriodSize = PA_MAX( minPlayback, minCapture );
- maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
-
- desiredLatency = (snd_pcm_uframes_t) (PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
- * sampleRate);
- /* Clamp desiredLatency */
- {
- snd_pcm_uframes_t tmp, maxBufferSize = ULONG_MAX;
- ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSize ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &tmp ), paUnanticipatedHostError );
- maxBufferSize = PA_MIN( maxBufferSize, tmp );
-
- desiredLatency = PA_MIN( desiredLatency, maxBufferSize );
- }
-
- /* Find the closest power of 2 */
- e = ilogb( minPeriodSize );
- if( minPeriodSize & (minPeriodSize - 1) )
- e += 1;
- periodSize = (snd_pcm_uframes_t) pow( 2, e );
-
- while( periodSize <= maxPeriodSize )
- {
- if( snd_pcm_hw_params_test_period_size( stream->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
- snd_pcm_hw_params_test_period_size( stream->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
- break; /* Ok! */
-
- periodSize *= 2;
- }
-
- /* 4 periods considered optimal */
- optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
- optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
-
- /* Find the closest power of 2 */
- e = ilogb( optimalPeriodSize );
- if( optimalPeriodSize & (optimalPeriodSize - 1) )
- e += 1;
- optimalPeriodSize = (snd_pcm_uframes_t) pow( 2, e );
-
- while( optimalPeriodSize >= periodSize )
- {
- pcm = stream->playback.pcm;
- if( snd_pcm_hw_params_test_period_size( pcm, hwParamsPlayback, optimalPeriodSize, 0 ) < 0 )
- continue;
-
- pcm = stream->capture.pcm;
- if( snd_pcm_hw_params_test_period_size( pcm, hwParamsCapture, optimalPeriodSize, 0 ) >= 0 )
- break;
-
- optimalPeriodSize /= 2;
- }
-
- if( optimalPeriodSize > periodSize )
- periodSize = optimalPeriodSize;
-
- if( periodSize <= maxPeriodSize )
- {
- /* Looks good */
- framesPerBuffer = periodSize;
- }
- else
- {
- /* Unable to find a common period size, oh well */
- optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
- optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
-
- /* ConfigureStream should find individual period sizes acceptable for each device */
- framesPerBuffer = optimalPeriodSize;
- /* PA_ENSURE( paBadIODeviceCombination ); */
- }
- }
- else /* half-duplex is a slightly simpler case */
- {
- unsigned long bufferSize, channels;
- snd_pcm_t *pcm;
- snd_pcm_hw_params_t *hwParams;
-
- snd_pcm_hw_params_alloca( &hwParams );
-
- if( stream->capture.pcm )
- {
- pcm = stream->capture.pcm;
- bufferSize = inputParameters->suggestedLatency * sampleRate;
- channels = numHostInputChannels;
- }
- else
- {
- pcm = stream->playback.pcm;
- bufferSize = outputParameters->suggestedLatency * sampleRate;
- channels = numHostOutputChannels;
- }
-
- ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( SetApproximateSampleRate( pcm, hwParams, sampleRate ), paInvalidSampleRate );
- ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, channels ), paBadIODeviceCombination );
-
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
-
- /* Using 5 as a base number of periods, we try to approximate the suggested latency (+1 period),
- finding a combination of period/buffer size which best fits these constraints */
- framesPerBuffer = bufferSize / 4;
- bufferSize += framesPerBuffer; /* One period doesn't count as latency */
- ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &bufferSize ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &framesPerBuffer, NULL ), paUnanticipatedHostError );
- }
-
- PA_UNLESS( framesPerBuffer != 0, paInternalError );
- *determinedFrames = framesPerBuffer;
-
-error:
- return result;
-}
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *callback,
- void *userData )
-{
- PaError result = paNoError;
- PaAlsaHostApiRepresentation *alsaHostApi = (PaAlsaHostApiRepresentation*)hostApi;
- PaAlsaStream *stream = NULL;
- PaSampleFormat hostInputSampleFormat = 0, hostOutputSampleFormat = 0;
- PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
- int numInputChannels = 0, numOutputChannels = 0;
- PaTime inputLatency, outputLatency;
- unsigned long framesPerHostBuffer;
- PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilBoundedHostBufferSize;
- unsigned long maxHostBufferSize=0; /* Upper bound of host buffer size */
-
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- return paInvalidFlag;
-
- if( inputParameters )
- {
- PA_ENSURE( ValidateParameters( inputParameters, hostApi, StreamDirection_In ) );
-
- numInputChannels = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- }
- if( outputParameters )
- {
- PA_ENSURE( ValidateParameters( outputParameters, hostApi, StreamDirection_Out ) );
-
- numOutputChannels = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- }
-
- /* XXX: Why do we support this anyway? */
- if( framesPerBuffer == paFramesPerBufferUnspecified && getenv( "PA_ALSA_PERIODSIZE" ) != NULL )
- {
- PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ ));
- framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
- }
- framesPerHostBuffer = framesPerBuffer;
-
- PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory );
- PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate,
- framesPerBuffer, callback, streamFlags, userData ) );
-
- /* If the number of frames per buffer is unspecified, we have to come up with
- * one. This is both a blessing and a curse: a blessing because we can optimize
- * the number to best meet the requirements, but a curse because that's really
- * hard to do well. For this reason we also support an interface where the user
- * specifies these by setting environment variables. */
- if( framesPerBuffer == paFramesPerBufferUnspecified )
- {
- PA_ENSURE( DetermineFramesPerBuffer( stream, sampleRate, inputParameters, outputParameters, &framesPerHostBuffer,
- hostApi ) );
- }
-
- PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerHostBuffer,
- &inputLatency, &outputLatency, &maxHostBufferSize ) );
- hostInputSampleFormat = stream->capture.hostSampleFormat;
- hostOutputSampleFormat = stream->playback.hostSampleFormat;
-
- if( framesPerHostBuffer != framesPerBuffer )
- {
- PA_DEBUG(( "%s: Number of frames per user and host buffer differs\n", __FUNCTION__ ));
- }
-
- PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- numInputChannels, inputSampleFormat, hostInputSampleFormat,
- numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerBuffer, maxHostBufferSize,
- hostBufferSizeMode, callback, userData ) );
-
- /* Ok, buffer processor is initialized, now we can deduce it's latency */
- if( numInputChannels > 0 )
- stream->streamRepresentation.streamInfo.inputLatency = inputLatency + PaUtil_GetBufferProcessorInputLatency(
- &stream->bufferProcessor );
- if( numOutputChannels > 0 )
- stream->streamRepresentation.streamInfo.outputLatency = outputLatency + PaUtil_GetBufferProcessorOutputLatency(
- &stream->bufferProcessor );
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
- if( stream )
- PaAlsaStream_Terminate( stream );
-
- return result;
-}
-
-static PaError CloseStream( PaStream* s )
-{
- PaError result = paNoError;
- PaAlsaStream *stream = (PaAlsaStream*)s;
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-
- PaAlsaStream_Terminate( stream );
-
- return result;
-}
-
-static void SilenceBuffer( PaAlsaStream *stream )
-{
- const snd_pcm_channel_area_t *areas;
- snd_pcm_uframes_t frames = (snd_pcm_uframes_t)snd_pcm_avail_update( stream->playback.pcm ), offset;
-
- snd_pcm_mmap_begin( stream->playback.pcm, &areas, &offset, &frames );
- snd_pcm_areas_silence( areas, offset, stream->playback.numHostChannels, frames, stream->playback.nativeFormat );
- snd_pcm_mmap_commit( stream->playback.pcm, offset, frames );
-}
-
-/** Start/prepare pcm(s) for streaming.
- *
- * Depending on wether the stream is in callback or blocking mode, we will respectively start or simply
- * prepare the playback pcm. If the buffer has _not_ been primed, we will in callback mode prepare and
- * silence the buffer before starting playback. In blocking mode we simply prepare, as the playback will
- * be started automatically as the user writes to output.
- *
- * The capture pcm, however, will simply be prepared and started.
- *
- * PaAlsaStream::startMtx makes sure access is synchronized (useful in callback mode)
- */
-static PaError AlsaStart( PaAlsaStream *stream, int priming )
-{
- PaError result = paNoError;
-
- if( stream->playback.pcm )
- {
- if( stream->callbackMode )
- {
- if( !priming )
- {
- /* Buffer isn't primed, so prepare and silence */
- ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
- SilenceBuffer( stream );
- }
- ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
- }
- else
- ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
- }
- if( stream->capture.pcm && !stream->pcmsSynced )
- {
- ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
- /* For a blocking stream we want to start capture as well, since nothing will happen otherwise */
- ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
- }
-
-end:
- return result;
-error:
- goto end;
-}
-
-/** Utility function for determining if pcms are in running state.
- *
- */
-static int IsRunning( PaAlsaStream *stream )
-{
- int result = 0;
-
- ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 ); /* Synchronize access to pcm state */
- if( stream->capture.pcm )
- {
- snd_pcm_state_t capture_state = snd_pcm_state( stream->capture.pcm );
-
- if( capture_state == SND_PCM_STATE_RUNNING || capture_state == SND_PCM_STATE_XRUN
- || capture_state == SND_PCM_STATE_DRAINING )
- {
- result = 1;
- goto end;
- }
- }
-
- if( stream->playback.pcm )
- {
- snd_pcm_state_t playback_state = snd_pcm_state( stream->playback.pcm );
-
- if( playback_state == SND_PCM_STATE_RUNNING || playback_state == SND_PCM_STATE_XRUN
- || playback_state == SND_PCM_STATE_DRAINING )
- {
- result = 1;
- goto end;
- }
- }
-
-end:
- ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );
-
- return result;
-}
-
-static PaError StartStream( PaStream *s )
-{
- PaError result = paNoError;
- PaAlsaStream *stream = (PaAlsaStream*)s;
- int streamStarted = 0; /* So we can know wether we need to take the stream down */
-
- /* Ready the processor */
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-
- /* Set now, so we can test for activity further down */
- stream->isActive = 1;
-
- if( stream->callbackMode )
- {
- int res = 0;
- PaTime pt = PaUtil_GetTime();
- struct timespec ts;
-
- PA_ENSURE( CreateCallbackThread( &stream->threading, &CallbackThreadFunc, stream ) );
- streamStarted = 1;
-
- /* Wait for stream to be started */
- ts.tv_sec = (time_t) floor( pt + 1 );
- ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000);
-
- /* Since we'll be holding a lock on the startMtx (when not waiting on the condition), IsRunning won't be checking
- * stream state at the same time as the callback thread affects it. We also check IsStreamActive, in the unlikely
- * case the callback thread exits in the meantime (the stream will be considered inactive after the thread exits) */
- ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );
-
- /* Due to possible spurious wakeups, we enclose in a loop */
- while( !IsRunning( stream ) && IsStreamActive( s ) && !res )
- {
- res = pthread_cond_timedwait( &stream->startCond, &stream->startMtx, &ts );
- }
- ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );
-
- PA_UNLESS( !res || res == ETIMEDOUT, paInternalError );
- PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - pt ));
-
- if( res == ETIMEDOUT )
- {
- PA_ENSURE( paTimedOut );
- }
- }
- else
- {
- PA_ENSURE( AlsaStart( stream, 0 ) );
- streamStarted = 1;
- }
-
-end:
- return result;
-error:
- if( streamStarted )
- AbortStream( stream );
- stream->isActive = 0;
-
- goto end;
-}
-
-static PaError AlsaStop( PaAlsaStream *stream, int abort )
-{
- PaError result = paNoError;
-
- if( abort )
- {
- if( stream->playback.pcm )
- ENSURE_( snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError );
- if( stream->capture.pcm && !stream->pcmsSynced )
- ENSURE_( snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError );
-
- PA_DEBUG(( "Dropped frames\n" ));
- }
- else
- {
- if( stream->playback.pcm )
- ENSURE_( snd_pcm_drain( stream->playback.pcm ), paUnanticipatedHostError );
- if( stream->capture.pcm && !stream->pcmsSynced )
- ENSURE_( snd_pcm_drain( stream->capture.pcm ), paUnanticipatedHostError );
- }
-
-end:
- return result;
-error:
- goto end;
-}
-
-/** Stop or abort stream.
- *
- * If a stream is in callback mode we will have to inspect wether the background thread has
- * finished, or we will have to take it out. In either case we join the thread before
- * returning. In blocking mode, we simply tell ALSA to stop abruptly (abort) or finish
- * buffers (drain)
- *
- * Stream will be considered inactive (!PaAlsaStream::isActive) after a call to this function
- */
-static PaError RealStop( PaAlsaStream *stream, int abort )
-{
- PaError result = paNoError;
-
- /* First deal with the callback thread, cancelling and/or joining
- * it if necessary
- */
- if( stream->callbackMode )
- {
- PaError threadRes, watchdogRes;
- stream->callbackAbort = abort;
-
- if( !abort )
- {
- PA_DEBUG(( "Stopping callback\n" ));
- stream->callbackStop = 1;
- }
- PA_ENSURE( KillCallbackThread( &stream->threading, !abort, &threadRes, &watchdogRes ) );
- if( threadRes != paNoError )
- PA_DEBUG(( "Callback thread returned: %d\n", threadRes ));
- if( watchdogRes != paNoError )
- PA_DEBUG(( "Watchdog thread returned: %d\n", watchdogRes ));
-
- stream->callbackStop = 0; /* The deed is done */
- stream->callback_finished = 0;
- }
- else
- {
- PA_ENSURE( AlsaStop( stream, abort ) );
- }
-
- stream->isActive = 0;
-
-end:
- return result;
-
-error:
- goto end;
-}
-
-static PaError StopStream( PaStream *s )
-{
- return RealStop( (PaAlsaStream *) s, 0 );
-}
-
-static PaError AbortStream( PaStream *s )
-{
- return RealStop( (PaAlsaStream * ) s, 1 );
-}
-
-/** The stream is considered stopped before StartStream, or AFTER a call to Abort/StopStream (callback
- * returning !paContinue is not considered)
- *
- */
-static PaError IsStreamStopped( PaStream *s )
-{
- PaAlsaStream *stream = (PaAlsaStream *)s;
-
- /* callback_finished indicates we need to join callback thread (ie. in Abort/StopStream) */
- return !IsStreamActive( s ) && !stream->callback_finished;
-}
-
-static PaError IsStreamActive( PaStream *s )
-{
- PaAlsaStream *stream = (PaAlsaStream*)s;
- return stream->isActive;
-}
-
-static PaTime GetStreamTime( PaStream *s )
-{
- PaAlsaStream *stream = (PaAlsaStream*)s;
-
- snd_timestamp_t timestamp;
- snd_pcm_status_t *status;
- snd_pcm_status_alloca( &status );
-
- /* TODO: what if we have both? does it really matter? */
-
- /* TODO: if running in callback mode, this will mean
- * libasound routines are being called from multiple threads.
- * need to verify that libasound is thread-safe. */
-
- if( stream->capture.pcm )
- {
- snd_pcm_status( stream->capture.pcm, status );
- }
- else if( stream->playback.pcm )
- {
- snd_pcm_status( stream->playback.pcm, status );
- }
-
- snd_pcm_status_get_tstamp( status, &timestamp );
- return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1000000.0;
-}
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaAlsaStream *stream = (PaAlsaStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-static int SetApproximateSampleRate( snd_pcm_t *pcm, snd_pcm_hw_params_t *hwParams, double sampleRate )
-{
- unsigned long approx = (unsigned long) sampleRate;
- int dir = 0;
- double fraction = sampleRate - approx;
-
- assert( pcm && hwParams );
-
- if( fraction > 0.0 )
- {
- if( fraction > 0.5 )
- {
- ++approx;
- dir = -1;
- }
- else
- dir = 1;
- }
-
- return snd_pcm_hw_params_set_rate( pcm, hwParams, approx, dir );
-}
-
-/* Return exact sample rate in param sampleRate */
-static int GetExactSampleRate( snd_pcm_hw_params_t *hwParams, double *sampleRate )
-{
- unsigned int num, den;
- int err;
-
- assert( hwParams );
-
- err = snd_pcm_hw_params_get_rate_numden( hwParams, &num, &den );
- *sampleRate = (double) num / den;
-
- return err;
-}
-
-/* Utility functions for blocking/callback interfaces */
-
-/* Atomic restart of stream (we don't want the intermediate state visible) */
-static PaError AlsaRestart( PaAlsaStream *stream )
-{
- PaError result = paNoError;
-
- ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 );
- PA_ENSURE( AlsaStop( stream, 0 ) );
- PA_ENSURE( AlsaStart( stream, 0 ) );
-
- PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ ));
-
-error:
- ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );
- return result;
-}
-
-/** Recover from xrun state.
- *
- */
-static PaError PaAlsaStream_HandleXrun( PaAlsaStream *self )
-{
- PaError result = paNoError;
- snd_pcm_status_t *st;
- PaTime now = PaUtil_GetTime();
- snd_timestamp_t t;
-
- snd_pcm_status_alloca( &st );
-
- if( self->playback.pcm )
- {
- snd_pcm_status( self->playback.pcm, st );
- if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
- {
- snd_pcm_status_get_trigger_tstamp( st, &t );
- self->underrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
- }
- }
- if( self->capture.pcm )
- {
- snd_pcm_status( self->capture.pcm, st );
- if( snd_pcm_status_get_state( st ) == SND_PCM_STATE_XRUN )
- {
- snd_pcm_status_get_trigger_tstamp( st, &t );
- self->overrun = now * 1000 - ((PaTime) t.tv_sec * 1000 + (PaTime) t.tv_usec / 1000);
- }
- }
-
- PA_ENSURE( AlsaRestart( self ) );
-
-end:
- return result;
-error:
- goto end;
-}
-
-/** Decide if we should continue polling for specified direction, eventually adjust the poll timeout.
- *
- */
-static PaError ContinuePoll( const PaAlsaStream *stream, StreamDirection streamDir, int *pollTimeout, int *continuePoll )
-{
- PaError result = paNoError;
- snd_pcm_sframes_t delay, margin;
- int err;
- const PaAlsaStreamComponent *component = NULL, *otherComponent = NULL;
-
- *continuePoll = 1;
-
- if( StreamDirection_In == streamDir )
- {
- component = &stream->capture;
- otherComponent = &stream->playback;
- }
- else
- {
- component = &stream->playback;
- otherComponent = &stream->capture;
- }
-
- /* ALSA docs say that negative delay should indicate xrun, but in my experience snd_pcm_delay returns -EPIPE */
- if( (err = snd_pcm_delay( otherComponent->pcm, &delay )) < 0 )
- {
- if( err == -EPIPE )
- {
- /* Xrun */
- *continuePoll = 0;
- goto error;
- }
-
- ENSURE_( err, paUnanticipatedHostError );
- }
-
- if( StreamDirection_Out == streamDir )
- {
- /* Number of eligible frames before capture overrun */
- delay = otherComponent->bufferSize - delay;
- }
- margin = delay - otherComponent->framesPerBuffer / 2;
-
- if( margin < 0 )
- {
- PA_DEBUG(( "%s: Stopping poll for %s\n", __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback" ));
- *continuePoll = 0;
- }
- else if( margin < otherComponent->framesPerBuffer )
- {
- *pollTimeout = CalculatePollTimeout( stream, margin );
- PA_DEBUG(( "%s: Trying to poll again for %s frames, pollTimeout: %d\n",
- __FUNCTION__, StreamDirection_In == streamDir ? "capture" : "playback", *pollTimeout ));
- }
-
-error:
- return result;
-}
-
-/* Callback interface */
-
-static void OnExit( void *data )
-{
- PaAlsaStream *stream = (PaAlsaStream *) data;
-
- assert( data );
-
- PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-
- stream->callback_finished = 1; /* Let the outside world know stream was stopped in callback */
- AlsaStop( stream, stream->callbackAbort );
- stream->callbackAbort = 0; /* Clear state */
-
- PA_DEBUG(( "OnExit: Stoppage\n" ));
-
- /* Eventually notify user all buffers have played */
- if( stream->streamRepresentation.streamFinishedCallback )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- stream->isActive = 0;
-}
-
-static void CalculateTimeInfo( PaAlsaStream *stream, PaStreamCallbackTimeInfo *timeInfo )
-{
- snd_pcm_status_t *capture_status, *playback_status;
- snd_timestamp_t capture_timestamp, playback_timestamp;
- PaTime capture_time = 0., playback_time = 0.;
-
- snd_pcm_status_alloca( &capture_status );
- snd_pcm_status_alloca( &playback_status );
-
- if( stream->capture.pcm )
- {
- snd_pcm_sframes_t capture_delay;
-
- snd_pcm_status( stream->capture.pcm, capture_status );
- snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
-
- capture_time = capture_timestamp.tv_sec +
- ((PaTime)capture_timestamp.tv_usec / 1000000.0);
- timeInfo->currentTime = capture_time;
-
- capture_delay = snd_pcm_status_get_delay( capture_status );
- timeInfo->inputBufferAdcTime = timeInfo->currentTime -
- (PaTime)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
- }
- if( stream->playback.pcm )
- {
- snd_pcm_sframes_t playback_delay;
-
- snd_pcm_status( stream->playback.pcm, playback_status );
- snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
-
- playback_time = playback_timestamp.tv_sec +
- ((PaTime)playback_timestamp.tv_usec / 1000000.0);
-
- if( stream->capture.pcm ) /* Full duplex */
- {
- /* Hmm, we have both a playback and a capture timestamp.
- * Hopefully they are the same... */
- if( fabs( capture_time - playback_time ) > 0.01 )
- PA_DEBUG(("Capture time and playback time differ by %f\n", fabs(capture_time-playback_time)));
- }
- else
- timeInfo->currentTime = playback_time;
-
- playback_delay = snd_pcm_status_get_delay( playback_status );
- timeInfo->outputBufferDacTime = timeInfo->currentTime +
- (PaTime)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
- }
-}
-
-/** Called after buffer processing is finished.
- *
- * A number of mmapped frames is committed, it is possible that an xrun has occurred in the meantime.
- *
- * @param numFrames The number of frames that has been processed
- * @param xrun Return whether an xrun has occurred
- */
-static PaError PaAlsaStreamComponent_EndProcessing( PaAlsaStreamComponent *self, unsigned long numFrames, int *xrun )
-{
- PaError result = paNoError;
- int res;
-
- /* @concern FullDuplex It is possible that only one direction is marked ready after polling, and processed
- * afterwards
- */
- if( !self->ready )
- goto end;
-
- res = snd_pcm_mmap_commit( self->pcm, self->offset, numFrames );
- if( res == -EPIPE || res == -ESTRPIPE )
- {
- *xrun = 1;
- }
- else
- {
- ENSURE_( res, paUnanticipatedHostError );
- }
-
-end:
-error:
- return result;
-}
-
-/* Extract buffer from channel area */
-static unsigned char *ExtractAddress( const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset )
-{
- return (unsigned char *) area->addr + (area->first + offset * area->step) / 8;
-}
-
-/** Do necessary adaption between user and host channels.
- *
- @concern ChannelAdaption Adapting between user and host channels can involve silencing unused channels and
- duplicating mono information if host outputs come in pairs.
- */
-static PaError PaAlsaStreamComponent_DoChannelAdaption( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp, int numFrames )
-{
- PaError result = paNoError;
- unsigned char *p;
- int i;
- int unusedChans = self->numHostChannels - self->numUserChannels;
- unsigned char *src, *dst;
- int convertMono = (self->numHostChannels % 2) == 0 && (self->numUserChannels % 2) != 0;
-
- assert( StreamDirection_Out == self->streamDir );
-
- if( self->hostInterleaved )
- {
- int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
- unsigned char *buffer = ExtractAddress( self->channelAreas, self->offset );
-
- /* Start after the last user channel */
- p = buffer + self->numUserChannels * swidth;
-
- if( convertMono )
- {
- /* Convert the last user channel into stereo pair */
- src = buffer + (self->numUserChannels - 1) * swidth;
- for( i = 0; i < numFrames; ++i )
- {
- dst = src + swidth;
- memcpy( dst, src, swidth );
- src += self->numHostChannels * swidth;
- }
-
- /* Don't touch the channel we just wrote to */
- p += swidth;
- --unusedChans;
- }
-
- if( unusedChans > 0 )
- {
- /* Silence unused output channels */
- for( i = 0; i < numFrames; ++i )
- {
- memset( p, 0, swidth * unusedChans );
- p += self->numHostChannels * swidth;
- }
- }
- }
- else
- {
- /* We extract the last user channel */
- if( convertMono )
- {
- ENSURE_( snd_pcm_area_copy( self->channelAreas + self->numUserChannels, self->offset, self->channelAreas +
- (self->numUserChannels - 1), self->offset, numFrames, self->nativeFormat ), paUnanticipatedHostError );
- --unusedChans;
- }
- if( unusedChans > 0 )
- {
- snd_pcm_areas_silence( self->channelAreas + (self->numHostChannels - unusedChans), self->offset, unusedChans, numFrames,
- self->nativeFormat );
- }
- }
-
-error:
- return result;
-}
-
-static PaError PaAlsaStream_EndProcessing( PaAlsaStream *self, unsigned long numFrames, int *xrunOccurred )
-{
- PaError result = paNoError;
- int xrun = 0;
-
- if( self->capture.pcm )
- {
- PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->capture, numFrames, &xrun ) );
- }
- if( self->playback.pcm )
- {
- if( self->playback.numHostChannels > self->playback.numUserChannels )
- PA_ENSURE( PaAlsaStreamComponent_DoChannelAdaption( &self->playback, &self->bufferProcessor, numFrames ) );
- PA_ENSURE( PaAlsaStreamComponent_EndProcessing( &self->playback, numFrames, &xrun ) );
- }
-
-error:
- *xrunOccurred = xrun;
- return result;
-}
-
-/** Update the number of available frames.
- *
- */
-static PaError PaAlsaStreamComponent_GetAvailableFrames( PaAlsaStreamComponent *self, unsigned long *numFrames, int *xrunOccurred )
-{
- PaError result = paNoError;
- snd_pcm_sframes_t framesAvail = snd_pcm_avail_update( self->pcm );
- *xrunOccurred = 0;
-
- if( -EPIPE == framesAvail )
- {
- *xrunOccurred = 1;
- framesAvail = 0;
- }
- else
- ENSURE_( framesAvail, paUnanticipatedHostError );
-
- *numFrames = framesAvail;
-
-error:
- return result;
-}
-
-/** Fill in pollfd objects.
- */
-static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent *self, struct pollfd *pfds )
-{
- PaError result = paNoError;
- int ret = snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds );
- assert( ret == self->nfds );
-
- self->ready = 0;
-
- return result;
-}
-
-/** Examine results from poll().
- *
- * @param pfds pollfds to inspect
- * @param shouldPoll Should we continue to poll
- * @param xrun Has an xrun occurred
- */
-static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent *self, struct pollfd *pfds, int *shouldPoll, int *xrun )
-{
- PaError result = paNoError;
- unsigned short revents;
-
- ENSURE_( snd_pcm_poll_descriptors_revents( self->pcm, pfds, self->nfds, &revents ), paUnanticipatedHostError );
- if( revents != 0 )
- {
- if( revents & POLLERR )
- {
- *xrun = 1;
- }
- else
- self->ready = 1;
-
- *shouldPoll = 0;
- }
-
-error:
- return result;
-}
-
-/** Return the number of available frames for this stream.
- *
- * @concern FullDuplex The minimum available for the two directions is calculated, it might be desirable to ignore
- * one direction however (not marked ready from poll), so this is controlled by queryCapture and queryPlayback.
- *
- * @param queryCapture Check available for capture
- * @param queryPlayback Check available for playback
- * @param available The returned number of frames
- * @param xrunOccurred Return whether an xrun has occurred
- */
-static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCapture, int queryPlayback, unsigned long
- *available, int *xrunOccurred )
-{
- PaError result = paNoError;
- unsigned long captureFrames, playbackFrames;
- *xrunOccurred = 0;
-
- assert( queryCapture || queryPlayback );
-
- if( queryCapture )
- {
- assert( self->capture.pcm );
- PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->capture, &captureFrames, xrunOccurred ) );
- if( *xrunOccurred )
- goto end;
- }
- if( queryPlayback )
- {
- assert( self->playback.pcm );
- PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &self->playback, &playbackFrames, xrunOccurred ) );
- if( *xrunOccurred )
- goto end;
- }
-
- if( queryCapture && queryPlayback )
- {
- *available = PA_MIN( captureFrames, playbackFrames );
- }
- else if( queryCapture )
- {
- *available = captureFrames;
- }
- else
- {
- *available = playbackFrames;
- }
-
-end:
-error:
- return result;
-}
-
-/** Wait for and report available buffer space from ALSA.
- *
- * Unless ALSA reports a minimum of frames available for I/O, we poll the ALSA filedescriptors for more.
- * Both of these operations can uncover xrun conditions.
- *
- * @concern Xruns Both polling and querying available frames can report an xrun condition.
- *
- * @param framesAvail Return the number of available frames
- * @param xrunOccurred Return whether an xrun has occurred
- */
-static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *framesAvail, int *xrunOccurred )
-{
- PaError result = paNoError;
- int pollPlayback = self->playback.pcm != NULL, pollCapture = self->capture.pcm != NULL;
- int pollTimeout = self->pollTimeout;
- int xrun = 0;
-
- assert( self );
- assert( framesAvail );
-
- if( !self->callbackMode )
- {
- /* In blocking mode we will only wait if necessary */
- PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, self->capture.pcm != NULL, self->playback.pcm != NULL,
- framesAvail, &xrun ) );
- if( xrun )
- {
- goto end;
- }
-
- if( *framesAvail > 0 )
- {
- /* Mark pcms ready from poll */
- if( self->capture.pcm )
- self->capture.ready = 1;
- if( self->playback.pcm )
- self->playback.ready = 1;
-
- goto end;
- }
- }
-
- while( pollPlayback || pollCapture )
- {
- int totalFds = 0;
- struct pollfd *capturePfds = NULL, *playbackPfds = NULL;
-
- pthread_testcancel();
-
- if( pollCapture )
- {
- capturePfds = self->pfds;
- PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->capture, capturePfds ) );
- totalFds += self->capture.nfds;
- }
- if( pollPlayback )
- {
- playbackPfds = self->pfds + (self->capture.pcm ? self->capture.nfds : 0);
- PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
- totalFds += self->playback.nfds;
- }
-
- if( poll( self->pfds, totalFds, pollTimeout ) < 0 )
- {
- /* XXX: Depend on preprocessor condition? */
- if( errno == EINTR ) { /* gdb */
- continue;
- }
-
- /* TODO: Add macro for checking system calls */
- PA_ENSURE( paInternalError );
- }
-
- /* check the return status of our pfds */
- if( pollCapture )
- {
- PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->capture, capturePfds, &pollCapture, &xrun ) );
- }
- if( pollPlayback )
- {
- PA_ENSURE( PaAlsaStreamComponent_EndPolling( &self->playback, playbackPfds, &pollPlayback, &xrun ) );
- }
- if( xrun )
- {
- break;
- }
-
- /* @concern FullDuplex If only one of two pcms is ready we may want to compromise between the two.
- * If there is less than half a period's worth of samples left of frames in the other pcm's buffer we will
- * stop polling.
- */
- if( self->capture.pcm && self->playback.pcm )
- {
- if( pollCapture && !pollPlayback )
- {
- PA_ENSURE( ContinuePoll( self, StreamDirection_In, &pollTimeout, &pollCapture ) );
- }
- else if( pollPlayback && !pollCapture )
- {
- PA_ENSURE( ContinuePoll( self, StreamDirection_Out, &pollTimeout, &pollPlayback ) );
- }
- }
- }
-
- if( !xrun )
- {
- /* Get the number of available frames for the pcms that are marked ready.
- * @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for
- * the other direction is returned. This under the assumption that input is dropped earlier if paNeverDropInput
- * is not specified.
- */
- int captureReady = self->capture.pcm ? self->capture.ready : 0,
- playbackReady = self->playback.pcm ? self->playback.ready : 0;
- PA_ENSURE( PaAlsaStream_GetAvailableFrames( self, captureReady, playbackReady, framesAvail, &xrun ) );
-
- if( self->capture.pcm && self->playback.pcm )
- {
- if( !self->playback.ready && !self->neverDropInput )
- {
- /* TODO: Drop input */
- }
- }
- }
-
-end:
-error:
- if( xrun )
- {
- /* Recover from the xrun state */
- PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
- *framesAvail = 0;
- }
- *xrunOccurred = xrun;
-
- return result;
-}
-
-/** Register per-channel ALSA buffer information with buffer processor.
- *
- * Mmapped buffer space is acquired from ALSA, and registered with the buffer processor. Differences between the
- * number of host and user channels is taken into account.
- *
- * @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames.
- */
-static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp,
- unsigned long *numFrames, int *xrun )
-{
- PaError result = paNoError;
- const snd_pcm_channel_area_t *areas, *area;
- void (*setChannel)(PaUtilBufferProcessor *, unsigned int, void *, unsigned int) =
- StreamDirection_In == self->streamDir ? PaUtil_SetInputChannel : PaUtil_SetOutputChannel;
- unsigned char *buffer, *p;
- int i;
- unsigned long framesAvail;
-
- /* This _must_ be called before mmap_begin */
- PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( self, &framesAvail, xrun ) );
- if( *xrun )
- {
- *numFrames = 0;
- goto end;
- }
-
- ENSURE_( snd_pcm_mmap_begin( self->pcm, &areas, &self->offset, numFrames ), paUnanticipatedHostError );
-
- if( self->hostInterleaved )
- {
- int swidth = snd_pcm_format_size( self->nativeFormat, 1 );
-
- p = buffer = ExtractAddress( areas, self->offset );
- for( i = 0; i < self->numUserChannels; ++i )
- {
- /* We're setting the channels up to userChannels, but the stride will be hostChannels samples */
- setChannel( bp, i, p, self->numHostChannels );
- p += swidth;
- }
- }
- else
- {
- for( i = 0; i < self->numUserChannels; ++i )
- {
- area = areas + i;
- buffer = ExtractAddress( area, self->offset );
- setChannel( bp, i, buffer, 1 );
- }
- }
-
- /* @concern ChannelAdaption Buffer address is recorded so we can do some channel adaption later */
- self->channelAreas = (snd_pcm_channel_area_t *)areas;
-
-end:
-error:
- return result;
-}
-
-/** Initiate buffer processing.
- *
- * ALSA buffers are registered with the PA buffer processor and the buffer size (in frames) set.
- *
- * @concern FullDuplex If both directions are being processed, the minimum amount of frames for the two directions is
- * calculated.
- *
- * @param numFrames On entrance the number of available frames, on exit the number of received frames
- * @param xrunOccurred Return whether an xrun has occurred
- */
-static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream *self, unsigned long *numFrames, int *xrunOccurred )
-{
- PaError result = paNoError;
- unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0;
- int xrun = 0;
-
- /* Extract per-channel ALSA buffer pointers and register them with the buffer processor.
- * It is possible that a direction is not marked ready however, because it is out of sync with the other.
- */
- if( self->capture.pcm && self->capture.ready )
- {
- captureFrames = *numFrames;
- PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->capture, &self->bufferProcessor, &captureFrames,
- &xrun ) );
- }
- if( self->playback.pcm && self->playback.ready )
- {
- playbackFrames = *numFrames;
- PA_ENSURE( PaAlsaStreamComponent_RegisterChannels( &self->playback, &self->bufferProcessor, &playbackFrames,
- &xrun ) );
- }
- if( xrun )
- {
- /* Nothing more to do */
- assert( 0 == commonFrames );
- goto end;
- }
-
- commonFrames = PA_MIN( captureFrames, playbackFrames );
- assert( commonFrames <= *numFrames );
-
- /* Inform PortAudio of the number of frames we got.
- * @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on
- * with output. If its output underflow however, depending on the paNeverDropInput flag, we may want to simply
- * discard the excess input or call the callback with paOutputOverflow flagged.
- */
- if( self->capture.pcm )
- {
- if( self->capture.ready )
- {
- PaUtil_SetInputFrameCount( &self->bufferProcessor, commonFrames );
- }
- else
- {
- /* We have input underflow */
- PaUtil_SetNoInput( &self->bufferProcessor );
- }
- }
- if( self->playback.pcm )
- {
- if( self->playback.ready )
- {
- PaUtil_SetOutputFrameCount( &self->bufferProcessor, commonFrames );
- }
- else
- {
- /* We have output underflow, but keeping input data (paNeverDropInput) */
- /* assert( self->neverDropInput ); */
- PaUtil_SetNoOutput( &self->bufferProcessor );
- }
- }
-
-end:
- *numFrames = commonFrames;
-error:
- if( xrun )
- {
- PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
- *numFrames = 0;
- }
- *xrunOccurred = xrun;
-
- return result;
-}
-
-/** Callback thread's function.
- *
- * Roughly, the workflow can be described in the following way: The number of available frames that can be processed
- * directly is obtained from ALSA, we then request as much directly accessible memory as possible within this amount
- * from ALSA. The buffer memory is registered with the PA buffer processor and processing is carried out with
- * PaUtil_EndBufferProcessing. Finally, the number of processed frames is reported to ALSA. The processing can
- * happen in several iterations untill we have consumed the known number of available frames (or an xrun is detected).
- */
-static void *CallbackThreadFunc( void *userData )
-{
- PaError result = paNoError, *pres = NULL;
- PaAlsaStream *stream = (PaAlsaStream*) userData;
- PaStreamCallbackTimeInfo timeInfo = {0, 0, 0};
- snd_pcm_sframes_t startThreshold = 0;
- int callbackResult = paContinue;
- PaStreamCallbackFlags cbFlags = 0; /* We might want to keep state across iterations */
- int streamStarted = 0;
-
- assert( stream );
-
- callbackThread_ = pthread_self();
- /* Execute OnExit when exiting */
- pthread_cleanup_push( &OnExit, stream );
-
- /* Not implemented */
- assert( !stream->primeBuffers );
-
- /* @concern StreamStart If the output is being primed the output pcm needs to be prepared, otherwise the
- * stream is started immediately. The latter involves signaling the waiting main thread.
- */
- if( stream->primeBuffers )
- {
- snd_pcm_sframes_t avail;
-
- if( stream->playback.pcm )
- ENSURE_( snd_pcm_prepare( stream->playback.pcm ), paUnanticipatedHostError );
- if( stream->capture.pcm && !stream->pcmsSynced )
- ENSURE_( snd_pcm_prepare( stream->capture.pcm ), paUnanticipatedHostError );
-
- /* We can't be certain that the whole ring buffer is available for priming, but there should be
- * at least one period */
- avail = snd_pcm_avail_update( stream->playback.pcm );
- startThreshold = avail - (avail % stream->playback.framesPerBuffer);
- assert( startThreshold >= stream->playback.framesPerBuffer );
- }
- else
- {
- ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );
- PA_ENSURE( AlsaStart( stream, 0 ) ); /* Buffer will be zeroed */
- ASSERT_CALL_( pthread_cond_signal( &stream->startCond ), 0 );
- ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );
-
- streamStarted = 1;
- }
-
- while( 1 )
- {
- unsigned long framesAvail, framesGot;
- int xrun = 0;
-
- pthread_testcancel();
-
- /* @concern StreamStop if the main thread has requested a stop and the stream has not been effectively
- * stopped we signal this condition by modifying callbackResult (we'll want to flush buffered output).
- */
- if( stream->callbackStop && paContinue == callbackResult )
- {
- PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
- callbackResult = paComplete;
- }
-
- if( paContinue != callbackResult )
- {
- stream->callbackAbort = (paAbort == callbackResult);
- if( stream->callbackAbort ||
- /** @concern BlockAdaption Go on if adaption buffers are empty */
- PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
- goto end;
-
- PA_DEBUG(( "%s: Flushing buffer processor\n", __FUNCTION__ ));
- /* There is still buffered output that needs to be processed */
- }
-
- /* Wait for data to become available, this comes down to polling the ALSA file descriptors untill we have
- * a number of available frames.
- */
- PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
- if( xrun )
- {
- assert( 0 == framesAvail );
- continue;
-
- /* XXX: Report xruns to the user? A situation is conceivable where the callback is never invoked due
- * to constant xruns, it might be desirable to notify the user of this.
- */
- }
-
- /* Consume buffer space. Once we have a number of frames available for consumption we must retrieve the
- * mmapped buffers from ALSA, this is contiguously accessible memory however, so we may receive smaller
- * portions at a time than is available as a whole. Therefore we should be prepared to process several
- * chunks successively. The buffers are passed to the PA buffer processor.
- */
- while( framesAvail > 0 )
- {
- xrun = 0;
-
- pthread_testcancel();
-
- /** @concern Xruns Under/overflows are to be reported to the callback */
- if( stream->underrun > 0.0 )
- {
- cbFlags |= paOutputUnderflow;
- stream->underrun = 0.0;
- }
- if( stream->overrun > 0.0 )
- {
- cbFlags |= paInputOverflow;
- stream->overrun = 0.0;
- }
- if( stream->capture.pcm && stream->playback.pcm )
- {
- /** @concern FullDuplex It's possible that only one direction is being processed to avoid an
- * under- or overflow, this should be reported correspondingly */
- if( !stream->capture.ready )
- {
- cbFlags |= paInputUnderflow;
- PA_DEBUG(( "%s: Input underflow\n", __FUNCTION__ ));
- }
- else if( !stream->playback.ready )
- {
- cbFlags |= paOutputOverflow;
- PA_DEBUG(( "%s: Output overflow\n", __FUNCTION__ ));
- }
- }
-
- CallbackUpdate( &stream->threading );
- CalculateTimeInfo( stream, &timeInfo );
- PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags );
- cbFlags = 0;
-
- /* CPU load measurement should include processing activivity external to the stream callback */
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
- framesGot = framesAvail;
- PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
- framesAvail -= framesGot;
-
- if( framesGot > 0 )
- {
- assert( !xrun );
-
- PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
- PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
- }
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot );
-
- if( framesGot == 0 )
- {
- if( !xrun )
- PA_DEBUG(( "%s: Received less frames than reported from ALSA!\n", __FUNCTION__ ));
-
- /* Go back to polling for more frames */
- break;
-
- }
-
- if( paContinue != callbackResult )
- break;
- }
- }
-
- /* Match pthread_cleanup_push */
- pthread_cleanup_pop( 1 );
-
-end:
- pthread_exit( pres );
-
-error:
- /* Pass on error code */
- pres = malloc( sizeof (PaError) );
- *pres = result;
-
- goto end;
-}
-
-/* Blocking interface */
-
-static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )
-{
- PaError result = paNoError;
- PaAlsaStream *stream = (PaAlsaStream*)s;
- unsigned long framesGot, framesAvail;
- void *userBuffer;
- snd_pcm_t *save = stream->playback.pcm;
-
- assert( stream );
-
- PA_UNLESS( stream->capture.pcm, paCanNotReadFromAnOutputOnlyStream );
-
- /* Disregard playback */
- stream->playback.pcm = NULL;
-
- if( stream->overrun > 0. )
- {
- result = paInputOverflowed;
- stream->overrun = 0.0;
- }
-
- if( stream->capture.userInterleaved )
- userBuffer = buffer;
- else
- {
- /* Copy channels into local array */
- userBuffer = stream->capture.userBuffers;
- memcpy( userBuffer, buffer, sizeof (void *) * stream->capture.numUserChannels );
- }
-
- /* Start stream if in prepared state */
- if( snd_pcm_state( stream->capture.pcm ) == SND_PCM_STATE_PREPARED )
- {
- ENSURE_( snd_pcm_start( stream->capture.pcm ), paUnanticipatedHostError );
- }
-
- while( frames > 0 )
- {
- int xrun = 0;
- PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
- framesGot = PA_MIN( framesAvail, frames );
-
- PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
- if( framesGot > 0 )
- {
- framesGot = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesGot );
- PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
- frames -= framesGot;
- }
- }
-
-end:
- stream->playback.pcm = save;
- return result;
-error:
- goto end;
-}
-
-static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frames )
-{
- PaError result = paNoError;
- signed long err;
- PaAlsaStream *stream = (PaAlsaStream*)s;
- snd_pcm_uframes_t framesGot, framesAvail;
- const void *userBuffer;
- snd_pcm_t *save = stream->capture.pcm;
-
- assert( stream );
-
- PA_UNLESS( stream->playback.pcm, paCanNotWriteToAnInputOnlyStream );
-
- /* Disregard capture */
- stream->capture.pcm = NULL;
-
- if( stream->underrun > 0. )
- {
- result = paOutputUnderflowed;
- stream->underrun = 0.0;
- }
-
- if( stream->playback.userInterleaved )
- userBuffer = buffer;
- else /* Copy channels into local array */
- {
- userBuffer = stream->playback.userBuffers;
- memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback.numUserChannels );
- }
-
- while( frames > 0 )
- {
- int xrun = 0;
- snd_pcm_uframes_t hwAvail;
-
- PA_ENSURE( PaAlsaStream_WaitForFrames( stream, &framesAvail, &xrun ) );
- framesGot = PA_MIN( framesAvail, frames );
-
- PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
- if( framesGot > 0 )
- {
- framesGot = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, framesGot );
- PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
- frames -= framesGot;
- }
-
- /* Frames residing in buffer */
- PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
- framesAvail = err;
- hwAvail = stream->playback.bufferSize - framesAvail;
-
- /* Start stream after one period of samples worth */
- if( snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
- hwAvail >= stream->playback.framesPerBuffer )
- {
- ENSURE_( snd_pcm_start( stream->playback.pcm ), paUnanticipatedHostError );
- }
- }
-
-end:
- stream->capture.pcm = save;
- return result;
-error:
- goto end;
-}
-
-/* Return frames available for reading. In the event of an overflow, the capture pcm will be restarted */
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaError result = paNoError;
- PaAlsaStream *stream = (PaAlsaStream*)s;
- unsigned long avail;
- int xrun;
-
- PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
- if( xrun )
- {
- PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
- PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->capture, &avail, &xrun ) );
- if( xrun )
- PA_ENSURE( paInputOverflowed );
- }
-
- return (signed long)avail;
-
-error:
- return result;
-}
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaError result = paNoError;
- PaAlsaStream *stream = (PaAlsaStream*)s;
- unsigned long avail;
- int xrun;
-
- PA_ENSURE( PaAlsaStreamComponent_GetAvailableFrames( &stream->playback, &avail, &xrun ) );
- if( xrun )
- {
- snd_pcm_sframes_t savail;
-
- PA_ENSURE( PaAlsaStream_HandleXrun( stream ) );
- savail = snd_pcm_avail_update( stream->playback.pcm );
-
- /* savail should not contain -EPIPE now, since PaAlsaStream_HandleXrun will only prepare the pcm */
- ENSURE_( savail, paUnanticipatedHostError );
-
- avail = (unsigned long) savail;
- }
-
- return (signed long)avail;
-
-error:
- return result;
-}
-
-/* Extensions */
-
-/* Initialize host api specific structure */
-void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info )
-{
- info->size = sizeof (PaAlsaStreamInfo);
- info->hostApiType = paALSA;
- info->version = 1;
- info->deviceString = NULL;
-}
-
-void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable )
-{
- PaAlsaStream *stream = (PaAlsaStream *) s;
- stream->threading.rtSched = enable;
-}
-
-void PaAlsa_EnableWatchdog( PaStream *s, int enable )
-{
- PaAlsaStream *stream = (PaAlsaStream *) s;
- stream->threading.useWatchdog = enable;
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h b/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h
deleted file mode 100644
index e6f44b16..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_linux_alsa.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef PA_LINUX_ALSA_H
-#define PA_LINUX_ALSA_H
-
-/*
- * $Id: pa_linux_alsa.h,v 1.1.2.12 2004/09/25 14:15:25 aknudsen Exp $
- * PortAudio Portable Real-Time Audio Library
- * ALSA-specific extensions
- *
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */
-
-/** @file
- * ALSA-specific PortAudio API extension header file.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct PaAlsaStreamInfo
-{
- unsigned long size;
- PaHostApiTypeId hostApiType;
- unsigned long version;
-
- const char *deviceString;
-}
-PaAlsaStreamInfo;
-
-void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info );
-
-void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable );
-
-void PaAlsa_EnableWatchdog( PaStream *s, int enable );
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core.c b/pjmedia/src/pjmedia/portaudio/pa_mac_core.c
deleted file mode 100644
index 304a32de..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core.c
+++ /dev/null
@@ -1,2042 +0,0 @@
-/*
- * Implementation of the PortAudio API for Apple AUHAL
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
- * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
- *
- * Dominic's code was based on code by Phil Burk, Darren Gibbs,
- * Gord Peters, Stephane Letz, and Greg Pfiel.
- *
- * The following people also deserve acknowledgements:
- *
- * Olivier Tristan for feedback and testing
- * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
- * interface.
- *
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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 pa_mac_core
- @ingroup hostapi_src
- @author Bjorn Roche
- @brief AUHAL implementation of PortAudio
-*/
-
-/* FIXME: not all error conditions call PaUtil_SetLastHostErrorInfo()
- * PaMacCore_SetError() will do this.
- */
-
-#include "pa_mac_core_internal.h"
-
-#include <string.h> /* strlen(), memcmp() etc. */
-
-#include "pa_mac_core.h"
-#include "pa_mac_core_utilities.h"
-#include "pa_mac_core_blocking.h"
-
-
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#define RING_BUFFER_ADVANCE_DENOMINATOR (4)
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static void setStreamStartTime( PaStream *stream );
-static OSStatus AudioIOProc( void *inRefCon,
- AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp,
- UInt32 inBusNumber,
- UInt32 inNumberFrames,
- AudioBufferList *ioData );
-static double GetStreamCpuLoad( PaStream* stream );
-
-static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
- PaDeviceInfo *deviceInfo,
- AudioDeviceID macCoreDeviceId,
- int isInput);
-
-static PaError OpenAndSetupOneAudioUnit(
- const PaStreamParameters *inStreamParams,
- const PaStreamParameters *outStreamParams,
- const unsigned long requestedFramesPerBuffer,
- unsigned long *actualInputFramesPerBuffer,
- unsigned long *actualOutputFramesPerBuffer,
- const PaMacAUHAL *auhalHostApi,
- AudioUnit *audioUnit,
- AudioConverterRef *srConverter,
- AudioDeviceID *audioDevice,
- const double sampleRate,
- void *refCon );
-
-/* for setting errors. */
-#define PA_AUHAL_SET_LAST_HOST_ERROR( errorCode, errorText ) \
- PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
-
-
-/*currently, this is only used in initialization, but it might be modified
- to be used when the list of devices changes.*/
-static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
-{
- UInt32 size;
- UInt32 propsize;
- VVDBUG(("gatherDeviceInfo()\n"));
- /* -- free any previous allocations -- */
- if( auhalHostApi->devIds )
- PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds);
- auhalHostApi->devIds = NULL;
-
- /* -- figure out how many devices there are -- */
- AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
- &propsize,
- NULL );
- auhalHostApi->devCount = propsize / sizeof( AudioDeviceID );
-
- VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) );
-
- /* -- copy the device IDs -- */
- auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory(
- auhalHostApi->allocations,
- propsize );
- if( !auhalHostApi->devIds )
- return paInsufficientMemory;
- AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
- &propsize,
- auhalHostApi->devIds );
-#ifdef MAC_CORE_VERBOSE_DEBUG
- {
- int i;
- for( i=0; i<auhalHostApi->devCount; ++i )
- printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] );
- }
-#endif
-
- size = sizeof(AudioDeviceID);
- auhalHostApi->defaultIn = kAudioDeviceUnknown;
- auhalHostApi->defaultOut = kAudioDeviceUnknown;
-
- /* determine the default device. */
- /* I am not sure how these calls to AudioHardwareGetProperty()
- could fail, but in case they do, we use the first available
- device as the default. */
- if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
- &size,
- &auhalHostApi->defaultIn) ) {
- int i;
- auhalHostApi->defaultIn = kAudioDeviceUnknown;
- VDBUG(("Failed to get default input device from OS."));
- VDBUG((" I will substitute the first available input Device."));
- for( i=0; i<auhalHostApi->devCount; ++i ) {
- PaDeviceInfo devInfo;
- if( 0 != GetChannelInfo( auhalHostApi, &devInfo,
- auhalHostApi->devIds[i], TRUE ) )
- if( devInfo.maxInputChannels ) {
- auhalHostApi->defaultIn = auhalHostApi->devIds[i];
- break;
- }
- }
- }
- if( 0 != AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
- &size,
- &auhalHostApi->defaultOut) ) {
- int i;
- auhalHostApi->defaultIn = kAudioDeviceUnknown;
- VDBUG(("Failed to get default output device from OS."));
- VDBUG((" I will substitute the first available output Device."));
- for( i=0; i<auhalHostApi->devCount; ++i ) {
- PaDeviceInfo devInfo;
- if( 0 != GetChannelInfo( auhalHostApi, &devInfo,
- auhalHostApi->devIds[i], FALSE ) )
- if( devInfo.maxOutputChannels ) {
- auhalHostApi->defaultOut = auhalHostApi->devIds[i];
- break;
- }
- }
- }
-
- VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) );
- VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) );
-
- return paNoError;
-}
-
-static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
- PaDeviceInfo *deviceInfo,
- AudioDeviceID macCoreDeviceId,
- int isInput)
-{
- UInt32 propSize;
- PaError err = paNoError;
- UInt32 i;
- int numChannels = 0;
- AudioBufferList *buflist = NULL;
- UInt32 frameLatency;
-
- VVDBUG(("GetChannelInfo()\n"));
-
- /* Get the number of channels from the stream configuration.
- Fail if we can't get this. */
-
- err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL));
- if (err)
- return err;
-
- buflist = PaUtil_AllocateMemory(propSize);
- if( !buflist )
- return paInsufficientMemory;
- err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist));
- if (err)
- goto error;
-
- for (i = 0; i < buflist->mNumberBuffers; ++i)
- numChannels += buflist->mBuffers[i].mNumberChannels;
-
- if (isInput)
- deviceInfo->maxInputChannels = numChannels;
- else
- deviceInfo->maxOutputChannels = numChannels;
-
- if (numChannels > 0) /* do not try to retrieve the latency if there is no channels. */
- {
- /* Get the latency. Don't fail if we can't get this. */
- /* default to something reasonable */
- deviceInfo->defaultLowInputLatency = .01;
- deviceInfo->defaultHighInputLatency = .10;
- deviceInfo->defaultLowOutputLatency = .01;
- deviceInfo->defaultHighOutputLatency = .10;
- propSize = sizeof(UInt32);
- err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
- if (!err)
- {
- /** FEEDBACK:
- * This code was arrived at by trial and error, and some extentive, but not exhaustive
- * testing. Sebastien Beaulieu <seb@plogue.com> has suggested using
- * kAudioDevicePropertyLatency + kAudioDevicePropertySafetyOffset + buffer size instead.
- * At the time this code was written, many users were reporting dropouts with audio
- * programs that probably used this formula. This was probably
- * around 10.4.4, and the problem is probably fixed now. So perhaps
- * his formula should be reviewed and used.
- * */
- double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
- if (isInput)
- {
- deviceInfo->defaultLowInputLatency = 3 * secondLatency;
- deviceInfo->defaultHighInputLatency = 3 * 10 * secondLatency;
- }
- else
- {
- deviceInfo->defaultLowOutputLatency = 3 * secondLatency;
- deviceInfo->defaultHighOutputLatency = 3 * 10 * secondLatency;
- }
- }
- }
- PaUtil_FreeMemory( buflist );
- return paNoError;
- error:
- PaUtil_FreeMemory( buflist );
- return err;
-}
-
-static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
- PaDeviceInfo *deviceInfo,
- AudioDeviceID macCoreDeviceId,
- PaHostApiIndex hostApiIndex )
-{
- Float64 sampleRate;
- char *name;
- PaError err = paNoError;
- UInt32 propSize;
-
- VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId));
-
- memset(deviceInfo, 0, sizeof(deviceInfo));
-
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
-
- /* Get the device name. Fail if we can't get it. */
- err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL));
- if (err)
- return err;
-
- name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,propSize);
- if ( !name )
- return paInsufficientMemory;
- err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name));
- if (err)
- return err;
- deviceInfo->name = name;
-
- /* Try to get the default sample rate. Don't fail if we can't get this. */
- propSize = sizeof(Float64);
- err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
- if (err)
- deviceInfo->defaultSampleRate = 0.0;
- else
- deviceInfo->defaultSampleRate = sampleRate;
-
- /* Get the maximum number of input and output channels. Fail if we can't get this. */
-
- err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 1);
- if (err)
- return err;
-
- err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 0);
- if (err)
- return err;
-
- return paNoError;
-}
-
-PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- int i;
- PaMacAUHAL *auhalHostApi;
- PaDeviceInfo *deviceInfoArray;
-
- VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex));
-
- auhalHostApi = (PaMacAUHAL*)PaUtil_AllocateMemory( sizeof(PaMacAUHAL) );
- if( !auhalHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- auhalHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !auhalHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- auhalHostApi->devIds = NULL;
- auhalHostApi->devCount = 0;
-
- /* get the info we need about the devices */
- result = gatherDeviceInfo( auhalHostApi );
- if( result != paNoError )
- goto error;
-
- *hostApi = &auhalHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paCoreAudio;
- (*hostApi)->info.name = "Core Audio";
-
- (*hostApi)->info.defaultInputDevice = paNoDevice;
- (*hostApi)->info.defaultOutputDevice = paNoDevice;
-
- (*hostApi)->info.deviceCount = 0;
-
- if( auhalHostApi->devCount > 0 )
- {
- (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount);
- if( !(*hostApi)->deviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* allocate all device info structs in a contiguous block */
- deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
- auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount );
- if( !deviceInfoArray )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- for( i=0; i < auhalHostApi->devCount; ++i )
- {
- int err;
- err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i],
- auhalHostApi->devIds[i],
- hostApiIndex );
- if (err == paNoError)
- { /* copy some info and set the defaults */
- (*hostApi)->deviceInfos[(*hostApi)->info.deviceCount] = &deviceInfoArray[i];
- if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn)
- (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
- if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut)
- (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
- (*hostApi)->info.deviceCount++;
- }
- else
- { /* there was an error. we need to shift the devices down, so we ignore this one */
- int j;
- auhalHostApi->devCount--;
- for( j=i; j<auhalHostApi->devCount; ++j )
- auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1];
- i--;
- }
- }
- }
-
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
- CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped,
- IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable,
- PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &auhalHostApi->blockingStreamInterface,
- CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped,
- IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream,
- GetStreamReadAvailable,
- GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( auhalHostApi )
- {
- if( auhalHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( auhalHostApi->allocations );
- PaUtil_DestroyAllocationGroup( auhalHostApi->allocations );
- }
-
- PaUtil_FreeMemory( auhalHostApi );
- }
- return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
-
- VVDBUG(("Terminate()\n"));
-
- /*
- IMPLEMENT ME:
- - clean up any resources not handled by the allocation group
- TODO: Double check that everything is handled by alloc group
- */
-
- if( auhalHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( auhalHostApi->allocations );
- PaUtil_DestroyAllocationGroup( auhalHostApi->allocations );
- }
-
- PaUtil_FreeMemory( auhalHostApi );
-}
-
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
-
- VVDBUG(("IsFormatSupported(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld sampleRate=%g\n",
- inputParameters ? inputParameters->channelCount : -1,
- inputParameters ? inputParameters->sampleFormat : -1,
- outputParameters ? outputParameters->channelCount : -1,
- outputParameters ? outputParameters->sampleFormat : -1,
- (float) sampleRate ));
-
- /** These first checks are standard PA checks. We do some fancier checks
- later. */
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( inputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
- }
- else
- {
- inputChannelCount = 0;
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( outputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support outputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- }
- else
- {
- outputChannelCount = 0;
- }
-
- /* FEEDBACK */
- /* I think the only way to check a given format SR combo is */
- /* to try opening it. This could be disruptive, is that Okay? */
- /* The alternative is to just read off available sample rates, */
- /* but this will not work %100 of the time (eg, a device that */
- /* supports N output at one rate but only N/2 at a higher rate.)*/
-
- /* The following code opens the device with the requested parameters to
- see if it works. */
- {
- PaError err;
- PaStream *s;
- err = OpenStream( hostApi, &s, inputParameters, outputParameters,
- sampleRate, 1024, 0, (PaStreamCallback *)1, NULL );
- if( err != paNoError && err != paInvalidSampleRate )
- DBUG( ( "OpenStream @ %g returned: %d: %s\n",
- (float) sampleRate, err, Pa_GetErrorText( err ) ) );
- if( err )
- return err;
- err = CloseStream( s );
- if( err ) {
- /* FEEDBACK: is this more serious? should we assert? */
- DBUG( ( "WARNING: could not close Stream. %d: %s\n",
- err, Pa_GetErrorText( err ) ) );
- }
- }
-
- return paFormatIsSupported;
-}
-
-static PaError OpenAndSetupOneAudioUnit(
- const PaStreamParameters *inStreamParams,
- const PaStreamParameters *outStreamParams,
- const unsigned long requestedFramesPerBuffer,
- unsigned long *actualInputFramesPerBuffer,
- unsigned long *actualOutputFramesPerBuffer,
- const PaMacAUHAL *auhalHostApi,
- AudioUnit *audioUnit,
- AudioConverterRef *srConverter,
- AudioDeviceID *audioDevice,
- const double sampleRate,
- void *refCon )
-{
- ComponentDescription desc;
- Component comp;
- /*An Apple TN suggests using CAStreamBasicDescription, but that is C++*/
- AudioStreamBasicDescription desiredFormat;
- OSErr result = noErr;
- PaError paResult = paNoError;
- int line = 0;
- UInt32 callbackKey;
- AURenderCallbackStruct rcbs;
- unsigned long macInputStreamFlags = paMacCorePlayNice;
- unsigned long macOutputStreamFlags = paMacCorePlayNice;
-
- VVDBUG(("OpenAndSetupOneAudioUnit(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld, requestedFramesPerBuffer=%ld\n",
- inStreamParams ? inStreamParams->channelCount : -1,
- inStreamParams ? inStreamParams->sampleFormat : -1,
- outStreamParams ? outStreamParams->channelCount : -1,
- outStreamParams ? outStreamParams->sampleFormat : -1,
- requestedFramesPerBuffer ));
-
- /* -- handle the degenerate case -- */
- if( !inStreamParams && !outStreamParams ) {
- *audioUnit = NULL;
- *audioDevice = kAudioDeviceUnknown;
- return paNoError;
- }
-
- /* -- get the user's api specific info, if they set any -- */
- if( inStreamParams && inStreamParams->hostApiSpecificStreamInfo )
- macInputStreamFlags=
- ((paMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo)
- ->flags;
- if( outStreamParams && outStreamParams->hostApiSpecificStreamInfo )
- macOutputStreamFlags=
- ((paMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo)
- ->flags;
- /* Override user's flags here, if desired for testing. */
-
- /*
- * The HAL AU is a Mac OS style "component".
- * the first few steps deal with that.
- * Later steps work on a combination of Mac OS
- * components and the slightly lower level
- * HAL.
- */
-
- /* -- describe the output type AudioUnit -- */
- /* Note: for the default AudioUnit, we could use the
- * componentSubType value kAudioUnitSubType_DefaultOutput;
- * but I don't think that's relevant here.
- */
- desc.componentType = kAudioUnitType_Output;
- desc.componentSubType = kAudioUnitSubType_HALOutput;
- desc.componentManufacturer = kAudioUnitManufacturer_Apple;
- desc.componentFlags = 0;
- desc.componentFlagsMask = 0;
- /* -- find the component -- */
- comp = FindNextComponent( NULL, &desc );
- if( !comp )
- {
- DBUG( ( "AUHAL component not found." ) );
- *audioUnit = NULL;
- *audioDevice = kAudioDeviceUnknown;
- return paUnanticipatedHostError;
- }
- /* -- open it -- */
- result = OpenAComponent( comp, audioUnit );
- if( result )
- {
- DBUG( ( "Failed to open AUHAL component." ) );
- *audioUnit = NULL;
- *audioDevice = kAudioDeviceUnknown;
- return ERR( result );
- }
- /* -- prepare a little error handling logic / hackery -- */
-#define ERR_WRAP(mac_err) do { result = mac_err ; line = __LINE__ ; if ( result != noErr ) goto error ; } while(0)
-
- /* -- if there is input, we have to explicitly enable input -- */
- if( inStreamParams )
- {
- UInt32 enableIO;
- enableIO = 1;
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioOutputUnitProperty_EnableIO,
- kAudioUnitScope_Input,
- INPUT_ELEMENT,
- &enableIO,
- sizeof(enableIO) ) );
- }
- /* -- if there is no output, we must explicitly disable output -- */
- if( !outStreamParams )
- {
- UInt32 enableIO;
- enableIO = 0;
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioOutputUnitProperty_EnableIO,
- kAudioUnitScope_Output,
- OUTPUT_ELEMENT,
- &enableIO,
- sizeof(enableIO) ) );
- }
- /* -- set the devices -- */
- /* make sure input and output are the same device if we are doing input and
- output. */
- if( inStreamParams && outStreamParams )
- assert( outStreamParams->device == inStreamParams->device );
- if( inStreamParams )
- {
- *audioDevice = auhalHostApi->devIds[inStreamParams->device] ;
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioOutputUnitProperty_CurrentDevice,
- kAudioUnitScope_Global,
- INPUT_ELEMENT,
- audioDevice,
- sizeof(AudioDeviceID) ) );
- }
- if( outStreamParams )
- {
- *audioDevice = auhalHostApi->devIds[outStreamParams->device] ;
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioOutputUnitProperty_CurrentDevice,
- kAudioUnitScope_Global,
- OUTPUT_ELEMENT,
- audioDevice,
- sizeof(AudioDeviceID) ) );
- }
-
- /* -- set format -- */
- bzero( &desiredFormat, sizeof(desiredFormat) );
- desiredFormat.mFormatID = kAudioFormatLinearPCM ;
- desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
- desiredFormat.mFramesPerPacket = 1;
- desiredFormat.mBitsPerChannel = sizeof( float ) * 8;
-
- result = 0;
- /* set device format first, but only touch the device if the user asked */
- if( inStreamParams ) {
- /*The callback never calls back if we don't set the FPB */
- /*This seems wierd, because I would think setting anything on the device
- would be disruptive.*/
- paResult = setBestFramesPerBuffer( *audioDevice, FALSE,
- requestedFramesPerBuffer,
- actualInputFramesPerBuffer );
- if( paResult ) goto error;
- if( macInputStreamFlags & paMacCore_ChangeDeviceParameters ) {
- bool requireExact;
- requireExact=macInputStreamFlags&paMacCore_FailIfConversionRequired;
- paResult = setBestSampleRateForDevice( *audioDevice, FALSE,
- requireExact, sampleRate );
- if( paResult ) goto error;
- }
- if( actualInputFramesPerBuffer && actualOutputFramesPerBuffer )
- *actualOutputFramesPerBuffer = *actualInputFramesPerBuffer ;
- }
- if( outStreamParams && !inStreamParams ) {
- /*The callback never calls back if we don't set the FPB */
- /*This seems wierd, because I would think setting anything on the device
- would be disruptive.*/
- paResult = setBestFramesPerBuffer( *audioDevice, TRUE,
- requestedFramesPerBuffer,
- actualOutputFramesPerBuffer );
- if( paResult ) goto error;
- if( macOutputStreamFlags & paMacCore_ChangeDeviceParameters ) {
- bool requireExact;
- requireExact=macOutputStreamFlags&paMacCore_FailIfConversionRequired;
- paResult = setBestSampleRateForDevice( *audioDevice, TRUE,
- requireExact, sampleRate );
- if( paResult ) goto error;
- }
- }
-
- /* -- set the quality of the output converter -- */
- if( outStreamParams ) {
- UInt32 value = kAudioConverterQuality_Max;
- switch( macOutputStreamFlags & 0x0700 ) {
- case 0x0100: /*paMacCore_ConversionQualityMin:*/
- value=kRenderQuality_Min;
- break;
- case 0x0200: /*paMacCore_ConversionQualityLow:*/
- value=kRenderQuality_Low;
- break;
- case 0x0300: /*paMacCore_ConversionQualityMedium:*/
- value=kRenderQuality_Medium;
- break;
- case 0x0400: /*paMacCore_ConversionQualityHigh:*/
- value=kRenderQuality_High;
- break;
- }
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioUnitProperty_RenderQuality,
- kAudioUnitScope_Global,
- OUTPUT_ELEMENT,
- &value,
- sizeof(value) ) );
- }
- /* now set the format on the Audio Units. */
- if( outStreamParams )
- {
- desiredFormat.mSampleRate =sampleRate;
- desiredFormat.mBytesPerPacket=sizeof(float)*outStreamParams->channelCount;
- desiredFormat.mBytesPerFrame =sizeof(float)*outStreamParams->channelCount;
- desiredFormat.mChannelsPerFrame = outStreamParams->channelCount;
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input,
- OUTPUT_ELEMENT,
- &desiredFormat,
- sizeof(AudioStreamBasicDescription) ) );
- }
- if( inStreamParams )
- {
- AudioStreamBasicDescription sourceFormat;
- UInt32 size = sizeof( AudioStreamBasicDescription );
-
- /* keep the sample rate of the device, or we confuse AUHAL */
- ERR_WRAP( AudioUnitGetProperty( *audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Input,
- INPUT_ELEMENT,
- &sourceFormat,
- &size ) );
- desiredFormat.mSampleRate = sourceFormat.mSampleRate;
- desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount;
- desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount;
- desiredFormat.mChannelsPerFrame = inStreamParams->channelCount;
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Output,
- INPUT_ELEMENT,
- &desiredFormat,
- sizeof(AudioStreamBasicDescription) ) );
- }
- /* set the maximumFramesPerSlice */
- /* not doing this causes real problems
- (eg. the callback might not be called). The idea of setting both this
- and the frames per buffer on the device is that we'll be most likely
- to actually get the frame size we requested in the callback with the
- minimum latency. */
- if( outStreamParams ) {
- UInt32 size = sizeof( *actualOutputFramesPerBuffer );
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioUnitProperty_MaximumFramesPerSlice,
- kAudioUnitScope_Input,
- OUTPUT_ELEMENT,
- actualOutputFramesPerBuffer,
- sizeof(unsigned long) ) );
- ERR_WRAP( AudioUnitGetProperty( *audioUnit,
- kAudioUnitProperty_MaximumFramesPerSlice,
- kAudioUnitScope_Global,
- OUTPUT_ELEMENT,
- actualOutputFramesPerBuffer,
- &size ) );
- }
- if( inStreamParams ) {
- /*UInt32 size = sizeof( *actualInputFramesPerBuffer );*/
- ERR_WRAP( AudioUnitSetProperty( *audioUnit,
- kAudioUnitProperty_MaximumFramesPerSlice,
- kAudioUnitScope_Output,
- INPUT_ELEMENT,
- actualInputFramesPerBuffer,
- sizeof(unsigned long) ) );
-/* Don't know why this causes problems
- ERR_WRAP( AudioUnitGetProperty( *audioUnit,
- kAudioUnitProperty_MaximumFramesPerSlice,
- kAudioUnitScope_Global, //Output,
- INPUT_ELEMENT,
- actualInputFramesPerBuffer,
- &size ) );
-*/
- }
-
- /* -- if we have input, we may need to setup an SR converter -- */
- /* even if we got the sample rate we asked for, we need to do
- the conversion in case another program changes the underlying SR. */
- /* FIXME: I think we need to monitor stream and change the converter if the incoming format changes. */
- if( inStreamParams ) {
- AudioStreamBasicDescription desiredFormat;
- AudioStreamBasicDescription sourceFormat;
- UInt32 sourceSize = sizeof( sourceFormat );
- bzero( &desiredFormat, sizeof(desiredFormat) );
- desiredFormat.mSampleRate = sampleRate;
- desiredFormat.mFormatID = kAudioFormatLinearPCM ;
- desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
- desiredFormat.mFramesPerPacket = 1;
- desiredFormat.mBitsPerChannel = sizeof( float ) * 8;
- desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount;
- desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount;
- desiredFormat.mChannelsPerFrame = inStreamParams->channelCount;
-
- /* get the source format */
- ERR_WRAP( AudioUnitGetProperty(
- *audioUnit,
- kAudioUnitProperty_StreamFormat,
- kAudioUnitScope_Output,
- INPUT_ELEMENT,
- &sourceFormat,
- &sourceSize ) );
-
- if( desiredFormat.mSampleRate != sourceFormat.mSampleRate )
- {
- UInt32 value = kAudioConverterQuality_Max;
- switch( macInputStreamFlags & 0x0700 ) {
- case 0x0100: /*paMacCore_ConversionQualityMin:*/
- value=kAudioConverterQuality_Min;
- break;
- case 0x0200: /*paMacCore_ConversionQualityLow:*/
- value=kAudioConverterQuality_Low;
- break;
- case 0x0300: /*paMacCore_ConversionQualityMedium:*/
- value=kAudioConverterQuality_Medium;
- break;
- case 0x0400: /*paMacCore_ConversionQualityHigh:*/
- value=kAudioConverterQuality_High;
- break;
- }
- VDBUG(( "Creating sample rate converter for input"
- " to convert from %g to %g\n",
- (float)sourceFormat.mSampleRate,
- (float)desiredFormat.mSampleRate ) );
- /* create our converter */
- ERR_WRAP( AudioConverterNew(
- &sourceFormat,
- &desiredFormat,
- srConverter ) );
- /* Set quality */
- ERR_WRAP( AudioConverterSetProperty(
- *srConverter,
- kAudioConverterSampleRateConverterQuality,
- sizeof( value ),
- &value ) );
- }
- }
- /* -- set IOProc (callback) -- */
- callbackKey = outStreamParams ? kAudioUnitProperty_SetRenderCallback
- : kAudioOutputUnitProperty_SetInputCallback ;
- rcbs.inputProc = AudioIOProc;
- rcbs.inputProcRefCon = refCon;
- ERR_WRAP( AudioUnitSetProperty(
- *audioUnit,
- callbackKey,
- kAudioUnitScope_Output,
- outStreamParams ? OUTPUT_ELEMENT : INPUT_ELEMENT,
- &rcbs,
- sizeof(rcbs)) );
-
- if( inStreamParams && outStreamParams && *srConverter )
- ERR_WRAP( AudioUnitSetProperty(
- *audioUnit,
- kAudioOutputUnitProperty_SetInputCallback,
- kAudioUnitScope_Output,
- INPUT_ELEMENT,
- &rcbs,
- sizeof(rcbs)) );
-
- /*IMPLEMENTME: may need to worry about channel mapping.*/
-
- /* initialize the audio unit */
- ERR_WRAP( AudioUnitInitialize(*audioUnit) );
-
- if( inStreamParams && outStreamParams )
- VDBUG( ("Opened device %ld for input and output.\n", *audioDevice ) );
- else if( inStreamParams )
- VDBUG( ("Opened device %ld for input.\n", *audioDevice ) );
- else if( outStreamParams )
- VDBUG( ("Opened device %ld for output.\n", *audioDevice ) );
- return paNoError;
-#undef ERR_WRAP
-
- error:
- CloseComponent( *audioUnit );
- *audioUnit = NULL;
- if( result )
- return PaMacCore_SetError( result, line, 1 );
- return paResult;
-}
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result = paNoError;
- PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
- PaMacCoreStream *stream = 0;
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
- VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n",
- inputParameters ? inputParameters->channelCount : -1,
- inputParameters ? inputParameters->sampleFormat : -1,
- outputParameters ? outputParameters->channelCount : -1,
- outputParameters ? outputParameters->sampleFormat : -1,
- (float) sampleRate,
- framesPerBuffer ));
- VDBUG( ("Opening Stream.\n") );
-
- /*These first few bits of code are from paSkeleton with few modifications.*/
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
-
- /* Host supports interleaved float32 */
- hostInputSampleFormat = paFloat32;
- }
- else
- {
- inputChannelCount = 0;
- inputSampleFormat = hostInputSampleFormat = paFloat32; /* Surpress 'uninitialised var' warnings. */
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support inputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* Host supports interleaved float32 */
- hostOutputSampleFormat = paFloat32;
- }
- else
- {
- outputChannelCount = 0;
- outputSampleFormat = hostOutputSampleFormat = paFloat32; /* Surpress 'uninitialized var' warnings. */
- }
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- return paInvalidFlag; /* unexpected platform specific flag */
-
- stream = (PaMacCoreStream*)PaUtil_AllocateMemory( sizeof(PaMacCoreStream) );
- if( !stream )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* If we fail after this point, we my be left in a bad state, with
- some data structures setup and others not. So, first thing we
- do is initialize everything so that if we fail, we know what hasn't
- been touched.
- */
-
- stream->inputAudioBufferList.mBuffers[0].mData = NULL;
- stream->inputRingBuffer.buffer = NULL;
- bzero( &stream->blio, sizeof( PaMacBlio ) );
-/*
- stream->blio.inputRingBuffer.buffer = NULL;
- stream->blio.outputRingBuffer.buffer = NULL;
- stream->blio.inputSampleFormat = inputParameters?inputParameters->sampleFormat:0;
- stream->blio.inputSampleSize = computeSampleSizeFromFormat(stream->blio.inputSampleFormat);
- stream->blio.outputSampleFormat=outputParameters?outputParameters->sampleFormat:0;
- stream->blio.outputSampleSize = computeSampleSizeFromFormat(stream->blio.outputSampleFormat);
-*/
- stream->inputSRConverter = NULL;
- stream->inputUnit = NULL;
- stream->outputUnit = NULL;
- stream->inputFramesPerBuffer = 0;
- stream->outputFramesPerBuffer = 0;
- stream->bufferProcessorIsInitialized = FALSE;
-
- /* assert( streamCallback ) ; */ /* only callback mode is implemented */
- if( streamCallback )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &auhalHostApi->callbackStreamInterface,
- streamCallback, userData );
- }
- else
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &auhalHostApi->blockingStreamInterface,
- BlioCallback, &stream->blio );
- }
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
- /* -- handle paFramesPerBufferUnspecified -- */
- if( framesPerBuffer == paFramesPerBufferUnspecified ) {
- long requested = 64;
- if( inputParameters )
- requested = MAX( requested, inputParameters->suggestedLatency * sampleRate / 2 );
- if( outputParameters )
- requested = MAX( requested, outputParameters->suggestedLatency *sampleRate / 2 );
- VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n",
- requested ) );
- if( requested <= 64 ) {
- /*requested a realtively low latency. make sure this is in range of devices */
- /*try to get the device's min natural buffer size and use that (but no smaller than 64).*/
- AudioValueRange audioRange;
- size_t size = sizeof( audioRange );
- if( inputParameters ) {
- WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
- 0,
- false,
- kAudioDevicePropertyBufferFrameSizeRange,
- &size, &audioRange ) );
- if( result )
- requested = MAX( requested, audioRange.mMinimum );
- }
- if( outputParameters ) {
- WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
- 0,
- false,
- kAudioDevicePropertyBufferFrameSizeRange,
- &size, &audioRange ) );
- if( result )
- requested = MAX( requested, audioRange.mMinimum );
- }
- } else {
- /* requested a realtively high latency. make sure this is in range of devices */
- /*try to get the device's max natural buffer size and use that (but no larger than 1024).*/
- AudioValueRange audioRange;
- size_t size = sizeof( audioRange );
- requested = MIN( requested, 1024 );
- if( inputParameters ) {
- WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
- 0,
- false,
- kAudioDevicePropertyBufferFrameSizeRange,
- &size, &audioRange ) );
- if( result )
- requested = MIN( requested, audioRange.mMaximum );
- }
- if( outputParameters ) {
- WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
- 0,
- false,
- kAudioDevicePropertyBufferFrameSizeRange,
- &size, &audioRange ) );
- if( result )
- requested = MIN( requested, audioRange.mMaximum );
- }
- }
- /* -- double check ranges -- */
- if( requested > 1024 ) requested = 1024;
- if( requested < 64 ) requested = 64;
- VDBUG(("After querying hardware, setting block size to %ld.\n", requested));
- framesPerBuffer = requested;
- }
-
- /* -- Now we actually open and setup streams. -- */
- if( inputParameters && outputParameters && outputParameters->device == inputParameters->device )
- { /* full duplex. One device. */
- result = OpenAndSetupOneAudioUnit( inputParameters,
- outputParameters,
- framesPerBuffer,
- &(stream->inputFramesPerBuffer),
- &(stream->outputFramesPerBuffer),
- auhalHostApi,
- &(stream->inputUnit),
- &(stream->inputSRConverter),
- &(stream->inputDevice),
- sampleRate,
- stream );
- stream->outputUnit = stream->inputUnit;
- stream->outputDevice = stream->inputDevice;
- if( result != paNoError )
- goto error;
- }
- else
- { /* full duplex, different devices OR simplex */
- result = OpenAndSetupOneAudioUnit( NULL,
- outputParameters,
- framesPerBuffer,
- NULL,
- &(stream->outputFramesPerBuffer),
- auhalHostApi,
- &(stream->outputUnit),
- NULL,
- &(stream->outputDevice),
- sampleRate,
- stream );
- if( result != paNoError )
- goto error;
- result = OpenAndSetupOneAudioUnit( inputParameters,
- NULL,
- framesPerBuffer,
- &(stream->inputFramesPerBuffer),
- NULL,
- auhalHostApi,
- &(stream->inputUnit),
- &(stream->inputSRConverter),
- &(stream->inputDevice),
- sampleRate,
- stream );
- if( result != paNoError )
- goto error;
- }
-
- if( stream->inputUnit ) {
- const size_t szfl = sizeof(float);
- /* setup the AudioBufferList used for input */
- bzero( &stream->inputAudioBufferList, sizeof( AudioBufferList ) );
- stream->inputAudioBufferList.mNumberBuffers = 1;
- stream->inputAudioBufferList.mBuffers[0].mNumberChannels
- = inputChannelCount;
- stream->inputAudioBufferList.mBuffers[0].mDataByteSize
- = stream->inputFramesPerBuffer*inputChannelCount*szfl;
- stream->inputAudioBufferList.mBuffers[0].mData
- = (float *) calloc(
- stream->inputFramesPerBuffer*inputChannelCount,
- szfl );
- if( !stream->inputAudioBufferList.mBuffers[0].mData )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /*
- * If input and output devs are different or we are doing SR conversion,
- * we also need a
- * ring buffer to store inpt data while waiting for output
- * data.
- */
- if( (stream->outputUnit && stream->inputUnit != stream->outputUnit)
- || stream->inputSRConverter )
- {
- /* May want the ringSize ot initial position in
- ring buffer to depend somewhat on sample rate change */
-
- void *data;
- long ringSize;
-
- ringSize = computeRingBufferSize( inputParameters,
- outputParameters,
- stream->inputFramesPerBuffer,
- stream->outputFramesPerBuffer,
- sampleRate );
- /*ringSize <<= 4; *//*16x bigger, for testing */
-
-
- /*now, we need to allocate memory for the ring buffer*/
- data = calloc( ringSize, szfl );
- if( !data )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* now we can initialize the ring buffer */
- /*assert( 0 ==*/
- RingBuffer_Init( &stream->inputRingBuffer,
- ringSize*szfl, data ) /*)*/;
- /* advance the read point a little, so we are reading from the
- middle of the buffer */
- if( stream->outputUnit )
- RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer, ringSize*szfl / RING_BUFFER_ADVANCE_DENOMINATOR );
- }
- }
-
- /* -- initialize Blio Buffer Processors -- */
- if( !streamCallback )
- {
- long ringSize;
-
- ringSize = computeRingBufferSize( inputParameters,
- outputParameters,
- stream->inputFramesPerBuffer,
- stream->outputFramesPerBuffer,
- sampleRate );
- result = initializeBlioRingBuffers( &stream->blio,
- inputParameters?inputParameters->sampleFormat:0 ,
- outputParameters?outputParameters->sampleFormat:0 ,
- MAX(stream->inputFramesPerBuffer,stream->outputFramesPerBuffer),
- ringSize,
- inputParameters?inputChannelCount:0 ,
- outputParameters?outputChannelCount:0 ) ;
- if( result != paNoError )
- goto error;
- }
-
- /* -- initialize Buffer Processor -- */
- {
- unsigned long maxHostFrames = stream->inputFramesPerBuffer;
- if( stream->outputFramesPerBuffer > maxHostFrames )
- maxHostFrames = stream->outputFramesPerBuffer;
- result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- inputChannelCount, inputSampleFormat,
- hostInputSampleFormat,
- outputChannelCount, outputSampleFormat,
- hostOutputSampleFormat,
- sampleRate,
- streamFlags,
- framesPerBuffer,
- /* If sample rate conversion takes place, the buffer size
- will not be known. */
- maxHostFrames,
- stream->inputSRConverter
- ? paUtilUnknownHostBufferSize
- : paUtilBoundedHostBufferSize,
- streamCallback ? streamCallback : BlioCallback,
- streamCallback ? userData : &stream->blio );
- if( result != paNoError )
- goto error;
- }
- stream->bufferProcessorIsInitialized = TRUE;
-
- /*
- IMPLEMENT ME: initialise the following fields with estimated or actual
- values.
- I think this is okay the way it is br 12/1/05
- maybe need to change input latency estimate if IO devs differ
- */
- stream->streamRepresentation.streamInfo.inputLatency =
- PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)/sampleRate;
- stream->streamRepresentation.streamInfo.outputLatency =
- PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)/sampleRate;
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
- stream->sampleRate = sampleRate;
- stream->outDeviceSampleRate = 0;
- if( stream->outputUnit ) {
- Float64 rate;
- UInt32 size = sizeof( rate );
- result = ERR( AudioDeviceGetProperty( stream->outputDevice,
- 0,
- FALSE,
- kAudioDevicePropertyNominalSampleRate,
- &size, &rate ) );
- if( result )
- goto error;
- stream->outDeviceSampleRate = rate;
- }
- stream->inDeviceSampleRate = 0;
- if( stream->inputUnit ) {
- Float64 rate;
- UInt32 size = sizeof( rate );
- result = ERR( AudioDeviceGetProperty( stream->inputDevice,
- 0,
- TRUE,
- kAudioDevicePropertyNominalSampleRate,
- &size, &rate ) );
- if( result )
- goto error;
- stream->inDeviceSampleRate = rate;
- }
- stream->userInChan = inputChannelCount;
- stream->userOutChan = outputChannelCount;
-
- stream->isTimeSet = FALSE;
- stream->state = STOPPED;
- stream->xrunFlags = 0;
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
- CloseStream( stream );
- return result;
-}
-
-PaTime GetStreamTime( PaStream *s )
-{
- /* FIXME: I am not at all sure this timing info stuff is right.
- patest_sine_time reports negative latencies, which is wierd.*/
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
- AudioTimeStamp timeStamp;
-
- VVDBUG(("GetStreamTime()\n"));
-
- if ( !stream->isTimeSet )
- return (PaTime)0;
-
- if ( stream->outputDevice ) {
- AudioDeviceGetCurrentTime( stream->outputDevice, &timeStamp);
- return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->outDeviceSampleRate;
- } else if ( stream->inputDevice ) {
- AudioDeviceGetCurrentTime( stream->inputDevice, &timeStamp);
- return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->inDeviceSampleRate;
- } else {
- return (PaTime)0;
- }
-}
-
-static void setStreamStartTime( PaStream *stream )
-{
- /* FIXME: I am not at all sure this timing info stuff is right.
- patest_sine_time reports negative latencies, which is wierd.*/
- PaMacCoreStream *s = (PaMacCoreStream *) stream;
- VVDBUG(("setStreamStartTime()\n"));
- if( s->outputDevice )
- AudioDeviceGetCurrentTime( s->outputDevice, &s->startTime);
- else if( s->inputDevice )
- AudioDeviceGetCurrentTime( s->inputDevice, &s->startTime);
- else
- bzero( &s->startTime, sizeof( s->startTime ) );
-
- //FIXME: we need a memory barier here
-
- s->isTimeSet = TRUE;
-}
-
-
-static PaTime TimeStampToSecs(PaMacCoreStream *stream, const AudioTimeStamp* timeStamp)
-{
- VVDBUG(("TimeStampToSecs()\n"));
- //printf( "ATS: %lu, %g, %g\n", timeStamp->mFlags, timeStamp->mSampleTime, timeStamp->mRateScalar );
- if (timeStamp->mFlags & kAudioTimeStampSampleTimeValid)
- return (timeStamp->mSampleTime / stream->sampleRate);
- else
- return 0;
-}
-
-#define RING_BUFFER_EMPTY (1000)
-
-static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter,
- UInt32*ioDataSize,
- void** outData,
- void*inUserData )
-{
- void *dummyData;
- long dummySize;
- RingBuffer *rb = (RingBuffer *) inUserData;
-
- VVDBUG(("ringBufferIOProc()\n"));
-
- assert( sizeof( UInt32 ) == sizeof( long ) );
- if( RingBuffer_GetReadAvailable( rb ) == 0 ) {
- *outData = NULL;
- *ioDataSize = 0;
- return RING_BUFFER_EMPTY;
- }
- RingBuffer_GetReadRegions( rb, *ioDataSize,
- outData, (long *)ioDataSize,
- &dummyData, &dummySize );
-
- assert( *ioDataSize );
- RingBuffer_AdvanceReadIndex( rb, *ioDataSize );
-
- return noErr;
-}
-
-/*
- * Called by the AudioUnit API to process audio from the sound card.
- * This is where the magic happens.
- */
-/* FEEDBACK: there is a lot of redundant code here because of how all the cases differ. This makes it hard to maintain, so if there are suggestinos for cleaning it up, I'm all ears. */
-static OSStatus AudioIOProc( void *inRefCon,
- AudioUnitRenderActionFlags *ioActionFlags,
- const AudioTimeStamp *inTimeStamp,
- UInt32 inBusNumber,
- UInt32 inNumberFrames,
- AudioBufferList *ioData )
-{
- unsigned long framesProcessed = 0;
- PaStreamCallbackTimeInfo timeInfo = {0,0,0};
- PaMacCoreStream *stream = (PaMacCoreStream*)inRefCon;
- const bool isRender = inBusNumber == OUTPUT_ELEMENT;
- int callbackResult = paContinue ;
-
- VVDBUG(("AudioIOProc()\n"));
-
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
- /* -----------------------------------------------------------------*\
- This output may be useful for debugging,
- But printing durring the callback is a bad enough idea that
- this is not enabled by enableing the usual debugging calls.
- \* -----------------------------------------------------------------*/
- /*
- static int renderCount = 0;
- static int inputCount = 0;
- printf( "------------------- starting reder/input\n" );
- if( isRender )
- printf("Render callback (%d):\t", ++renderCount);
- else
- printf("Input callback (%d):\t", ++inputCount);
- printf( "Call totals: %d (input), %d (render)\n", inputCount, renderCount );
-
- printf( "--- inBusNumber: %lu\n", inBusNumber );
- printf( "--- inNumberFrames: %lu\n", inNumberFrames );
- printf( "--- %x ioData\n", (unsigned) ioData );
- if( ioData )
- {
- int i=0;
- printf( "--- ioData.mNumBuffers %lu: \n", ioData->mNumberBuffers );
- for( i=0; i<ioData->mNumberBuffers; ++i )
- printf( "--- ioData buffer %d size: %lu.\n", i, ioData->mBuffers[i].mDataByteSize );
- }
- ----------------------------------------------------------------- */
-
- if( !stream->isTimeSet )
- setStreamStartTime( stream );
-
- if( isRender ) {
- AudioTimeStamp currentTime;
- timeInfo.outputBufferDacTime = TimeStampToSecs(stream, inTimeStamp);
- AudioDeviceGetCurrentTime(stream->outputDevice, &currentTime);
- timeInfo.currentTime = TimeStampToSecs(stream, &currentTime);
- }
- if( isRender && stream->inputUnit == stream->outputUnit )
- timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
- if( !isRender ) {
- AudioTimeStamp currentTime;
- timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
- AudioDeviceGetCurrentTime(stream->inputDevice, &currentTime);
- timeInfo.currentTime = TimeStampToSecs(stream, &currentTime);
- }
-
- //printf( "---%g, %g, %g\n", timeInfo.inputBufferAdcTime, timeInfo.currentTime, timeInfo.outputBufferDacTime );
-
- if( isRender && stream->inputUnit == stream->outputUnit
- && !stream->inputSRConverter )
- {
- /* --------- Full Duplex, One Device, no SR Conversion -------
- *
- * This is the lowest latency case, and also the simplest.
- * Input data and output data are available at the same time.
- * we do not use the input SR converter or the input ring buffer.
- *
- */
- OSErr err = 0;
- unsigned long frames;
-
- /* -- start processing -- */
- PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
- &timeInfo,
- stream->xrunFlags );
- stream->xrunFlags = 0;
-
- /* -- compute frames. do some checks -- */
- assert( ioData->mNumberBuffers == 1 );
- assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan );
- frames = ioData->mBuffers[0].mDataByteSize;
- frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
- /* -- copy and process input data -- */
- err= AudioUnitRender(stream->inputUnit,
- ioActionFlags,
- inTimeStamp,
- INPUT_ELEMENT,
- inNumberFrames,
- &stream->inputAudioBufferList );
- /* FEEDBACK: I'm not sure what to do when this call fails */
- assert( !err );
-
- PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
- PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- stream->inputAudioBufferList.mBuffers[0].mData,
- stream->inputAudioBufferList.mBuffers[0].mNumberChannels);
- /* -- Copy and process output data -- */
- PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames );
- PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor),
- 0,
- ioData->mBuffers[0].mData,
- ioData->mBuffers[0].mNumberChannels);
- /* -- complete processing -- */
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- }
- else if( isRender )
- {
- /* -------- Output Side of Full Duplex (Separate Devices or SR Conversion)
- * -- OR Simplex Output
- *
- * This case handles output data as in the full duplex case,
- * and, if there is input data, reads it off the ring buffer
- * and into the PA buffer processor. If sample rate conversion
- * is required on input, that is done here as well.
- */
- unsigned long frames;
-
- /* Sometimes, when stopping a duplex stream we get erroneous
- xrun flags, so if this is our last run, clear the flags. */
- int xrunFlags = stream->xrunFlags;
-/*
- if( xrunFlags & paInputUnderflow )
- printf( "input underflow.\n" );
- if( xrunFlags & paInputOverflow )
- printf( "input overflow.\n" );
-*/
- if( stream->state == STOPPING || stream->state == CALLBACK_STOPPED )
- xrunFlags = 0;
-
- /* -- start processing -- */
- PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
- &timeInfo,
- xrunFlags );
- stream->xrunFlags = 0; /* FEEDBACK: we only send flags to Buf Proc once */
-
- /* -- Copy and process output data -- */
- assert( ioData->mNumberBuffers == 1 );
- frames = ioData->mBuffers[0].mDataByteSize;
- frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
- assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan );
- PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames );
- PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor),
- 0,
- ioData->mBuffers[0].mData,
- ioData->mBuffers[0].mNumberChannels);
-
- /* -- copy and process input data, and complete processing -- */
- if( stream->inputUnit ) {
- const int flsz = sizeof( float );
- /* Here, we read the data out of the ring buffer, through the
- audio converter. */
- int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels;
- if( stream->inputSRConverter )
- {
- OSStatus err;
- UInt32 size;
- float data[ inChan * frames ];
- size = sizeof( data );
- err = AudioConverterFillBuffer(
- stream->inputSRConverter,
- ringBufferIOProc,
- &stream->inputRingBuffer,
- &size,
- (void *)&data );
- if( err == RING_BUFFER_EMPTY )
- { /*the ring buffer callback underflowed */
- err = 0;
- bzero( ((char *)data) + size, sizeof(data)-size );
- stream->xrunFlags |= paInputUnderflow;
- }
- ERR( err );
- assert( !err );
-
- PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
- PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- data,
- inChan );
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- }
- else
- {
- /* Without the AudioConverter is actually a bit more complex
- because we have to do a little buffer processing that the
- AudioConverter would otherwise handle for us. */
- void *data1, *data2;
- long size1, size2;
- RingBuffer_GetReadRegions( &stream->inputRingBuffer,
- inChan*frames*flsz,
- &data1, &size1,
- &data2, &size2 );
- if( size1 / ( flsz * inChan ) == frames ) {
- /* simplest case: all in first buffer */
- PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
- PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- data1,
- inChan );
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- RingBuffer_AdvanceReadIndex(&stream->inputRingBuffer, size1 );
- } else if( ( size1 + size2 ) / ( flsz * inChan ) < frames ) {
- /*we underflowed. take what data we can, zero the rest.*/
- float data[frames*inChan];
- if( size1 )
- memcpy( data, data1, size1 );
- if( size2 )
- memcpy( data+size1, data2, size2 );
- bzero( data+size1+size2, frames*flsz*inChan - size1 - size2 );
-
- PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
- PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- data,
- inChan );
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- RingBuffer_AdvanceReadIndex( &stream->inputRingBuffer,
- size1+size2 );
- /* flag underflow */
- stream->xrunFlags |= paInputUnderflow;
- } else {
- /*we got all the data, but split between buffers*/
- PaUtil_SetInputFrameCount( &(stream->bufferProcessor),
- size1 / ( flsz * inChan ) );
- PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- data1,
- inChan );
- PaUtil_Set2ndInputFrameCount( &(stream->bufferProcessor),
- size2 / ( flsz * inChan ) );
- PaUtil_Set2ndInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- data2,
- inChan );
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- RingBuffer_AdvanceReadIndex(&stream->inputRingBuffer, size1+size2 );
- }
- }
- } else {
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- }
-
- }
- else
- {
- /* ------------------ Input
- *
- * First, we read off the audio data and put it in the ring buffer.
- * if this is an input-only stream, we need to process it more,
- * otherwise, we let the output case deal with it.
- */
- OSErr err = 0;
- int chan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels ;
- /* FIXME: looping here may not actually be necessary, but it was something I tried in testing. */
- do {
- err= AudioUnitRender(stream->inputUnit,
- ioActionFlags,
- inTimeStamp,
- INPUT_ELEMENT,
- inNumberFrames,
- &stream->inputAudioBufferList );
- if( err == -10874 )
- inNumberFrames /= 2;
- } while( err == -10874 && inNumberFrames > 1 );
- /* FEEDBACK: I'm not sure what to do when this call fails */
- ERR( err );
- assert( !err );
- if( stream->inputSRConverter || stream->outputUnit )
- {
- /* If this is duplex or we use a converter, put the data
- into the ring buffer. */
- long bytesIn, bytesOut;
- bytesIn = sizeof( float ) * inNumberFrames * chan;
- bytesOut = RingBuffer_Write( &stream->inputRingBuffer,
- stream->inputAudioBufferList.mBuffers[0].mData,
- bytesIn );
- if( bytesIn != bytesOut )
- stream->xrunFlags |= paInputOverflow ;
- }
- else
- {
- /* for simplex input w/o SR conversion,
- just pop the data into the buffer processor.*/
- PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
- &timeInfo,
- stream->xrunFlags );
- stream->xrunFlags = 0;
-
- PaUtil_SetInputFrameCount( &(stream->bufferProcessor), inNumberFrames);
- PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- stream->inputAudioBufferList.mBuffers[0].mData,
- chan );
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- }
- if( !stream->outputUnit && stream->inputSRConverter )
- {
- /* ------------------ Simplex Input w/ SR Conversion
- *
- * if this is a simplex input stream, we need to read off the buffer,
- * do our sample rate conversion and pass the results to the buffer
- * processor.
- * The logic here is complicated somewhat by the fact that we don't
- * know how much data is available, so we loop on reasonably sized
- * chunks, and let the BufferProcessor deal with the rest.
- *
- */
- /*This might be too big or small depending on SR conversion*/
- float data[ chan * inNumberFrames ];
- OSStatus err;
- do
- { /*Run the buffer processor until we are out of data*/
- UInt32 size;
- long f;
-
- size = sizeof( data );
- err = AudioConverterFillBuffer(
- stream->inputSRConverter,
- ringBufferIOProc,
- &stream->inputRingBuffer,
- &size,
- (void *)data );
- if( err != RING_BUFFER_EMPTY )
- ERR( err );
- assert( err == 0 || err == RING_BUFFER_EMPTY );
-
- f = size / ( chan * sizeof(float) );
- PaUtil_SetInputFrameCount( &(stream->bufferProcessor), f );
- if( f )
- {
- PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
- &timeInfo,
- stream->xrunFlags );
- stream->xrunFlags = 0;
-
- PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
- 0,
- data,
- chan );
- framesProcessed =
- PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
- &callbackResult );
- }
- } while( callbackResult == paContinue && !err );
- }
- }
-
- switch( callbackResult )
- {
- case paContinue: break;
- case paComplete:
- case paAbort:
- stream->isTimeSet = FALSE;
- stream->state = CALLBACK_STOPPED ;
- if( stream->outputUnit )
- AudioOutputUnitStop(stream->outputUnit);
- if( stream->inputUnit )
- AudioOutputUnitStop(stream->inputUnit);
- break;
- }
-
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
- return noErr;
-}
-
-
-/*
- When CloseStream() is called, the multi-api layer ensures that
- the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
- /* This may be called from a failed OpenStream.
- Therefore, each piece of info is treated seperately. */
- PaError result = paNoError;
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- VVDBUG(("CloseStream()\n"));
- VDBUG( ( "Closing stream.\n" ) );
-
- if( stream ) {
- if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) {
- AudioUnitUninitialize( stream->outputUnit );
- CloseComponent( stream->outputUnit );
- }
- stream->outputUnit = NULL;
- if( stream->inputUnit )
- {
- AudioUnitUninitialize( stream->inputUnit );
- CloseComponent( stream->inputUnit );
- stream->inputUnit = NULL;
- }
- if( stream->inputRingBuffer.buffer )
- free( (void *) stream->inputRingBuffer.buffer );
- stream->inputRingBuffer.buffer = NULL;
- /*TODO: is there more that needs to be done on error
- from AudioConverterDispose?*/
- if( stream->inputSRConverter )
- ERR( AudioConverterDispose( stream->inputSRConverter ) );
- stream->inputSRConverter = NULL;
- if( stream->inputAudioBufferList.mBuffers[0].mData )
- free( stream->inputAudioBufferList.mBuffers[0].mData );
- stream->inputAudioBufferList.mBuffers[0].mData = NULL;
-
- result = destroyBlioRingBuffers( &stream->blio );
- if( result )
- return result;
- if( stream->bufferProcessorIsInitialized )
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- PaUtil_FreeMemory( stream );
- }
-
- return result;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
- OSErr result = noErr;
- VVDBUG(("StartStream()\n"));
- VDBUG( ( "Starting stream.\n" ) );
-
-#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0)
-
- /*FIXME: maybe want to do this on close/abort for faster start? */
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
- if( stream->inputSRConverter )
- ERR_WRAP( AudioConverterReset( stream->inputSRConverter ) );
-
- /* -- start -- */
- stream->state = ACTIVE;
- if( stream->inputUnit ) {
- ERR_WRAP( AudioOutputUnitStart(stream->inputUnit) );
- }
- if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) {
- ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) );
- }
-
- //setStreamStartTime( stream );
- //stream->isTimeSet = TRUE;
-
- return paNoError;
-#undef ERR_WRAP
-}
-
-
-static PaError StopStream( PaStream *s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
- OSErr result = noErr;
- PaError paErr;
- VVDBUG(("StopStream()\n"));
-
- VDBUG( ("Waiting for BLIO.\n") );
- waitUntilBlioWriteBufferIsFlushed( &stream->blio );
- VDBUG( ( "Stopping stream.\n" ) );
-
- stream->isTimeSet = FALSE;
- stream->state = STOPPING;
-
-#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0)
- /* -- stop and reset -- */
- if( stream->inputUnit == stream->outputUnit && stream->inputUnit )
- {
- ERR_WRAP( AudioOutputUnitStop(stream->inputUnit) );
- ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 1) );
- ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 0) );
- }
- else
- {
- if( stream->inputUnit )
- {
- ERR_WRAP(AudioOutputUnitStop(stream->inputUnit) );
- ERR_WRAP(AudioUnitReset(stream->inputUnit,kAudioUnitScope_Global,1));
- }
- if( stream->outputUnit )
- {
- ERR_WRAP(AudioOutputUnitStop(stream->outputUnit));
- ERR_WRAP(AudioUnitReset(stream->outputUnit,kAudioUnitScope_Global,0));
- }
- }
- if( stream->inputRingBuffer.buffer ) {
- RingBuffer_Flush( &stream->inputRingBuffer );
- bzero( (void *)stream->inputRingBuffer.buffer,
- stream->inputRingBuffer.bufferSize );
- /* advance the write point a little, so we are reading from the
- middle of the buffer. We'll need extra at the end because
- testing has shown that this helps. */
- if( stream->outputUnit )
- RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer,
- stream->inputRingBuffer.bufferSize
- / RING_BUFFER_ADVANCE_DENOMINATOR );
- }
-
- stream->xrunFlags = 0;
- stream->state = STOPPED;
-
- paErr = resetBlioRingBuffers( &stream->blio );
- if( paErr )
- return paErr;
-
-/*
- //stream->isTimeSet = FALSE;
-*/
-
- VDBUG( ( "Stream Stopped.\n" ) );
- return paNoError;
-#undef ERR_WRAP
-}
-
-static PaError AbortStream( PaStream *s )
-{
- VVDBUG(("AbortStream()->StopStream()\n"));
- VDBUG( ( "Aborting stream.\n" ) );
- /* We have nothing faster than StopStream. */
- return StopStream(s);
-}
-
-
-static PaError IsStreamStopped( PaStream *s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
- VVDBUG(("IsStreamStopped()\n"));
-
- return stream->state == STOPPED ? 1 : 0;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
- VVDBUG(("IsStreamActive()\n"));
- return ( stream->state == ACTIVE || stream->state == STOPPING );
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
- VVDBUG(("GetStreamCpuLoad()\n"));
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core.h b/pjmedia/src/pjmedia/portaudio/pa_mac_core.h
deleted file mode 100644
index f810e2f6..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * PortAudio Portable Real-Time Audio Library
- * Macintosh Core Audio specific extensions
- * portaudio.h should be included before this file.
- *
- * Copyright (c) 2005-2006 Bjorn Roche
- *
- * 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.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
- * A pointer to a paMacCoreStreamInfo may be passed as
- * the hostApiSpecificStreamInfo in the PaStreamParameters struct
- * when opening a stream or querying the format. Use NULL, for the
- * defaults. Note that for duplex streams, both infos should be the
- * same or behaviour is undefined.
- */
-typedef struct paMacCoreStreamInfo
-{
- unsigned long size; /**size of whole structure including this header */
- PaHostApiTypeId hostApiType;/**host API for which this data is intended */
- unsigned long version; /**structure version */
- unsigned long flags; /* flags to modify behaviour */
-} paMacCoreStreamInfo;
-
-/* Use this function to initialize a paMacCoreStreamInfo struct
- using the requested flags. */
-void paSetupMacCoreStreamInfo( paMacCoreStreamInfo *data, unsigned long flags )
-{
- bzero( data, sizeof( paMacCoreStreamInfo ) );
- data->size = sizeof( paMacCoreStreamInfo );
- data->hostApiType = paCoreAudio;
- data->version = 0x01;
- data->flags = flags;
-}
-
-/*
- * The following flags alter the behaviour of PA on the mac platform.
- * they can be ORed together. These should work both for opening and
- * checking a device.
- */
-/* Allows PortAudio to change things like the device's frame size,
- * which allows for much lower latency, but might disrupt the device
- * if other programs are using it, even when you are just Querying
- * the device. */
-const unsigned long paMacCore_ChangeDeviceParameters = 0x01;
-
-/* In combination with the above flag,
- * causes the stream opening to fail, unless the exact sample rates
- * are supported by the device. */
-const unsigned long paMacCore_FailIfConversionRequired = 0x02;
-
-/* These flags set the SR conversion quality, if required. The wierd ordering
- * allows Maximum Quality to be the default.*/
-const unsigned long paMacCore_ConversionQualityMin = 0x0100;
-const unsigned long paMacCore_ConversionQualityMedium = 0x0200;
-const unsigned long paMacCore_ConversionQualityLow = 0x0300;
-const unsigned long paMacCore_ConversionQualityHigh = 0x0400;
-const unsigned long paMacCore_ConversionQualityMax = 0x0000;
-
-/*
- * Here are some "preset" combinations of flags (above) to get to some
- * common configurations. THIS IS OVERKILL, but if more flags are added
- * it won't be.
- */
-/*This is the default setting: do as much sample rate conversion as possible
- * and as little mucking with the device as possible. */
-const unsigned long paMacCorePlayNice = 0x00;
-/*This setting is tuned for pro audio apps. It allows SR conversion on input
- and output, but it tries to set the appropriate SR on the device.*/
-const unsigned long paMacCorePro = 0x01;
-/*This is a setting to minimize CPU usage and still play nice.*/
-const unsigned long paMacCoreMinimizeCPUButPlayNice = 0x0100;
-/*This is a setting to minimize CPU usage, even if that means interrupting the device. */
-const unsigned long paMacCoreMinimizeCPU = 0x0101;
-
-#ifdef PA_OLD_CORE_AUDIO
-# define kAudioOutputUnitProperty_EnableIO 2003
-# define kAudioOutputUnitProperty_SetInputCallback 2005
-#endif
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.c b/pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.c
deleted file mode 100644
index f474e7b0..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Implementation of the PortAudio API for Apple AUHAL
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
- * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
- *
- * Dominic's code was based on code by Phil Burk, Darren Gibbs,
- * Gord Peters, Stephane Letz, and Greg Pfiel.
- *
- * The following people also deserve acknowledgements:
- *
- * Olivier Tristan for feedback and testing
- * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
- * interface.
- *
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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 hostaip_src
-
- This file contains the implementation
- required for blocking I/O. It is separated from pa_mac_core.c simply to ease
- development.
-*/
-
-#include "pa_mac_core_blocking.h"
-#include "pa_mac_core_internal.h"
-#include <assert.h>
-#ifdef MOSX_USE_NON_ATOMIC_FLAG_BITS
-# define OSAtomicOr32( a, b ) ( (*(b)) |= (a) )
-# define OSAtomicAnd32( a, b ) ( (*(b)) &= (a) )
-#else
-# include <libkern/OSAtomic.h>
-#endif
-
-/*
- * This fnuction determines the size of a particular sample format.
- * if the format is not recognized, this returns zero.
- */
-static size_t computeSampleSizeFromFormat( PaSampleFormat format )
-{
- switch( format ) {
- case paFloat32: return 4;
- case paInt32: return 4;
- case paInt24: return 3;
- case paInt16: return 2;
- case paInt8: case paUInt8: return 1;
- default: return 0;
- }
-}
-
-
-/*
- * Functions for initializing, resetting, and destroying BLIO structures.
- *
- */
-
-/* This should be called with the relevant info when initializing a stream for
- callback. */
-PaError initializeBlioRingBuffers(
- PaMacBlio *blio,
- PaSampleFormat inputSampleFormat,
- PaSampleFormat outputSampleFormat,
- size_t framesPerBuffer,
- long ringBufferSize,
- int inChan,
- int outChan )
-{
- void *data;
- int result;
-
- /* zeroify things */
- bzero( blio, sizeof( PaMacBlio ) );
- /* this is redundant, but the buffers are used to check
- if the bufffers have been initialized, so we do it explicitly. */
- blio->inputRingBuffer.buffer = NULL;
- blio->outputRingBuffer.buffer = NULL;
-
- /* initialize simple data */
- blio->inputSampleFormat = inputSampleFormat;
- blio->inputSampleSize = computeSampleSizeFromFormat(inputSampleFormat);
- blio->outputSampleFormat = outputSampleFormat;
- blio->outputSampleSize = computeSampleSizeFromFormat(outputSampleFormat);
- blio->framesPerBuffer = framesPerBuffer;
- blio->inChan = inChan;
- blio->outChan = outChan;
- blio->statusFlags = 0;
- blio->errors = paNoError;
-#ifdef PA_MAC_BLIO_MUTEX
- blio->isInputEmpty = false;
- blio->isOutputFull = false;
-#endif
-
- /* setup ring buffers */
-#ifdef PA_MAC_BLIO_MUTEX
- result = PaMacCore_SetUnixError( pthread_mutex_init(&(blio->inputMutex),NULL), 0 );
- if( result )
- goto error;
- result = UNIX_ERR( pthread_cond_init( &(blio->inputCond), NULL ) );
- if( result )
- goto error;
- result = UNIX_ERR( pthread_mutex_init(&(blio->outputMutex),NULL) );
- if( result )
- goto error;
- result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) );
-#endif
- if( inChan ) {
- data = calloc( ringBufferSize, blio->inputSampleSize );
- if( !data )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- assert( 0 == RingBuffer_Init(
- &blio->inputRingBuffer,
- ringBufferSize*blio->inputSampleSize,
- data ) );
- }
- if( outChan ) {
- data = calloc( ringBufferSize, blio->outputSampleSize );
- if( !data )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- assert( 0 == RingBuffer_Init(
- &blio->outputRingBuffer,
- ringBufferSize*blio->outputSampleSize,
- data ) );
- }
-
- result = resetBlioRingBuffers( blio );
- if( result )
- goto error;
-
- return 0;
-
- error:
- destroyBlioRingBuffers( blio );
- return result;
-}
-
-#ifdef PA_MAC_BLIO_MUTEX
-PaError blioSetIsInputEmpty( PaMacBlio *blio, bool isEmpty )
-{
- PaError result = paNoError;
- if( isEmpty == blio->isInputEmpty )
- goto done;
-
- /* we need to update the value. Here's what we do:
- * - Lock the mutex, so noone else can write.
- * - update the value.
- * - unlock.
- * - broadcast to all listeners.
- */
- result = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
- if( result )
- goto done;
- blio->isInputEmpty = isEmpty;
- result = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
- if( result )
- goto done;
- result = UNIX_ERR( pthread_cond_broadcast( &blio->inputCond ) );
- if( result )
- goto done;
-
- done:
- return result;
-}
-PaError blioSetIsOutputFull( PaMacBlio *blio, bool isFull )
-{
- PaError result = paNoError;
- if( isFull == blio->isOutputFull )
- goto done;
-
- /* we need to update the value. Here's what we do:
- * - Lock the mutex, so noone else can write.
- * - update the value.
- * - unlock.
- * - broadcast to all listeners.
- */
- result = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
- if( result )
- goto done;
- blio->isOutputFull = isFull;
- result = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) );
- if( result )
- goto done;
- result = UNIX_ERR( pthread_cond_broadcast( &blio->outputCond ) );
- if( result )
- goto done;
-
- done:
- return result;
-}
-#endif
-
-/* This should be called after stopping or aborting the stream, so that on next
- start, the buffers will be ready. */
-PaError resetBlioRingBuffers( PaMacBlio *blio )
-{
-#ifdef PA_MAC__BLIO_MUTEX
- int result;
-#endif
- blio->statusFlags = 0;
- if( blio->outputRingBuffer.buffer ) {
- RingBuffer_Flush( &blio->outputRingBuffer );
- bzero( blio->outputRingBuffer.buffer,
- blio->outputRingBuffer.bufferSize );
- /* Advance buffer */
- RingBuffer_AdvanceWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize );
-
- /* Update isOutputFull. */
-#ifdef PA_MAC__BLIO_MUTEX
- result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize );
- if( result )
- goto error;
-#endif
-/*
- printf( "------%d\n" , blio->framesPerBuffer );
- printf( "------%d\n" , blio->outChan );
- printf( "------%d\n" , blio->outputSampleSize );
- printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize );
-*/
- }
- if( blio->inputRingBuffer.buffer ) {
- RingBuffer_Flush( &blio->inputRingBuffer );
- bzero( blio->inputRingBuffer.buffer,
- blio->inputRingBuffer.bufferSize );
- /* Update isInputEmpty. */
-#ifdef PA_MAC__BLIO_MUTEX
- result = blioSetIsInputEmpty( blio, true );
- if( result )
- goto error;
-#endif
- }
- return paNoError;
-#ifdef PA_MAC__BLIO_MUTEX
- error:
- return result;
-#endif
-}
-
-/*This should be called when you are done with the blio. It can safely be called
- multiple times if there are no exceptions. */
-PaError destroyBlioRingBuffers( PaMacBlio *blio )
-{
- PaError result = paNoError;
- if( blio->inputRingBuffer.buffer ) {
- free( blio->inputRingBuffer.buffer );
-#ifdef PA_MAC__BLIO_MUTEX
- result = UNIX_ERR( pthread_mutex_destroy( & blio->inputMutex ) );
- if( result ) return result;
- result = UNIX_ERR( pthread_cond_destroy( & blio->inputCond ) );
- if( result ) return result;
-#endif
- }
- blio->inputRingBuffer.buffer = NULL;
- if( blio->outputRingBuffer.buffer ) {
- free( blio->outputRingBuffer.buffer );
-#ifdef PA_MAC__BLIO_MUTEX
- result = UNIX_ERR( pthread_mutex_destroy( & blio->outputMutex ) );
- if( result ) return result;
- result = UNIX_ERR( pthread_cond_destroy( & blio->outputCond ) );
- if( result ) return result;
-#endif
- }
- blio->outputRingBuffer.buffer = NULL;
-
- return result;
-}
-
-/*
- * this is the BlioCallback function. It expects to recieve a PaMacBlio Object
- * pointer as userData.
- *
- */
-int BlioCallback( const void *input, void *output, unsigned long frameCount,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData )
-{
- PaMacBlio *blio = (PaMacBlio*)userData;
- long avail;
- long toRead;
- long toWrite;
-
- /* set flags returned by OS: */
- OSAtomicOr32( statusFlags, &blio->statusFlags ) ;
-
- /* --- Handle Input Buffer --- */
- if( blio->inChan ) {
- avail = RingBuffer_GetWriteAvailable( &blio->inputRingBuffer );
-
- /* check for underflow */
- if( avail < frameCount * blio->inputSampleSize * blio->inChan )
- OSAtomicOr32( paInputOverflow, &blio->statusFlags );
-
- toRead = MIN( avail, frameCount * blio->inputSampleSize * blio->inChan );
-
- /* copy the data */
- /*printf( "reading %d\n", toRead );*/
- assert( toRead == RingBuffer_Write( &blio->inputRingBuffer, input, toRead ) );
-#ifdef PA_MAC__BLIO_MUTEX
- /* Priority inversion. See notes below. */
- blioSetIsInputEmpty( blio, false );
-#endif
- }
-
-
- /* --- Handle Output Buffer --- */
- if( blio->outChan ) {
- avail = RingBuffer_GetReadAvailable( &blio->outputRingBuffer );
-
- /* check for underflow */
- if( avail < frameCount * blio->outputSampleSize * blio->outChan )
- OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
-
- toWrite = MIN( avail, frameCount * blio->outputSampleSize * blio->outChan );
-
- if( toWrite != frameCount * blio->outputSampleSize * blio->outChan )
- bzero( ((char *)output)+toWrite,
- frameCount * blio->outputSampleSize * blio->outChan - toWrite );
- /* copy the data */
- /*printf( "writing %d\n", toWrite );*/
- assert( toWrite == RingBuffer_Read( &blio->outputRingBuffer, output, toWrite ) );
-#ifdef PA_MAC__BLIO_MUTEX
- /* We have a priority inversion here. However, we will only have to
- wait if this was true and is now false, which means we've got
- some room in the buffer.
- Hopefully problems will be minimized. */
- blioSetIsOutputFull( blio, false );
-#endif
- }
-
- return paContinue;
-}
-
-PaError ReadStream( PaStream* stream,
- void *buffer,
- unsigned long frames )
-{
- PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
- char *cbuf = (char *) buffer;
- PaError ret = paNoError;
- VVDBUG(("ReadStream()\n"));
-
- while( frames > 0 ) {
- long avail;
- long toRead;
- do {
- avail = RingBuffer_GetReadAvailable( &blio->inputRingBuffer );
-/*
- printf( "Read Buffer is %%%g full: %ld of %ld.\n",
- 100 * (float)avail / (float) blio->inputRingBuffer.bufferSize,
- avail, blio->inputRingBuffer.bufferSize );
-*/
- if( avail == 0 ) {
-#ifdef PA_MAC_BLIO_MUTEX
- /**block when empty*/
- ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
- if( ret )
- return ret;
- while( blio->isInputEmpty ) {
- ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) );
- if( ret )
- return ret;
- }
- ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
- if( ret )
- return ret;
-#else
- Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
-#endif
- }
- } while( avail == 0 );
- toRead = MIN( avail, frames * blio->inputSampleSize * blio->inChan );
- toRead -= toRead % blio->inputSampleSize * blio->inChan ;
- RingBuffer_Read( &blio->inputRingBuffer, (void *)cbuf, toRead );
- cbuf += toRead;
- frames -= toRead / ( blio->inputSampleSize * blio->inChan );
-
- if( toRead == avail ) {
-#ifdef PA_MAC_BLIO_MUTEX
- /* we just emptied the buffer, so we need to mark it as empty. */
- ret = blioSetIsInputEmpty( blio, true );
- if( ret )
- return ret;
- /* of course, in the meantime, the callback may have put some sats
- in, so
- so check for that, too, to avoid a race condition. */
- if( RingBuffer_GetReadAvailable( &blio->inputRingBuffer ) ) {
- blioSetIsInputEmpty( blio, false );
- if( ret )
- return ret;
- }
-#endif
- }
- }
-
- /* Report either paNoError or paInputOverflowed. */
- /* may also want to report other errors, but this is non-standard. */
- ret = blio->statusFlags & paInputOverflow;
-
- /* report underflow only once: */
- if( ret ) {
- OSAtomicAnd32( ~paInputOverflow, &blio->statusFlags );
- ret = paInputOverflowed;
- }
-
- return ret;
-}
-
-
-PaError WriteStream( PaStream* stream,
- const void *buffer,
- unsigned long frames )
-{
- PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
- char *cbuf = (char *) buffer;
- PaError ret = paNoError;
- VVDBUG(("WriteStream()\n"));
-
- while( frames > 0 ) {
- long avail = 0;
- long toWrite;
-
- do {
- avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
-/*
- printf( "Write Buffer is %%%g full: %ld of %ld.\n",
- 100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize,
- avail, blio->outputRingBuffer.bufferSize );
-*/
- if( avail == 0 ) {
-#ifdef PA_MAC_BLIO_MUTEX
- /*block while full*/
- ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
- if( ret )
- return ret;
- while( blio->isOutputFull ) {
- ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) );
- if( ret )
- return ret;
- }
- ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) );
- if( ret )
- return ret;
-#else
- Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
-#endif
- }
- } while( avail == 0 );
-
- toWrite = MIN( avail, frames * blio->outputSampleSize * blio->outChan );
- toWrite -= toWrite % blio->outputSampleSize * blio->outChan ;
- RingBuffer_Write( &blio->outputRingBuffer, (void *)cbuf, toWrite );
- cbuf += toWrite;
- frames -= toWrite / ( blio->outputSampleSize * blio->outChan );
-
-#ifdef PA_MAC_BLIO_MUTEX
- if( toWrite == avail ) {
- /* we just filled up the buffer, so we need to mark it as filled. */
- ret = blioSetIsOutputFull( blio, true );
- if( ret )
- return ret;
- /* of course, in the meantime, we may have emptied the buffer, so
- so check for that, too, to avoid a race condition. */
- if( RingBuffer_GetWriteAvailable( &blio->outputRingBuffer ) ) {
- blioSetIsOutputFull( blio, false );
- if( ret )
- return ret;
- }
- }
-#endif
- }
-
- /* Report either paNoError or paOutputUnderflowed. */
- /* may also want to report other errors, but this is non-standard. */
- ret = blio->statusFlags & paOutputUnderflow;
-
- /* report underflow only once: */
- if( ret ) {
- OSAtomicAnd32( ~paOutputUnderflow, &blio->statusFlags );
- ret = paOutputUnderflowed;
- }
-
- return ret;
-}
-
-/*
- *
- */
-void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
-{
- if( blio->outputRingBuffer.buffer ) {
- long avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
- while( avail != blio->outputRingBuffer.bufferSize ) {
- if( avail == 0 )
- Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
- avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
- }
- }
-}
-
-
-signed long GetStreamReadAvailable( PaStream* stream )
-{
- PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
- VVDBUG(("GetStreamReadAvailable()\n"));
-
- return RingBuffer_GetReadAvailable( &blio->inputRingBuffer )
- / ( blio->outputSampleSize * blio->outChan );
-}
-
-
-signed long GetStreamWriteAvailable( PaStream* stream )
-{
- PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
- VVDBUG(("GetStreamWriteAvailable()\n"));
-
- return RingBuffer_GetWriteAvailable( &blio->outputRingBuffer )
- / ( blio->outputSampleSize * blio->outChan );
-}
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.h b/pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.h
deleted file mode 100644
index 8185e203..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core_blocking.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Internal blocking interfaces for PortAudio Apple AUHAL implementation
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
- * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
- *
- * Dominic's code was based on code by Phil Burk, Darren Gibbs,
- * Gord Peters, Stephane Letz, and Greg Pfiel.
- *
- * The following people also deserve acknowledgements:
- *
- * Olivier Tristan for feedback and testing
- * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
- * interface.
- *
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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 hostaip_src
-*/
-
-#ifndef PA_MAC_CORE_BLOCKING_H_
-#define PA_MAC_CORE_BLOCKING_H_
-
-#include "ringbuffer.h"
-#include "portaudio.h"
-#include "pa_mac_core_utilities.h"
-
-/*
- * Number of miliseconds to busy wait whil waiting for data in blocking calls.
- */
-#define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5)
-/*
- * Define exactly one of these blocking methods
- * PA_MAC_BLIO_MUTEX is not actively maintained.
- */
-#define PA_MAC_BLIO_BUSY_WAIT
-/*
-#define PA_MAC_BLIO_MUTEX
-*/
-
-typedef struct {
- RingBuffer inputRingBuffer;
- RingBuffer outputRingBuffer;
- PaSampleFormat inputSampleFormat;
- size_t inputSampleSize;
- PaSampleFormat outputSampleFormat;
- size_t outputSampleSize;
-
- size_t framesPerBuffer;
-
- int inChan;
- int outChan;
-
- //PaStreamCallbackFlags statusFlags;
- uint32_t statusFlags;
- PaError errors;
-
- /* Here we handle blocking, using condition variables. */
-#ifdef PA_MAC_BLIO_MUTEX
- volatile bool isInputEmpty;
- pthread_mutex_t inputMutex;
- pthread_cond_t inputCond;
-
- volatile bool isOutputFull;
- pthread_mutex_t outputMutex;
- pthread_cond_t outputCond;
-#endif
-}
-PaMacBlio;
-
-/*
- * These functions operate on condition and related variables.
- */
-
-PaError initializeBlioRingBuffers(
- PaMacBlio *blio,
- PaSampleFormat inputSampleFormat,
- PaSampleFormat outputSampleFormat,
- size_t framesPerBuffer,
- long ringBufferSize,
- int inChan,
- int outChan );
-PaError destroyBlioRingBuffers( PaMacBlio *blio );
-PaError resetBlioRingBuffers( PaMacBlio *blio );
-
-int BlioCallback(
- const void *input, void *output,
- unsigned long frameCount,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData );
-
-void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio );
-
-#endif /*PA_MAC_CORE_BLOCKING_H_*/
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core_internal.h b/pjmedia/src/pjmedia/portaudio/pa_mac_core_internal.h
deleted file mode 100644
index 095b3b38..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core_internal.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Internal interfaces for PortAudio Apple AUHAL implementation
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
- * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
- *
- * Dominic's code was based on code by Phil Burk, Darren Gibbs,
- * Gord Peters, Stephane Letz, and Greg Pfiel.
- *
- * The following people also deserve acknowledgements:
- *
- * Olivier Tristan for feedback and testing
- * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
- * interface.
- *
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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 pa_mac_core
- @ingroup hostapi_src
- @author Bjorn Roche
- @brief AUHAL implementation of PortAudio
-*/
-
-#ifndef PA_MAC_CORE_INTERNAL_H__
-#define PA_MAC_CORE_INTERNAL_H__
-
-#include <AudioUnit/AudioUnit.h>
-#include <AudioToolbox/AudioToolbox.h>
-
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_allocation.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-#include "ringbuffer.h"
-
-#include "pa_mac_core_blocking.h"
-
-/* function prototypes */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#define RING_BUFFER_ADVANCE_DENOMINATOR (4)
-
-PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-signed long GetStreamReadAvailable( PaStream* stream );
-signed long GetStreamWriteAvailable( PaStream* stream );
-/* PaMacAUHAL - host api datastructure specific to this implementation */
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- /* implementation specific data goes here */
- long devCount;
- AudioDeviceID *devIds; /*array of all audio devices*/
- AudioDeviceID defaultIn;
- AudioDeviceID defaultOut;
-}
-PaMacAUHAL;
-
-
-
-/* stream data structure specifically for this implementation */
-typedef struct PaMacCoreStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- /* implementation specific data goes here */
- bool bufferProcessorIsInitialized;
- AudioUnit inputUnit;
- AudioUnit outputUnit;
- AudioDeviceID inputDevice;
- AudioDeviceID outputDevice;
- size_t userInChan;
- size_t userOutChan;
- size_t inputFramesPerBuffer;
- size_t outputFramesPerBuffer;
- PaMacBlio blio;
- /* We use this ring buffer when input and out devs are different. */
- RingBuffer inputRingBuffer;
- /* We may need to do SR conversion on input. */
- AudioConverterRef inputSRConverter;
- /* We need to preallocate an inputBuffer for reading data. */
- AudioBufferList inputAudioBufferList;
- AudioTimeStamp startTime;
- volatile PaStreamCallbackFlags xrunFlags;
- volatile bool isTimeSet;
- volatile enum {
- STOPPED = 0, /* playback is completely stopped,
- and the user has called StopStream(). */
- CALLBACK_STOPPED = 1, /* callback has requested stop,
- but user has not yet called StopStream(). */
- STOPPING = 2, /* The stream is in the process of closing.
- This state is just used internally;
- externally it is indistinguishable from
- ACTIVE.*/
- ACTIVE = 3 /* The stream is active and running. */
- } state;
- double sampleRate;
- //these may be different from the stream sample rate due to SR conversion:
- double outDeviceSampleRate;
- double inDeviceSampleRate;
-}
-PaMacCoreStream;
-
-#endif /* PA_MAC_CORE_INTERNAL_H__ */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core_old.c b/pjmedia/src/pjmedia/portaudio/pa_mac_core_old.c
deleted file mode 100644
index acb02c4a..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core_old.c
+++ /dev/null
@@ -1,914 +0,0 @@
-/*
- * $Id$
- * pa_mac_core.c
- * Implementation of PortAudio for Mac OS X CoreAudio
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Authors: Ross Bencina and Phil Burk
- * 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 <CoreAudio/CoreAudio.h>
-#include <AudioToolbox/AudioToolbox.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <assert.h>
-
-#include "portaudio.h"
-#include "pa_trace.h"
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-// ===== constants =====
-
-// ===== structs =====
-#pragma mark structs
-
-// PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation
-typedef struct PaMacCore_HAR
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
- AudioDeviceID *macCoreDeviceIds;
-}
-PaMacCoreHostApiRepresentation;
-
-typedef struct PaMacCore_DI
-{
- PaDeviceInfo inheritedDeviceInfo;
-}
-PaMacCoreDeviceInfo;
-
-// PaMacCoreStream - a stream data structure specifically for this implementation
-typedef struct PaMacCore_S
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- int primeStreamUsingCallback;
-
- AudioDeviceID inputDevice;
- AudioDeviceID outputDevice;
-
- // Processing thread management --------------
-// HANDLE abortEvent;
-// HANDLE processingThread;
-// DWORD processingThreadId;
-
- char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle
- int processingThreadPriority;
- int highThreadPriority;
- int throttledThreadPriority;
- unsigned long throttledSleepMsecs;
-
- int isStopped;
- volatile int isActive;
- volatile int stopProcessing; // stop thread once existing buffers have been returned
- volatile int abortProcessing; // stop thread immediately
-
-// DWORD allBuffersDurationMs; // used to calculate timeouts
-}
-PaMacCoreStream;
-
-// Data needed by the CoreAudio callback functions
-typedef struct PaMacCore_CD
-{
- PaMacCoreStream *stream;
- PaStreamCallback *callback;
- void *userData;
- PaUtilConverter *inputConverter;
- PaUtilConverter *outputConverter;
- void *inputBuffer;
- void *outputBuffer;
- int inputChannelCount;
- int outputChannelCount;
- PaSampleFormat inputSampleFormat;
- PaSampleFormat outputSampleFormat;
- PaUtilTriangularDitherGenerator *ditherGenerator;
-}
-PaMacClientData;
-
-// ===== CoreAudio-PortAudio bridge functions =====
-#pragma mark CoreAudio-PortAudio bridge functions
-
-// Maps CoreAudio OSStatus codes to PortAudio PaError codes
-static PaError conv_err(OSStatus error)
-{
- PaError result;
-
- switch (error) {
- case kAudioHardwareNoError:
- result = paNoError; break;
- case kAudioHardwareNotRunningError:
- result = paInternalError; break;
- case kAudioHardwareUnspecifiedError:
- result = paInternalError; break;
- case kAudioHardwareUnknownPropertyError:
- result = paInternalError; break;
- case kAudioHardwareBadPropertySizeError:
- result = paInternalError; break;
- case kAudioHardwareIllegalOperationError:
- result = paInternalError; break;
- case kAudioHardwareBadDeviceError:
- result = paInvalidDevice; break;
- case kAudioHardwareBadStreamError:
- result = paBadStreamPtr; break;
- //bennylp:
- //case kAudioHardwareUnsupportedOperationError:
- // result = paInternalError; break;
- case kAudioDeviceUnsupportedFormatError:
- result = paSampleFormatNotSupported; break;
- case kAudioDevicePermissionsError:
- result = paDeviceUnavailable; break;
- default:
- result = paInternalError;
- }
-
- return result;
-}
-
-/* This function is unused
-static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate)
-{
- struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription));
- streamDescription->mSampleRate = sampleRate;
- streamDescription->mFormatID = kAudioFormatLinearPCM;
- streamDescription->mFormatFlags = 0;
- streamDescription->mFramesPerPacket = 1;
-
- if (parameters->sampleFormat & paNonInterleaved) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved;
- streamDescription->mChannelsPerFrame = 1;
- streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat);
- streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat);
- }
- else {
- streamDescription->mChannelsPerFrame = parameters->channelCount;
- }
-
- streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame;
- streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket;
-
- if (parameters->sampleFormat & paFloat32) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
- streamDescription->mBitsPerChannel = 32;
- }
- else if (parameters->sampleFormat & paInt32) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 32;
- }
- else if (parameters->sampleFormat & paInt24) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 24;
- }
- else if (parameters->sampleFormat & paInt16) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 16;
- }
- else if (parameters->sampleFormat & paInt8) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 8;
- }
- else if (parameters->sampleFormat & paInt32) {
- streamDescription->mBitsPerChannel = 8;
- }
-
- return streamDescription;
-}
-*/
-
-static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime)
-{
- PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo));
-
- timeInfo->inputBufferAdcTime = inputTime->mSampleTime;
- timeInfo->currentTime = now->mSampleTime;
- timeInfo->outputBufferDacTime = outputTime->mSampleTime;
-
- return timeInfo;
-}
-
-// ===== support functions =====
-#pragma mark support functions
-
-static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi)
-{
- if( macCoreHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( macCoreHostApi->allocations );
- PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations );
- }
-
- PaUtil_FreeMemory( macCoreHostApi );
-}
-
-static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput)
-{
- UInt32 propSize;
- PaError err = paNoError;
- UInt32 i;
- int numChannels = 0;
- AudioBufferList *buflist;
-
- err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL));
- buflist = PaUtil_AllocateMemory(propSize);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist));
- if (!err) {
- for (i = 0; i < buflist->mNumberBuffers; ++i) {
- numChannels += buflist->mBuffers[i].mNumberChannels;
- }
-
- if (isInput)
- deviceInfo->maxInputChannels = numChannels;
- else
- deviceInfo->maxOutputChannels = numChannels;
-
- int frameLatency;
- propSize = sizeof(UInt32);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
- if (!err) {
- double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
- if (isInput) {
- deviceInfo->defaultLowInputLatency = secondLatency;
- deviceInfo->defaultHighInputLatency = secondLatency;
- }
- else {
- deviceInfo->defaultLowOutputLatency = secondLatency;
- deviceInfo->defaultHighOutputLatency = secondLatency;
- }
- }
- }
- PaUtil_FreeMemory(buflist);
-
- return err;
-}
-
-static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex )
-{
- PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo;
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
-
- PaError err = paNoError;
- UInt32 propSize;
-
- err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL));
- // FIXME: this allocation should be part of the allocations group
- char *name = PaUtil_AllocateMemory(propSize);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name));
- if (!err) {
- deviceInfo->name = name;
- }
-
- Float64 sampleRate;
- propSize = sizeof(Float64);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
- if (!err) {
- deviceInfo->defaultSampleRate = sampleRate;
- }
-
-
- // Get channel info
- err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1);
- err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0);
-
- return err;
-}
-
-static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- PaUtilHostApiRepresentation *hostApi;
- PaMacCoreDeviceInfo *deviceInfoArray;
-
- // initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized.
- hostApi = &macCoreHostApi->inheritedHostApiRep;
- hostApi->info.deviceCount = 0;
- hostApi->info.defaultInputDevice = paNoDevice;
- hostApi->info.defaultOutputDevice = paNoDevice;
-
- UInt32 propsize;
- AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL);
- int numDevices = propsize / sizeof(AudioDeviceID);
- hostApi->info.deviceCount = numDevices;
- if (numDevices > 0) {
- hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
- if( !hostApi->deviceInfos )
- {
- return paInsufficientMemory;
- }
-
- // allocate all device info structs in a contiguous block
- deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory(
- macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices );
- if( !deviceInfoArray )
- {
- return paInsufficientMemory;
- }
-
- macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize);
- AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds);
-
- AudioDeviceID defaultInputDevice, defaultOutputDevice;
- propsize = sizeof(AudioDeviceID);
- AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice);
- AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice);
-
- UInt32 i;
- for (i = 0; i < numDevices; ++i) {
- if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) {
- hostApi->info.defaultInputDevice = i;
- }
- if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) {
- hostApi->info.defaultOutputDevice = i;
- }
- InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex);
- hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo);
- }
- }
-
- return result;
-}
-
-static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput)
-{
- UInt32 propSize = sizeof(AudioStreamBasicDescription);
- AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize);
-
- streamDescription->mSampleRate = sampleRate;
- streamDescription->mFormatID = 0;
- streamDescription->mFormatFlags = 0;
- streamDescription->mBytesPerPacket = 0;
- streamDescription->mFramesPerPacket = 0;
- streamDescription->mBytesPerFrame = 0;
- streamDescription->mChannelsPerFrame = 0;
- streamDescription->mBitsPerChannel = 0;
- streamDescription->mReserved = 0;
-
- OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription);
- PaUtil_FreeMemory(streamDescription);
- return result;
-}
-
-static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount)
-{
- int frameSpacing, channelSpacing;
- if (destination->inputSampleFormat & paNonInterleaved) {
- frameSpacing = 1;
- channelSpacing = destination->inputChannelCount;
- }
- else {
- frameSpacing = destination->inputChannelCount;
- channelSpacing = 1;
- }
-
- AudioBuffer const *inputBuffer = &source->mBuffers[0];
- void *coreAudioBuffer = inputBuffer->mData;
- void *portAudioBuffer = destination->inputBuffer;
- UInt32 i, streamNumber, streamChannel;
- for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) {
- if (streamChannel >= inputBuffer->mNumberChannels) {
- ++streamNumber;
- inputBuffer = &source->mBuffers[streamNumber];
- coreAudioBuffer = inputBuffer->mData;
- streamChannel = 0;
- }
- destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator);
- coreAudioBuffer += sizeof(Float32);
- portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing;
- }
- return noErr;
-}
-
-static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount)
-{
- int frameSpacing, channelSpacing;
- if (source->outputSampleFormat & paNonInterleaved) {
- frameSpacing = 1;
- channelSpacing = source->outputChannelCount;
- }
- else {
- frameSpacing = source->outputChannelCount;
- channelSpacing = 1;
- }
-
- AudioBuffer *outputBuffer = &destination->mBuffers[0];
- void *coreAudioBuffer = outputBuffer->mData;
- void *portAudioBuffer = source->outputBuffer;
- UInt32 i, streamNumber, streamChannel;
- for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) {
- if (streamChannel >= outputBuffer->mNumberChannels) {
- ++streamNumber;
- outputBuffer = &destination->mBuffers[streamNumber];
- coreAudioBuffer = outputBuffer->mData;
- streamChannel = 0;
- }
- source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL);
- coreAudioBuffer += sizeof(Float32);
- portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing;
- }
- return noErr;
-}
-
-static OSStatus AudioIOProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData)
-{
- PaMacClientData *clientData = (PaMacClientData *)inClientData;
- PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
-
- PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
-
- AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
- unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
-
- if (clientData->inputBuffer) {
- CopyInputData(clientData, inInputData, frameCount);
- }
- PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
- if (clientData->outputBuffer) {
- CopyOutputData(outOutputData, clientData, frameCount);
- }
-
- PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
-
- if (result == paComplete || result == paAbort) {
- Pa_StopStream(clientData->stream);
- }
-
- PaUtil_FreeMemory( timeInfo );
- return noErr;
-}
-
-// This is not for input-only streams, this is for streams where the input device is different from the output device
-static OSStatus AudioInputProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData)
-{
- PaMacClientData *clientData = (PaMacClientData *)inClientData;
- PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
-
- PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
-
- AudioBuffer const *inputBuffer = &inInputData->mBuffers[0];
- unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32));
-
- CopyInputData(clientData, inInputData, frameCount);
- PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
-
- PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
- if( result == paComplete || result == paAbort )
- Pa_StopStream(clientData->stream);
- PaUtil_FreeMemory( timeInfo );
- return noErr;
-}
-
-// This is not for output-only streams, this is for streams where the input device is different from the output device
-static OSStatus AudioOutputProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData)
-{
- PaMacClientData *clientData = (PaMacClientData *)inClientData;
- //PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
-
- PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
-
- AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
- unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
-
- //clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
-
- CopyOutputData(outOutputData, clientData, frameCount);
-
- PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
- return noErr;
-}
-
-static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput)
-{
- PaError result = paNoError;
-
- double actualSampleRate;
- UInt32 propSize = sizeof(double);
- result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate));
-
- result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate));
-
- if (result == paNoError && actualSampleRate != sampleRate) {
- result = paInvalidSampleRate;
- }
-
- return result;
-}
-
-static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput)
-{
- PaError result = paNoError;
- UInt32 preferredFramesPerBuffer = framesPerBuffer;
- // while (preferredFramesPerBuffer > UINT32_MAX) {
- // preferredFramesPerBuffer /= 2;
- // }
-
- UInt32 actualFramesPerBuffer;
- UInt32 propSize = sizeof(UInt32);
- result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer));
-
- result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer));
-
- if (result != paNoError) {
- // do nothing
- }
- else if (actualFramesPerBuffer > framesPerBuffer) {
- result = paBufferTooSmall;
- }
- else if (actualFramesPerBuffer < framesPerBuffer) {
- result = paBufferTooBig;
- }
-
- return result;
-}
-
-static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput)
-{
- PaError err = paNoError;
- err = SetSampleRate(device, sampleRate, isInput);
- if( err == paNoError )
- err = SetFramesPerBuffer(device, framesPerBuffer, isInput);
- return err;
-}
-
-// ===== PortAudio functions =====
-#pragma mark PortAudio functions
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif // __cplusplus
-
- PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
-
- CleanUp(macCoreHostApi);
-}
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
- PaDeviceInfo *deviceInfo;
-
- PaError result = paNoError;
- if (inputParameters) {
- deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
- if (inputParameters->channelCount > deviceInfo->maxInputChannels)
- result = paInvalidChannelCount;
- else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) {
- result = paInvalidSampleRate;
- }
- }
- if (outputParameters && result == paNoError) {
- deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
- if (outputParameters->channelCount > deviceInfo->maxOutputChannels)
- result = paInvalidChannelCount;
- else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) {
- result = paInvalidSampleRate;
- }
- }
-
- return result;
-}
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError err = paNoError;
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi;
- PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream));
- stream->isActive = 0;
- stream->isStopped = 1;
- stream->inputDevice = kAudioDeviceUnknown;
- stream->outputDevice = kAudioDeviceUnknown;
-
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- ( (streamCallback)
- ? &macCoreHostApi->callbackStreamInterface
- : &macCoreHostApi->blockingStreamInterface ),
- streamCallback, userData );
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
- *s = (PaStream*)stream;
- PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData));
- clientData->stream = stream;
- clientData->callback = streamCallback;
- clientData->userData = userData;
- clientData->inputBuffer = 0;
- clientData->outputBuffer = 0;
- clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator));
- PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator);
-
- if (inputParameters != NULL) {
- stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device];
- clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags);
- clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount);
- clientData->inputChannelCount = inputParameters->channelCount;
- clientData->inputSampleFormat = inputParameters->sampleFormat;
- err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1);
- }
-
- if (err == paNoError && outputParameters != NULL) {
- stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device];
- clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags);
- clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount);
- clientData->outputChannelCount = outputParameters->channelCount;
- clientData->outputSampleFormat = outputParameters->sampleFormat;
- err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0);
- }
-
- if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) {
- AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice;
-
- AudioDeviceAddIOProc(device, AudioIOProc, clientData);
- }
- else {
- // using different devices for input and output
- AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData);
- AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData);
- }
-
- return err;
-}
-
-// Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted.
-static PaError CloseStream( PaStream* s )
-{
- PaError err = paNoError;
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-
- if (stream->inputDevice != kAudioDeviceUnknown) {
- if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
- err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc));
- }
- else {
- err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc));
- err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc));
- }
- }
- else {
- err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc));
- }
-
- return err;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
- PaError err = paNoError;
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- if (stream->inputDevice != kAudioDeviceUnknown) {
- if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
- err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc));
- }
- else {
- err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc));
- err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc));
- }
- }
- else {
- err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc));
- }
-
- stream->isActive = 1;
- stream->isStopped = 0;
- return err;
-}
-
-static PaError AbortStream( PaStream *s )
-{
- PaError err = paNoError;
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- if (stream->inputDevice != kAudioDeviceUnknown) {
- if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
- err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc));
- }
- else {
- err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc));
- err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc));
- }
- }
- else {
- err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc));
- }
-
- stream->isActive = 0;
- stream->isStopped = 1;
- return err;
-}
-
-static PaError StopStream( PaStream *s )
-{
- // TODO: this should be nicer than abort
- return AbortStream(s);
-}
-
-static PaError IsStreamStopped( PaStream *s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- return stream->isStopped;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- return stream->isActive;
-}
-
-
-static PaTime GetStreamTime( PaStream *s )
-{
- OSStatus err;
- PaTime result;
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp));
- if (stream->inputDevice != kAudioDeviceUnknown) {
- err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp);
- }
- else {
- err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp);
- }
-
- result = err ? 0 : timeStamp->mSampleTime;
- PaUtil_FreeMemory(timeStamp);
-
- return result;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-// As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams.
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- return paInternalError;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- return paInternalError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- return paInternalError;
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- return paInternalError;
-}
-
-// HostAPI-specific initialization function
-PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) );
- if( !macCoreHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- macCoreHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !macCoreHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- *hostApi = &macCoreHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paCoreAudio;
- (*hostApi)->info.name = "CoreAudio";
-
- result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex);
- if (result != paNoError) {
- goto error;
- }
-
- // Set up the proper callbacks to this HostApi's functions
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( macCoreHostApi ) {
- CleanUp(macCoreHostApi);
- }
-
- return result;
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.c b/pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.c
deleted file mode 100644
index 5a0f8b8d..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.c
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- * Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation)
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
- * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
- *
- * Dominic's code was based on code by Phil Burk, Darren Gibbs,
- * Gord Peters, Stephane Letz, and Greg Pfiel.
- *
- * The following people also deserve acknowledgements:
- *
- * Olivier Tristan for feedback and testing
- * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
- * interface.
- *
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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 hostapi_src
-*/
-
-#include "pa_mac_core_utilities.h"
-
-
-PaError PaMacCore_SetUnixError( int err, int line )
-{
- PaError ret;
- const char *errorText;
-
- if( err == 0 )
- {
- return paNoError;
- }
-
- ret = paNoError;
- errorText = strerror( err );
-
- /** Map Unix error to PaError. Pretty much the only one that maps
- is ENOMEM. */
- if( err == ENOMEM )
- ret = paInsufficientMemory;
- else
- ret = paInternalError;
-
- DBUG(("%d on line %d: msg='%s'\n", err, line, errorText));
- PaUtil_SetLastHostErrorInfo( paCoreAudio, err, errorText );
-
- return ret;
-}
-
-/*
- * Translates MacOS generated errors into PaErrors
- */
-PaError PaMacCore_SetError(OSStatus error, int line, int isError)
-{
- /*FIXME: still need to handle possible ComponentResult values.*/
- /* unfortunately, they don't seem to be documented anywhere.*/
- PaError result;
- const char *errorType;
- const char *errorText;
-
- switch (error) {
- case kAudioHardwareNoError:
- return paNoError;
- case kAudioHardwareNotRunningError:
- errorText = "Audio Hardware Not Running";
- result = paInternalError; break;
- case kAudioHardwareUnspecifiedError:
- errorText = "Unspecified Audio Hardware Error";
- result = paInternalError; break;
- case kAudioHardwareUnknownPropertyError:
- errorText = "Audio Hardware: Unknown Property";
- result = paInternalError; break;
- case kAudioHardwareBadPropertySizeError:
- errorText = "Audio Hardware: Bad Property Size";
- result = paInternalError; break;
- case kAudioHardwareIllegalOperationError:
- errorText = "Audio Hardware: Illegal Operation";
- result = paInternalError; break;
- case kAudioHardwareBadDeviceError:
- errorText = "Audio Hardware: Bad Device";
- result = paInvalidDevice; break;
- case kAudioHardwareBadStreamError:
- errorText = "Audio Hardware: BadStream";
- result = paBadStreamPtr; break;
- case kAudioHardwareUnsupportedOperationError:
- errorText = "Audio Hardware: Unsupported Operation";
- result = paInternalError; break;
- case kAudioDeviceUnsupportedFormatError:
- errorText = "Audio Device: Unsupported Format";
- result = paSampleFormatNotSupported; break;
- case kAudioDevicePermissionsError:
- errorText = "Audio Device: Permissions Error";
- result = paDeviceUnavailable; break;
- /* Audio Unit Errors: http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_units/chapter_5_section_3.html */
- case kAudioUnitErr_InvalidProperty:
- errorText = "Audio Unit: Invalid Property";
- result = paInternalError; break;
- case kAudioUnitErr_InvalidParameter:
- errorText = "Audio Unit: Invalid Parameter";
- result = paInternalError; break;
- case kAudioUnitErr_NoConnection:
- errorText = "Audio Unit: No Connection";
- result = paInternalError; break;
- case kAudioUnitErr_FailedInitialization:
- errorText = "Audio Unit: Initialization Failed";
- result = paInternalError; break;
- case kAudioUnitErr_TooManyFramesToProcess:
- errorText = "Audio Unit: Too Many Frames";
- result = paInternalError; break;
- case kAudioUnitErr_IllegalInstrument:
- errorText = "Audio Unit: Illegal Instrument";
- result = paInternalError; break;
- case kAudioUnitErr_InstrumentTypeNotFound:
- errorText = "Audio Unit: Instrument Type Not Found";
- result = paInternalError; break;
- case kAudioUnitErr_InvalidFile:
- errorText = "Audio Unit: Invalid File";
- result = paInternalError; break;
- case kAudioUnitErr_UnknownFileType:
- errorText = "Audio Unit: Unknown File Type";
- result = paInternalError; break;
- case kAudioUnitErr_FileNotSpecified:
- errorText = "Audio Unit: File Not Specified";
- result = paInternalError; break;
- case kAudioUnitErr_FormatNotSupported:
- errorText = "Audio Unit: Format Not Supported";
- result = paInternalError; break;
- case kAudioUnitErr_Uninitialized:
- errorText = "Audio Unit: Unitialized";
- result = paInternalError; break;
- case kAudioUnitErr_InvalidScope:
- errorText = "Audio Unit: Invalid Scope";
- result = paInternalError; break;
- case kAudioUnitErr_PropertyNotWritable:
- errorText = "Audio Unit: PropertyNotWritable";
- result = paInternalError; break;
- case kAudioUnitErr_InvalidPropertyValue:
- errorText = "Audio Unit: Invalid Property Value";
- result = paInternalError; break;
- case kAudioUnitErr_PropertyNotInUse:
- errorText = "Audio Unit: Property Not In Use";
- result = paInternalError; break;
- case kAudioUnitErr_Initialized:
- errorText = "Audio Unit: Initialized";
- result = paInternalError; break;
- case kAudioUnitErr_InvalidOfflineRender:
- errorText = "Audio Unit: Invalid Offline Render";
- result = paInternalError; break;
- case kAudioUnitErr_Unauthorized:
- errorText = "Audio Unit: Unauthorized";
- result = paInternalError; break;
- case kAudioUnitErr_CannotDoInCurrentContext:
- errorText = "Audio Unit: cannot do in current context";
- result = paInternalError; break;
- default:
- errorText = "Unknown Error";
- result = paInternalError;
- }
-
- if (isError)
- errorType = "Error";
- else
- errorType = "Warning";
-
- if ((int)error < -99999 || (int)error > 99999)
- DBUG(("%s on line %d: err='%4s', msg='%s'\n", errorType, line, (const char *)&error, errorText));
- else
- DBUG(("%s on line %d: err=%d, 0x%x, msg='%s'\n", errorType, line, (int)error, (unsigned)error, errorText));
-
- PaUtil_SetLastHostErrorInfo( paCoreAudio, error, errorText );
-
- return result;
-}
-
-/*
- * This function computes an appropriate ring buffer size given
- * a requested latency (in seconds), sample rate and framesPerBuffer.
- *
- * The returned ringBufferSize is computed using the following
- * constraints:
- * - it must be at least 4.
- * - it must be at least 3x framesPerBuffer.
- * - it must be at least 2x the suggestedLatency.
- * - it must be a power of 2.
- * This function attempts to compute the minimum such size.
- *
- * FEEDBACK: too liberal/conservative/another way?
- */
-long computeRingBufferSize( const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- long inputFramesPerBuffer,
- long outputFramesPerBuffer,
- double sampleRate )
-{
- long ringSize;
- int index;
- int i;
- double latencyTimesChannelCount ;
- long framesPerBufferTimesChannelCount ;
-
- VVDBUG(( "computeRingBufferSize()\n" ));
-
- assert( inputParameters || outputParameters );
-
- if( outputParameters && inputParameters )
- {
- latencyTimesChannelCount = MAX(
- inputParameters->suggestedLatency * inputParameters->channelCount,
- outputParameters->suggestedLatency * outputParameters->channelCount );
- framesPerBufferTimesChannelCount = MAX(
- inputFramesPerBuffer * inputParameters->channelCount,
- outputFramesPerBuffer * outputParameters->channelCount );
- }
- else if( outputParameters )
- {
- latencyTimesChannelCount
- = outputParameters->suggestedLatency * outputParameters->channelCount;
- framesPerBufferTimesChannelCount
- = outputFramesPerBuffer * outputParameters->channelCount;
- }
- else /* we have inputParameters */
- {
- latencyTimesChannelCount
- = inputParameters->suggestedLatency * inputParameters->channelCount;
- framesPerBufferTimesChannelCount
- = inputFramesPerBuffer * inputParameters->channelCount;
- }
-
- ringSize = (long) ( latencyTimesChannelCount * sampleRate * 2 + .5);
- VDBUG( ( "suggested latency * channelCount: %d\n", (int) (latencyTimesChannelCount*sampleRate) ) );
- if( ringSize < framesPerBufferTimesChannelCount * 3 )
- ringSize = framesPerBufferTimesChannelCount * 3 ;
- VDBUG(("framesPerBuffer*channelCount:%d\n",(int)framesPerBufferTimesChannelCount));
- VDBUG(("Ringbuffer size (1): %d\n", (int)ringSize ));
-
- /* make sure it's at least 4 */
- ringSize = MAX( ringSize, 4 );
-
- /* round up to the next power of 2 */
- index = -1;
- for( i=0; i<sizeof(long)*8; ++i )
- if( ringSize >> i & 0x01 )
- index = i;
- assert( index > 0 );
- if( ringSize <= ( 0x01 << index ) )
- ringSize = 0x01 << index ;
- else
- ringSize = 0x01 << ( index + 1 );
-
- VDBUG(( "Final Ringbuffer size (2): %d\n", (int)ringSize ));
- return ringSize;
-}
-
-
-/*
- * Durring testing of core audio, I found that serious crashes could occur
- * if properties such as sample rate were changed multiple times in rapid
- * succession. The function below has some fancy logic to make sure that changes
- * are acknowledged before another is requested. That seems to help a lot.
- */
-
-OSStatus propertyProc(
- AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- void* inClientData )
-{
- MutexAndBool *mab = (MutexAndBool *) inClientData;
- mab->once = TRUE;
- pthread_mutex_unlock( &(mab->mutex) );
- return noErr;
-}
-
-/* sets the value of the given property and waits for the change to
- be acknowledged, and returns the final value, which is not guaranteed
- by this function to be the same as the desired value. Obviously, this
- function can only be used for data whose input and output are the
- same size and format, and their size and format are known in advance.*/
-PaError AudioDeviceSetPropertyNowAndWaitForChange(
- AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- UInt32 inPropertyDataSize,
- const void *inPropertyData,
- void *outPropertyData )
-{
- OSStatus macErr;
- int unixErr;
- MutexAndBool mab;
- UInt32 outPropertyDataSize = inPropertyDataSize;
-
- /* First, see if it already has that value. If so, return. */
- macErr = AudioDeviceGetProperty( inDevice, inChannel,
- isInput, inPropertyID,
- &outPropertyDataSize, outPropertyData );
- if( macErr )
- goto failMac2;
- if( inPropertyDataSize!=outPropertyDataSize )
- return paInternalError;
- if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) )
- return paNoError;
-
- /* setup and lock mutex */
- mab.once = FALSE;
- unixErr = pthread_mutex_init( &mab.mutex, NULL );
- if( unixErr )
- goto failUnix2;
- unixErr = pthread_mutex_lock( &mab.mutex );
- if( unixErr )
- goto failUnix;
-
- /* add property listener */
- macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput,
- inPropertyID, propertyProc,
- &mab );
- if( macErr )
- goto failMac;
- /* set property */
- macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel,
- isInput, inPropertyID,
- inPropertyDataSize, inPropertyData );
- if( macErr ) {
- /* we couldn't set the property, so we'll just unlock the mutex
- and move on. */
- pthread_mutex_unlock( &mab.mutex );
- }
-
- /* wait for property to change */
- unixErr = pthread_mutex_lock( &mab.mutex );
- if( unixErr )
- goto failUnix;
-
- /* now read the property back out */
- macErr = AudioDeviceGetProperty( inDevice, inChannel,
- isInput, inPropertyID,
- &outPropertyDataSize, outPropertyData );
- if( macErr )
- goto failMac;
- /* cleanup */
- AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
- inPropertyID, propertyProc );
- unixErr = pthread_mutex_unlock( &mab.mutex );
- if( unixErr )
- goto failUnix2;
- unixErr = pthread_mutex_destroy( &mab.mutex );
- if( unixErr )
- goto failUnix2;
-
- return paNoError;
-
- failUnix:
- pthread_mutex_destroy( &mab.mutex );
- AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
- inPropertyID, propertyProc );
-
- failUnix2:
- DBUG( ("Error #%d while setting a device property: %s\n", unixErr, strerror( unixErr ) ) );
- return paUnanticipatedHostError;
-
- failMac:
- pthread_mutex_destroy( &mab.mutex );
- AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
- inPropertyID, propertyProc );
- failMac2:
- return ERR( macErr );
-}
-
-/*
- * Sets the sample rate the HAL device.
- * if requireExact: set the sample rate or fail.
- *
- * otherwise : set the exact sample rate.
- * If that fails, check for available sample rates, and choose one
- * higher than the requested rate. If there isn't a higher one,
- * just use the highest available.
- */
-PaError setBestSampleRateForDevice( const AudioDeviceID device,
- const bool isOutput,
- const bool requireExact,
- const Float64 desiredSrate )
-{
- /*FIXME: changing the sample rate is disruptive to other programs using the
- device, so it might be good to offer a custom flag to not change the
- sample rate and just do conversion. (in my casual tests, there is
- no disruption unless the sample rate really does need to change) */
- const bool isInput = isOutput ? 0 : 1;
- Float64 srate;
- UInt32 propsize = sizeof( Float64 );
- OSErr err;
- AudioValueRange *ranges;
- int i=0;
- Float64 max = -1; /*the maximum rate available*/
- Float64 best = -1; /*the lowest sample rate still greater than desired rate*/
- VDBUG(("Setting sample rate for device %ld to %g.\n",device,(float)desiredSrate));
-
- /* -- try setting the sample rate -- */
- err = AudioDeviceSetPropertyNowAndWaitForChange(
- device, 0, isInput,
- kAudioDevicePropertyNominalSampleRate,
- propsize, &desiredSrate, &srate );
- if( err )
- return err;
-
- /* -- if the rate agrees, and we got no errors, we are done -- */
- if( !err && srate == desiredSrate )
- return paNoError;
- /* -- we've failed if the rates disagree and we are setting input -- */
- if( requireExact )
- return paInvalidSampleRate;
-
- /* -- generate a list of available sample rates -- */
- err = AudioDeviceGetPropertyInfo( device, 0, isInput,
- kAudioDevicePropertyAvailableNominalSampleRates,
- &propsize, NULL );
- if( err )
- return ERR( err );
- ranges = (AudioValueRange *)calloc( 1, propsize );
- if( !ranges )
- return paInsufficientMemory;
- err = AudioDeviceGetProperty( device, 0, isInput,
- kAudioDevicePropertyAvailableNominalSampleRates,
- &propsize, ranges );
- if( err )
- {
- free( ranges );
- return ERR( err );
- }
- VDBUG(("Requested sample rate of %g was not available.\n", (float)desiredSrate));
- VDBUG(("%lu Available Sample Rates are:\n",propsize/sizeof(AudioValueRange)));
-#ifdef MAC_CORE_VERBOSE_DEBUG
- for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
- VDBUG( ("\t%g-%g\n",
- (float) ranges[i].mMinimum,
- (float) ranges[i].mMaximum ) );
-#endif
- VDBUG(("-----\n"));
-
- /* -- now pick the best available sample rate -- */
- for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
- {
- if( ranges[i].mMaximum > max ) max = ranges[i].mMaximum;
- if( ranges[i].mMinimum > desiredSrate ) {
- if( best < 0 )
- best = ranges[i].mMinimum;
- else if( ranges[i].mMinimum < best )
- best = ranges[i].mMinimum;
- }
- }
- if( best < 0 )
- best = max;
- VDBUG( ("Maximum Rate %g. best is %g.\n", max, best ) );
- free( ranges );
-
- /* -- set the sample rate -- */
- propsize = sizeof( best );
- err = AudioDeviceSetPropertyNowAndWaitForChange(
- device, 0, isInput,
- kAudioDevicePropertyNominalSampleRate,
- propsize, &best, &srate );
- if( err )
- return err;
-
- if( err )
- return ERR( err );
- /* -- if the set rate matches, we are done -- */
- if( srate == best )
- return paNoError;
-
- /* -- otherwise, something wierd happened: we didn't set the rate, and we got no errors. Just bail. */
- return paInternalError;
-}
-
-
-/*
- Attempts to set the requestedFramesPerBuffer. If it can't set the exact
- value, it settles for something smaller if available. If nothing smaller
- is available, it uses the smallest available size.
- actualFramesPerBuffer will be set to the actual value on successful return.
- OK to pass NULL to actualFramesPerBuffer.
- The logic is very simmilar too setBestSampleRate only failure here is
- not usually catastrophic.
-*/
-PaError setBestFramesPerBuffer( const AudioDeviceID device,
- const bool isOutput,
- unsigned long requestedFramesPerBuffer,
- unsigned long *actualFramesPerBuffer )
-{
- UInt32 afpb;
- const bool isInput = !isOutput;
- UInt32 propsize = sizeof(UInt32);
- OSErr err;
- Float64 min = -1; /*the min blocksize*/
- Float64 best = -1; /*the best blocksize*/
- int i=0;
- AudioValueRange *ranges;
-
- if( actualFramesPerBuffer == NULL )
- actualFramesPerBuffer = &afpb;
-
-
- /* -- try and set exact FPB -- */
- err = AudioDeviceSetProperty( device, NULL, 0, isInput,
- kAudioDevicePropertyBufferFrameSize,
- propsize, &requestedFramesPerBuffer);
- err = AudioDeviceGetProperty( device, 0, isInput,
- kAudioDevicePropertyBufferFrameSize,
- &propsize, actualFramesPerBuffer);
- if( err )
- return ERR( err );
- if( *actualFramesPerBuffer == requestedFramesPerBuffer )
- return paNoError; /* we are done */
-
- /* -- fetch available block sizes -- */
- err = AudioDeviceGetPropertyInfo( device, 0, isInput,
- kAudioDevicePropertyBufferSizeRange,
- &propsize, NULL );
- if( err )
- return ERR( err );
- ranges = (AudioValueRange *)calloc( 1, propsize );
- if( !ranges )
- return paInsufficientMemory;
- err = AudioDeviceGetProperty( device, 0, isInput,
- kAudioDevicePropertyBufferSizeRange,
- &propsize, ranges );
- if( err )
- {
- free( ranges );
- return ERR( err );
- }
- VDBUG(("Requested block size of %lu was not available.\n",
- requestedFramesPerBuffer ));
- VDBUG(("%lu Available block sizes are:\n",propsize/sizeof(AudioValueRange)));
-#ifdef MAC_CORE_VERBOSE_DEBUG
- for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
- VDBUG( ("\t%g-%g\n",
- (float) ranges[i].mMinimum,
- (float) ranges[i].mMaximum ) );
-#endif
- VDBUG(("-----\n"));
-
- /* --- now pick the best available framesPerBuffer -- */
- for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
- {
- if( min == -1 || ranges[i].mMinimum < min ) min = ranges[i].mMinimum;
- if( ranges[i].mMaximum < requestedFramesPerBuffer ) {
- if( best < 0 )
- best = ranges[i].mMaximum;
- else if( ranges[i].mMaximum > best )
- best = ranges[i].mMaximum;
- }
- }
- if( best == -1 )
- best = min;
- VDBUG( ("Minimum FPB %g. best is %g.\n", min, best ) );
- free( ranges );
-
- /* --- set the buffer size (ignore errors) -- */
- requestedFramesPerBuffer = (UInt32) best ;
- propsize = sizeof( UInt32 );
- err = AudioDeviceSetProperty( device, NULL, 0, isInput,
- kAudioDevicePropertyBufferSize,
- propsize, &requestedFramesPerBuffer );
- /* --- read the property to check that it was set -- */
- err = AudioDeviceGetProperty( device, 0, isInput,
- kAudioDevicePropertyBufferSize,
- &propsize, actualFramesPerBuffer );
-
- if( err )
- return ERR( err );
-
- return paNoError;
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.h b/pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.h
deleted file mode 100644
index 63ef22a9..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_core_utilities.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation)
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
- * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
- *
- * Dominic's code was based on code by Phil Burk, Darren Gibbs,
- * Gord Peters, Stephane Letz, and Greg Pfiel.
- *
- * The following people also deserve acknowledgements:
- *
- * Olivier Tristan for feedback and testing
- * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
- * interface.
- *
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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 hostapi_src
-*/
-
-#ifndef PA_MAC_CORE_UTILITIES_H__
-#define PA_MAC_CORE_UTILITIES_H__
-
-#include <pthread.h>
-#include "portaudio.h"
-#include "pa_util.h"
-#include <AudioUnit/AudioUnit.h>
-#include <AudioToolbox/AudioToolbox.h>
-
-#ifndef MIN
-#define MIN(a, b) (((a)<(b))?(a):(b))
-#endif
-
-#ifndef MAX
-#define MAX(a, b) (((a)<(b))?(b):(a))
-#endif
-
-#define ERR(mac_error) PaMacCore_SetError(mac_error, __LINE__, 1 )
-#define WARNING(mac_error) PaMacCore_SetError(mac_error, __LINE__, 0 )
-
-
-/* Help keep track of AUHAL element numbers */
-#define INPUT_ELEMENT (1)
-#define OUTPUT_ELEMENT (0)
-
-/* Normal level of debugging: fine for most apps that don't mind the occational warning being printf'ed */
-/*
- */
-#define MAC_CORE_DEBUG
-#ifdef MAC_CORE_DEBUG
-# define DBUG(MSG) do { printf("||PaMacCore (AUHAL)|| "); printf MSG ; fflush(stdout); } while(0)
-#else
-# define DBUG(MSG)
-#endif
-
-/* Verbose Debugging: useful for developement */
-/*
-#define MAC_CORE_VERBOSE_DEBUG
-*/
-#ifdef MAC_CORE_VERBOSE_DEBUG
-# define VDBUG(MSG) do { printf("||PaMacCore (v )|| "); printf MSG ; fflush(stdout); } while(0)
-#else
-# define VDBUG(MSG)
-#endif
-
-/* Very Verbose Debugging: Traces every call. */
-/*
-#define MAC_CORE_VERY_VERBOSE_DEBUG
- */
-#ifdef MAC_CORE_VERY_VERBOSE_DEBUG
-# define VVDBUG(MSG) do { printf("||PaMacCore (vv)|| "); printf MSG ; fflush(stdout); } while(0)
-#else
-# define VVDBUG(MSG)
-#endif
-
-
-
-
-
-#define UNIX_ERR(err) PaMacCore_SetUnixError( err, __LINE__ )
-
-PaError PaMacCore_SetUnixError( int err, int line );
-
-/*
- * Translates MacOS generated errors into PaErrors
- */
-PaError PaMacCore_SetError(OSStatus error, int line, int isError);
-
-/*
- * This function computes an appropriate ring buffer size given
- * a requested latency (in seconds), sample rate and framesPerBuffer.
- *
- * The returned ringBufferSize is computed using the following
- * constraints:
- * - it must be at least 4.
- * - it must be at least 3x framesPerBuffer.
- * - it must be at least 2x the suggestedLatency.
- * - it must be a power of 2.
- * This function attempts to compute the minimum such size.
- *
- */
-long computeRingBufferSize( const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- long inputFramesPerBuffer,
- long outputFramesPerBuffer,
- double sampleRate );
-
-/*
- * Durring testing of core audio, I found that serious crashes could occur
- * if properties such as sample rate were changed multiple times in rapid
- * succession. The function below has some fancy logic to make sure that changes
- * are acknowledged before another is requested. That seems to help a lot.
- */
-
-typedef struct {
- bool once; /* I didn't end up using this. bdr */
- pthread_mutex_t mutex;
-} MutexAndBool ;
-
-OSStatus propertyProc(
- AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- void* inClientData );
-
-/* sets the value of the given property and waits for the change to
- be acknowledged, and returns the final value, which is not guaranteed
- by this function to be the same as the desired value. Obviously, this
- function can only be used for data whose input and output are the
- same size and format, and their size and format are known in advance.*/
-PaError AudioDeviceSetPropertyNowAndWaitForChange(
- AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- UInt32 inPropertyDataSize,
- const void *inPropertyData,
- void *outPropertyData );
-
-/*
- * Sets the sample rate the HAL device.
- * if requireExact: set the sample rate or fail.
- *
- * otherwise : set the exact sample rate.
- * If that fails, check for available sample rates, and choose one
- * higher than the requested rate. If there isn't a higher one,
- * just use the highest available.
- */
-PaError setBestSampleRateForDevice( const AudioDeviceID device,
- const bool isOutput,
- const bool requireExact,
- const Float64 desiredSrate );
-/*
- Attempts to set the requestedFramesPerBuffer. If it can't set the exact
- value, it settles for something smaller if available. If nothing smaller
- is available, it uses the smallest available size.
- actualFramesPerBuffer will be set to the actual value on successful return.
- OK to pass NULL to actualFramesPerBuffer.
- The logic is very simmilar too setBestSampleRate only failure here is
- not usually catastrophic.
-*/
-PaError setBestFramesPerBuffer( const AudioDeviceID device,
- const bool isOutput,
- unsigned long requestedFramesPerBuffer,
- unsigned long *actualFramesPerBuffer );
-
-#ifdef PA_OLD_CORE_AUDIO
-# define kAudioUnitErr_PropertyNotInUse 10850
-# define kAudioHardwareUnsupportedOperationError 1
-# define kAudioUnitErr_Initialized 10849
-# define kAudioUnitErr_InvalidOfflineRender 10848
-# define kAudioUnitErr_Unauthorized 10847
-#endif
-
-#endif /* PA_MAC_CORE_UTILITIES_H__*/
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_mac_hostapis.c b/pjmedia/src/pjmedia/portaudio/pa_mac_hostapis.c
deleted file mode 100644
index 89622d6b..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_mac_hostapis.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * $Id$
- * Portable Audio I/O Library Macintosh initialization table
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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 macosx_src
-Mac OS host API initialization function table.
-*/
-
-
-#include "pa_hostapi.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
- PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
- PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
- PaError PaMacSm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
- PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
- PaError PaMacAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-PaUtilHostApiInitializer *paHostApiInitializers[] =
-{
-#ifdef PA_USE_COREAUDIO
- PaMacCore_Initialize,
-#endif
-
-#ifdef PA_USE_SM
- PaMacSm_Initialize,
-#endif
-
-#ifdef PA_USE_JACK
- PaJack_Initialize,
-#endif
-
-#ifdef PA_USE_ASIO
- PaMacAsio_Initialize,
-#endif
-
- PaSkeleton_Initialize, /* just for testing */
-
- 0 /* NULL terminated array */
-};
-
-
-int paDefaultHostApiIndex = 0;
diff --git a/pjmedia/src/pjmedia/portaudio/pa_process.c b/pjmedia/src/pjmedia/portaudio/pa_process.c
deleted file mode 100644
index cf711d41..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_process.c
+++ /dev/null
@@ -1,1756 +0,0 @@
-/*
- * $Id: pa_process.c,v 1.1.2.48 2004/12/13 09:48:43 rossbencina Exp $
- * Portable Audio I/O Library
- * streamCallback <-> host buffer processing adapter
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Buffer Processor implementation.
-
- The code in this file is not optimised yet - although it's not clear that
- it needs to be. there may appear to be redundancies
- that could be factored into common functions, but the redundanceis are left
- intentionally as each appearance may have different optimisation possibilities.
-
- The optimisations which are planned involve only converting data in-place
- where possible, rather than copying to the temp buffer(s).
-
- Note that in the extreme case of being able to convert in-place, and there
- being no conversion necessary there should be some code which short-circuits
- the operation.
-
- @todo Consider cache tilings for intereave<->deinterleave.
-
- @todo implement timeInfo->currentTime int PaUtil_BeginBufferProcessing()
-
- @todo specify and implement some kind of logical policy for handling the
- underflow and overflow stream flags when the underflow/overflow overlaps
- multiple user buffers/callbacks.
-
- @todo provide support for priming the buffers with data from the callback.
- The client interface is now implemented through PaUtil_SetNoInput()
- which sets bp->hostInputChannels[0][0].data to zero. However this is
- currently only implemented in NonAdaptingProcess(). It shouldn't be
- needed for AdaptingInputOnlyProcess() (no priming should ever be
- requested for AdaptingInputOnlyProcess()).
- Not sure if additional work should be required to make it work with
- AdaptingOutputOnlyProcess, but it definitely is required for
- AdaptingProcess.
-
- @todo implement PaUtil_SetNoOutput for AdaptingProcess
-
- @todo don't allocate temp buffers for blocking streams unless they are
- needed. At the moment they are needed, but perhaps for host APIs
- where the implementation passes a buffer to the host they could be
- used.
-*/
-
-
-#include <assert.h>
-#include <string.h> /* memset() */
-
-#include "pa_process.h"
-#include "pa_util.h"
-
-
-#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024
-
-#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
-
-
-/* greatest common divisor - PGCD in French */
-static unsigned long GCD( unsigned long a, unsigned long b )
-{
- return (b==0) ? a : GCD( b, a%b);
-}
-
-/* least common multiple - PPCM in French */
-static unsigned long LCM( unsigned long a, unsigned long b )
-{
- return (a*b) / GCD(a,b);
-}
-
-#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
-
-static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
-{
- unsigned long result = 0;
- unsigned long i;
- unsigned long lcm;
-
- assert( M > 0 );
- assert( N > 0 );
-
- lcm = LCM( M, N );
- for( i = M; i < lcm; i += M )
- result = PA_MAX_( result, i % N );
-
- return result;
-}
-
-
-PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
- int inputChannelCount, PaSampleFormat userInputSampleFormat,
- PaSampleFormat hostInputSampleFormat,
- int outputChannelCount, PaSampleFormat userOutputSampleFormat,
- PaSampleFormat hostOutputSampleFormat,
- double sampleRate,
- PaStreamFlags streamFlags,
- unsigned long framesPerUserBuffer,
- unsigned long framesPerHostBuffer,
- PaUtilHostBufferSizeMode hostBufferSizeMode,
- PaStreamCallback *streamCallback, void *userData )
-{
- PaError result = paNoError;
- PaError bytesPerSample;
- unsigned long tempInputBufferSize, tempOutputBufferSize;
-
- /* initialize buffer ptrs to zero so they can be freed if necessary in error */
- bp->tempInputBuffer = 0;
- bp->tempInputBufferPtrs = 0;
- bp->tempOutputBuffer = 0;
- bp->tempOutputBufferPtrs = 0;
-
- bp->framesPerUserBuffer = framesPerUserBuffer;
- bp->framesPerHostBuffer = framesPerHostBuffer;
-
- bp->inputChannelCount = inputChannelCount;
- bp->outputChannelCount = outputChannelCount;
-
- bp->hostBufferSizeMode = hostBufferSizeMode;
-
- bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0;
- bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0;
-
- if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
- {
- bp->useNonAdaptingProcess = 1;
- bp->initialFramesInTempInputBuffer = 0;
- bp->initialFramesInTempOutputBuffer = 0;
-
- if( hostBufferSizeMode == paUtilFixedHostBufferSize
- || hostBufferSizeMode == paUtilBoundedHostBufferSize )
- {
- bp->framesPerTempBuffer = framesPerHostBuffer;
- }
- else /* unknown host buffer size */
- {
- bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
- }
- }
- else
- {
- bp->framesPerTempBuffer = framesPerUserBuffer;
-
- if( hostBufferSizeMode == paUtilFixedHostBufferSize
- && framesPerHostBuffer % framesPerUserBuffer == 0 )
- {
- bp->useNonAdaptingProcess = 1;
- bp->initialFramesInTempInputBuffer = 0;
- bp->initialFramesInTempOutputBuffer = 0;
- }
- else
- {
- bp->useNonAdaptingProcess = 0;
-
- if( inputChannelCount > 0 && outputChannelCount > 0 )
- {
- /* full duplex */
- if( hostBufferSizeMode == paUtilFixedHostBufferSize )
- {
- unsigned long frameShift =
- CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
-
- if( framesPerUserBuffer > framesPerHostBuffer )
- {
- bp->initialFramesInTempInputBuffer = frameShift;
- bp->initialFramesInTempOutputBuffer = 0;
- }
- else
- {
- bp->initialFramesInTempInputBuffer = 0;
- bp->initialFramesInTempOutputBuffer = frameShift;
- }
- }
- else /* variable host buffer size, add framesPerUserBuffer latency */
- {
- bp->initialFramesInTempInputBuffer = 0;
- bp->initialFramesInTempOutputBuffer = framesPerUserBuffer;
- }
- }
- else
- {
- /* half duplex */
- bp->initialFramesInTempInputBuffer = 0;
- bp->initialFramesInTempOutputBuffer = 0;
- }
- }
- }
-
-
- bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
- bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
-
-
- if( inputChannelCount > 0 )
- {
- bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
- if( bytesPerSample > 0 )
- {
- bp->bytesPerHostInputSample = bytesPerSample;
- }
- else
- {
- result = bytesPerSample;
- goto error;
- }
-
- bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
- if( bytesPerSample > 0 )
- {
- bp->bytesPerUserInputSample = bytesPerSample;
- }
- else
- {
- result = bytesPerSample;
- goto error;
- }
-
- bp->inputConverter =
- PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags );
-
- bp->inputZeroer = PaUtil_SelectZeroer( hostInputSampleFormat );
-
- bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
-
-
- tempInputBufferSize =
- bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
-
- bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
- if( bp->tempInputBuffer == 0 )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- if( bp->framesInTempInputBuffer > 0 )
- memset( bp->tempInputBuffer, 0, tempInputBufferSize );
-
- if( userInputSampleFormat & paNonInterleaved )
- {
- bp->tempInputBufferPtrs =
- (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
- if( bp->tempInputBufferPtrs == 0 )
- {
- result = paInsufficientMemory;
- goto error;
- }
- }
-
- bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
- PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
- if( bp->hostInputChannels[0] == 0 )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
- }
-
- if( outputChannelCount > 0 )
- {
- bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
- if( bytesPerSample > 0 )
- {
- bp->bytesPerHostOutputSample = bytesPerSample;
- }
- else
- {
- result = bytesPerSample;
- goto error;
- }
-
- bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
- if( bytesPerSample > 0 )
- {
- bp->bytesPerUserOutputSample = bytesPerSample;
- }
- else
- {
- result = bytesPerSample;
- goto error;
- }
-
- bp->outputConverter =
- PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
-
- bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );
-
- bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
-
- tempOutputBufferSize =
- bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
-
- bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
- if( bp->tempOutputBuffer == 0 )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- if( bp->framesInTempOutputBuffer > 0 )
- memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
-
- if( userOutputSampleFormat & paNonInterleaved )
- {
- bp->tempOutputBufferPtrs =
- (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
- if( bp->tempOutputBufferPtrs == 0 )
- {
- result = paInsufficientMemory;
- goto error;
- }
- }
-
- bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
- PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
- if( bp->hostOutputChannels[0] == 0 )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
- }
-
- PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
-
- bp->samplePeriod = 1. / sampleRate;
-
- bp->streamCallback = streamCallback;
- bp->userData = userData;
-
- return result;
-
-error:
- if( bp->tempInputBuffer )
- PaUtil_FreeMemory( bp->tempInputBuffer );
-
- if( bp->tempInputBufferPtrs )
- PaUtil_FreeMemory( bp->tempInputBufferPtrs );
-
- if( bp->hostInputChannels[0] )
- PaUtil_FreeMemory( bp->hostInputChannels[0] );
-
- if( bp->tempOutputBuffer )
- PaUtil_FreeMemory( bp->tempOutputBuffer );
-
- if( bp->tempOutputBufferPtrs )
- PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
-
- if( bp->hostOutputChannels[0] )
- PaUtil_FreeMemory( bp->hostOutputChannels[0] );
-
- return result;
-}
-
-
-void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
-{
- if( bp->tempInputBuffer )
- PaUtil_FreeMemory( bp->tempInputBuffer );
-
- if( bp->tempInputBufferPtrs )
- PaUtil_FreeMemory( bp->tempInputBufferPtrs );
-
- if( bp->hostInputChannels[0] )
- PaUtil_FreeMemory( bp->hostInputChannels[0] );
-
- if( bp->tempOutputBuffer )
- PaUtil_FreeMemory( bp->tempOutputBuffer );
-
- if( bp->tempOutputBufferPtrs )
- PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
-
- if( bp->hostOutputChannels[0] )
- PaUtil_FreeMemory( bp->hostOutputChannels[0] );
-}
-
-
-void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )
-{
- unsigned long tempInputBufferSize, tempOutputBufferSize;
-
- bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
- bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
-
- if( bp->framesInTempInputBuffer > 0 )
- {
- tempInputBufferSize =
- bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;
- memset( bp->tempInputBuffer, 0, tempInputBufferSize );
- }
-
- if( bp->framesInTempOutputBuffer > 0 )
- {
- tempOutputBufferSize =
- bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;
- memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
- }
-}
-
-
-unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bp )
-{
- return bp->initialFramesInTempInputBuffer;
-}
-
-
-unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bp )
-{
- return bp->initialFramesInTempOutputBuffer;
-}
-
-
-void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
- unsigned long frameCount )
-{
- if( frameCount == 0 )
- bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
- else
- bp->hostInputFrameCount[0] = frameCount;
-}
-
-
-void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )
-{
- assert( bp->inputChannelCount > 0 );
-
- bp->hostInputChannels[0][0].data = 0;
-}
-
-
-void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data, unsigned int stride )
-{
- assert( channel < bp->inputChannelCount );
-
- bp->hostInputChannels[0][channel].data = data;
- bp->hostInputChannels[0][channel].stride = stride;
-}
-
-
-void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
- unsigned int firstChannel, void *data, unsigned int channelCount )
-{
- unsigned int i;
- unsigned int channel = firstChannel;
- unsigned char *p = (unsigned char*)data;
-
- if( channelCount == 0 )
- channelCount = bp->inputChannelCount;
-
- assert( firstChannel < bp->inputChannelCount );
- assert( firstChannel + channelCount <= bp->inputChannelCount );
-
- for( i=0; i< channelCount; ++i )
- {
- bp->hostInputChannels[0][channel+i].data = p;
- p += bp->bytesPerHostInputSample;
- bp->hostInputChannels[0][channel+i].stride = channelCount;
- }
-}
-
-
-void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data )
-{
- assert( channel < bp->inputChannelCount );
-
- bp->hostInputChannels[0][channel].data = data;
- bp->hostInputChannels[0][channel].stride = 1;
-}
-
-
-void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
- unsigned long frameCount )
-{
- bp->hostInputFrameCount[1] = frameCount;
-}
-
-
-void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data, unsigned int stride )
-{
- assert( channel < bp->inputChannelCount );
-
- bp->hostInputChannels[1][channel].data = data;
- bp->hostInputChannels[1][channel].stride = stride;
-}
-
-
-void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
- unsigned int firstChannel, void *data, unsigned int channelCount )
-{
- unsigned int i;
- unsigned int channel = firstChannel;
- unsigned char *p = (unsigned char*)data;
-
- if( channelCount == 0 )
- channelCount = bp->inputChannelCount;
-
- assert( firstChannel < bp->inputChannelCount );
- assert( firstChannel + channelCount <= bp->inputChannelCount );
-
- for( i=0; i< channelCount; ++i )
- {
- bp->hostInputChannels[1][channel+i].data = p;
- p += bp->bytesPerHostInputSample;
- bp->hostInputChannels[1][channel+i].stride = channelCount;
- }
-}
-
-
-void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data )
-{
- assert( channel < bp->inputChannelCount );
-
- bp->hostInputChannels[1][channel].data = data;
- bp->hostInputChannels[1][channel].stride = 1;
-}
-
-
-void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
- unsigned long frameCount )
-{
- if( frameCount == 0 )
- bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
- else
- bp->hostOutputFrameCount[0] = frameCount;
-}
-
-
-void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )
-{
- assert( bp->outputChannelCount > 0 );
-
- bp->hostOutputChannels[0][0].data = 0;
-}
-
-
-void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data, unsigned int stride )
-{
- assert( channel < bp->outputChannelCount );
-
- bp->hostOutputChannels[0][channel].data = data;
- bp->hostOutputChannels[0][channel].stride = stride;
-}
-
-
-void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
- unsigned int firstChannel, void *data, unsigned int channelCount )
-{
- unsigned int i;
- unsigned int channel = firstChannel;
- unsigned char *p = (unsigned char*)data;
-
- if( channelCount == 0 )
- channelCount = bp->outputChannelCount;
-
- assert( firstChannel < bp->outputChannelCount );
- assert( firstChannel + channelCount <= bp->outputChannelCount );
-
- for( i=0; i< channelCount; ++i )
- {
- bp->hostOutputChannels[0][channel+i].data = p;
- p += bp->bytesPerHostOutputSample;
- bp->hostOutputChannels[0][channel+i].stride = channelCount;
- }
-}
-
-
-void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data )
-{
- assert( channel < bp->outputChannelCount );
-
- bp->hostOutputChannels[0][channel].data = data;
- bp->hostOutputChannels[0][channel].stride = 1;
-}
-
-
-void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
- unsigned long frameCount )
-{
- bp->hostOutputFrameCount[1] = frameCount;
-}
-
-
-void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data, unsigned int stride )
-{
- assert( channel < bp->outputChannelCount );
-
- bp->hostOutputChannels[1][channel].data = data;
- bp->hostOutputChannels[1][channel].stride = stride;
-}
-
-
-void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
- unsigned int firstChannel, void *data, unsigned int channelCount )
-{
- unsigned int i;
- unsigned int channel = firstChannel;
- unsigned char *p = (unsigned char*)data;
-
- if( channelCount == 0 )
- channelCount = bp->outputChannelCount;
-
- assert( firstChannel < bp->outputChannelCount );
- assert( firstChannel + channelCount <= bp->outputChannelCount );
-
- for( i=0; i< channelCount; ++i )
- {
- bp->hostOutputChannels[1][channel+i].data = p;
- p += bp->bytesPerHostOutputSample;
- bp->hostOutputChannels[1][channel+i].stride = channelCount;
- }
-}
-
-
-void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
- unsigned int channel, void *data )
-{
- assert( channel < bp->outputChannelCount );
-
- bp->hostOutputChannels[1][channel].data = data;
- bp->hostOutputChannels[1][channel].stride = 1;
-}
-
-
-void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,
- PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )
-{
- bp->timeInfo = timeInfo;
-
- /* the first streamCallback will be called to process samples which are
- currently in the input buffer before the ones starting at the timeInfo time */
-
- bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
-
- bp->timeInfo->currentTime = 0; /** FIXME: @todo time info currentTime not implemented */
-
- /* the first streamCallback will be called to generate samples which will be
- outputted after the frames currently in the output buffer have been
- outputted. */
- bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
-
- bp->callbackStatusFlags = callbackStatusFlags;
-
- bp->hostInputFrameCount[1] = 0;
- bp->hostOutputFrameCount[1] = 0;
-}
-
-
-/*
- NonAdaptingProcess() is a simple buffer copying adaptor that can handle
- both full and half duplex copies. It processes framesToProcess frames,
- broken into blocks bp->framesPerTempBuffer long.
- This routine can be used when the streamCallback doesn't care what length
- the buffers are, or when framesToProcess is an integer multiple of
- bp->framesPerTempBuffer, in which case streamCallback will always be called
- with bp->framesPerTempBuffer samples.
-*/
-static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
- int *streamCallbackResult,
- PaUtilChannelDescriptor *hostInputChannels,
- PaUtilChannelDescriptor *hostOutputChannels,
- unsigned long framesToProcess )
-{
- void *userInput, *userOutput;
- unsigned char *srcBytePtr, *destBytePtr;
- unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int i;
- unsigned long frameCount;
- unsigned long framesToGo = framesToProcess;
- unsigned long framesProcessed = 0;
-
-
- if( *streamCallbackResult == paContinue )
- {
- do
- {
- frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );
-
- /* configure user input buffer and convert input data (host -> user) */
- if( bp->inputChannelCount == 0 )
- {
- /* no input */
- userInput = 0;
- }
- else /* there are input channels */
- {
- /*
- could use more elaborate logic here and sometimes process
- buffers in-place.
- */
-
- destBytePtr = (unsigned char *)bp->tempInputBuffer;
-
- if( bp->userInputIsInterleaved )
- {
- destSampleStrideSamples = bp->inputChannelCount;
- destChannelStrideBytes = bp->bytesPerUserInputSample;
- userInput = bp->tempInputBuffer;
- }
- else /* user input is not interleaved */
- {
- destSampleStrideSamples = 1;
- destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
-
- /* setup non-interleaved ptrs */
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
- i * bp->bytesPerUserInputSample * frameCount;
- }
-
- userInput = bp->tempInputBufferPtrs;
- }
-
- if( !bp->hostInputChannels[0][0].data )
- {
- /* no input was supplied (see PaUtil_SetNoInput), so
- zero the input buffer */
-
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );
- destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
- }
- }
- else
- {
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- bp->inputConverter( destBytePtr, destSampleStrideSamples,
- hostInputChannels[i].data,
- hostInputChannels[i].stride,
- frameCount, &bp->ditherGenerator );
-
- destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
-
- /* advance src ptr for next iteration */
- hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
- frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
- }
- }
- }
-
- /* configure user output buffer */
- if( bp->outputChannelCount == 0 )
- {
- /* no output */
- userOutput = 0;
- }
- else /* there are output channels */
- {
- if( bp->userOutputIsInterleaved )
- {
- userOutput = bp->tempOutputBuffer;
- }
- else /* user output is not interleaved */
- {
- for( i = 0; i < bp->outputChannelCount; ++i )
- {
- bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
- i * bp->bytesPerUserOutputSample * frameCount;
- }
-
- userOutput = bp->tempOutputBufferPtrs;
- }
- }
-
- *streamCallbackResult = bp->streamCallback( userInput, userOutput,
- frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
-
- if( *streamCallbackResult == paAbort )
- {
- /* callback returned paAbort, don't advance framesProcessed
- and framesToGo, they will be handled below */
- }
- else
- {
- bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
- bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
-
- /* convert output data (user -> host) */
-
- if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
- {
- /*
- could use more elaborate logic here and sometimes process
- buffers in-place.
- */
-
- srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
-
- if( bp->userOutputIsInterleaved )
- {
- srcSampleStrideSamples = bp->outputChannelCount;
- srcChannelStrideBytes = bp->bytesPerUserOutputSample;
- }
- else /* user output is not interleaved */
- {
- srcSampleStrideSamples = 1;
- srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
- }
-
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- bp->outputConverter( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- srcBytePtr, srcSampleStrideSamples,
- frameCount, &bp->ditherGenerator );
-
- srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
- }
-
- framesProcessed += frameCount;
-
- framesToGo -= frameCount;
- }
- }
- while( framesToGo > 0 && *streamCallbackResult == paContinue );
- }
-
- if( framesToGo > 0 )
- {
- /* zero any remaining frames output. There will only be remaining frames
- if the callback has returned paComplete or paAbort */
-
- frameCount = framesToGo;
-
- if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
- {
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- bp->outputZeroer( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- frameCount );
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
- }
-
- framesProcessed += frameCount;
- }
-
- return framesProcessed;
-}
-
-
-/*
- AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
- converts data from the input buffers into the temporary input buffer,
- when the temporary input buffer is full, it calls the streamCallback.
-*/
-static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
- int *streamCallbackResult,
- PaUtilChannelDescriptor *hostInputChannels,
- unsigned long framesToProcess )
-{
- void *userInput, *userOutput;
- unsigned char *destBytePtr;
- unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int i;
- unsigned long frameCount;
- unsigned long framesToGo = framesToProcess;
- unsigned long framesProcessed = 0;
-
- userOutput = 0;
-
- do
- {
- frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
- ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
- : framesToGo;
-
- /* convert frameCount samples into temp buffer */
-
- if( bp->userInputIsInterleaved )
- {
- destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
- bp->bytesPerUserInputSample * bp->inputChannelCount *
- bp->framesInTempInputBuffer;
-
- destSampleStrideSamples = bp->inputChannelCount;
- destChannelStrideBytes = bp->bytesPerUserInputSample;
-
- userInput = bp->tempInputBuffer;
- }
- else /* user input is not interleaved */
- {
- destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
- bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
-
- destSampleStrideSamples = 1;
- destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
-
- /* setup non-interleaved ptrs */
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
- i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
- }
-
- userInput = bp->tempInputBufferPtrs;
- }
-
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- bp->inputConverter( destBytePtr, destSampleStrideSamples,
- hostInputChannels[i].data,
- hostInputChannels[i].stride,
- frameCount, &bp->ditherGenerator );
-
- destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
-
- /* advance src ptr for next iteration */
- hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
- frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
- }
-
- bp->framesInTempInputBuffer += frameCount;
-
- if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
- {
- /**
- @todo (non-critical optimisation)
- The conditional below implements the continue/complete/abort mechanism
- simply by continuing on iterating through the input buffer, but not
- passing the data to the callback. With care, the outer loop could be
- terminated earlier, thus some unneeded conversion cycles would be
- saved.
- */
- if( *streamCallbackResult == paContinue )
- {
- bp->timeInfo->outputBufferDacTime = 0;
-
- *streamCallbackResult = bp->streamCallback( userInput, userOutput,
- bp->framesPerUserBuffer, bp->timeInfo,
- bp->callbackStatusFlags, bp->userData );
-
- bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
- }
-
- bp->framesInTempInputBuffer = 0;
- }
-
- framesProcessed += frameCount;
-
- framesToGo -= frameCount;
- }while( framesToGo > 0 );
-
- return framesProcessed;
-}
-
-
-/*
- AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
- It converts data from the temporary output buffer, to the output buffers,
- when the temporary output buffer is empty, it calls the streamCallback.
-*/
-static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
- int *streamCallbackResult,
- PaUtilChannelDescriptor *hostOutputChannels,
- unsigned long framesToProcess )
-{
- void *userInput, *userOutput;
- unsigned char *srcBytePtr;
- unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int i;
- unsigned long frameCount;
- unsigned long framesToGo = framesToProcess;
- unsigned long framesProcessed = 0;
-
- do
- {
- if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )
- {
- userInput = 0;
-
- /* setup userOutput */
- if( bp->userOutputIsInterleaved )
- {
- userOutput = bp->tempOutputBuffer;
- }
- else /* user output is not interleaved */
- {
- for( i = 0; i < bp->outputChannelCount; ++i )
- {
- bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
- i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
- }
-
- userOutput = bp->tempOutputBufferPtrs;
- }
-
- bp->timeInfo->inputBufferAdcTime = 0;
-
- *streamCallbackResult = bp->streamCallback( userInput, userOutput,
- bp->framesPerUserBuffer, bp->timeInfo,
- bp->callbackStatusFlags, bp->userData );
-
- if( *streamCallbackResult == paAbort )
- {
- /* if the callback returned paAbort, we disregard its output */
- }
- else
- {
- bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
-
- bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
- }
- }
-
- if( bp->framesInTempOutputBuffer > 0 )
- {
- /* convert frameCount frames from user buffer to host buffer */
-
- frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );
-
- if( bp->userOutputIsInterleaved )
- {
- srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
- bp->bytesPerUserOutputSample * bp->outputChannelCount *
- (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-
- srcSampleStrideSamples = bp->outputChannelCount;
- srcChannelStrideBytes = bp->bytesPerUserOutputSample;
- }
- else /* user output is not interleaved */
- {
- srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
- bp->bytesPerUserOutputSample *
- (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-
- srcSampleStrideSamples = 1;
- srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
- }
-
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- bp->outputConverter( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- srcBytePtr, srcSampleStrideSamples,
- frameCount, &bp->ditherGenerator );
-
- srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
-
- bp->framesInTempOutputBuffer -= frameCount;
- }
- else
- {
- /* no more user data is available because the callback has returned
- paComplete or paAbort. Fill the remainder of the host buffer
- with zeros.
- */
-
- frameCount = framesToGo;
-
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- bp->outputZeroer( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- frameCount );
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
- }
-
- framesProcessed += frameCount;
-
- framesToGo -= frameCount;
-
- }while( framesToGo > 0 );
-
- return framesProcessed;
-}
-
-/* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from
- tempOutputBuffer to hostOutputChannels. This includes data conversion
- and interleaving.
-*/
-static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
-{
- unsigned long maxFramesToCopy;
- PaUtilChannelDescriptor *hostOutputChannels;
- unsigned int frameCount;
- unsigned char *srcBytePtr;
- unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int i;
-
- /* copy frames from user to host output buffers */
- while( bp->framesInTempOutputBuffer > 0 &&
- ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
- {
- maxFramesToCopy = bp->framesInTempOutputBuffer;
-
- /* select the output buffer set (1st or 2nd) */
- if( bp->hostOutputFrameCount[0] > 0 )
- {
- hostOutputChannels = bp->hostOutputChannels[0];
- frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );
- }
- else
- {
- hostOutputChannels = bp->hostOutputChannels[1];
- frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );
- }
-
- if( bp->userOutputIsInterleaved )
- {
- srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
- bp->bytesPerUserOutputSample * bp->outputChannelCount *
- (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-
- srcSampleStrideSamples = bp->outputChannelCount;
- srcChannelStrideBytes = bp->bytesPerUserOutputSample;
- }
- else /* user output is not interleaved */
- {
- srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
- bp->bytesPerUserOutputSample *
- (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
-
- srcSampleStrideSamples = 1;
- srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
- }
-
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- bp->outputConverter( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- srcBytePtr, srcSampleStrideSamples,
- frameCount, &bp->ditherGenerator );
-
- srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
-
- if( bp->hostOutputFrameCount[0] > 0 )
- bp->hostOutputFrameCount[0] -= frameCount;
- else
- bp->hostOutputFrameCount[1] -= frameCount;
-
- bp->framesInTempOutputBuffer -= frameCount;
- }
-}
-
-/*
- AdaptingProcess is a full duplex adapting buffer processor. It converts
- data from the temporary output buffer into the host output buffers, then
- from the host input buffers into the temporary input buffers. Calling the
- streamCallback when necessary.
- When processPartialUserBuffers is 0, all available input data will be
- consumed and all available output space will be filled. When
- processPartialUserBuffers is non-zero, as many full user buffers
- as possible will be processed, but partial buffers will not be consumed.
-*/
-static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
- int *streamCallbackResult, int processPartialUserBuffers )
-{
- void *userInput, *userOutput;
- unsigned long framesProcessed = 0;
- unsigned long framesAvailable;
- unsigned long endProcessingMinFrameCount;
- unsigned long maxFramesToCopy;
- PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
- unsigned int frameCount;
- unsigned char *destBytePtr;
- unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int i, j;
-
-
- framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */
-
- if( processPartialUserBuffers )
- endProcessingMinFrameCount = 0;
- else
- endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
-
- /* Fill host output with remaining frames in user output (tempOutputBuffer) */
- CopyTempOutputBuffersToHostOutputBuffers( bp );
-
- while( framesAvailable > endProcessingMinFrameCount )
- {
-
- if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )
- {
- /* the callback will not be called any more, so zero what remains
- of the host output buffers */
-
- for( i=0; i<2; ++i )
- {
- frameCount = bp->hostOutputFrameCount[i];
- if( frameCount > 0 )
- {
- hostOutputChannels = bp->hostOutputChannels[i];
-
- for( j=0; j<bp->outputChannelCount; ++j )
- {
- bp->outputZeroer( hostOutputChannels[j].data,
- hostOutputChannels[j].stride,
- frameCount );
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +
- frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;
- }
- bp->hostOutputFrameCount[i] = 0;
- }
- }
- }
-
-
- /* copy frames from host to user input buffers */
- while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
- ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
- {
- maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
-
- /* select the input buffer set (1st or 2nd) */
- if( bp->hostInputFrameCount[0] > 0 )
- {
- hostInputChannels = bp->hostInputChannels[0];
- frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );
- }
- else
- {
- hostInputChannels = bp->hostInputChannels[1];
- frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );
- }
-
- /* configure conversion destination pointers */
- if( bp->userInputIsInterleaved )
- {
- destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
- bp->bytesPerUserInputSample * bp->inputChannelCount *
- bp->framesInTempInputBuffer;
-
- destSampleStrideSamples = bp->inputChannelCount;
- destChannelStrideBytes = bp->bytesPerUserInputSample;
- }
- else /* user input is not interleaved */
- {
- destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
- bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
-
- destSampleStrideSamples = 1;
- destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
- }
-
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- bp->inputConverter( destBytePtr, destSampleStrideSamples,
- hostInputChannels[i].data,
- hostInputChannels[i].stride,
- frameCount, &bp->ditherGenerator );
-
- destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
-
- /* advance src ptr for next iteration */
- hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
- frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
- }
-
- if( bp->hostInputFrameCount[0] > 0 )
- bp->hostInputFrameCount[0] -= frameCount;
- else
- bp->hostInputFrameCount[1] -= frameCount;
-
- bp->framesInTempInputBuffer += frameCount;
-
- /* update framesAvailable and framesProcessed based on input consumed
- unless something is very wrong this will also correspond to the
- amount of output generated */
- framesAvailable -= frameCount;
- framesProcessed += frameCount;
- }
-
- /* call streamCallback */
- if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
- bp->framesInTempOutputBuffer == 0 )
- {
- if( *streamCallbackResult == paContinue )
- {
- /* setup userInput */
- if( bp->userInputIsInterleaved )
- {
- userInput = bp->tempInputBuffer;
- }
- else /* user input is not interleaved */
- {
- for( i = 0; i < bp->inputChannelCount; ++i )
- {
- bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
- i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
- }
-
- userInput = bp->tempInputBufferPtrs;
- }
-
- /* setup userOutput */
- if( bp->userOutputIsInterleaved )
- {
- userOutput = bp->tempOutputBuffer;
- }
- else /* user output is not interleaved */
- {
- for( i = 0; i < bp->outputChannelCount; ++i )
- {
- bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
- i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
- }
-
- userOutput = bp->tempOutputBufferPtrs;
- }
-
- /* call streamCallback */
-
- *streamCallbackResult = bp->streamCallback( userInput, userOutput,
- bp->framesPerUserBuffer, bp->timeInfo,
- bp->callbackStatusFlags, bp->userData );
-
- bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
- bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
-
- bp->framesInTempInputBuffer = 0;
-
- if( *streamCallbackResult == paAbort )
- bp->framesInTempOutputBuffer = 0;
- else
- bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
- }
- else
- {
- /* paComplete or paAbort has already been called. */
-
- bp->framesInTempInputBuffer = 0;
- }
- }
-
- /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels)
- Means to process the user output provided by the callback. Has to be called after
- each callback. */
- CopyTempOutputBuffersToHostOutputBuffers( bp );
-
- }
-
- return framesProcessed;
-}
-
-
-unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
-{
- unsigned long framesToProcess, framesToGo;
- unsigned long framesProcessed = 0;
-
- if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0
- && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */
- && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )
- {
- assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
- (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
- }
-
- assert( *streamCallbackResult == paContinue
- || *streamCallbackResult == paComplete
- || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */
-
- if( bp->useNonAdaptingProcess )
- {
- if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
- {
- /* full duplex non-adapting process, splice buffers if they are
- different lengths */
-
- framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */
-
- do{
- unsigned long noInputInputFrameCount;
- unsigned long *hostInputFrameCount;
- PaUtilChannelDescriptor *hostInputChannels;
- unsigned long noOutputOutputFrameCount;
- unsigned long *hostOutputFrameCount;
- PaUtilChannelDescriptor *hostOutputChannels;
- unsigned long framesProcessedThisIteration;
-
- if( !bp->hostInputChannels[0][0].data )
- {
- /* no input was supplied (see PaUtil_SetNoInput)
- NonAdaptingProcess knows how to deal with this
- */
- noInputInputFrameCount = framesToGo;
- hostInputFrameCount = &noInputInputFrameCount;
- hostInputChannels = 0;
- }
- else if( bp->hostInputFrameCount[0] != 0 )
- {
- hostInputFrameCount = &bp->hostInputFrameCount[0];
- hostInputChannels = bp->hostInputChannels[0];
- }
- else
- {
- hostInputFrameCount = &bp->hostInputFrameCount[1];
- hostInputChannels = bp->hostInputChannels[1];
- }
-
- if( !bp->hostOutputChannels[0][0].data )
- {
- /* no output was supplied (see PaUtil_SetNoOutput)
- NonAdaptingProcess knows how to deal with this
- */
- noOutputOutputFrameCount = framesToGo;
- hostOutputFrameCount = &noOutputOutputFrameCount;
- hostOutputChannels = 0;
- }
- if( bp->hostOutputFrameCount[0] != 0 )
- {
- hostOutputFrameCount = &bp->hostOutputFrameCount[0];
- hostOutputChannels = bp->hostOutputChannels[0];
- }
- else
- {
- hostOutputFrameCount = &bp->hostOutputFrameCount[1];
- hostOutputChannels = bp->hostOutputChannels[1];
- }
-
- framesToProcess = PA_MIN_( *hostInputFrameCount,
- *hostOutputFrameCount );
-
- assert( framesToProcess != 0 );
-
- framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
- hostInputChannels, hostOutputChannels,
- framesToProcess );
-
- *hostInputFrameCount -= framesProcessedThisIteration;
- *hostOutputFrameCount -= framesProcessedThisIteration;
-
- framesProcessed += framesProcessedThisIteration;
- framesToGo -= framesProcessedThisIteration;
-
- }while( framesToGo > 0 );
- }
- else
- {
- /* half duplex non-adapting process, just process 1st and 2nd buffer */
- /* process first buffer */
-
- framesToProcess = (bp->inputChannelCount != 0)
- ? bp->hostInputFrameCount[0]
- : bp->hostOutputFrameCount[0];
-
- framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
- bp->hostInputChannels[0], bp->hostOutputChannels[0],
- framesToProcess );
-
- /* process second buffer if provided */
-
- framesToProcess = (bp->inputChannelCount != 0)
- ? bp->hostInputFrameCount[1]
- : bp->hostOutputFrameCount[1];
- if( framesToProcess > 0 )
- {
- framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
- bp->hostInputChannels[1], bp->hostOutputChannels[1],
- framesToProcess );
- }
- }
- }
- else /* block adaption necessary*/
- {
-
- if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
- {
- /* full duplex */
-
- if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed )
- {
- framesProcessed = AdaptingProcess( bp, streamCallbackResult,
- 0 /* dont process partial user buffers */ );
- }
- else
- {
- framesProcessed = AdaptingProcess( bp, streamCallbackResult,
- 1 /* process partial user buffers */ );
- }
- }
- else if( bp->inputChannelCount != 0 )
- {
- /* input only */
- framesToProcess = bp->hostInputFrameCount[0];
-
- framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
- bp->hostInputChannels[0], framesToProcess );
-
- framesToProcess = bp->hostInputFrameCount[1];
- if( framesToProcess > 0 )
- {
- framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
- bp->hostInputChannels[1], framesToProcess );
- }
- }
- else
- {
- /* output only */
- framesToProcess = bp->hostOutputFrameCount[0];
-
- framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
- bp->hostOutputChannels[0], framesToProcess );
-
- framesToProcess = bp->hostOutputFrameCount[1];
- if( framesToProcess > 0 )
- {
- framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
- bp->hostOutputChannels[1], framesToProcess );
- }
- }
- }
-
- return framesProcessed;
-}
-
-
-int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )
-{
- return (bp->framesInTempOutputBuffer) ? 0 : 1;
-}
-
-
-unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,
- void **buffer, unsigned long frameCount )
-{
- PaUtilChannelDescriptor *hostInputChannels;
- unsigned int framesToCopy;
- unsigned char *destBytePtr;
- void **nonInterleavedDestPtrs;
- unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int i;
-
- hostInputChannels = bp->hostInputChannels[0];
- framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );
-
- if( bp->userInputIsInterleaved )
- {
- destBytePtr = (unsigned char*)*buffer;
-
- destSampleStrideSamples = bp->inputChannelCount;
- destChannelStrideBytes = bp->bytesPerUserInputSample;
-
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- bp->inputConverter( destBytePtr, destSampleStrideSamples,
- hostInputChannels[i].data,
- hostInputChannels[i].stride,
- framesToCopy, &bp->ditherGenerator );
-
- destBytePtr += destChannelStrideBytes; /* skip to next source channel */
-
- /* advance dest ptr for next iteration */
- hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
- framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
- }
-
- /* advance callers dest pointer (buffer) */
- *buffer = ((unsigned char *)*buffer) +
- framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;
- }
- else
- {
- /* user input is not interleaved */
-
- nonInterleavedDestPtrs = (void**)*buffer;
-
- destSampleStrideSamples = 1;
-
- for( i=0; i<bp->inputChannelCount; ++i )
- {
- destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];
-
- bp->inputConverter( destBytePtr, destSampleStrideSamples,
- hostInputChannels[i].data,
- hostInputChannels[i].stride,
- framesToCopy, &bp->ditherGenerator );
-
- /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */
- destBytePtr += bp->bytesPerUserInputSample * framesToCopy;
- nonInterleavedDestPtrs[i] = destBytePtr;
-
- /* advance dest ptr for next iteration */
- hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
- framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
- }
- }
-
- bp->hostInputFrameCount[0] -= framesToCopy;
-
- return framesToCopy;
-}
-
-unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,
- const void ** buffer, unsigned long frameCount )
-{
- PaUtilChannelDescriptor *hostOutputChannels;
- unsigned int framesToCopy;
- unsigned char *srcBytePtr;
- void **nonInterleavedSrcPtrs;
- unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
- unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
- unsigned int i;
-
- hostOutputChannels = bp->hostOutputChannels[0];
- framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
-
- if( bp->userOutputIsInterleaved )
- {
- srcBytePtr = (unsigned char*)*buffer;
-
- srcSampleStrideSamples = bp->outputChannelCount;
- srcChannelStrideBytes = bp->bytesPerUserOutputSample;
-
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- bp->outputConverter( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- srcBytePtr, srcSampleStrideSamples,
- framesToCopy, &bp->ditherGenerator );
-
- srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
-
- /* advance callers source pointer (buffer) */
- *buffer = ((unsigned char *)*buffer) +
- framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;
-
- }
- else
- {
- /* user output is not interleaved */
-
- nonInterleavedSrcPtrs = (void**)*buffer;
-
- srcSampleStrideSamples = 1;
-
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];
-
- bp->outputConverter( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- srcBytePtr, srcSampleStrideSamples,
- framesToCopy, &bp->ditherGenerator );
-
-
- /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */
- srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;
- nonInterleavedSrcPtrs[i] = srcBytePtr;
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
- }
-
- bp->hostOutputFrameCount[0] += framesToCopy;
-
- return framesToCopy;
-}
-
-
-unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )
-{
- PaUtilChannelDescriptor *hostOutputChannels;
- unsigned int framesToZero;
- unsigned int i;
-
- hostOutputChannels = bp->hostOutputChannels[0];
- framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
-
- for( i=0; i<bp->outputChannelCount; ++i )
- {
- bp->outputZeroer( hostOutputChannels[i].data,
- hostOutputChannels[i].stride,
- framesToZero );
-
-
- /* advance dest ptr for next iteration */
- hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
- framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
- }
-
- bp->hostOutputFrameCount[0] += framesToZero;
-
- return framesToZero;
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_process.h b/pjmedia/src/pjmedia/portaudio/pa_process.h
deleted file mode 100644
index c52e9ea0..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_process.h
+++ /dev/null
@@ -1,741 +0,0 @@
-#ifndef PA_PROCESS_H
-#define PA_PROCESS_H
-/*
- * $Id: pa_process.h,v 1.1.2.30 2004/12/13 09:48:44 rossbencina Exp $
- * Portable Audio I/O Library callback buffer processing adapters
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Buffer Processor prototypes. A Buffer Processor performs buffer length
- adaption, coordinates sample format conversion, and interleaves/deinterleaves
- channels.
-
- <h3>Overview</h3>
-
- The "Buffer Processor" (PaUtilBufferProcessor) manages conversion of audio
- data from host buffers to user buffers and back again. Where required, the
- buffer processor takes care of converting between host and user sample formats,
- interleaving and deinterleaving multichannel buffers, and adapting between host
- and user buffers with different lengths. The buffer processor may be used with
- full and half duplex streams, for both callback streams and blocking read/write
- streams.
-
- One of the important capabilities provided by the buffer processor is
- the ability to adapt between user and host buffer sizes of different lengths
- with minimum latency. Although this task is relatively easy to perform when
- the host buffer size is an integer multiple of the user buffer size, the
- problem is more complicated when this is not the case - especially for
- full-duplex callback streams. Where necessary the adaption is implemented by
- internally buffering some input and/or output data. The buffer adation
- algorithm used by the buffer processor was originally implemented by
- Stephan Letz for the ASIO version of PortAudio, and is described in his
- Callback_adaption_.pdf which is included in the distribution.
-
- The buffer processor performs sample conversion using the functions provided
- by pa_converters.c.
-
- The following sections provide an overview of how to use the buffer processor.
- Interested readers are advised to consult the host API implementations for
- examples of buffer processor usage.
-
-
- <h4>Initialization, resetting and termination</h4>
-
- When a stream is opened, the buffer processor should be initialized using
- PaUtil_InitializeBufferProcessor. This function initializes internal state
- and allocates temporary buffers as neccesary according to the supplied
- configuration parameters. Some of the parameters correspond to those requested
- by the user in their call to Pa_OpenStream(), others reflect the requirements
- of the host API implementation - they indicate host buffer sizes, formats,
- and the type of buffering which the Host API uses. The buffer processor should
- be initialized for callback streams and blocking read/write streams.
-
- Call PaUtil_ResetBufferProcessor to clear any sample data which is present
- in the buffer processor before starting to use it (for example when
- Pa_StartStream is called).
-
- When the buffer processor is no longer used call
- PaUtil_TerminateBufferProcessor.
-
-
- <h4>Using the buffer processor for a callback stream</h4>
-
- The buffer processor's role in a callback stream is to take host input buffers
- process them with the stream callback, and fill host output buffers. For a
- full duplex stream, the buffer processor handles input and output simultaneously
- due to the requirements of the minimum-latency buffer adation algorithm.
-
- When a host buffer becomes available, the implementation should call
- the buffer processor to process the buffer. The buffer processor calls the
- stream callback to consume and/or produce audio data as necessary. The buffer
- processor will convert sample formats, interleave/deinterleave channels,
- and slice or chunk the data to the appropriate buffer lengths according to
- the requirements of the stream callback and the host API.
-
- To process a host buffer (or a pair of host buffers for a full-duplex stream)
- use the following calling sequence:
-
- -# Call PaUtil_BeginBufferProcessing
- -# For a stream which takes input:
- - Call PaUtil_SetInputFrameCount with the number of frames in the host input
- buffer.
- - Call one of the following functions one or more times to tell the
- buffer processor about the host input buffer(s): PaUtil_SetInputChannel,
- PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.
- Which function you call will depend on whether the host buffer(s) are
- interleaved or not.
- - If the available host data is split accross two buffers (for example a
- data range at the end of a circular buffer and another range at the
- beginning of the circular buffer), also call
- PaUtil_Set2ndInputFrameCount, PaUtil_Set2ndInputChannel,
- PaUtil_Set2ndInterleavedInputChannels,
- PaUtil_Set2ndNonInterleavedInputChannel as necessary to tell the buffer
- processor about the second buffer.
- -# For a stream which generates output:
- - Call PaUtil_SetOutputFrameCount with the number of frames in the host
- output buffer.
- - Call one of the following functions one or more times to tell the
- buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,
- PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.
- Which function you call will depend on whether the host buffer(s) are
- interleaved or not.
- - If the available host output buffer space is split accross two buffers
- (for example a data range at the end of a circular buffer and another
- range at the beginning of the circular buffer), call
- PaUtil_Set2ndOutputFrameCount, PaUtil_Set2ndOutputChannel,
- PaUtil_Set2ndInterleavedOutputChannels,
- PaUtil_Set2ndNonInterleavedOutputChannel as necessary to tell the buffer
- processor about the second buffer.
- -# Call PaUtil_EndBufferProcessing, this function performs the actual data
- conversion and processing.
-
-
- <h4>Using the buffer processor for a blocking read/write stream</h4>
-
- Blocking read/write streams use the buffer processor to convert and copy user
- output data to a host buffer, and to convert and copy host input data to
- the user's buffer. The buffer processor does not perform any buffer adaption.
- When using the buffer processor in a blocking read/write stream the input and
- output conversion are performed separately by the PaUtil_CopyInput and
- PaUtil_CopyOutput functions.
-
- To copy data from a host input buffer to the buffer(s) which the user supplies
- to Pa_ReadStream, use the following calling sequence.
-
- - Repeat the following three steps until the user buffer(s) have been filled
- with samples from the host input buffers:
- -# Call PaUtil_SetInputFrameCount with the number of frames in the host
- input buffer.
- -# Call one of the following functions one or more times to tell the
- buffer processor about the host input buffer(s): PaUtil_SetInputChannel,
- PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.
- Which function you call will depend on whether the host buffer(s) are
- interleaved or not.
- -# Call PaUtil_CopyInput with the user buffer pointer (or a copy of the
- array of buffer pointers for a non-interleaved stream) passed to
- Pa_ReadStream, along with the number of frames in the user buffer(s).
- Be careful to pass a <i>copy</i> of the user buffer pointers to
- PaUtil_CopyInput because PaUtil_CopyInput advances the pointers to
- the start of the next region to copy.
- - PaUtil_CopyInput will not copy more data than is available in the
- host buffer(s), so the above steps need to be repeated until the user
- buffer(s) are full.
-
-
- To copy data to the host output buffer from the user buffers(s) supplied
- to Pa_WriteStream use the following calling sequence.
-
- - Repeat the following three steps until all frames from the user buffer(s)
- have been copied to the host API:
- -# Call PaUtil_SetOutputFrameCount with the number of frames in the host
- output buffer.
- -# Call one of the following functions one or more times to tell the
- buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,
- PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.
- Which function you call will depend on whether the host buffer(s) are
- interleaved or not.
- -# Call PaUtil_CopyOutput with the user buffer pointer (or a copy of the
- array of buffer pointers for a non-interleaved stream) passed to
- Pa_WriteStream, along with the number of frames in the user buffer(s).
- Be careful to pass a <i>copy</i> of the user buffer pointers to
- PaUtil_CopyOutput because PaUtil_CopyOutput advances the pointers to
- the start of the next region to copy.
- - PaUtil_CopyOutput will not copy more data than fits in the host buffer(s),
- so the above steps need to be repeated until all user data is copied.
-*/
-
-
-#include "portaudio.h"
-#include "pa_converters.h"
-#include "pa_dither.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** @brief Mode flag passed to PaUtil_InitializeBufferProcessor indicating the type
- of buffering that the host API uses.
-
- The mode used depends on whether the host API or the implementation manages
- the buffers, and how these buffers are used (scatter gather, circular buffer).
-*/
-typedef enum {
-/** The host buffer size is a fixed known size. */
- paUtilFixedHostBufferSize,
-
-/** The host buffer size may vary, but has a known maximum size. */
- paUtilBoundedHostBufferSize,
-
-/** Nothing is known about the host buffer size. */
- paUtilUnknownHostBufferSize,
-
-/** The host buffer size varies, and the client does not require the buffer
- processor to consume all of the input and fill all of the output buffer. This
- is useful when the implementation has access to the host API's circular buffer
- and only needs to consume/fill some of it, not necessarily all of it, with each
- call to the buffer processor. This is the only mode where
- PaUtil_EndBufferProcessing() may not consume the whole buffer.
-*/
- paUtilVariableHostBufferSizePartialUsageAllowed
-}PaUtilHostBufferSizeMode;
-
-
-/** @brief An auxilliary data structure used internally by the buffer processor
- to represent host input and output buffers. */
-typedef struct PaUtilChannelDescriptor{
- void *data;
- unsigned int stride; /**< stride in samples, not bytes */
-}PaUtilChannelDescriptor;
-
-
-/** @brief The main buffer processor data structure.
-
- Allocate one of these, initialize it with PaUtil_InitializeBufferProcessor
- and terminate it with PaUtil_TerminateBufferProcessor.
-*/
-typedef struct {
- unsigned long framesPerUserBuffer;
- unsigned long framesPerHostBuffer;
-
- PaUtilHostBufferSizeMode hostBufferSizeMode;
- int useNonAdaptingProcess;
- unsigned long framesPerTempBuffer;
-
- unsigned int inputChannelCount;
- unsigned int bytesPerHostInputSample;
- unsigned int bytesPerUserInputSample;
- int userInputIsInterleaved;
- PaUtilConverter *inputConverter;
- PaUtilZeroer *inputZeroer;
-
- unsigned int outputChannelCount;
- unsigned int bytesPerHostOutputSample;
- unsigned int bytesPerUserOutputSample;
- int userOutputIsInterleaved;
- PaUtilConverter *outputConverter;
- PaUtilZeroer *outputZeroer;
-
- unsigned long initialFramesInTempInputBuffer;
- unsigned long initialFramesInTempOutputBuffer;
-
- void *tempInputBuffer; /**< used for slips, block adaption, and conversion. */
- void **tempInputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */
- unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
-
- void *tempOutputBuffer; /**< used for slips, block adaption, and conversion. */
- void **tempOutputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */
- unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
-
- PaStreamCallbackTimeInfo *timeInfo;
-
- PaStreamCallbackFlags callbackStatusFlags;
-
- unsigned long hostInputFrameCount[2];
- PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors.
- pointers are NULL for half-duplex output processing.
- hostInputChannels[i].data is NULL when the caller
- calls PaUtil_SetNoInput()
- */
- unsigned long hostOutputFrameCount[2];
- PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors.
- pointers are NULL for half-duplex input processing.
- hostOutputChannels[i].data is NULL when the caller
- calls PaUtil_SetNoOutput()
- */
-
- PaUtilTriangularDitherGenerator ditherGenerator;
-
- double samplePeriod;
-
- PaStreamCallback *streamCallback;
- void *userData;
-} PaUtilBufferProcessor;
-
-
-/** @name Initialization, termination, resetting and info */
-/*@{*/
-
-/** Initialize a buffer processor's representation stored in a
- PaUtilBufferProcessor structure. Be sure to call
- PaUtil_TerminateBufferProcessor after finishing with a buffer processor.
-
- @param bufferProcessor The buffer processor structure to initialize.
-
- @param inputChannelCount The number of input channels as passed to
- Pa_OpenStream or 0 for an output-only stream.
-
- @param userInputSampleFormat Format of user input samples, as passed to
- Pa_OpenStream. This parameter is ignored for ouput-only streams.
-
- @param hostInputSampleFormat Format of host input samples. This parameter is
- ignored for output-only streams. See note about host buffer interleave below.
-
- @param outputChannelCount The number of output channels as passed to
- Pa_OpenStream or 0 for an input-only stream.
-
- @param userOutputSampleFormat Format of user output samples, as passed to
- Pa_OpenStream. This parameter is ignored for input-only streams.
-
- @param hostOutputSampleFormat Format of host output samples. This parameter is
- ignored for input-only streams. See note about host buffer interleave below.
-
- @param sampleRate Sample rate of the stream. The more accurate this is the
- better - it is used for updating time stamps when adapting buffers.
-
- @param streamFlags Stream flags as passed to Pa_OpenStream, this parameter is
- used for selecting special sample conversion options such as clipping and
- dithering.
-
- @param framesPerUserBuffer Number of frames per user buffer, as requested
- by the framesPerBuffer parameter to Pa_OpenStream. This parameter may be
- zero to indicate that the user will accept any (and varying) buffer sizes.
-
- @param framesPerHostBuffer Specifies the number of frames per host buffer
- for the fixed buffer size mode, and the maximum number of frames
- per host buffer for the bounded host buffer size mode. It is ignored for
- the other modes.
-
- @param hostBufferSizeMode A mode flag indicating the size variability of
- host buffers that will be passed to the buffer processor. See
- PaUtilHostBufferSizeMode for further details.
-
- @param streamCallback The user stream callback passed to Pa_OpenStream.
-
- @param userData The user data field passed to Pa_OpenStream.
-
- @note The interleave flag is ignored for host buffer formats. Host
- interleave is determined by the use of different SetInput and SetOutput
- functions.
-
- @return An error code indicating whether the initialization was successful.
- If the error code is not PaNoError, the buffer processor was not initialized
- and should not be used.
-
- @see Pa_OpenStream, PaUtilHostBufferSizeMode, PaUtil_TerminateBufferProcessor
-*/
-PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor,
- int inputChannelCount, PaSampleFormat userInputSampleFormat,
- PaSampleFormat hostInputSampleFormat,
- int outputChannelCount, PaSampleFormat userOutputSampleFormat,
- PaSampleFormat hostOutputSampleFormat,
- double sampleRate,
- PaStreamFlags streamFlags,
- unsigned long framesPerUserBuffer, /* 0 indicates don't care */
- unsigned long framesPerHostBuffer,
- PaUtilHostBufferSizeMode hostBufferSizeMode,
- PaStreamCallback *streamCallback, void *userData );
-
-
-/** Terminate a buffer processor's representation. Deallocates any temporary
- buffers allocated by PaUtil_InitializeBufferProcessor.
-
- @param bufferProcessor The buffer processor structure to terminate.
-
- @see PaUtil_InitializeBufferProcessor.
-*/
-void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Clear any internally buffered data. If you call
- PaUtil_InitializeBufferProcessor in your OpenStream routine, make sure you
- call PaUtil_ResetBufferProcessor in your StartStream call.
-
- @param bufferProcessor The buffer processor to reset.
-*/
-void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Retrieve the input latency of a buffer processor.
-
- @param bufferProcessor The buffer processor examine.
-
- @return The input latency introduced by the buffer processor, in frames.
-
- @see PaUtil_GetBufferProcessorOutputLatency
-*/
-unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bufferProcessor );
-
-/** Retrieve the output latency of a buffer processor.
-
- @param bufferProcessor The buffer processor examine.
-
- @return The output latency introduced by the buffer processor, in frames.
-
- @see PaUtil_GetBufferProcessorInputLatency
-*/
-unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bufferProcessor );
-
-/*@}*/
-
-
-/** @name Host buffer pointer configuration
-
- Functions to set host input and output buffers, used by both callback streams
- and blocking read/write streams.
-*/
-/*@{*/
-
-
-/** Set the number of frames in the input host buffer(s) specified by the
- PaUtil_Set*InputChannel functions.
-
- @param bufferProcessor The buffer processor.
-
- @param frameCount The number of host input frames. A 0 frameCount indicates to
- use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.
-
- @see PaUtil_SetNoInput, PaUtil_SetInputChannel,
- PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel
-*/
-void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
- unsigned long frameCount );
-
-
-/** Indicate that no input is avalable. This function should be used when
- priming the output of a full-duplex stream opened with the
- paPrimeOutputBuffersUsingStreamCallback flag. Note that it is not necessary
- to call this or any othe PaUtil_Set*Input* functions for ouput-only streams.
-
- @param bufferProcessor The buffer processor.
-*/
-void PaUtil_SetNoInput( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Provide the buffer processor with a pointer to a host input channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
- @param stride The stride from one sample to the next, in samples. For
- interleaved host buffers, the stride will usually be the same as the number of
- channels in the buffer.
-*/
-void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data, unsigned int stride );
-
-
-/** Provide the buffer processor with a pointer to an number of interleaved
- host input channels.
-
- @param bufferProcessor The buffer processor.
- @param firstChannel The first channel number.
- @param data The buffer.
- @param channelCount The number of interleaved channels in the buffer. If
- channelCount is zero, the number of channels specified to
- PaUtil_InitializeBufferProcessor will be used.
-*/
-void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
- unsigned int firstChannel, void *data, unsigned int channelCount );
-
-
-/** Provide the buffer processor with a pointer to one non-interleaved host
- output channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
-*/
-void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data );
-
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetInputFrameCount
-*/
-void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
- unsigned long frameCount );
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetInputChannel
-*/
-void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data, unsigned int stride );
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetInterleavedInputChannels
-*/
-void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
- unsigned int firstChannel, void *data, unsigned int channelCount );
-
-/** Use for the second buffer half when the input buffer is split in two halves.
- @see PaUtil_SetNonInterleavedInputChannel
-*/
-void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data );
-
-
-/** Set the number of frames in the output host buffer(s) specified by the
- PaUtil_Set*OutputChannel functions.
-
- @param bufferProcessor The buffer processor.
-
- @param frameCount The number of host output frames. A 0 frameCount indicates to
- use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.
-
- @see PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels,
- PaUtil_SetNonInterleavedOutputChannel
-*/
-void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
- unsigned long frameCount );
-
-
-/** Indicate that the output will be discarded. This function should be used
- when implementing the paNeverDropInput mode for full duplex streams.
-
- @param bufferProcessor The buffer processor.
-*/
-void PaUtil_SetNoOutput( PaUtilBufferProcessor* bufferProcessor );
-
-
-/** Provide the buffer processor with a pointer to a host output channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
- @param stride The stride from one sample to the next, in samples. For
- interleaved host buffers, the stride will usually be the same as the number of
- channels in the buffer.
-*/
-void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data, unsigned int stride );
-
-
-/** Provide the buffer processor with a pointer to a number of interleaved
- host output channels.
-
- @param bufferProcessor The buffer processor.
- @param firstChannel The first channel number.
- @param data The buffer.
- @param channelCount The number of interleaved channels in the buffer. If
- channelCount is zero, the number of channels specified to
- PaUtil_InitializeBufferProcessor will be used.
-*/
-void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
- unsigned int firstChannel, void *data, unsigned int channelCount );
-
-
-/** Provide the buffer processor with a pointer to one non-interleaved host
- output channel.
-
- @param bufferProcessor The buffer processor.
- @param channel The channel number.
- @param data The buffer.
-*/
-void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data );
-
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetOutputFrameCount
-*/
-void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
- unsigned long frameCount );
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetOutputChannel
-*/
-void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data, unsigned int stride );
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetInterleavedOutputChannels
-*/
-void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
- unsigned int firstChannel, void *data, unsigned int channelCount );
-
-/** Use for the second buffer half when the output buffer is split in two halves.
- @see PaUtil_SetNonInterleavedOutputChannel
-*/
-void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
- unsigned int channel, void *data );
-
-/*@}*/
-
-
-/** @name Buffer processing functions for callback streams
-*/
-/*@{*/
-
-/** Commence processing a host buffer (or a pair of host buffers in the
- full-duplex case) for a callback stream.
-
- @param bufferProcessor The buffer processor.
-
- @param timeInfo Timing information for the first sample of the host
- buffer(s). This information may be adjusted when buffer adaption is being
- performed.
-
- @param callbackStatusFlags Flags indicating whether underruns and overruns
- have occurred since the last time the buffer processor was called.
-*/
-void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
- PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags );
-
-
-/** Finish processing a host buffer (or a pair of host buffers in the
- full-duplex case) for a callback stream.
-
- @param bufferProcessor The buffer processor.
-
- @param callbackResult On input, indicates a previous callback result, and on
- exit, the result of the user stream callback, if it is called.
- On entry callbackResult should contain one of { paContinue, paComplete, or
- paAbort}. If paComplete is passed, the stream callback will not be called
- but any audio that was generated by previous stream callbacks will be copied
- to the output buffer(s). You can check whether the buffer processor's internal
- buffer is empty by calling PaUtil_IsBufferProcessorOutputEmpty.
-
- If the stream callback is called its result is stored in *callbackResult. If
- the stream callback returns paComplete or paAbort, all output buffers will be
- full of valid data - some of which may be zeros to acount for data that
- wasn't generated by the terminating callback.
-
- @return The number of frames processed. This usually corresponds to the
- number of frames specified by the PaUtil_Set*FrameCount functions, exept in
- the paUtilVariableHostBufferSizePartialUsageAllowed buffer size mode when a
- smaller value may be returned.
-*/
-unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
- int *callbackResult );
-
-
-/** Determine whether any callback generated output remains in the bufffer
- processor's internal buffers. This method may be used to determine when to
- continue calling PaUtil_EndBufferProcessing() after the callback has returned
- a callbackResult of paComplete.
-
- @param bufferProcessor The buffer processor.
-
- @return Returns non-zero when callback generated output remains in the internal
- buffer and zero (0) when there internal buffer contains no callback generated
- data.
-*/
-int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bufferProcessor );
-
-/*@}*/
-
-
-/** @name Buffer processing functions for blocking read/write streams
-*/
-/*@{*/
-
-/** Copy samples from host input channels set up by the PaUtil_Set*InputChannels
- functions to a user supplied buffer. This function is intended for use with
- blocking read/write streams. Copies the minimum of the number of
- user frames (specified by the frameCount parameter) and the number of available
- host frames (specified in a previous call to SetInputFrameCount()).
-
- @param bufferProcessor The buffer processor.
-
- @param buffer A pointer to the user buffer pointer, or a pointer to a pointer
- to an array of user buffer pointers for a non-interleaved stream. It is
- important that this parameter points to a copy of the user buffer pointers,
- not to the actual user buffer pointers, because this function updates the
- pointers before returning.
-
- @param frameCount The number of frames of data in the buffer(s) pointed to by
- the buffer parameter.
-
- @return The number of frames copied. The buffer pointer(s) pointed to by the
- buffer parameter are advanced to point to the frame(s) following the last one
- filled.
-*/
-unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bufferProcessor,
- void **buffer, unsigned long frameCount );
-
-
-/* Copy samples from a user supplied buffer to host output channels set up by
- the PaUtil_Set*OutputChannels functions. This function is intended for use with
- blocking read/write streams. Copies the minimum of the number of
- user frames (specified by the frameCount parameter) and the number of
- host frames (specified in a previous call to SetOutputFrameCount()).
-
- @param bufferProcessor The buffer processor.
-
- @param buffer A pointer to the user buffer pointer, or a pointer to a pointer
- to an array of user buffer pointers for a non-interleaved stream. It is
- important that this parameter points to a copy of the user buffer pointers,
- not to the actual user buffer pointers, because this function updates the
- pointers before returning.
-
- @param frameCount The number of frames of data in the buffer(s) pointed to by
- the buffer parameter.
-
- @return The number of frames copied. The buffer pointer(s) pointed to by the
- buffer parameter are advanced to point to the frame(s) following the last one
- copied.
-*/
-unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bufferProcessor,
- const void ** buffer, unsigned long frameCount );
-
-
-/* Zero samples in host output channels set up by the PaUtil_Set*OutputChannels
- functions. This function is useful for flushing streams.
- Zeros the minimum of frameCount and the number of host frames specified in a
- previous call to SetOutputFrameCount().
-
- @param bufferProcessor The buffer processor.
-
- @param frameCount The maximum number of frames to zero.
-
- @return The number of frames zeroed.
-*/
-unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bufferProcessor,
- unsigned long frameCount );
-
-
-/*@}*/
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_PROCESS_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_skeleton.c b/pjmedia/src/pjmedia/portaudio/pa_skeleton.c
deleted file mode 100644
index ebc1f501..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_skeleton.c
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * $Id: pa_skeleton.c,v 1.1.2.39 2003/11/26 14:56:09 rossbencina Exp $
- * Portable Audio I/O Library skeleton implementation
- * demonstrates how to use the common functions to implement support
- * for a host API
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Skeleton implementation of support for a host API.
-
- @note This file is provided as a starting point for implementing support for
- a new host API. IMPLEMENT ME comments are used to indicate functionality
- which much be customised for each implementation.
-*/
-
-
-#include <string.h> /* strlen() */
-
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-
-/* IMPLEMENT ME: a macro like the following one should be used for reporting
- host errors */
-#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
- PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
-
-/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- /* implementation specific data goes here */
-}
-PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */
-
-
-PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- int i, deviceCount;
- PaSkeletonHostApiRepresentation *skeletonHostApi;
- PaDeviceInfo *deviceInfoArray;
-
- skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
- if( !skeletonHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !skeletonHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- *hostApi = &skeletonHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */
- (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */
-
- (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */
- (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
-
- (*hostApi)->info.deviceCount = 0;
-
- deviceCount = 0; /* IMPLEMENT ME */
-
- if( deviceCount > 0 )
- {
- (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
- if( !(*hostApi)->deviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* allocate all device info structs in a contiguous block */
- deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
- skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
- if( !deviceInfoArray )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- for( i=0; i < deviceCount; ++i )
- {
- PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
- deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
- if( !deviceName )
- {
- result = paInsufficientMemory;
- goto error;
- }
- strcpy( deviceName, srcName );
- deviceInfo->name = deviceName;
- */
-
- deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */
- deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */
-
- deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */
- deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */
- deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */
- deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */
-
- deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
-
- (*hostApi)->deviceInfos[i] = deviceInfo;
- ++(*hostApi)->info.deviceCount;
- }
- }
-
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( skeletonHostApi )
- {
- if( skeletonHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
- PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
- }
-
- PaUtil_FreeMemory( skeletonHostApi );
- }
- return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
-
- /*
- IMPLEMENT ME:
- - clean up any resources not handled by the allocation group
- */
-
- if( skeletonHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
- PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
- }
-
- PaUtil_FreeMemory( skeletonHostApi );
-}
-
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( inputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
-
- /* validate inputStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- inputChannelCount = 0;
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( outputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support outputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* validate outputStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- outputChannelCount = 0;
- }
-
- /*
- IMPLEMENT ME:
-
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported if necessary
-
- - check that the device supports sampleRate
-
- Because the buffer adapter handles conversion between all standard
- sample formats, the following checks are only required if paCustomFormat
- is implemented, or under some other unusual conditions.
-
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from inputSampleFormat to
- a native format
-
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
- */
-
-
- /* suppress unused variable warnings */
- (void) sampleRate;
-
- return paFormatIsSupported;
-}
-
-/* PaSkeletonStream - a stream data structure specifically for this implementation */
-
-typedef struct PaSkeletonStream
-{ /* IMPLEMENT ME: rename this */
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- /* IMPLEMENT ME:
- - implementation specific data goes here
- */
- unsigned long framesPerHostCallback; /* just an example */
-}
-PaSkeletonStream;
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result = paNoError;
- PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
- PaSkeletonStream *stream = 0;
- unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
-
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
-
- /* validate inputStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-
- /* IMPLEMENT ME - establish which host formats are available */
- hostInputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
- }
- else
- {
- inputChannelCount = 0;
- inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support inputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* validate outputStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
-
- /* IMPLEMENT ME - establish which host formats are available */
- hostOutputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
- }
- else
- {
- outputChannelCount = 0;
- outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
- }
-
- /*
- IMPLEMENT ME:
-
- ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
-
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported
-
- - check that the device supports sampleRate
-
- - alter sampleRate to a close allowable rate if possible / necessary
-
- - validate suggestedInputLatency and suggestedOutputLatency parameters,
- use default values where necessary
- */
-
-
-
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- return paInvalidFlag; /* unexpected platform specific flag */
-
-
- stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
- if( !stream )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- if( streamCallback )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &skeletonHostApi->callbackStreamInterface, streamCallback, userData );
- }
- else
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &skeletonHostApi->blockingStreamInterface, streamCallback, userData );
- }
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
-
- /* we assume a fixed host buffer size in this example, but the buffer processor
- can also support bounded and unknown host buffer sizes by passing
- paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
- paUtilFixedHostBufferSize below. */
-
- result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- inputChannelCount, inputSampleFormat, hostInputSampleFormat,
- outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerBuffer,
- framesPerHostBuffer, paUtilFixedHostBufferSize,
- streamCallback, userData );
- if( result != paNoError )
- goto error;
-
-
- /*
- IMPLEMENT ME: initialise the following fields with estimated or actual
- values.
- */
- stream->streamRepresentation.streamInfo.inputLatency =
- PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);
- stream->streamRepresentation.streamInfo.outputLatency =
- PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-
- /*
- IMPLEMENT ME:
- - additional stream setup + opening
- */
-
- stream->framesPerHostCallback = framesPerHostBuffer;
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
- if( stream )
- PaUtil_FreeMemory( stream );
-
- return result;
-}
-
-/*
- ExampleHostProcessingLoop() illustrates the kind of processing which may
- occur in a host implementation.
-
-*/
-static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)userData;
- PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
- int callbackResult;
- unsigned long framesProcessed;
-
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
- /*
- IMPLEMENT ME:
- - generate timing information
- - handle buffer slips
- */
-
- /*
- If you need to byte swap or shift inputBuffer to convert it into a
- portaudio format, do it here.
- */
-
-
-
- PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
-
- /*
- depending on whether the host buffers are interleaved, non-interleaved
- or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
- PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
- */
-
- PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
- 0, /* first channel of inputBuffer is channel 0 */
- inputBuffer,
- 0 ); /* 0 - use inputChannelCount passed to init buffer processor */
-
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
- 0, /* first channel of outputBuffer is channel 0 */
- outputBuffer,
- 0 ); /* 0 - use outputChannelCount passed to init buffer processor */
-
- /* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
- in general you would pass paContinue for normal operation, and
- paComplete to drain the buffer processor's internal output buffer.
- You can check whether the buffer processor's output buffer is empty
- using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
- */
- callbackResult = paContinue;
- framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
-
-
- /*
- If you need to byte swap or shift outputBuffer to convert it to
- host format, do it here.
- */
-
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
-
- if( callbackResult == paContinue )
- {
- /* nothing special to do */
- }
- else if( callbackResult == paAbort )
- {
- /* IMPLEMENT ME - finish playback immediately */
-
- /* once finished, call the finished callback */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
- else
- {
- /* User callback has asked us to stop with paComplete or other non-zero value */
-
- /* IMPLEMENT ME - finish playback once currently queued audio has completed */
-
- /* once finished, call the finished callback */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
-}
-
-
-/*
- When CloseStream() is called, the multi-api layer ensures that
- the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
- PaError result = paNoError;
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /*
- IMPLEMENT ME:
- - additional stream closing + cleanup
- */
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- PaUtil_FreeMemory( stream );
-
- return result;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
- PaError result = paNoError;
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-
- /* IMPLEMENT ME, see portaudio.h for required behavior */
-
- /* suppress unused function warning. the code in ExampleHostProcessingLoop or
- something similar should be implemented to feed samples to and from the
- host after StartStream() is called.
- */
- (void) ExampleHostProcessingLoop;
-
- return result;
-}
-
-
-static PaError StopStream( PaStream *s )
-{
- PaError result = paNoError;
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior */
-
- return result;
-}
-
-
-static PaError AbortStream( PaStream *s )
-{
- PaError result = paNoError;
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior */
-
- return result;
-}
-
-
-static PaError IsStreamStopped( PaStream *s )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior */
-
- return 0;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior */
-
- return 0;
-}
-
-
-static PaTime GetStreamTime( PaStream *s )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return 0;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return paNoError;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return paNoError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return 0;
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaSkeletonStream *stream = (PaSkeletonStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return 0;
-}
-
-
-
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_stream.c b/pjmedia/src/pjmedia/portaudio/pa_stream.c
deleted file mode 100644
index 044dde29..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_stream.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * $Id: pa_stream.c,v 1.1.2.12 2003/09/20 21:31:00 rossbencina Exp $
- * Portable Audio I/O Library
- *
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2002 Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Interface used by pa_front to virtualize functions which operate on
- streams.
-*/
-
-
-#include "pa_stream.h"
-
-
-void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
- PaError (*Close)( PaStream* ),
- PaError (*Start)( PaStream* ),
- PaError (*Stop)( PaStream* ),
- PaError (*Abort)( PaStream* ),
- PaError (*IsStopped)( PaStream* ),
- PaError (*IsActive)( PaStream* ),
- PaTime (*GetTime)( PaStream* ),
- double (*GetCpuLoad)( PaStream* ),
- PaError (*Read)( PaStream*, void *, unsigned long ),
- PaError (*Write)( PaStream*, const void *, unsigned long ),
- signed long (*GetReadAvailable)( PaStream* ),
- signed long (*GetWriteAvailable)( PaStream* ) )
-{
- streamInterface->Close = Close;
- streamInterface->Start = Start;
- streamInterface->Stop = Stop;
- streamInterface->Abort = Abort;
- streamInterface->IsStopped = IsStopped;
- streamInterface->IsActive = IsActive;
- streamInterface->GetTime = GetTime;
- streamInterface->GetCpuLoad = GetCpuLoad;
- streamInterface->Read = Read;
- streamInterface->Write = Write;
- streamInterface->GetReadAvailable = GetReadAvailable;
- streamInterface->GetWriteAvailable = GetWriteAvailable;
-}
-
-
-void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation,
- PaUtilStreamInterface *streamInterface,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- streamRepresentation->magic = PA_STREAM_MAGIC;
- streamRepresentation->nextOpenStream = 0;
- streamRepresentation->streamInterface = streamInterface;
- streamRepresentation->streamCallback = streamCallback;
- streamRepresentation->streamFinishedCallback = 0;
-
- streamRepresentation->userData = userData;
-
- streamRepresentation->streamInfo.inputLatency = 0.;
- streamRepresentation->streamInfo.outputLatency = 0.;
- streamRepresentation->streamInfo.sampleRate = 0.;
-}
-
-
-void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation )
-{
- streamRepresentation->magic = 0;
-}
-
-
-PaError PaUtil_DummyRead( PaStream* stream,
- void *buffer,
- unsigned long frames )
-{
- (void)stream; /* unused parameter */
- (void)buffer; /* unused parameter */
- (void)frames; /* unused parameter */
-
- return paCanNotReadFromACallbackStream;
-}
-
-
-PaError PaUtil_DummyWrite( PaStream* stream,
- const void *buffer,
- unsigned long frames )
-{
- (void)stream; /* unused parameter */
- (void)buffer; /* unused parameter */
- (void)frames; /* unused parameter */
-
- return paCanNotWriteToACallbackStream;
-}
-
-
-signed long PaUtil_DummyGetReadAvailable( PaStream* stream )
-{
- (void)stream; /* unused parameter */
-
- return paCanNotReadFromACallbackStream;
-}
-
-
-signed long PaUtil_DummyGetWriteAvailable( PaStream* stream )
-{
- (void)stream; /* unused parameter */
-
- return paCanNotWriteToACallbackStream;
-}
-
-
-double PaUtil_DummyGetCpuLoad( PaStream* stream )
-{
- (void)stream; /* unused parameter */
-
- return 0.0;
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_stream.h b/pjmedia/src/pjmedia/portaudio/pa_stream.h
deleted file mode 100644
index 8b86943b..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_stream.h
+++ /dev/null
@@ -1,196 +0,0 @@
-#ifndef PA_STREAM_H
-#define PA_STREAM_H
-/*
- * $Id: pa_stream.h,v 1.1.2.13 2003/11/01 06:37:28 rossbencina Exp $
- * Portable Audio I/O Library
- * stream interface
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Interface used by pa_front to virtualize functions which operate on
- streams.
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-#define PA_STREAM_MAGIC (0x18273645)
-
-
-/** A structure representing an (abstract) interface to a host API. Contains
- pointers to functions which implement the interface.
-
- All PaStreamInterface functions are guaranteed to be called with a non-null,
- valid stream parameter.
-*/
-typedef struct {
- PaError (*Close)( PaStream* stream );
- PaError (*Start)( PaStream *stream );
- PaError (*Stop)( PaStream *stream );
- PaError (*Abort)( PaStream *stream );
- PaError (*IsStopped)( PaStream *stream );
- PaError (*IsActive)( PaStream *stream );
- PaTime (*GetTime)( PaStream *stream );
- double (*GetCpuLoad)( PaStream* stream );
- PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames );
- PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames );
- signed long (*GetReadAvailable)( PaStream* stream );
- signed long (*GetWriteAvailable)( PaStream* stream );
-} PaUtilStreamInterface;
-
-
-/** Initialize the fields of a PaUtilStreamInterface structure.
-*/
-void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
- PaError (*Close)( PaStream* ),
- PaError (*Start)( PaStream* ),
- PaError (*Stop)( PaStream* ),
- PaError (*Abort)( PaStream* ),
- PaError (*IsStopped)( PaStream* ),
- PaError (*IsActive)( PaStream* ),
- PaTime (*GetTime)( PaStream* ),
- double (*GetCpuLoad)( PaStream* ),
- PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ),
- PaError (*Write)( PaStream* stream, const void *buffer, unsigned long frames ),
- signed long (*GetReadAvailable)( PaStream* stream ),
- signed long (*GetWriteAvailable)( PaStream* stream ) );
-
-
-/** Dummy Read function for use in interfaces to a callback based streams.
- Pass to the Read parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-PaError PaUtil_DummyRead( PaStream* stream,
- void *buffer,
- unsigned long frames );
-
-
-/** Dummy Write function for use in an interfaces to callback based streams.
- Pass to the Write parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-PaError PaUtil_DummyWrite( PaStream* stream,
- const void *buffer,
- unsigned long frames );
-
-
-/** Dummy GetReadAvailable function for use in interfaces to callback based
- streams. Pass to the GetReadAvailable parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-signed long PaUtil_DummyGetReadAvailable( PaStream* stream );
-
-
-/** Dummy GetWriteAvailable function for use in interfaces to callback based
- streams. Pass to the GetWriteAvailable parameter of PaUtil_InitializeStreamInterface.
- @return An error code indicating that the function has no effect
- because the stream is a callback stream.
-*/
-signed long PaUtil_DummyGetWriteAvailable( PaStream* stream );
-
-
-
-/** Dummy GetCpuLoad function for use in an interface to a read/write stream.
- Pass to the GetCpuLoad parameter of PaUtil_InitializeStreamInterface.
- @return Returns 0.
-*/
-double PaUtil_DummyGetCpuLoad( PaStream* stream );
-
-
-/** Non host specific data for a stream. This data is used by pa_front to
- forward to the appropriate functions in the streamInterface structure.
-*/
-typedef struct PaUtilStreamRepresentation {
- unsigned long magic; /**< set to PA_STREAM_MAGIC */
- struct PaUtilStreamRepresentation *nextOpenStream; /**< field used by multi-api code */
- PaUtilStreamInterface *streamInterface;
- PaStreamCallback *streamCallback;
- PaStreamFinishedCallback *streamFinishedCallback;
- void *userData;
- PaStreamInfo streamInfo;
-} PaUtilStreamRepresentation;
-
-
-/** Initialize a PaUtilStreamRepresentation structure.
-
- @see PaUtil_InitializeStreamRepresentation
-*/
-void PaUtil_InitializeStreamRepresentation(
- PaUtilStreamRepresentation *streamRepresentation,
- PaUtilStreamInterface *streamInterface,
- PaStreamCallback *streamCallback,
- void *userData );
-
-
-/** Clean up a PaUtilStreamRepresentation structure previously initialized
- by a call to PaUtil_InitializeStreamRepresentation.
-
- @see PaUtil_InitializeStreamRepresentation
-*/
-void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation );
-
-
-/** Check that the stream pointer is valid.
-
- @return Returns paNoError if the stream pointer appears to be OK, otherwise
- returns an error indicating the cause of failure.
-*/
-PaError PaUtil_ValidateStreamPointer( PaStream *stream );
-
-
-/** Cast an opaque stream pointer into a pointer to a PaUtilStreamRepresentation.
-
- @see PaUtilStreamRepresentation
-*/
-#define PA_STREAM_REP( stream )\
- ((PaUtilStreamRepresentation*) (stream) )
-
-
-/** Cast an opaque stream pointer into a pointer to a PaUtilStreamInterface.
-
- @see PaUtilStreamRepresentation, PaUtilStreamInterface
-*/
-#define PA_STREAM_INTERFACE( stream )\
- PA_STREAM_REP( (stream) )->streamInterface
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_STREAM_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_trace.c b/pjmedia/src/pjmedia/portaudio/pa_trace.c
deleted file mode 100644
index 83514a05..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_trace.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * $Id: pa_trace.c,v 1.1.1.1.2.3 2003/09/20 21:09:15 rossbencina Exp $
- * Portable Audio I/O Library Trace Facility
- * Store trace information in real-time for later printing.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Event trace mechanism for debugging.
-*/
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "pa_trace.h"
-
-#if PA_TRACE_REALTIME_EVENTS
-
-static char *traceTextArray[MAX_TRACE_RECORDS];
-static int traceIntArray[MAX_TRACE_RECORDS];
-static int traceIndex = 0;
-static int traceBlock = 0;
-
-/*********************************************************************/
-void PaUtil_ResetTraceMessages()
-{
- traceIndex = 0;
-}
-
-/*********************************************************************/
-void PaUtil_DumpTraceMessages()
-{
- int i;
- int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS;
-
- printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
- for( i=0; i<messageCount; i++ )
- {
- printf("%3d: %s = 0x%08X\n",
- i, traceTextArray[i], traceIntArray[i] );
- }
- ResetTraceMessages();
- fflush(stdout);
-}
-
-/*********************************************************************/
-void PaUtil_AddTraceMessage( const char *msg, int data )
-{
- if( (traceIndex == PA_MAX_TRACE_RECORDS) && (traceBlock == 0) )
- {
- traceBlock = 1;
- /* PaUtil_DumpTraceMessages(); */
- }
- else if( traceIndex < PA_MAX_TRACE_RECORDS )
- {
- traceTextArray[traceIndex] = msg;
- traceIntArray[traceIndex] = data;
- traceIndex++;
- }
-}
-
-#endif /* TRACE_REALTIME_EVENTS */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_trace.h b/pjmedia/src/pjmedia/portaudio/pa_trace.h
deleted file mode 100644
index f72a78b3..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_trace.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef PA_TRACE_H
-#define PA_TRACE_H
-/*
- * $Id: pa_trace.h,v 1.1.1.1.2.3 2003/09/20 21:09:15 rossbencina Exp $
- * Portable Audio I/O Library Trace Facility
- * Store trace information in real-time for later printing.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Event trace mechanism for debugging.
-
- Allows data to be written to the buffer at interrupt time and dumped later.
-*/
-
-
-#define PA_TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
-#define PA_MAX_TRACE_RECORDS (2048)
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-#if PA_TRACE_REALTIME_EVENTS
-
-void PaUtil_ResetTraceMessages();
-void PaUtil_AddTraceMessage( const char *msg, int data );
-void PaUtil_DumpTraceMessages();
-
-#else
-
-#define PaUtil_ResetTraceMessages() /* noop */
-#define PaUtil_AddTraceMessage(msg,data) /* noop */
-#define PaUtil_DumpTraceMessages() /* noop */
-
-#endif
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PA_TRACE_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_types.h b/pjmedia/src/pjmedia/portaudio/pa_types.h
deleted file mode 100644
index 343dc8cf..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_types.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#ifndef PA_TYPES_H
-#define PA_TYPES_H
-
-/*
- SIZEOF_SHORT, SIZEOF_INT and SIZEOF_LONG are set by the configure script
- when it is used. Otherwise we default to the common 32 bit values, if your
- platform doesn't use configure, and doesn't use the default values below
- you will need to explicitly define these symbols in your make file.
-
- A PA_VALIDATE_SIZES macro is provided to assert that the values set in this
- file are correct.
-*/
-
-#ifndef SIZEOF_SHORT
-#define SIZEOF_SHORT 2
-#endif
-
-#ifndef SIZEOF_INT
-#define SIZEOF_INT 4
-#endif
-
-#ifndef SIZEOF_LONG
-#define SIZEOF_LONG 4
-#endif
-
-
-#if SIZEOF_SHORT == 2
-typedef signed short PaInt16;
-typedef unsigned short PaUint16;
-#elif SIZEOF_INT == 2
-typedef signed int PaInt16;
-typedef unsigned int PaUint16;
-#else
-#error pa_types.h was unable to determine which type to use for 16bit integers on the target platform
-#endif
-
-#if SIZEOF_SHORT == 4
-typedef signed short PaInt32;
-typedef unsigned short PaUint32;
-#elif SIZEOF_INT == 4
-typedef signed int PaInt32;
-typedef unsigned int PaUint32;
-#elif SIZEOF_LONG == 4
-typedef signed long PaInt32;
-typedef unsigned long PaUint32;
-#else
-#error pa_types.h was unable to determine which type to use for 32bit integers on the target platform
-#endif
-
-
-/* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to
- ensure that PortAudio was configured correctly, and raises an assertion if
- they don't match the expected values. <assert.h> must be included in the
- context in which this macro is used.
-*/
-#define PA_VALIDATE_TYPE_SIZES \
- { \
- assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint16 ) == 2 ); \
- assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt16 ) == 2 ); \
- assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint32 ) == 4 ); \
- assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt32 ) == 4 ); \
- }
-
-
-#endif /* PA_TYPES_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c b/pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c
deleted file mode 100644
index d01e916e..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_hostapis.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * $Id: pa_unix_hostapis.c,v 1.1.2.5 2003/10/02 12:35:46 pieter Exp $
- * Portable Audio I/O Library UNIX initialization table
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-
-#include "pa_hostapi.h"
-
-PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-/* Added for IRIX, Pieter, oct 2, 2003: */
-PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-
-PaUtilHostApiInitializer *paHostApiInitializers[] =
- {
-#ifdef PA_USE_ALSA
- PaAlsa_Initialize,
-#endif
-
-#ifdef PA_USE_OSS
- PaOSS_Initialize,
-#endif
-
-#ifdef PA_USE_JACK
- PaJack_Initialize,
-#endif
- /* Added for IRIX, Pieter, oct 2, 2003: */
-#ifdef PA_USE_SGI
- PaSGI_Initialize,
-#endif
- 0 /* NULL terminated array */
- };
-
-int paDefaultHostApiIndex = 0;
-
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_oss.c b/pjmedia/src/pjmedia/portaudio/pa_unix_oss.c
deleted file mode 100644
index 840de3b0..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_oss.c
+++ /dev/null
@@ -1,1918 +0,0 @@
-/*
- * $Id: pa_unix_oss.c,v 1.6.2.22 2005/03/08 21:26:53 aknudsen Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * OSS implementation by:
- * Douglas Repetto
- * Phil Burk
- * Dominic Mazzoni
- * Arve Knudsen
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <alloca.h>
-#include <malloc.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <limits.h>
-#include <semaphore.h>
-
-#ifdef __linux__
-# include <linux/soundcard.h>
-# define DEVICE_NAME_BASE "/dev/dsp"
-#else
-# include <machine/soundcard.h> /* JH20010905 */
-# define DEVICE_NAME_BASE "/dev/audio"
-#endif
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-#include "pa_unix_util.h"
-
-static int sysErr_;
-static pthread_t mainThread_;
-
-/* Check return value of system call, and map it to PaError */
-#define ENSURE_(expr, code) \
- do { \
- if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \
- { \
- /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
- if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
- { \
- PaUtil_SetLastHostErrorInfo( paALSA, sysErr_, strerror( errno ) ); \
- } \
- \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
- result = (code); \
- goto error; \
- } \
- } while( 0 );
-
-#ifndef AFMT_S16_NE
-#define AFMT_S16_NE Get_AFMT_S16_NE()
-/*********************************************************************
- * Some versions of OSS do not define AFMT_S16_NE. So check CPU.
- * PowerPC is Big Endian. X86 is Little Endian.
- */
-static int Get_AFMT_S16_NE( void )
-{
- long testData = 1;
- char *ptr = (char *) &testData;
- int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */
- return isLittle ? AFMT_S16_LE : AFMT_S16_BE;
-}
-#endif
-
-/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- PaHostApiIndex hostApiIndex;
-}
-PaOSSHostApiRepresentation;
-
-/** Per-direction structure for PaOssStream.
- *
- * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback,
- * but with different number of channels we will have to adapt between the number of user and host
- * channels for at least one direction, since the configuration space is the same for both directions
- * of an OSS device.
- */
-typedef struct
-{
- int fd;
- const char *devName;
- int userChannelCount, hostChannelCount;
- int userInterleaved;
- void *buffer;
- PaSampleFormat userFormat, hostFormat;
- double latency;
- unsigned long hostFrames, numBufs;
- void **userBuffers; /* For non-interleaved blocking */
-} PaOssStreamComponent;
-
-/** Implementation specific representation of a PaStream.
- *
- */
-typedef struct PaOssStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- PaUtilThreading threading;
-
- int sharedDevice;
- unsigned long framesPerHostBuffer;
- int triggered; /* Have the devices been triggered yet (first start) */
-
- int isActive;
- int isStopped;
-
- int lastPosPtr;
- double lastStreamBytes;
-
- int framesProcessed;
-
- double sampleRate;
-
- int callbackMode;
- int callbackStop, callbackAbort;
-
- PaOssStreamComponent *capture, *playback;
- unsigned long pollTimeout;
- sem_t semaphore;
-}
-PaOssStream;
-
-typedef enum {
- StreamMode_In,
- StreamMode_Out
-} StreamMode;
-
-/* prototypes for functions declared in this file */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );
-
-
-/** Initialize the OSS API implementation.
- *
- * This function will initialize host API datastructures and query host devices for information.
- *
- * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here
- *
- * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function,
- * this happens with the usual "error" label.
- */
-PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- PaOSSHostApiRepresentation *ossHostApi = NULL;
-
- PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ),
- paInsufficientMemory );
- PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
- ossHostApi->hostApiIndex = hostApiIndex;
-
- /* Initialize host API structure */
- *hostApi = &ossHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paOSS;
- (*hostApi)->info.name = "OSS";
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PA_ENSURE( BuildDeviceList( ossHostApi ) );
-
- PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable,
- PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- mainThread_ = pthread_self();
-
- return result;
-
-error:
- if( ossHostApi )
- {
- if( ossHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( ossHostApi->allocations );
- PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
- }
-
- PaUtil_FreeMemory( ossHostApi );
- }
- return result;
-}
-
-PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels,
- int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency,
- PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations )
-{
- PaError result = paNoError;
-
- deviceInfo->structVersion = 2;
- if( allocations )
- {
- size_t len = strlen( name ) + 1;
- PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory );
- strncpy( (char *)deviceInfo->name, name, len );
- }
- else
- deviceInfo->name = name;
-
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->maxInputChannels = maxInputChannels;
- deviceInfo->maxOutputChannels = maxOutputChannels;
- deviceInfo->defaultLowInputLatency = defaultLowInputLatency;
- deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency;
- deviceInfo->defaultHighInputLatency = defaultHighInputLatency;
- deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;
- deviceInfo->defaultSampleRate = defaultSampleRate;
-
-error:
- return result;
-}
-
-static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,
- double *defaultLowLatency, double *defaultHighLatency )
-{
- PaError result = paNoError;
- int numChannels, maxNumChannels;
- int busy = 0;
- int devHandle = -1;
- int sr;
- *maxChannelCount = 0; /* Default value in case this fails */
-
- if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK )) < 0 )
- {
- if( errno == EBUSY || errno == EAGAIN )
- {
- PA_DEBUG(( "%s: Device %s busy\n", __FUNCTION__, deviceName ));
- }
- else
- {
- PA_DEBUG(( "%s: Can't access device: %s\n", __FUNCTION__, strerror( errno ) ));
- }
-
- return paDeviceUnavailable;
- }
-
- /* Negotiate for the maximum number of channels for this device. PLB20010927
- * Consider up to 16 as the upper number of channels.
- * Variable maxNumChannels should contain the actual upper limit after the call.
- * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.
- */
- maxNumChannels = 0;
- for( numChannels = 1; numChannels <= 16; numChannels++ )
- {
- int temp = numChannels;
- if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )
- {
- busy = EAGAIN == errno || EBUSY == errno;
- /* ioctl() failed so bail out if we already have stereo */
- if( maxNumChannels >= 2 )
- break;
- }
- else
- {
- /* ioctl() worked but bail out if it does not support numChannels.
- * We don't want to leave gaps in the numChannels supported.
- */
- if( (numChannels > 2) && (temp != numChannels) )
- break;
- if( temp > maxNumChannels )
- maxNumChannels = temp; /* Save maximum. */
- }
- }
- /* A: We're able to open a device for capture if it's busy playing back and vice versa,
- * but we can't configure anything */
- if( 0 == maxNumChannels && busy )
- {
- result = paDeviceUnavailable;
- goto error;
- }
-
- /* The above negotiation may fail for an old driver so try this older technique. */
- if( maxNumChannels < 1 )
- {
- int stereo = 1;
- if( ioctl( devHandle, SNDCTL_DSP_STEREO, &stereo ) < 0 )
- {
- maxNumChannels = 1;
- }
- else
- {
- maxNumChannels = (stereo) ? 2 : 1;
- }
- PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels ))
- }
-
- /* During channel negotiation, the last ioctl() may have failed. This can
- * also cause sample rate negotiation to fail. Hence the following, to return
- * to a supported number of channels. SG20011005 */
- {
- /* use most reasonable default value */
- int temp = PA_MIN( maxNumChannels, 2 );
- ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );
- }
-
- /* Get supported sample rate closest to 44100 Hz */
- if( *defaultSampleRate < 0 )
- {
- sr = 44100;
- if( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ) < 0 )
- {
- result = paUnanticipatedHostError;
- goto error;
- }
-
- *defaultSampleRate = sr;
- }
-
- *maxChannelCount = maxNumChannels;
- /* TODO */
- *defaultLowLatency = 512. / *defaultSampleRate;
- *defaultHighLatency = 2048. / *defaultSampleRate;
-
-error:
- if( devHandle >= 0 )
- close( devHandle );
-
- return result;
-}
-
-/** Query OSS device.
- *
- * This is where PaDeviceInfo objects are constructed and filled in with relevant information.
- *
- * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed
- * in place.
- */
-static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo )
-{
- PaError result = paNoError;
- double sampleRate = -1.;
- int maxInputChannels, maxOutputChannels;
- PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency;
- PaError tmpRes = paNoError;
- int busy = 0;
- *deviceInfo = NULL;
-
- /* douglas:
- we have to do this querying in a slightly different order. apparently
- some sound cards will give you different info based on their settins.
- e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
- the correct order for OSS is: format, channels, sample rate
- */
-
- /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is
- * opened in, it may have more channels available for capture than playback and vice versa. Therefore
- * we will open the device in both read- and write-only mode to determine the supported number.
- */
- if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency,
- &defaultHighInputLatency )) != paNoError )
- {
- if( tmpRes != paDeviceUnavailable )
- {
- PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName ));
- /* PA_ENSURE( tmpRes ); */
- }
- ++busy;
- }
- if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency,
- &defaultHighOutputLatency )) != paNoError )
- {
- if( tmpRes != paDeviceUnavailable )
- {
- PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName ));
- /* PA_ENSURE( tmpRes ); */
- }
- ++busy;
- }
- assert( 0 <= busy && busy <= 2 );
- if( 2 == busy ) /* Both directions are unavailable to us */
- {
- result = paDeviceUnavailable;
- goto error;
- }
-
- PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory );
- PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels,
- defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate,
- ossApi->allocations ) );
-
-error:
- return result;
-}
-
-/** Query host devices.
- *
- * Loop over host devices and query their capabilitiesu
- *
- * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object
- * per device, these are placed in the host api representation's deviceInfos array.
- */
-static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
-{
- PaError result = paNoError;
- PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
- int i;
- int numDevices = 0, maxDeviceInfos = 1;
- PaDeviceInfo **deviceInfos = NULL;
-
- /* These two will be set to the first working input and output device, respectively */
- commonApi->info.defaultInputDevice = paNoDevice;
- commonApi->info.defaultOutputDevice = paNoDevice;
-
- /* Find devices by calling QueryDevice on each
- * potential device names. When we find a valid one,
- * add it to a linked list.
- * A: Can there only be 10 devices? */
-
- for( i = 0; i < 10; i++ )
- {
- char deviceName[32];
- PaDeviceInfo *deviceInfo;
- int testResult;
- struct stat stbuf;
-
- if( i == 0 )
- snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE);
- else
- snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i);
-
- /* PA_DEBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); */
- if( stat( deviceName, &stbuf ) < 0 )
- {
- if( ENOENT != errno )
- PA_DEBUG(( "%s: Error stat'ing %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) ));
- continue;
- }
- if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError )
- {
- if( testResult != paDeviceUnavailable )
- PA_ENSURE( testResult );
-
- continue;
- }
-
- ++numDevices;
- if( !deviceInfos || numDevices > maxDeviceInfos )
- {
- maxDeviceInfos *= 2;
- PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ),
- paInsufficientMemory );
- }
- deviceInfos[numDevices - 1] = deviceInfo;
-
- if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 )
- commonApi->info.defaultInputDevice = i;
- if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 )
- commonApi->info.defaultOutputDevice = i;
- }
-
- /* Make an array of PaDeviceInfo pointers out of the linked list */
-
- PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices));
-
- commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
- memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) );
-
- commonApi->info.deviceCount = numDevices;
-
-error:
- free( deviceInfos );
-
- return result;
-}
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
-
- if( ossHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( ossHostApi->allocations );
- PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
- }
-
- PaUtil_FreeMemory( ossHostApi );
-}
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaError result = paNoError;
- PaDeviceIndex device;
- PaDeviceInfo *deviceInfo;
- char *deviceName;
- int inputChannelCount, outputChannelCount;
- int tempDevHandle = -1;
- int flags;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
-
- /* validate inputStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- inputChannelCount = 0;
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support inputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* validate outputStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- outputChannelCount = 0;
- }
-
- if (inputChannelCount == 0 && outputChannelCount == 0)
- return paInvalidChannelCount;
-
- /* if full duplex, make sure that they're the same device */
-
- if (inputChannelCount > 0 && outputChannelCount > 0 &&
- inputParameters->device != outputParameters->device)
- return paInvalidDevice;
-
- /* if full duplex, also make sure that they're the same number of channels */
-
- if (inputChannelCount > 0 && outputChannelCount > 0 &&
- inputChannelCount != outputChannelCount)
- return paInvalidChannelCount;
-
- /* open the device so we can do more tests */
-
- if( inputChannelCount > 0 )
- {
- result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
- if (result != paNoError)
- return result;
- }
- else
- {
- result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
- if (result != paNoError)
- return result;
- }
-
- deviceInfo = hostApi->deviceInfos[device];
- deviceName = (char *)deviceInfo->name;
-
- flags = O_NONBLOCK;
- if (inputChannelCount > 0 && outputChannelCount > 0)
- flags |= O_RDWR;
- else if (inputChannelCount > 0)
- flags |= O_RDONLY;
- else
- flags |= O_WRONLY;
-
- ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable );
-
- /* PaOssStream_Configure will do the rest of the checking for us */
- /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */
-
- /* everything succeeded! */
-
- error:
- if( tempDevHandle >= 0 )
- close( tempDevHandle );
-
- return result;
-}
-
-/** Validate stream parameters.
- *
- * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device
- */
-static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode )
-{
- int maxChans;
-
- assert( parameters );
-
- if( parameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- return paInvalidDevice;
- }
-
- maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels :
- deviceInfo->maxOutputChannels);
- if( parameters->channelCount > maxChans )
- {
- return paInvalidChannelCount;
- }
-
- return paNoError;
-}
-
-static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters,
- int callbackMode, int fd, const char *deviceName )
-{
- PaError result = paNoError;
- assert( component );
-
- memset( component, 0, sizeof (PaOssStreamComponent) );
-
- component->fd = fd;
- component->devName = deviceName;
- component->userChannelCount = parameters->channelCount;
- component->userFormat = parameters->sampleFormat;
- component->latency = parameters->suggestedLatency;
- component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved);
-
- if( !callbackMode && !component->userInterleaved )
- {
- /* Pre-allocate non-interleaved user provided buffers */
- PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ),
- paInsufficientMemory );
- }
-
-error:
- return result;
-}
-
-static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component )
-{
- assert( component );
-
- if( component->fd >= 0 )
- close( component->fd );
- if( component->buffer )
- PaUtil_FreeMemory( component->buffer );
-
- if( component->userBuffers )
- PaUtil_FreeMemory( component->userBuffers );
-
- PaUtil_FreeMemory( component );
-}
-
-static PaError ModifyBlocking( int fd, int blocking )
-{
- PaError result = paNoError;
- int fflags;
-
- ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError );
-
- if( blocking )
- fflags &= ~O_NONBLOCK;
- else
- fflags |= O_NONBLOCK;
-
- ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError );
-
-error:
- return result;
-}
-
-static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev )
-{
- PaError result = paNoError;
- int flags = O_NONBLOCK, duplex = 0;
- int enableBits = 0;
- *idev = *odev = -1;
-
- if( idevName && odevName )
- {
- duplex = 1;
- flags |= O_RDWR;
- }
- else if( idevName )
- flags |= O_RDONLY;
- else
- flags |= O_WRONLY;
-
- /* open first in nonblocking mode, in case it's busy...
- * A: then unset the non-blocking attribute */
- assert( flags & O_NONBLOCK );
- if( idevName )
- {
- ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable );
- PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */
-
- /* Initially disable */
- enableBits = ~PCM_ENABLE_INPUT;
- ENSURE_( ioctl( *idev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- if( odevName )
- {
- if( !idevName )
- {
- ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable );
- PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */
-
- /* Initially disable */
- enableBits = ~PCM_ENABLE_OUTPUT;
- ENSURE_( ioctl( *odev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- else
- {
- ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError );
- }
- }
-
-error:
- return result;
-}
-
-static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,
- PaStreamCallback callback, void *userData, PaStreamFlags streamFlags,
- PaOSSHostApiRepresentation *ossApi )
-{
- PaError result = paNoError;
- int idev, odev;
- PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep;
- const char *idevName = NULL, *odevName = NULL;
-
- assert( stream );
-
- memset( stream, 0, sizeof (PaOssStream) );
- stream->isStopped = 1;
-
- PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) );
-
- if( inputParameters && outputParameters )
- {
- if( inputParameters->device == outputParameters->device )
- stream->sharedDevice = 1;
- }
-
- if( inputParameters )
- idevName = hostApi->deviceInfos[inputParameters->device]->name;
- if( outputParameters )
- odevName = hostApi->deviceInfos[outputParameters->device]->name;
- PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) );
- if( inputParameters )
- {
- PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
- PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) );
- }
- if( outputParameters )
- {
- PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
- PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) );
- }
-
- if( callback != NULL )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &ossApi->callbackStreamInterface, callback, userData );
- stream->callbackMode = 1;
- }
- else
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &ossApi->blockingStreamInterface, callback, userData );
- }
-
- ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError );
-
-error:
- return result;
-}
-
-static void PaOssStream_Terminate( PaOssStream *stream )
-{
- assert( stream );
-
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- PaUtil_TerminateThreading( &stream->threading );
-
- if( stream->capture )
- PaOssStreamComponent_Terminate( stream->capture );
- if( stream->playback )
- PaOssStreamComponent_Terminate( stream->playback );
-
- sem_destroy( &stream->semaphore );
-
- PaUtil_FreeMemory( stream );
-}
-
-/** Translate from PA format to OSS native.
- *
- */
-static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat )
-{
- switch( paFormat )
- {
- case paUInt8:
- *ossFormat = AFMT_U8;
- break;
- case paInt8:
- *ossFormat = AFMT_S8;
- break;
- case paInt16:
- *ossFormat = AFMT_S16_NE;
- break;
- default:
- return paInternalError; /* This shouldn't happen */
- }
-
- return paNoError;
-}
-
-/** Return the PA-compatible formats that this device can support.
- *
- */
-static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats )
-{
- PaError result = paNoError;
- int mask = 0;
- PaSampleFormat frmts = 0;
-
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError );
- if( mask & AFMT_U8 )
- frmts |= paUInt8;
- if( mask & AFMT_S8 )
- frmts |= paInt8;
- if( mask & AFMT_S16_NE )
- frmts |= paInt16;
- else
- result = paSampleFormatNotSupported;
-
- *availableFormats = frmts;
-
-error:
- return result;
-}
-
-static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component )
-{
- return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount;
-}
-
-/** Buffer size in bytes.
- *
- */
-static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component )
-{
- return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;
-}
-
-static int CalcHigherLogTwo( int n )
-{
- int log2 = 0;
- while( (1<<log2) < n ) log2++;
- return log2;
-}
-
-static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long framesPerBuffer,
- StreamMode streamMode, PaOssStreamComponent *master )
-{
- PaError result = paNoError;
- int temp, nativeFormat;
- int sr = (int)sampleRate;
- PaSampleFormat availableFormats = 0, hostFormat;
- int chans = component->userChannelCount;
- int frgmt;
- int numBufs;
- int bytesPerBuf;
- double bufSz;
- unsigned long fragSz;
- audio_buf_info bufInfo;
-
- /* We may have a situation where only one component (the master) is configured, if both point to the same device.
- * In that case, the second component will copy settings from the other */
- if( !master )
- {
- /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size.
- * The hardware need not respect the requested fragment size, so we may have to adapt.
- */
- if( framesPerBuffer == paFramesPerBufferUnspecified )
- {
- bufSz = component->latency * sampleRate;
- fragSz = bufSz / 4;
- }
- else
- {
- fragSz = framesPerBuffer;
- bufSz = component->latency * sampleRate + fragSz; /* Latency + 1 buffer */
- }
-
- PA_ENSURE( GetAvailableFormats( component, &availableFormats ) );
- hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat );
-
- /* OSS demands at least 2 buffers, and 16 bytes per buffer */
- numBufs = PA_MAX( bufSz / fragSz, 2 );
- bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 );
-
- /* The fragment parameters are encoded like this:
- * Most significant byte: number of fragments
- * Least significant byte: exponent of fragment size (i.e., for 256, 8)
- */
- frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff);
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );
-
- /* A: according to the OSS programmer's guide parameters should be set in this order:
- * format, channels, rate */
-
- /* This format should be deemed good before we get this far */
- PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) );
- nativeFormat = temp;
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError );
- PA_UNLESS( temp == nativeFormat, paInternalError );
-
- /* try to set the number of channels */
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported ); /* XXX: Should be paInvalidChannelCount? */
- /* It's possible that the minimum number of host channels is greater than what the user requested */
- PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount );
-
- /* try to set the sample rate */
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate );
-
- /* reject if there's no sample rate within 1% of the one requested */
- if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 )
- {
- PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));
- PA_ENSURE( paInvalidSampleRate );
- }
-
- ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ),
- paUnanticipatedHostError );
- component->numBufs = bufInfo.fragstotal;
-
- /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError );
-
- component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans;
- component->hostChannelCount = chans;
- component->hostFormat = hostFormat;
- }
- else
- {
- component->hostFormat = master->hostFormat;
- component->hostFrames = master->hostFrames;
- component->hostChannelCount = master->hostChannelCount;
- component->numBufs = master->numBufs;
- }
-
- PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ),
- paInsufficientMemory );
-
-error:
- return result;
-}
-
-static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames )
-{
- PaError result = paNoError;
- size_t len = *frames * PaOssStreamComponent_FrameSize( component );
- ssize_t bytesRead;
-
- ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError );
- *frames = bytesRead / PaOssStreamComponent_FrameSize( component );
-
-error:
- return result;
-}
-
-static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames )
-{
- PaError result = paNoError;
- size_t len = *frames * PaOssStreamComponent_FrameSize( component );
- ssize_t bytesWritten;
-
- ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError );
- *frames = bytesWritten / PaOssStreamComponent_FrameSize( component );
-
-error:
- return result;
-}
-
-/** Configure the stream according to input/output parameters.
- *
- * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by
- * the user, if so we'll record the actual number of host channels and adapt later.
- */
-static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer,
- double *inputLatency, double *outputLatency )
-{
- PaError result = paNoError;
- int duplex = stream->capture && stream->playback;
- unsigned long framesPerHostBuffer = 0;
-
- /* We should request full duplex first thing after opening the device */
- if( duplex && stream->sharedDevice )
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError );
-
- if( stream->capture )
- {
- PaOssStreamComponent *component = stream->capture;
- PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In, NULL );
-
- assert( component->hostChannelCount > 0 );
- assert( component->hostFrames > 0 );
-
- *inputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;
- }
- if( stream->playback )
- {
- PaOssStreamComponent *component = stream->playback, *master = stream->sharedDevice ? stream->capture : NULL;
- PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_Out,
- master ) );
-
- assert( component->hostChannelCount > 0 );
- assert( component->hostFrames > 0 );
-
- *outputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;
- }
-
- if( duplex )
- framesPerHostBuffer = PA_MIN( stream->capture->hostFrames, stream->playback->hostFrames );
- else if( stream->capture )
- framesPerHostBuffer = stream->capture->hostFrames;
- else if( stream->playback )
- framesPerHostBuffer = stream->playback->hostFrames;
-
- stream->framesPerHostBuffer = framesPerHostBuffer;
- stream->pollTimeout = (int) ceil( 1e6 * framesPerHostBuffer / sampleRate ); /* Period in usecs, rounded up */
-
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-error:
- return result;
-}
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-/** Open a PA OSS stream.
- *
- * Aspect StreamChannels: The number of channels is specified per direction (in/out), and can differ between the
- * two. However, OSS doesn't support separate configuration spaces for capture and playback so if both
- * directions are the same device we will demand the same number of channels. The number of channels can range
- * from 1 to the maximum supported by the device.
- *
- * Aspect BufferSettings: If framesPerBuffer != paFramesPerBufferUnspecified the number of frames per callback
- * must reflect this, in addition the host latency per device should approximate the corresponding
- * suggestedLatency. Based on these constraints we need to determine a number of frames per host buffer that
- * both capture and playback can agree on (they can be different devices), the buffer processor can adapt
- * between host and user buffer size, but the ratio should preferably be integral.
- */
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result = paNoError;
- PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
- PaOssStream *stream = NULL;
- int inputChannelCount = 0, outputChannelCount = 0;
- PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0, inputHostFormat = 0, outputHostFormat = 0;
- const PaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0;
- int bpInitialized = 0;
- double inLatency=0, outLatency=0;
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- return paInvalidFlag; /* unexpected platform specific flag */
-
- if( inputParameters )
- {
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- inputDeviceInfo = hostApi->deviceInfos[inputParameters->device];
- PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, StreamMode_In ) );
-
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- }
- if( outputParameters )
- {
- outputDeviceInfo = hostApi->deviceInfos[outputParameters->device];
- PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, StreamMode_Out ) );
-
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- }
-
- /* Aspect StreamChannels: We currently demand that number of input and output channels are the same, if the same
- * device is opened for both directions
- */
- if( inputChannelCount > 0 && outputChannelCount > 0 )
- {
- if( inputParameters->device == outputParameters->device )
- {
- if( inputParameters->channelCount != outputParameters->channelCount )
- return paInvalidChannelCount;
- }
- }
-
- /* allocate and do basic initialization of the stream structure */
- PA_UNLESS( stream = (PaOssStream*)PaUtil_AllocateMemory( sizeof(PaOssStream) ), paInsufficientMemory );
- PaOssStream_Initialize( stream, inputParameters, outputParameters, streamCallback, userData, streamFlags, ossHostApi );
-
- PA_ENSURE( PaOssStream_Configure( stream, sampleRate, framesPerBuffer, &inLatency, &outLatency ) );
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
- if( inputParameters )
- {
- inputHostFormat = stream->capture->hostFormat;
- stream->streamRepresentation.streamInfo.inputLatency = inLatency +
- PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) / sampleRate;
- }
- if( outputParameters )
- {
- outputHostFormat = stream->playback->hostFormat;
- stream->streamRepresentation.streamInfo.outputLatency = outLatency +
- PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) / sampleRate;
- }
-
- /* Initialize buffer processor with fixed host buffer size.
- * Aspect StreamSampleFormat: Here we commit the user and host sample formats, PA infrastructure will
- * convert between the two.
- */
- PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- inputChannelCount, inputSampleFormat, inputHostFormat, outputChannelCount, outputSampleFormat,
- outputHostFormat, sampleRate, streamFlags, framesPerBuffer, stream->framesPerHostBuffer,
- paUtilFixedHostBufferSize, streamCallback, userData ) );
- bpInitialized = 1;
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
- if( bpInitialized )
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- if( stream )
- PaOssStream_Terminate( stream );
-
- return result;
-}
-
-/*! Poll on I/O filedescriptors.
-
- Poll till we've determined there's data for read or write. In the full-duplex case,
- we don't want to hang around forever waiting for either input or output frames, so
- whenever we have a timed out filedescriptor we check if we're nearing under/overrun
- for the other direction (critical limit set at one buffer). If so, we exit the waiting
- state, and go on with what we got. We align the number of frames on a host buffer
- boundary because it is possible that the buffer size differs for the two directions and
- the host buffer size is a compromise between the two.
- */
-static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *frames )
-{
- PaError result = paNoError;
- int pollPlayback = 0, pollCapture = 0;
- int captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail;
- audio_buf_info bufInfo;
- /* int ofs = 0, nfds = stream->nfds; */
- fd_set readFds, writeFds;
- int nfds = 0;
- struct timeval selectTimeval = {0, 0};
- unsigned long timeout = stream->pollTimeout; /* In usecs */
- int captureFd = -1, playbackFd = -1;
-
- assert( stream );
- assert( frames );
-
- if( stream->capture )
- {
- pollCapture = 1;
- captureFd = stream->capture->fd;
- /* stream->capture->pfd->events = POLLIN; */
- }
- if( stream->playback )
- {
- pollPlayback = 1;
- playbackFd = stream->playback->fd;
- /* stream->playback->pfd->events = POLLOUT; */
- }
-
- FD_ZERO( &readFds );
- FD_ZERO( &writeFds );
-
- while( pollPlayback || pollCapture )
- {
- pthread_testcancel();
-
- /* select may modify the timeout parameter */
- selectTimeval.tv_usec = timeout;
- nfds = 0;
-
- if( pollCapture )
- {
- FD_SET( captureFd, &readFds );
- nfds = captureFd + 1;
- }
- if( pollPlayback )
- {
- FD_SET( playbackFd, &writeFds );
- nfds = PA_MAX( nfds, playbackFd + 1 );
- }
- ENSURE_( select( nfds, &readFds, &writeFds, NULL, &selectTimeval ), paUnanticipatedHostError );
- /*
- if( poll( stream->pfds + ofs, nfds, stream->pollTimeout ) < 0 )
- {
-
- ENSURE_( -1, paUnanticipatedHostError );
- }
- */
- pthread_testcancel();
-
- if( pollCapture )
- {
- if( FD_ISSET( captureFd, &readFds ) )
- {
- FD_CLR( captureFd, &readFds );
- pollCapture = 0;
- }
- /*
- if( stream->capture->pfd->revents & POLLIN )
- {
- --nfds;
- ++ofs;
- pollCapture = 0;
- }
- */
- else if( stream->playback ) /* Timed out, go on with playback? */
- {
- /*PA_DEBUG(( "%s: Trying to poll again for capture frames, pollTimeout: %d\n",
- __FUNCTION__, stream->pollTimeout ));*/
- }
- }
- if( pollPlayback )
- {
- if( FD_ISSET( playbackFd, &writeFds ) )
- {
- FD_CLR( playbackFd, &writeFds );
- pollPlayback = 0;
- }
- /*
- if( stream->playback->pfd->revents & POLLOUT )
- {
- --nfds;
- pollPlayback = 0;
- }
- */
- else if( stream->capture ) /* Timed out, go on with capture? */
- {
- /*PA_DEBUG(( "%s: Trying to poll again for playback frames, pollTimeout: %d\n\n",
- __FUNCTION__, stream->pollTimeout ));*/
- }
- }
- }
-
- if( stream->capture )
- {
- ENSURE_( ioctl( captureFd, SNDCTL_DSP_GETISPACE, &bufInfo ), paUnanticipatedHostError );
- captureAvail = bufInfo.fragments * stream->capture->hostFrames;
- if( !captureAvail )
- PA_DEBUG(( "%s: captureAvail: 0\n", __FUNCTION__ ));
-
- captureAvail = captureAvail == 0 ? INT_MAX : captureAvail; /* Disregard if zero */
- }
- if( stream->playback )
- {
- ENSURE_( ioctl( playbackFd, SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError );
- playbackAvail = bufInfo.fragments * stream->playback->hostFrames;
- if( !playbackAvail )
- {
- PA_DEBUG(( "%s: playbackAvail: 0\n", __FUNCTION__ ));
- }
-
- playbackAvail = playbackAvail == 0 ? INT_MAX : playbackAvail; /* Disregard if zero */
- }
-
- commonAvail = PA_MIN( captureAvail, playbackAvail );
- if( commonAvail == INT_MAX )
- commonAvail = 0;
- commonAvail -= commonAvail % stream->framesPerHostBuffer;
-
- assert( commonAvail != INT_MAX );
- assert( commonAvail >= 0 );
- *frames = commonAvail;
-
-error:
- return result;
-}
-
-/** Prepare stream for capture/playback.
- *
- * In order to synchronize capture and playback properly we use the SETTRIGGER command.
- */
-static PaError PaOssStream_Prepare( PaOssStream *stream )
-{
- PaError result = paNoError;
- int enableBits = 0;
-
- if( stream->triggered )
- return result;
-
- if( stream->playback )
- {
- size_t bufSz = PaOssStreamComponent_BufferSize( stream->playback );
- memset( stream->playback->buffer, 0, bufSz );
-
- /* Looks like we have to turn off blocking before we try this, but if we don't fill the buffer
- * OSS will complain. */
- PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
- while (1)
- {
- if( write( stream->playback->fd, stream->playback->buffer, bufSz ) < 0 )
- break;
- }
- PA_ENSURE( ModifyBlocking( stream->playback->fd, 1 ) );
- }
-
- if( stream->sharedDevice )
- {
- enableBits = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- else
- {
- if( stream->capture )
- {
- enableBits = PCM_ENABLE_INPUT;
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- if( stream->playback )
- {
- enableBits = PCM_ENABLE_OUTPUT;
- ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- }
-
- /* Ok, we have triggered the stream */
- stream->triggered = 1;
-
-error:
- return result;
-}
-
-/** Stop audio processing
- *
- */
-static PaError PaOssStream_Stop( PaOssStream *stream, int abort )
-{
- PaError result = paNoError;
-
- /* Looks like the only safe way to stop audio without reopening the device is SNDCTL_DSP_POST.
- * Also disable capture/playback till the stream is started again */
- if( stream->capture )
- {
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );
- }
- if( stream->playback && !stream->sharedDevice )
- {
- ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );
- }
-
-error:
- return result;
-}
-
-/** Clean up after thread exit.
- *
- * Aspect StreamState: If the user has registered a streamFinishedCallback it will be called here
- */
-static void OnExit( void *data )
-{
- PaOssStream *stream = (PaOssStream *) data;
- assert( data );
-
- PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-
- PaOssStream_Stop( stream, stream->callbackAbort );
-
- PA_DEBUG(( "OnExit: Stoppage\n" ));
-
- /* Eventually notify user all buffers have played */
- if( stream->streamRepresentation.streamFinishedCallback )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-
- stream->callbackAbort = 0; /* Clear state */
- stream->isActive = 0;
-}
-
-static PaError SetUpBuffers( PaOssStream *stream, unsigned long framesAvail )
-{
- PaError result = paNoError;
-
- if( stream->capture )
- {
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer,
- stream->capture->hostChannelCount );
- PaUtil_SetInputFrameCount( &stream->bufferProcessor, framesAvail );
- }
- if( stream->playback )
- {
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer,
- stream->playback->hostChannelCount );
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, framesAvail );
- }
-
- return result;
-}
-
-/** Thread procedure for callback processing.
- *
- * Aspect StreamState: StartStream will wait on this to initiate audio processing, useful in case the
- * callback should be used for buffer priming. When the stream is cancelled a separate function will
- * take care of the transition to the Callback Finished state (the stream isn't considered Stopped
- * before StopStream() or AbortStream() are called).
- */
-static void *PaOSS_AudioThreadProc( void *userData )
-{
- PaError result = paNoError;
- PaOssStream *stream = (PaOssStream*)userData;
- unsigned long framesAvail=0, framesProcessed;
- int callbackResult = paContinue;
- int triggered = stream->triggered; /* See if SNDCTL_DSP_TRIGGER has been issued already */
- int initiateProcessing = triggered; /* Already triggered? */
- PaStreamCallbackFlags cbFlags = 0; /* We might want to keep state across iterations */
-
- /*
-#if ( SOUND_VERSION > 0x030904 )
- audio_errinfo errinfo;
-#endif
-*/
-
- assert( stream );
-
- pthread_cleanup_push( &OnExit, stream ); /* Execute OnExit when exiting */
-
- /* The first time the stream is started we use SNDCTL_DSP_TRIGGER to accurately start capture and
- * playback in sync, when the stream is restarted after being stopped we simply start by reading/
- * writing.
- */
- PA_ENSURE( PaOssStream_Prepare( stream ) );
-
- /* If we are to initiate processing implicitly by reading/writing data, we start off in blocking mode */
- if( initiateProcessing )
- {
- /* Make sure devices are in blocking mode */
- if( stream->capture )
- ModifyBlocking( stream->capture->fd, 1 );
- if( stream->playback )
- ModifyBlocking( stream->playback->fd, 1 );
- }
-
- while( 1 )
- {
- PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */
-
- pthread_testcancel();
-
- if( stream->callbackStop && callbackResult == paContinue )
- {
- PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
- callbackResult = paComplete;
- }
-
- /* Aspect StreamState: Because of the messy OSS scheme we can't explicitly trigger device start unless
- * the stream has been recently started, we will have to go right ahead and read/write in blocking
- * fashion to trigger operation. Therefore we begin with processing one host buffer before we switch
- * to non-blocking mode.
- */
- if( !initiateProcessing )
- {
- PA_ENSURE( PaOssStream_WaitForFrames( stream, &framesAvail ) ); /* Wait on available frames */
- assert( framesAvail % stream->framesPerHostBuffer == 0 );
- }
- else
- {
- framesAvail = stream->framesPerHostBuffer;
- }
-
- while( framesAvail > 0 )
- {
- unsigned long frames = framesAvail;
-
- pthread_testcancel();
-
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
- /* Read data */
- if ( stream->capture )
- {
- PA_ENSURE( PaOssStreamComponent_Read( stream->capture, &frames ) );
- assert( frames == framesAvail );
- }
-
-#if ( SOUND_VERSION >= 0x030904 )
- /*
- Check with OSS to see if there have been any under/overruns
- since last time we checked.
- */
- /*
- if( ioctl( stream->deviceHandle, SNDCTL_DSP_GETERROR, &errinfo ) >= 0 )
- {
- if( errinfo.play_underruns )
- cbFlags |= paOutputUnderflow ;
- if( errinfo.record_underruns )
- cbFlags |= paInputUnderflow ;
- }
- else
- PA_DEBUG(( "SNDCTL_DSP_GETERROR command failed: %s\n", strerror( errno ) ));
- */
-#endif
-
- PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
- cbFlags );
- cbFlags = 0;
- PA_ENSURE( SetUpBuffers( stream, framesAvail ) );
-
- framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
- &callbackResult );
- assert( framesProcessed == framesAvail );
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
- if ( stream->playback )
- {
- frames = framesAvail;
-
- PA_ENSURE( PaOssStreamComponent_Write( stream->playback, &frames ) );
- assert( frames == framesAvail );
-
- /* TODO: handle bytesWritten != bytesRequested (slippage?) */
- }
-
- framesAvail -= framesProcessed;
- stream->framesProcessed += framesProcessed;
-
- if( callbackResult != paContinue )
- break;
- }
-
- if( initiateProcessing || !triggered )
- {
- /* Non-blocking */
- if( stream->capture )
- PA_ENSURE( ModifyBlocking( stream->capture->fd, 0 ) );
- if( stream->playback && !stream->sharedDevice )
- PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
-
- initiateProcessing = 0;
- sem_post( &stream->semaphore );
- }
-
- if( callbackResult != paContinue )
- {
- stream->callbackAbort = callbackResult == paAbort;
- if( stream->callbackAbort || PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
- break;
- }
- }
-
- pthread_cleanup_pop( 1 );
-
-error:
- pthread_exit( NULL );
-}
-
-/** Close the stream.
- *
- */
-static PaError CloseStream( PaStream* s )
-{
- PaError result = paNoError;
- PaOssStream *stream = (PaOssStream*)s;
-
- assert( stream );
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaOssStream_Terminate( stream );
-
- return result;
-}
-
-/** Start the stream.
- *
- * Aspect StreamState: After returning, the stream shall be in the Active state, implying that an eventual
- * callback will be repeatedly called in a separate thread. If a separate thread is started this function
- * will block untill it has started processing audio, otherwise audio processing is started directly.
- */
-static PaError StartStream( PaStream *s )
-{
- PaError result = paNoError;
- PaOssStream *stream = (PaOssStream*)s;
-
- stream->isActive = 1;
- stream->isStopped = 0;
- stream->lastPosPtr = 0;
- stream->lastStreamBytes = 0;
- stream->framesProcessed = 0;
-
- /* only use the thread for callback streams */
- if( stream->bufferProcessor.streamCallback )
- {
- PA_ENSURE( PaUtil_StartThreading( &stream->threading, &PaOSS_AudioThreadProc, stream ) );
- sem_wait( &stream->semaphore );
- }
- else
- PA_ENSURE( PaOssStream_Prepare( stream ) );
-
-error:
- return result;
-}
-
-static PaError RealStop( PaOssStream *stream, int abort )
-{
- PaError result = paNoError;
-
- if( stream->callbackMode )
- {
- if( abort )
- stream->callbackAbort = 1;
- else
- stream->callbackStop = 1;
-
- PA_ENSURE( PaUtil_CancelThreading( &stream->threading, !abort, NULL ) );
-
- stream->callbackStop = stream->callbackAbort = 0;
- }
- else
- PA_ENSURE( PaOssStream_Stop( stream, abort ) );
-
- stream->isStopped = 1;
-
-error:
- return result;
-}
-
-/** Stop the stream.
- *
- * Aspect StreamState: This will cause the stream to transition to the Stopped state, playing all enqueued
- * buffers.
- */
-static PaError StopStream( PaStream *s )
-{
- return RealStop( (PaOssStream *)s, 0 );
-}
-
-/** Abort the stream.
- *
- * Aspect StreamState: This will cause the stream to transition to the Stopped state, discarding all enqueued
- * buffers. Note that the buffers are not currently correctly discarded, this is difficult without closing
- * the OSS device.
- */
-static PaError AbortStream( PaStream *s )
-{
- return RealStop( (PaOssStream *)s, 1 );
-}
-
-/** Is the stream in the Stopped state.
- *
- */
-static PaError IsStreamStopped( PaStream *s )
-{
- PaOssStream *stream = (PaOssStream*)s;
-
- return (stream->isStopped);
-}
-
-/** Is the stream in the Active state.
- *
- */
-static PaError IsStreamActive( PaStream *s )
-{
- PaOssStream *stream = (PaOssStream*)s;
-
- return (stream->isActive);
-}
-
-static PaTime GetStreamTime( PaStream *s )
-{
- PaOssStream *stream = (PaOssStream*)s;
- count_info info;
- int delta;
-
- if( stream->playback ) {
- if( ioctl( stream->playback->fd, SNDCTL_DSP_GETOPTR, &info) == 0 ) {
- delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;
- return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->playback ) / stream->sampleRate;
- }
- }
- else {
- if (ioctl( stream->capture->fd, SNDCTL_DSP_GETIPTR, &info) == 0) {
- delta = (info.bytes - stream->lastPosPtr) & 0x000FFFFF;
- return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->capture ) / stream->sampleRate;
- }
- }
-
- /* the ioctl failed, but we can still give a coarse estimate */
-
- return stream->framesProcessed / stream->sampleRate;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaOssStream *stream = (PaOssStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
-*/
-
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaOssStream *stream = (PaOssStream*)s;
- int bytesRequested, bytesRead;
- unsigned long framesRequested;
- void *userBuffer;
-
- /* If user input is non-interleaved, PaUtil_CopyInput will manipulate the channel pointers,
- * so we copy the user provided pointers */
- if( stream->bufferProcessor.userInputIsInterleaved )
- userBuffer = buffer;
- else /* Copy channels into local array */
- {
- userBuffer = stream->capture->userBuffers;
- memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->capture->userChannelCount );
- }
-
- while( frames )
- {
- framesRequested = PA_MIN( frames, stream->capture->hostFrames );
-
- bytesRequested = framesRequested * PaOssStreamComponent_FrameSize( stream->capture );
- bytesRead = read( stream->capture->fd, stream->capture->buffer, bytesRequested );
- if ( bytesRequested != bytesRead )
- return paUnanticipatedHostError;
-
- PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->capture->hostFrames );
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount );
- PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesRequested );
- frames -= framesRequested;
- }
- return paNoError;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaOssStream *stream = (PaOssStream*)s;
- int bytesRequested, bytesWritten;
- unsigned long framesConverted;
- const void *userBuffer;
-
- /* If user output is non-interleaved, PaUtil_CopyOutput will manipulate the channel pointers,
- * so we copy the user provided pointers */
- if( stream->bufferProcessor.userOutputIsInterleaved )
- userBuffer = buffer;
- else /* Copy channels into local array */
- {
- userBuffer = stream->playback->userBuffers;
- memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback->userChannelCount );
- }
-
- while( frames )
- {
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->playback->hostFrames );
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount );
-
- framesConverted = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames );
- frames -= framesConverted;
-
- bytesRequested = framesConverted * PaOssStreamComponent_FrameSize( stream->playback );
- bytesWritten = write( stream->playback->fd, stream->playback->buffer, bytesRequested );
-
- if ( bytesRequested != bytesWritten )
- return paUnanticipatedHostError;
- }
- return paNoError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaOssStream *stream = (PaOssStream*)s;
- audio_buf_info info;
-
- if( ioctl( stream->capture->fd, SNDCTL_DSP_GETISPACE, &info ) < 0 )
- return paUnanticipatedHostError;
- return info.fragments * stream->capture->hostFrames;
-}
-
-
-/* TODO: Compute number of allocated bytes somewhere else, can we use ODELAY with capture */
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaOssStream *stream = (PaOssStream*)s;
- int delay = 0;
-
- if( ioctl( stream->playback->fd, SNDCTL_DSP_GETODELAY, &delay ) < 0 )
- return paUnanticipatedHostError;
-
- return (PaOssStreamComponent_BufferSize( stream->playback ) - delay) / PaOssStreamComponent_FrameSize( stream->playback );
-}
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_util.c b/pjmedia/src/pjmedia/portaudio/pa_unix_util.c
deleted file mode 100644
index cec60913..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_util.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * $Id: pa_unix_util.c,v 1.1.2.7 2005/03/31 15:02:48 aknudsen Exp $
- * Portable Audio I/O Library
- * UNIX platform-specific support functions
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-#include <pthread.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <assert.h>
-#include <string.h> /* For memset */
-
-#include "pa_util.h"
-#include "pa_unix_util.h"
-
-/*
- Track memory allocations to avoid leaks.
- */
-
-#if PA_TRACK_MEMORY
-static int numAllocations_ = 0;
-#endif
-
-
-void *PaUtil_AllocateMemory( long size )
-{
- void *result = malloc( size );
-
-#if PA_TRACK_MEMORY
- if( result != NULL ) numAllocations_ += 1;
-#endif
- return result;
-}
-
-
-void PaUtil_FreeMemory( void *block )
-{
- if( block != NULL )
- {
- free( block );
-#if PA_TRACK_MEMORY
- numAllocations_ -= 1;
-#endif
-
- }
-}
-
-
-int PaUtil_CountCurrentlyAllocatedBlocks( void )
-{
-#if PA_TRACK_MEMORY
- return numAllocations_;
-#else
- return 0;
-#endif
-}
-
-
-void Pa_Sleep( long msec )
-{
- while( msec > 999 ) /* For OpenBSD and IRIX, argument */
- { /* to usleep must be < 1000000. */
- usleep( 999000 );
- msec -= 999;
- }
- usleep( msec * 1000 );
-}
-
-/* *** NOT USED YET: ***
-static int usePerformanceCounter_;
-static double microsecondsPerTick_;
-*/
-
-void PaUtil_InitializeClock( void )
-{
- /* TODO */
-}
-
-
-PaTime PaUtil_GetTime( void )
-{
- struct timeval tv;
- gettimeofday( &tv, NULL );
- return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec;
-}
-
-PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
-{
- (void) paUtilErr_;
- return paNoError;
-}
-
-void PaUtil_TerminateThreading( PaUtilThreading *threading )
-{
-}
-
-PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )
-{
- pthread_create( &threading->callbackThread, NULL, threadRoutine, data );
- return paNoError;
-}
-
-PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )
-{
- PaError result = paNoError;
- void *pret;
-
- if( exitResult )
- *exitResult = paNoError;
-
- /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
- if( !wait )
- pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
- pthread_join( threading->callbackThread, &pret );
-
-#ifdef PTHREAD_CANCELED
- if( pret && PTHREAD_CANCELED != pret )
-#else
- /* !wait means the thread may have been canceled */
- if( pret && wait )
-#endif
- {
- if( exitResult )
- *exitResult = *(PaError *) pret;
- free( pret );
- }
-
- return result;
-}
-
-/*
-static void *CanaryFunc( void *userData )
-{
- const unsigned intervalMsec = 1000;
- PaUtilThreading *th = (PaUtilThreading *) userData;
-
- while( 1 )
- {
- th->canaryTime = PaUtil_GetTime();
-
- pthread_testcancel();
- Pa_Sleep( intervalMsec );
- }
-
- pthread_exit( NULL );
-}
-*/
diff --git a/pjmedia/src/pjmedia/portaudio/pa_unix_util.h b/pjmedia/src/pjmedia/portaudio/pa_unix_util.h
deleted file mode 100644
index 01dda01e..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_unix_util.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef PA_UNIX_UTIL_H
-#define PA_UNIX_UTIL_H
-
-#include "pa_cpuload.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-#define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) )
-#define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) )
-
-/* Utilize GCC branch prediction for error tests */
-#if defined __GNUC__ && __GNUC__ >= 3
-#define UNLIKELY(expr) __builtin_expect( (expr), 0 )
-#else
-#define UNLIKELY(expr) (expr)
-#endif
-
-#define STRINGIZE_HELPER(expr) #expr
-#define STRINGIZE(expr) STRINGIZE_HELPER(expr)
-
-#define PA_UNLESS(expr, code) \
- do { \
- if( UNLIKELY( (expr) == 0 ) ) \
- { \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
- result = (code); \
- goto error; \
- } \
- } while (0);
-
-static PaError paUtilErr_; /* Used with PA_ENSURE */
-
-/* Check PaError */
-#define PA_ENSURE(expr) \
- do { \
- if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \
- { \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
- result = paUtilErr_; \
- goto error; \
- } \
- } while (0);
-
-typedef struct {
- pthread_t callbackThread;
-} PaUtilThreading;
-
-PaError PaUtil_InitializeThreading( PaUtilThreading *threading );
-void PaUtil_TerminateThreading( PaUtilThreading *threading );
-PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data );
-PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult );
-
-/* State accessed by utility functions */
-
-/*
-void PaUnix_SetRealtimeScheduling( int rt );
-
-void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm );
-
-PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s );
-
-PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult );
-
-void PaUtil_CallbackUpdate( PaUtilThreading *th );
-*/
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif
diff --git a/pjmedia/src/pjmedia/portaudio/pa_util.h b/pjmedia/src/pjmedia/portaudio/pa_util.h
deleted file mode 100644
index 149fbca3..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_util.h
+++ /dev/null
@@ -1,167 +0,0 @@
-#ifndef PA_UTIL_H
-#define PA_UTIL_H
-/*
- * $Id: pa_util.h,v 1.1.2.12 2003/09/20 21:09:55 rossbencina Exp $
- * Portable Audio I/O Library implementation utilities header
- * common implementation utilities and interfaces
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief Prototypes for utility functions used by PortAudio implementations.
-
- @todo Document and adhere to the alignment guarantees provided by
- PaUtil_AllocateMemory().
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-struct PaUtilHostApiRepresentation;
-
-
-/** Retrieve a specific host API representation. This function can be used
- by implementations to retrieve a pointer to their representation in
- host api specific extension functions which aren't passed a rep pointer
- by pa_front.c.
-
- @param hostApi A pointer to a host API represenation pointer. Apon success
- this will receive the requested representation pointer.
-
- @param type A valid host API type identifier.
-
- @returns An error code. If the result is PaNoError then a pointer to the
- requested host API representation will be stored in *hostApi. If the host API
- specified by type is not found, this function returns paHostApiNotFound.
-*/
-PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
- PaHostApiTypeId type );
-
-
-/** Convert a PortAudio device index into a host API specific device index.
- @param hostApiDevice Pointer to a device index, on success this will recieve the
- converted device index value.
- @param device The PortAudio device index to convert.
- @param hostApi The host api which the index should be converted for.
-
- @returns On success returns PaNoError and places the converted index in the
- hostApiDevice parameter.
-*/
-PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
- PaDeviceIndex *hostApiDevice, PaDeviceIndex device,
- struct PaUtilHostApiRepresentation *hostApi );
-
-
-/** Set the host error information returned by Pa_GetLastHostErrorInfo. This
- function and the paUnanticipatedHostError error code should be used as a
- last resort. Implementors should use existing PA error codes where possible,
- or nominate new ones. Note that at it is always better to use
- PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an
- ambiguous or inaccurate PaError code.
-
- @param hostApiType The host API which encountered the error (ie of the caller)
-
- @param errorCode The error code returned by the native API function.
-
- @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo
- makes a copy of the string, so it is not necessary for the pointer to remain
- valid after the call to PaUtil_SetLastHostErrorInfo() returns.
-
-*/
-void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
- const char *errorText );
-
-
-
-/** PA_DEBUG() provides a simple debug message printing facility. The macro
- passes it's argument to a printf-like function called PaUtil_DebugPrint()
- which prints to stderr and always flushes the stream after printing.
- Because preprocessor macros cannot directly accept variable length argument
- lists, calls to the macro must include an additional set of parenthesis, eg:
- PA_DEBUG(("errorno: %d", 1001 ));
-*/
-
-void PaUtil_DebugPrint( const char *format, ... );
-
-#if (0) /* set to 1 to print debug messages */
-#define PA_DEBUG(x) PaUtil_DebugPrint x ;
-#else
-#define PA_DEBUG(x)
-#endif
-
-
-/* the following functions are implemented in a platform platform specific
- .c file
-*/
-
-/** Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */
-void *PaUtil_AllocateMemory( long size );
-
-
-/** Realease block if non-NULL. block may be NULL */
-void PaUtil_FreeMemory( void *block );
-
-
-/** Return the number of currently allocated blocks. This function can be
- used for detecting memory leaks.
-
- @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If
- it isn't, this function will always return 0.
-*/
-int PaUtil_CountCurrentlyAllocatedBlocks( void );
-
-
-/** Initialize the clock used by PaUtil_GetTime(). Call this before calling
- PaUtil_GetTime.
-
- @see PaUtil_GetTime
-*/
-void PaUtil_InitializeClock( void );
-
-
-/** Return the system time in seconds. Used to implement CPU load functions
-
- @see PaUtil_InitializeClock
-*/
-double PaUtil_GetTime( void );
-
-
-/* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_UTIL_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_ds.c b/pjmedia/src/pjmedia/portaudio/pa_win_ds.c
deleted file mode 100644
index eb44f263..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_win_ds.c
+++ /dev/null
@@ -1,1835 +0,0 @@
-/*
- * $Id: pa_win_ds.c,v 1.1.2.49 2004/05/16 04:08:55 rossbencina Exp $
- * Portable Audio I/O Library DirectSound implementation
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
-
- @todo implement paInputOverflow callback status flag
-
- @todo implement paNeverDropInput.
-
- @todo implement host api specific extension to set i/o buffer sizes in frames
-
- @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
-
- @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
-
- @todo audit handling of DirectSound result codes - in many cases we could convert a HRESULT into
- a native portaudio error code. Standard DirectSound result codes are documented at msdn.
-
- @todo implement IsFormatSupported
-
- @todo check that CoInitialize() CoUninitialize() are always correctly
- paired, even in error cases.
-
- @todo call PaUtil_SetLastHostErrorInfo with a specific error string (currently just "DSound error").
-
- @todo make sure all buffers have been played before stopping the stream
- when the stream callback returns paComplete
-
- old TODOs from phil, need to work out if these have been done:
- O- fix "patest_stop.c"
-*/
-
-#include <stdio.h>
-#include <string.h> /* strlen() */
-
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-#include "dsound_wrapper.h"
-
-#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) /* MSC version 6 and above */
-#pragma comment( lib, "dsound.lib" )
-#pragma comment( lib, "winmm.lib" )
-#endif
-
-
-#include <pj/unicode.h>
-
-#define PRINT(x) /* { printf x; fflush(stdout); } */
-#define ERR_RPT(x) PRINT(x)
-#define DBUG(x) /* PRINT(x) */
-#define DBUGX(x) /* PRINT(x) */
-
-#define PA_USE_HIGH_LATENCY (0)
-#if PA_USE_HIGH_LATENCY
-#define PA_WIN_9X_LATENCY (500)
-#define PA_WIN_NT_LATENCY (600)
-#else
-#define PA_WIN_9X_LATENCY (140)
-#define PA_WIN_NT_LATENCY (280)
-#endif
-
-#define PA_WIN_WDM_LATENCY (120)
-
-#define SECONDS_PER_MSEC (0.001)
-#define MSEC_PER_SECOND (1000)
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-
-/* FIXME: should convert hr to a string */
-#define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \
- PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" )
-
-/************************************************* DX Prototypes **********/
-static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID,
- LPCTSTR lpszDesc,
- LPCTSTR lpszDrvName,
- LPVOID lpContext );
-
-/************************************************************************************/
-/********************** Structures **************************************************/
-/************************************************************************************/
-/* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct PaWinDsDeviceInfo
-{
- GUID guid;
- GUID *lpGUID;
- double sampleRates[3];
-} PaWinDsDeviceInfo;
-
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- /* implementation specific data goes here */
- PaWinDsDeviceInfo *winDsDeviceInfos;
-
-} PaWinDsHostApiRepresentation;
-
-/* PaWinDsStream - a stream data structure specifically for this implementation */
-
-typedef struct PaWinDsStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
-/* DirectSound specific data. */
- DSoundWrapper directSoundWrapper;
- MMRESULT timerID;
- BOOL ifInsideCallback; /* Test for reentrancy. */
- int framesPerDSBuffer;
- double framesWritten;
- double secondsPerHostByte; /* Used to optimize latency calculation for outTime */
-
- PaStreamCallbackFlags callbackFlags;
-
-/* FIXME - move all below to PaUtilStreamRepresentation */
- volatile int isStarted;
- volatile int isActive;
- volatile int stopProcessing; /* stop thread once existing buffers have been returned */
- volatile int abortProcessing; /* stop thread immediately */
-} PaWinDsStream;
-
-
-/************************************************************************************
-** Duplicate the input string using the allocations allocator.
-** A NULL string is converted to a zero length string.
-** If memory cannot be allocated, NULL is returned.
-**/
-static char *DuplicateDeviceNameString( PaUtilAllocationGroup *allocations, const char* src )
-{
- char *result = 0;
-
- if( src != NULL )
- {
- size_t len = strlen(src);
- result = (char*)PaUtil_GroupAllocateMemory( allocations, (long)(len + 1) );
- if( result )
- memcpy( (void *) result, src, len+1 );
- }
- else
- {
- result = (char*)PaUtil_GroupAllocateMemory( allocations, 1 );
- if( result )
- result[0] = '\0';
- }
-
- return result;
-}
-
-/************************************************************************************
-** DSDeviceNameAndGUID, DSDeviceNameAndGUIDVector used for collecting preliminary
-** information during device enumeration.
-*/
-typedef struct DSDeviceNameAndGUID{
- char *name; // allocated from parent's allocations, never deleted by this structure
- GUID guid;
- LPGUID lpGUID;
-} DSDeviceNameAndGUID;
-
-typedef struct DSDeviceNameAndGUIDVector{
- PaUtilAllocationGroup *allocations;
- PaError enumerationError;
-
- int count;
- int free;
- DSDeviceNameAndGUID *items; // Allocated using LocalAlloc()
-} DSDeviceNameAndGUIDVector;
-
-static PaError InitializeDSDeviceNameAndGUIDVector(
- DSDeviceNameAndGUIDVector *guidVector, PaUtilAllocationGroup *allocations )
-{
- PaError result = paNoError;
-
- guidVector->allocations = allocations;
- guidVector->enumerationError = paNoError;
-
- guidVector->count = 0;
- guidVector->free = 8;
- guidVector->items = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * guidVector->free );
- if( guidVector->items == NULL )
- result = paInsufficientMemory;
-
- return result;
-}
-
-static PaError ExpandDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector )
-{
- PaError result = paNoError;
- DSDeviceNameAndGUID *newItems;
- int i;
-
- /* double size of vector */
- int size = guidVector->count + guidVector->free;
- guidVector->free += size;
-
- newItems = (DSDeviceNameAndGUID*)LocalAlloc( LMEM_FIXED, sizeof(DSDeviceNameAndGUID) * size * 2 );
- if( newItems == NULL )
- {
- result = paInsufficientMemory;
- }
- else
- {
- for( i=0; i < guidVector->count; ++i )
- {
- newItems[i].name = guidVector->items[i].name;
- if( guidVector->items[i].lpGUID == NULL )
- {
- newItems[i].lpGUID = NULL;
- }
- else
- {
- newItems[i].lpGUID = &newItems[i].guid;
- memcpy( &newItems[i].guid, guidVector->items[i].lpGUID, sizeof(GUID) );;
- }
- }
-
- LocalFree( guidVector->items );
- guidVector->items = newItems;
- }
-
- return result;
-}
-
-/*
- it's safe to call DSDeviceNameAndGUIDVector multiple times
-*/
-static PaError TerminateDSDeviceNameAndGUIDVector( DSDeviceNameAndGUIDVector *guidVector )
-{
- PaError result = paNoError;
-
- if( guidVector->items != NULL )
- {
- if( LocalFree( guidVector->items ) != NULL )
- result = paInsufficientMemory; /** @todo this isn't the correct error to return from a deallocation failure */
-
- guidVector->items = NULL;
- }
-
- return result;
-}
-
-/************************************************************************************
-** Collect preliminary device information during DirectSound enumeration
-*/
-static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID,
- LPCTSTR lpszDesc,
- LPCTSTR lpszDrvName,
- LPVOID lpContext )
-{
- DSDeviceNameAndGUIDVector *namesAndGUIDs = (DSDeviceNameAndGUIDVector*)lpContext;
- PaError error;
- PJ_DECL_ANSI_TEMP_BUF(atemp,128)
-
- (void) lpszDrvName; /* unused variable */
-
- if( namesAndGUIDs->free == 0 )
- {
- error = ExpandDSDeviceNameAndGUIDVector( namesAndGUIDs );
- if( error != paNoError )
- {
- namesAndGUIDs->enumerationError = error;
- return FALSE;
- }
- }
-
- /* Set GUID pointer, copy GUID to storage in DSDeviceNameAndGUIDVector. */
- if( lpGUID == NULL )
- {
- namesAndGUIDs->items[namesAndGUIDs->count].lpGUID = NULL;
- }
- else
- {
- namesAndGUIDs->items[namesAndGUIDs->count].lpGUID =
- &namesAndGUIDs->items[namesAndGUIDs->count].guid;
-
- memcpy( &namesAndGUIDs->items[namesAndGUIDs->count].guid, lpGUID, sizeof(GUID) );
- }
-
- namesAndGUIDs->items[namesAndGUIDs->count].name =
- DuplicateDeviceNameString( namesAndGUIDs->allocations,
- PJ_NATIVE_TO_STRING(lpszDesc,atemp,sizeof(atemp)));
- if( namesAndGUIDs->items[namesAndGUIDs->count].name == NULL )
- {
- namesAndGUIDs->enumerationError = paInsufficientMemory;
- return FALSE;
- }
-
- ++namesAndGUIDs->count;
- --namesAndGUIDs->free;
-
- return TRUE;
-}
-
-
-#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */
-static double defaultSampleRateSearchOrder_[] =
- { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,
- 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
-
-
-/************************************************************************************
-** Extract capabilities from an output device, and add it to the device info list
-** if successful. This function assumes that there is enough room in the
-** device info list to accomodate all entries.
-**
-** The device will not be added to the device list if any errors are encountered.
-*/
-static PaError AddOutputDeviceInfoFromDirectSound(
- PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID )
-{
- PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep;
- PaDeviceInfo *deviceInfo = hostApi->deviceInfos[hostApi->info.deviceCount];
- PaWinDsDeviceInfo *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[hostApi->info.deviceCount];
- HRESULT hr;
- LPDIRECTSOUND lpDirectSound;
- DSCAPS caps;
- int deviceOK = TRUE;
- PaError result = paNoError;
- int i;
-
- /* Copy GUID to the device info structure. Set pointer. */
- if( lpGUID == NULL )
- {
- winDsDeviceInfo->lpGUID = NULL;
- }
- else
- {
- memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) );
- winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid;
- }
-
-
- /* Create a DirectSound object for the specified GUID
- Note that using CoCreateInstance doesn't work on windows CE.
- */
- hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL );
-
- /** try using CoCreateInstance because DirectSoundCreate was hanging under
- some circumstances - note this was probably related to the
- #define BOOL short bug which has now been fixed
- @todo delete this comment and the following code once we've ensured
- there is no bug.
- */
- /*
- hr = CoCreateInstance( &CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
- &IID_IDirectSound, (void**)&lpDirectSound );
-
- if( hr == S_OK )
- {
- hr = IDirectSound_Initialize( lpDirectSound, lpGUID );
- }
- */
-
- if( hr != DS_OK )
- {
- DBUG(("Cannot create DirectSound for %s. Result = 0x%x\n", name, hr ));
- deviceOK = FALSE;
- }
- else
- {
- /* Query device characteristics. */
- memset( &caps, 0, sizeof(caps) );
- caps.dwSize = sizeof(caps);
- hr = IDirectSound_GetCaps( lpDirectSound, &caps );
- if( hr != DS_OK )
- {
- DBUG(("Cannot GetCaps() for DirectSound device %s. Result = 0x%x\n", name, hr ));
- deviceOK = FALSE;
- }
- else
- {
-
-#ifndef PA_NO_WMME
- if( caps.dwFlags & DSCAPS_EMULDRIVER )
- {
- /* If WMME supported, then reject Emulated drivers because they are lousy. */
- deviceOK = FALSE;
- }
-#endif
-
- if( deviceOK )
- {
- deviceInfo->maxInputChannels = 0;
- /* Mono or stereo device? */
- deviceInfo->maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
-
- deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */
- deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */
- deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */
- deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */
-
- /* initialize defaultSampleRate */
-
- if( caps.dwFlags & DSCAPS_CONTINUOUSRATE )
- {
- /* initialize to caps.dwMaxSecondarySampleRate incase none of the standard rates match */
- deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;
-
- for( i = 0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )
- {
- if( defaultSampleRateSearchOrder_[i] >= caps.dwMinSecondarySampleRate
- && defaultSampleRateSearchOrder_[i] <= caps.dwMaxSecondarySampleRate ){
-
- deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[i];
- break;
- }
- }
- }
- else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )
- {
- if( caps.dwMinSecondarySampleRate == 0 )
- {
- /*
- ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!
- ** But it supports continuous sampling.
- ** So fake range of rates, and hope it really supports it.
- */
- deviceInfo->defaultSampleRate = 44100.0f;
-
- DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
- }
- else
- {
- deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;
- }
- }
- else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )
- {
- /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.
- ** But we know that they really support a range of rates!
- ** So when we see a ridiculous set of rates, assume it is a range.
- */
- deviceInfo->defaultSampleRate = 44100.0f;
- DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
- }
- else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;
-
-
- //printf( "min %d max %d\n", caps.dwMinSecondarySampleRate, caps.dwMaxSecondarySampleRate );
- // dwFlags | DSCAPS_CONTINUOUSRATE
- }
- }
-
- IDirectSound_Release( lpDirectSound );
- }
-
- if( deviceOK )
- {
- deviceInfo->name = name;
-
- if( lpGUID == NULL )
- hostApi->info.defaultOutputDevice = hostApi->info.deviceCount;
-
- hostApi->info.deviceCount++;
- }
-
- return result;
-}
-
-
-/************************************************************************************
-** Extract capabilities from an input device, and add it to the device info list
-** if successful. This function assumes that there is enough room in the
-** device info list to accomodate all entries.
-**
-** The device will not be added to the device list if any errors are encountered.
-*/
-static PaError AddInputDeviceInfoFromDirectSoundCapture(
- PaWinDsHostApiRepresentation *winDsHostApi, char *name, LPGUID lpGUID )
-{
- PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep;
- PaDeviceInfo *deviceInfo = hostApi->deviceInfos[hostApi->info.deviceCount];
- PaWinDsDeviceInfo *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[hostApi->info.deviceCount];
- HRESULT hr;
- LPDIRECTSOUNDCAPTURE lpDirectSoundCapture;
- DSCCAPS caps;
- int deviceOK = TRUE;
- PaError result = paNoError;
-
- /* Copy GUID to the device info structure. Set pointer. */
- if( lpGUID == NULL )
- {
- winDsDeviceInfo->lpGUID = NULL;
- }
- else
- {
- winDsDeviceInfo->lpGUID = &winDsDeviceInfo->guid;
- memcpy( &winDsDeviceInfo->guid, lpGUID, sizeof(GUID) );
- }
-
-
- hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL );
-
- /** try using CoCreateInstance because DirectSoundCreate was hanging under
- some circumstances - note this was probably related to the
- #define BOOL short bug which has now been fixed
- @todo delete this comment and the following code once we've ensured
- there is no bug.
- */
- /*
- hr = CoCreateInstance( &CLSID_DirectSoundCapture, NULL, CLSCTX_INPROC_SERVER,
- &IID_IDirectSoundCapture, (void**)&lpDirectSoundCapture );
- */
- if( hr != DS_OK )
- {
- DBUG(("Cannot create Capture for %s. Result = 0x%x\n", name, hr ));
- deviceOK = FALSE;
- }
- else
- {
- /* Query device characteristics. */
- memset( &caps, 0, sizeof(caps) );
- caps.dwSize = sizeof(caps);
- hr = IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );
- if( hr != DS_OK )
- {
- DBUG(("Cannot GetCaps() for Capture device %s. Result = 0x%x\n", name, hr ));
- deviceOK = FALSE;
- }
- else
- {
-#ifndef PA_NO_WMME
- if( caps.dwFlags & DSCAPS_EMULDRIVER )
- {
- /* If WMME supported, then reject Emulated drivers because they are lousy. */
- deviceOK = FALSE;
- }
-#endif
-
- if( deviceOK )
- {
- deviceInfo->maxInputChannels = caps.dwChannels;
- deviceInfo->maxOutputChannels = 0;
-
- deviceInfo->defaultLowInputLatency = 0.; /** @todo IMPLEMENT ME */
- deviceInfo->defaultLowOutputLatency = 0.; /** @todo IMPLEMENT ME */
- deviceInfo->defaultHighInputLatency = 0.; /** @todo IMPLEMENT ME */
- deviceInfo->defaultHighOutputLatency = 0.; /** @todo IMPLEMENT ME */
-
-/* constants from a WINE patch by Francois Gouget, see:
- http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html
-
- ---
- Date: Fri, 14 May 2004 10:38:12 +0200 (CEST)
- From: Francois Gouget <fgouget@ ... .fr>
- To: Ross Bencina <rbencina@ ... .au>
- Subject: Re: Permission to use wine 48/96 wave patch in BSD licensed library
-
- [snip]
-
- I give you permission to use the patch below under the BSD license.
- http://www.winehq.com/hypermail/wine-patches/2003/01/0290.html
-
- [snip]
-*/
-#ifndef WAVE_FORMAT_48M08
-#define WAVE_FORMAT_48M08 0x00001000 /* 48 kHz, Mono, 8-bit */
-#define WAVE_FORMAT_48S08 0x00002000 /* 48 kHz, Stereo, 8-bit */
-#define WAVE_FORMAT_48M16 0x00004000 /* 48 kHz, Mono, 16-bit */
-#define WAVE_FORMAT_48S16 0x00008000 /* 48 kHz, Stereo, 16-bit */
-#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
-#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */
-#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */
-#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
-#endif
-
- /* defaultSampleRate */
- if( caps.dwChannels == 2 )
- {
- if( caps.dwFormats & WAVE_FORMAT_4S16 )
- deviceInfo->defaultSampleRate = 44100.0;
- else if( caps.dwFormats & WAVE_FORMAT_48S16 )
- deviceInfo->defaultSampleRate = 48000.0;
- else if( caps.dwFormats & WAVE_FORMAT_2S16 )
- deviceInfo->defaultSampleRate = 22050.0;
- else if( caps.dwFormats & WAVE_FORMAT_1S16 )
- deviceInfo->defaultSampleRate = 11025.0;
- else if( caps.dwFormats & WAVE_FORMAT_96S16 )
- deviceInfo->defaultSampleRate = 96000.0;
- else
- deviceInfo->defaultSampleRate = 0.;
- }
- else if( caps.dwChannels == 1 )
- {
- if( caps.dwFormats & WAVE_FORMAT_4M16 )
- deviceInfo->defaultSampleRate = 44100.0;
- else if( caps.dwFormats & WAVE_FORMAT_48M16 )
- deviceInfo->defaultSampleRate = 48000.0;
- else if( caps.dwFormats & WAVE_FORMAT_2M16 )
- deviceInfo->defaultSampleRate = 22050.0;
- else if( caps.dwFormats & WAVE_FORMAT_1M16 )
- deviceInfo->defaultSampleRate = 11025.0;
- else if( caps.dwFormats & WAVE_FORMAT_96M16 )
- deviceInfo->defaultSampleRate = 96000.0;
- else
- deviceInfo->defaultSampleRate = 0.;
- }
- else deviceInfo->defaultSampleRate = 0.;
- }
- }
-
- IDirectSoundCapture_Release( lpDirectSoundCapture );
- }
-
- if( deviceOK )
- {
- deviceInfo->name = name;
-
- if( lpGUID == NULL )
- hostApi->info.defaultInputDevice = hostApi->info.deviceCount;
-
- hostApi->info.deviceCount++;
- }
-
- return result;
-}
-
-
-/***********************************************************************************/
-PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- int i, deviceCount;
- PaWinDsHostApiRepresentation *winDsHostApi;
- DSDeviceNameAndGUIDVector inputNamesAndGUIDs, outputNamesAndGUIDs;
- PaDeviceInfo *deviceInfoArray;
-
- HRESULT hr = CoInitialize(NULL); /** @todo: should uninitialize too */
- if( FAILED(hr) ){
- return paUnanticipatedHostError;
- }
-
- /* initialise guid vectors so they can be safely deleted on error */
- inputNamesAndGUIDs.items = NULL;
- outputNamesAndGUIDs.items = NULL;
-
- DSW_InitializeDSoundEntryPoints();
-
- winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) );
- if( !winDsHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- winDsHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !winDsHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- *hostApi = &winDsHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paDirectSound;
- (*hostApi)->info.name = "Windows DirectSound";
-
- (*hostApi)->info.deviceCount = 0;
- (*hostApi)->info.defaultInputDevice = paNoDevice;
- (*hostApi)->info.defaultOutputDevice = paNoDevice;
-
-
-/* DSound - enumerate devices to count them and to gather their GUIDs */
-
-
- result = InitializeDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs, winDsHostApi->allocations );
- if( result != paNoError )
- goto error;
-
- result = InitializeDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs, winDsHostApi->allocations );
- if( result != paNoError )
- goto error;
-
- dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&inputNamesAndGUIDs );
-
- dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)CollectGUIDsProc, (void *)&outputNamesAndGUIDs );
-
- if( inputNamesAndGUIDs.enumerationError != paNoError )
- {
- result = inputNamesAndGUIDs.enumerationError;
- goto error;
- }
-
- if( outputNamesAndGUIDs.enumerationError != paNoError )
- {
- result = outputNamesAndGUIDs.enumerationError;
- goto error;
- }
-
- deviceCount = inputNamesAndGUIDs.count + outputNamesAndGUIDs.count;
-
- if( deviceCount > 0 )
- {
- /* allocate array for pointers to PaDeviceInfo structs */
- (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
- if( !(*hostApi)->deviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* allocate all PaDeviceInfo structs in a contiguous block */
- deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
- winDsHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
- if( !deviceInfoArray )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* allocate all DSound specific info structs in a contiguous block */
- winDsHostApi->winDsDeviceInfos = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
- winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
- if( !winDsHostApi->winDsDeviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- for( i=0; i < deviceCount; ++i )
- {
- PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->name = 0;
- (*hostApi)->deviceInfos[i] = deviceInfo;
- }
-
- for( i=0; i< inputNamesAndGUIDs.count; ++i )
- {
- result = AddInputDeviceInfoFromDirectSoundCapture( winDsHostApi,
- inputNamesAndGUIDs.items[i].name,
- inputNamesAndGUIDs.items[i].lpGUID );
- if( result != paNoError )
- goto error;
- }
-
- for( i=0; i< outputNamesAndGUIDs.count; ++i )
- {
- result = AddOutputDeviceInfoFromDirectSound( winDsHostApi,
- outputNamesAndGUIDs.items[i].name,
- outputNamesAndGUIDs.items[i].lpGUID );
- if( result != paNoError )
- goto error;
- }
- }
-
- result = TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );
- if( result != paNoError )
- goto error;
-
- result = TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );
- if( result != paNoError )
- goto error;
-
-
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( winDsHostApi )
- {
- if( winDsHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( winDsHostApi->allocations );
- PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
- }
-
- PaUtil_FreeMemory( winDsHostApi );
- }
-
- TerminateDSDeviceNameAndGUIDVector( &inputNamesAndGUIDs );
- TerminateDSDeviceNameAndGUIDVector( &outputNamesAndGUIDs );
-
- return result;
-}
-
-
-/***********************************************************************************/
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
-
- /*
- IMPLEMENT ME:
- - clean up any resources not handled by the allocation group
- */
-
- if( winDsHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( winDsHostApi->allocations );
- PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
- }
-
- PaUtil_FreeMemory( winDsHostApi );
-
- DSW_TerminateDSoundEntryPoints();
-
- CoUninitialize();
-}
-
-
-/* Set minimal latency based on whether NT or Win95.
- * NT has higher latency.
- */
-static int PaWinDS_GetMinSystemLatency( void )
-{
- int minLatencyMsec;
- /* Set minimal latency based on whether NT or other OS.
- * NT has higher latency.
- */
- OSVERSIONINFO osvi;
- osvi.dwOSVersionInfoSize = sizeof( osvi );
- GetVersionEx( &osvi );
- DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
- DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
- DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
- /* Check for NT */
- if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
- {
- minLatencyMsec = PA_WIN_NT_LATENCY;
- }
- else if(osvi.dwMajorVersion >= 5)
- {
- minLatencyMsec = PA_WIN_WDM_LATENCY;
- }
- else
- {
- minLatencyMsec = PA_WIN_9X_LATENCY;
- }
- return minLatencyMsec;
-}
-
-/***********************************************************************************/
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
-
- /* validate inputStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- inputChannelCount = 0;
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support inputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* validate outputStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- outputChannelCount = 0;
- }
-
- /*
- IMPLEMENT ME:
-
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported if necessary
-
- - check that the device supports sampleRate
-
- Because the buffer adapter handles conversion between all standard
- sample formats, the following checks are only required if paCustomFormat
- is implemented, or under some other unusual conditions.
-
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
- */
-
- return paFormatIsSupported;
-}
-
-
-/*************************************************************************
-** Determine minimum number of buffers required for this host based
-** on minimum latency. Latency can be optionally set by user by setting
-** an environment variable. For example, to set latency to 200 msec, put:
-**
-** set PA_MIN_LATENCY_MSEC=200
-**
-** in the AUTOEXEC.BAT file and reboot.
-** If the environment variable is not set, then the latency will be determined
-** based on the OS. Windows NT has higher latency than Win95.
-*/
-#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
-#define PA_ENV_BUF_SIZE (32)
-
-static int PaWinDs_GetMinLatencyFrames( double sampleRate )
-{
- char envbuf[PA_ENV_BUF_SIZE];
- DWORD hresult;
- int minLatencyMsec = 0;
-
- /* Let user determine minimal latency by setting environment variable. */
-#ifdef UNDER_CE
- hresult = 0;
-#else
- hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
-#endif
- if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
- {
- minLatencyMsec = atoi( envbuf );
- }
- else
- {
- minLatencyMsec = PaWinDS_GetMinSystemLatency();
-#if PA_USE_HIGH_LATENCY
- PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
-#endif
-
- }
-
- return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC);
-}
-
-#ifndef NDEBUG
-#define EZ = 0
-#else
-#define EZ
-#endif
-
-/***********************************************************************************/
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result = paNoError;
- PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
- PaWinDsStream *stream = 0;
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat EZ, outputSampleFormat EZ;
- PaSampleFormat hostInputSampleFormat EZ, hostOutputSampleFormat EZ;
- unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames;
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- suggestedInputLatencyFrames = (unsigned long)(inputParameters->suggestedLatency * sampleRate);
-
- /* IDEA: the following 3 checks could be performed by default by pa_front
- unless some flag indicated otherwise */
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
-
- /* validate hostApiSpecificStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- inputChannelCount = 0;
- suggestedInputLatencyFrames = 0;
- }
-
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- suggestedOutputLatencyFrames = (unsigned long)(outputParameters->suggestedLatency * sampleRate);
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support inputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* validate hostApiSpecificStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- outputChannelCount = 0;
- suggestedOutputLatencyFrames = 0;
- }
-
-
- /*
- IMPLEMENT ME:
-
- ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() )
-
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported
-
- - check that the device supports sampleRate
-
- - alter sampleRate to a close allowable rate if possible / necessary
-
- - validate suggestedInputLatency and suggestedOutputLatency parameters,
- use default values where necessary
- */
-
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- return paInvalidFlag; /* unexpected platform specific flag */
-
-
- stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) );
- if( !stream )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- if( streamCallback )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &winDsHostApi->callbackStreamInterface, streamCallback, userData );
- }
- else
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &winDsHostApi->blockingStreamInterface, streamCallback, userData );
- }
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
-
- if( inputParameters )
- {
- /* IMPLEMENT ME - establish which host formats are available */
- hostInputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputParameters->sampleFormat );
- }
-
- if( outputParameters )
- {
- /* IMPLEMENT ME - establish which host formats are available */
- hostOutputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputParameters->sampleFormat );
- }
-
- result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- inputChannelCount, inputSampleFormat, hostInputSampleFormat,
- outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerBuffer,
- framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */
- /* This next mode is required because DS can split the host buffer when it wraps around. */
- paUtilVariableHostBufferSizePartialUsageAllowed,
- streamCallback, userData );
- if( result != paNoError )
- goto error;
-
-
- stream->streamRepresentation.streamInfo.inputLatency =
- PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */
- stream->streamRepresentation.streamInfo.outputLatency =
- PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor); /* FIXME: not initialised anywhere else */
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-
-/* DirectSound specific initialization */
- {
- HRESULT hr;
- int bytesPerDirectSoundBuffer;
- DSoundWrapper *dsw;
- int userLatencyFrames;
- int minLatencyFrames;
-
- stream->timerID = 0;
- dsw = &stream->directSoundWrapper;
- DSW_Init( dsw );
-
- /* Get system minimum latency. */
- minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate );
-
- /* Let user override latency by passing latency parameter. */
- userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)
- ? suggestedInputLatencyFrames
- : suggestedOutputLatencyFrames;
- if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames;
-
- /* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */
- if( framesPerBuffer == paFramesPerBufferUnspecified )
- {
- /* App support variable framesPerBuffer */
- stream->framesPerDSBuffer = minLatencyFrames;
-
- stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate;
- }
- else
- {
- /* Round up to number of buffers needed to guarantee that latency. */
- int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer;
- if( numUserBuffers < 1 ) numUserBuffers = 1;
- numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */
- stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers;
-
- stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate;
- }
-
- {
- /** @todo REVIEW: this calculation seems incorrect to me - rossb. */
- int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate);
- PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency ));
- }
-
-
- /* ------------------ OUTPUT */
- if( outputParameters )
- {
- /*
- PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ];
- DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputParameters->device));
- */
-
- bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * sizeof(short);
- if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
- {
- result = paBufferTooSmall;
- goto error;
- }
- else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
- {
- result = paBufferTooBig;
- goto error;
- }
-
-
- hr = dswDSoundEntryPoints.DirectSoundCreate( winDsHostApi->winDsDeviceInfos[outputParameters->device].lpGUID,
- &dsw->dsw_pDirectSound, NULL );
- if( hr != DS_OK )
- {
- ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
- goto error;
- }
- hr = DSW_InitOutputBuffer( dsw,
- (unsigned long) (sampleRate + 0.5),
- (WORD)outputParameters->channelCount, bytesPerDirectSoundBuffer );
- DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
- if( hr != DS_OK )
- {
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
- goto error;
- }
- /* Calculate value used in latency calculation to avoid real-time divides. */
- stream->secondsPerHostByte = 1.0 /
- (stream->bufferProcessor.bytesPerHostOutputSample *
- outputChannelCount * sampleRate);
- }
-
- /* ------------------ INPUT */
- if( inputParameters )
- {
- /*
- PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ];
- DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", inputParameters->device));
- */
-
- bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * sizeof(short);
- if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
- {
- result = paBufferTooSmall;
- goto error;
- }
- else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
- {
- result = paBufferTooBig;
- goto error;
- }
-
- hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( winDsHostApi->winDsDeviceInfos[inputParameters->device].lpGUID,
- &dsw->dsw_pDirectSoundCapture, NULL );
- if( hr != DS_OK )
- {
- ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
- goto error;
- }
- hr = DSW_InitInputBuffer( dsw,
- (unsigned long) (sampleRate + 0.5),
- (WORD)inputParameters->channelCount, bytesPerDirectSoundBuffer );
- DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
- if( hr != DS_OK )
- {
- ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
- goto error;
- }
- }
-
- }
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
- if( stream )
- PaUtil_FreeMemory( stream );
-
- return result;
-}
-
-
-/***********************************************************************************/
-static PaError Pa_TimeSlice( PaWinDsStream *stream )
-{
- PaError result = 0; /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/
- DSoundWrapper *dsw;
- long numFrames = 0;
- long bytesEmpty = 0;
- long bytesFilled = 0;
- long bytesToXfer = 0;
- long framesToXfer = 0;
- long numInFramesReady = 0;
- long numOutFramesReady = 0;
- long bytesProcessed;
- HRESULT hresult;
- double outputLatency = 0;
- PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */
-
-/* Input */
- LPBYTE lpInBuf1 = NULL;
- LPBYTE lpInBuf2 = NULL;
- DWORD dwInSize1 = 0;
- DWORD dwInSize2 = 0;
-/* Output */
- LPBYTE lpOutBuf1 = NULL;
- LPBYTE lpOutBuf2 = NULL;
- DWORD dwOutSize1 = 0;
- DWORD dwOutSize2 = 0;
-
- dsw = &stream->directSoundWrapper;
-
- /* How much input data is available? */
- if( stream->bufferProcessor.inputChannelCount > 0 )
- {
- DSW_QueryInputFilled( dsw, &bytesFilled );
- framesToXfer = numInFramesReady = bytesFilled / dsw->dsw_BytesPerInputFrame;
- outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte;
-
- /** @todo Check for overflow */
- }
-
- /* How much output room is available? */
- if( stream->bufferProcessor.outputChannelCount > 0 )
- {
- UINT previousUnderflowCount = dsw->dsw_OutputUnderflows;
- DSW_QueryOutputSpace( dsw, &bytesEmpty );
- framesToXfer = numOutFramesReady = bytesEmpty / dsw->dsw_BytesPerOutputFrame;
-
- /* Check for underflow */
- if( dsw->dsw_OutputUnderflows != previousUnderflowCount )
- stream->callbackFlags |= paOutputUnderflow;
- }
-
- if( (numInFramesReady > 0) && (numOutFramesReady > 0) )
- {
- framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady;
- }
-
- if( framesToXfer > 0 )
- {
-
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
- /* The outputBufferDacTime parameter should indicates the time at which
- the first sample of the output buffer is heard at the DACs. */
- timeInfo.currentTime = PaUtil_GetTime();
- timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency;
-
-
- PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, stream->callbackFlags );
- stream->callbackFlags = 0;
-
- /* Input */
- if( stream->bufferProcessor.inputChannelCount > 0 )
- {
- bytesToXfer = framesToXfer * dsw->dsw_BytesPerInputFrame;
- hresult = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer,
- dsw->dsw_ReadOffset, bytesToXfer,
- (void **) &lpInBuf1, &dwInSize1,
- (void **) &lpInBuf2, &dwInSize2, 0);
- if (hresult != DS_OK)
- {
- ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult));
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
- goto error2;
- }
-
- numFrames = dwInSize1 / dsw->dsw_BytesPerInputFrame;
- PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames );
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 );
- /* Is input split into two regions. */
- if( dwInSize2 > 0 )
- {
- numFrames = dwInSize2 / dsw->dsw_BytesPerInputFrame;
- PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames );
- PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 );
- }
- }
-
- /* Output */
- if( stream->bufferProcessor.outputChannelCount > 0 )
- {
- bytesToXfer = framesToXfer * dsw->dsw_BytesPerOutputFrame;
- hresult = IDirectSoundBuffer_Lock ( dsw->dsw_OutputBuffer,
- dsw->dsw_WriteOffset, bytesToXfer,
- (void **) &lpOutBuf1, &dwOutSize1,
- (void **) &lpOutBuf2, &dwOutSize2, 0);
- if (hresult != DS_OK)
- {
- ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult));
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
- goto error1;
- }
-
- numFrames = dwOutSize1 / dsw->dsw_BytesPerOutputFrame;
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames );
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 );
-
- /* Is output split into two regions. */
- if( dwOutSize2 > 0 )
- {
- numFrames = dwOutSize2 / dsw->dsw_BytesPerOutputFrame;
- PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames );
- PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 );
- }
- }
-
- result = paContinue;
- numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result );
- stream->framesWritten += numFrames;
-
- if( stream->bufferProcessor.outputChannelCount > 0 )
- {
- /* FIXME: an underflow could happen here */
-
- /* Update our buffer offset and unlock sound buffer */
- bytesProcessed = numFrames * dsw->dsw_BytesPerOutputFrame;
- dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + bytesProcessed) % dsw->dsw_OutputSize;
- IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);
- dsw->dsw_FramesWritten += numFrames;
- }
-
-error1:
- if( stream->bufferProcessor.inputChannelCount > 0 )
- {
- /* FIXME: an overflow could happen here */
-
- /* Update our buffer offset and unlock sound buffer */
- bytesProcessed = numFrames * dsw->dsw_BytesPerInputFrame;
- dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + bytesProcessed) % dsw->dsw_InputSize;
- IDirectSoundCaptureBuffer_Unlock( dsw->dsw_InputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2);
- }
-error2:
-
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames );
-
- }
-
- return result;
-}
-/*******************************************************************/
-static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
-{
- PaWinDsStream *stream;
-
- /* suppress unused variable warnings */
- (void) uID;
- (void) uMsg;
- (void) dw1;
- (void) dw2;
-
- stream = (PaWinDsStream *) dwUser;
- if( stream == NULL ) return;
-
- if( stream->isActive )
- {
- if( stream->abortProcessing )
- {
- stream->isActive = 0;
- }
- else if( stream->stopProcessing )
- {
- DSoundWrapper *dsw = &stream->directSoundWrapper;
- if( stream->bufferProcessor.outputChannelCount > 0 )
- {
- DSW_ZeroEmptySpace( dsw );
- /* clear isActive when all sound played */
- if( dsw->dsw_FramesPlayed >= stream->framesWritten )
- {
- stream->isActive = 0;
- }
- }
- else
- {
- stream->isActive = 0;
- }
- }
- else
- {
- if( Pa_TimeSlice( stream ) != 0) /* Call time slice independant of timing method. */
- {
- /* FIXME implement handling of paComplete and paAbort if possible */
- stream->stopProcessing = 1;
- }
- }
-
- if( !stream->isActive ){
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
- }
- }
-}
-
-/***********************************************************************************
- When CloseStream() is called, the multi-api layer ensures that
- the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
- PaError result = paNoError;
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- DSW_Term( &stream->directSoundWrapper );
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- PaUtil_FreeMemory( stream );
-
- return result;
-}
-
-/***********************************************************************************/
-static PaError StartStream( PaStream *s )
-{
- PaError result = paNoError;
- PaWinDsStream *stream = (PaWinDsStream*)s;
- HRESULT hr;
-
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-
- if( stream->bufferProcessor.inputChannelCount > 0 )
- {
- hr = DSW_StartInput( &stream->directSoundWrapper );
- DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr));
- if( hr != DS_OK )
- {
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
- goto error;
- }
- }
-
- stream->framesWritten = 0;
- stream->callbackFlags = 0;
-
- stream->abortProcessing = 0;
- stream->stopProcessing = 0;
- stream->isActive = 1;
-
- if( stream->bufferProcessor.outputChannelCount > 0 )
- {
- /* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */
- result = Pa_TimeSlice( stream );
- if( result != paNoError ) return result; // FIXME - what if finished?
-
- hr = DSW_StartOutput( &stream->directSoundWrapper );
- DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
- if( hr != DS_OK )
- {
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
- goto error;
- }
- }
-
-
- /* Create timer that will wake us up so we can fill the DSound buffer. */
- {
- int resolution;
- int framesPerWakeup = stream->framesPerDSBuffer / 4;
- int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate;
- if( msecPerWakeup < 10 ) msecPerWakeup = 10;
- else if( msecPerWakeup > 100 ) msecPerWakeup = 100;
- resolution = msecPerWakeup/4;
- stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
- (DWORD) stream, TIME_PERIODIC );
- }
- if( stream->timerID == 0 )
- {
- stream->isActive = 0;
- result = paUnanticipatedHostError;
- PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
- goto error;
- }
-
- stream->isStarted = TRUE;
-
-error:
- return result;
-}
-
-
-/***********************************************************************************/
-static PaError StopStream( PaStream *s )
-{
- PaError result = paNoError;
- PaWinDsStream *stream = (PaWinDsStream*)s;
- HRESULT hr;
- int timeoutMsec;
-
- stream->stopProcessing = 1;
- /* Set timeout at 20% beyond maximum time we might wait. */
- timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate);
- while( stream->isActive && (timeoutMsec > 0) )
- {
- Sleep(10);
- timeoutMsec -= 10;
- }
- if( stream->timerID != 0 )
- {
- timeKillEvent(stream->timerID); /* Stop callback timer. */
- stream->timerID = 0;
- }
-
-
- if( stream->bufferProcessor.outputChannelCount > 0 )
- {
- hr = DSW_StopOutput( &stream->directSoundWrapper );
- }
-
- if( stream->bufferProcessor.inputChannelCount > 0 )
- {
- hr = DSW_StopInput( &stream->directSoundWrapper );
- }
-
- stream->isStarted = FALSE;
-
- return result;
-}
-
-
-/***********************************************************************************/
-static PaError AbortStream( PaStream *s )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- stream->abortProcessing = 1;
- return StopStream( s );
-}
-
-
-/***********************************************************************************/
-static PaError IsStreamStopped( PaStream *s )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- return !stream->isStarted;
-}
-
-
-/***********************************************************************************/
-static PaError IsStreamActive( PaStream *s )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- return stream->isActive;
-}
-
-/***********************************************************************************/
-static PaTime GetStreamTime( PaStream *s )
-{
- /* suppress unused variable warnings */
- (void) s;
-
-
-/*
- new behavior for GetStreamTime is to return a stream based seconds clock
- used for the outTime parameter to the callback.
- FIXME: delete this comment when the other unnecessary related code has
- been cleaned from this file.
-
- PaWinDsStream *stream = (PaWinDsStream*)s;
- DSoundWrapper *dsw;
- dsw = &stream->directSoundWrapper;
- return dsw->dsw_FramesPlayed;
-*/
- return PaUtil_GetTime();
-}
-
-
-/***********************************************************************************/
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-
-/***********************************************************************************
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return paNoError;
-}
-
-
-/***********************************************************************************/
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- /* suppress unused variable warnings */
- (void) buffer;
- (void) frames;
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return paNoError;
-}
-
-
-/***********************************************************************************/
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return 0;
-}
-
-
-/***********************************************************************************/
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaWinDsStream *stream = (PaWinDsStream*)s;
-
- /* suppress unused variable warnings */
- (void) stream;
-
- /* IMPLEMENT ME, see portaudio.h for required behavior*/
-
- return 0;
-}
-
-
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c b/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
deleted file mode 100644
index eb1d3aba..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_win_hostapis.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * $Id: pa_win_hostapis.c,v 1.1.2.10 2004/09/08 17:31:37 rossbencina Exp $
- * Portable Audio I/O Library Windows initialization table
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- Win32 host API initialization function table.
-
- @todo Consider using PA_USE_WMME etc instead of PA_NO_WMME. This is what
- the Unix version does, we should consider being consistent.
-*/
-
-
-#include <pa_hostapi.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-PaUtilHostApiInitializer *paHostApiInitializers[] =
- {
-
-#ifndef PA_NO_DS
- PaWinDs_Initialize,
-#endif
-
-#ifndef PA_NO_WMME
- PaWinMme_Initialize,
-#endif
-
-#ifndef PA_NO_ASIO
- PaAsio_Initialize,
-#endif
-
-/*
-#ifndef PA_NO_WDMKS
- PaWinWdm_Initialize,
-#endif
-*/
-
- PaSkeleton_Initialize, /* just for testing */
-
- 0 /* NULL terminated array */
- };
-
-
-int paDefaultHostApiIndex = 0;
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_util.c b/pjmedia/src/pjmedia/portaudio/pa_win_util.c
deleted file mode 100644
index bf065b8e..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_win_util.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * $Id: pa_win_util.c,v 1.1.2.7 2003/09/15 18:30:26 rossbencina Exp $
- * Portable Audio I/O Library
- * Win32 platform-specific support functions
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Ross Bencina
- *
- * 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.
- *
- * 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.
- *
- * 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.
- */
-/** @file
- Win32 platform-specific support functions.
-
- @todo Implement workaround for QueryPerformanceCounter() skipping forward
- bug. (see msdn kb Q274323).
-*/
-
-#include <windows.h>
-#include <mmsystem.h> /* for timeGetTime() */
-
-#include "pa_util.h"
-
-
-/*
- Track memory allocations to avoid leaks.
- */
-
-#if PA_TRACK_MEMORY
-static int numAllocations_ = 0;
-#endif
-
-
-void *PaUtil_AllocateMemory( long size )
-{
- void *result = GlobalAlloc( GPTR, size );
-
-#if PA_TRACK_MEMORY
- if( result != NULL ) numAllocations_ += 1;
-#endif
- return result;
-}
-
-
-void PaUtil_FreeMemory( void *block )
-{
- if( block != NULL )
- {
- GlobalFree( block );
-#if PA_TRACK_MEMORY
- numAllocations_ -= 1;
-#endif
-
- }
-}
-
-
-int PaUtil_CountCurrentlyAllocatedBlocks( void )
-{
-#if PA_TRACK_MEMORY
- return numAllocations_;
-#else
- return 0;
-#endif
-}
-
-
-void Pa_Sleep( long msec )
-{
- Sleep( msec );
-}
-
-static int usePerformanceCounter_;
-static double secondsPerTick_;
-
-void PaUtil_InitializeClock( void )
-{
- LARGE_INTEGER ticksPerSecond;
-
- if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 )
- {
- usePerformanceCounter_ = 1;
- secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart;
- }
- else
- {
- usePerformanceCounter_ = 0;
- }
-}
-
-
-double PaUtil_GetTime( void )
-{
- LARGE_INTEGER time;
-
- if( usePerformanceCounter_ )
- {
- /* FIXME:
- according to this knowledge-base article, QueryPerformanceCounter
- can skip forward by seconds!
- http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&
-
- it may be better to use the rtdsc instruction using inline asm,
- however then a method is needed to calculate a ticks/seconds ratio.
- */
- QueryPerformanceCounter( &time );
- return time.QuadPart * secondsPerTick_;
- }
- else
- {
-#ifndef UNDER_CE
- return timeGetTime() * .001;
-#else
- return GetTickCount() * .001;
-#endif
- }
-}
diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.c b/pjmedia/src/pjmedia/portaudio/pa_win_wmme.c
deleted file mode 100644
index d7291145..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.c
+++ /dev/null
@@ -1,3633 +0,0 @@
-/*
- * $Id: pa_win_wmme.c,v 1.6.2.86 2004/02/21 11:38:28 rossbencina Exp $
- * pa_win_wmme.c
- * Implementation of PortAudio for Windows MultiMedia Extensions (WMME)
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- *
- * Authors: Ross Bencina and Phil Burk
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */
-
-/* Modification History:
- PLB = Phil Burk
- JM = Julien Maillard
- RDB = Ross Bencina
- PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)
- PLB20010413 - check for excessive numbers of channels
- PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
- including conditional inclusion of memory.h,
- and explicit typecasting on memory allocation
- PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory
- PLB20010816 - pass process instead of thread to SetPriorityClass()
- PLB20010927 - use number of frames instead of real-time for CPULoad calculation.
- JM20020118 - prevent hung thread when buffers underflow.
- PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount
- RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init
- RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices
- refactoring, renaming and fixed a few edge case bugs
- RDB20020531 - converted to V19 framework
- ** NOTE maintanance history is now stored in CVS **
-*/
-
-/** @file
-
- @todo Fix buffer catch up code, can sometimes get stuck (perhaps fixed now,
- needs to be reviewed and tested.)
-
- @todo implement paInputUnderflow, paOutputOverflow streamCallback statusFlags, paNeverDropInput.
-
- @todo BUG: PA_MME_SET_LAST_WAVEIN/OUT_ERROR is used in functions which may
- be called asynchronously from the callback thread. this is bad.
-
- @todo implement inputBufferAdcTime in callback thread
-
- @todo review/fix error recovery and cleanup in marked functions
-
- @todo implement timeInfo for stream priming
-
- @todo handle the case where the callback returns paAbort or paComplete during stream priming.
-
- @todo review input overflow and output underflow handling in ReadStream and WriteStream
-
-Non-critical stuff for the future:
-
- @todo Investigate supporting host buffer formats > 16 bits
-
- @todo define UNICODE and _UNICODE in the project settings and see what breaks
-
-*/
-
-/*
- How it works:
-
- For both callback and blocking read/write streams we open the MME devices
- in CALLBACK_EVENT mode. In this mode, MME signals an Event object whenever
- it has finished with a buffer (either filled it for input, or played it
- for output). Where necessary we block waiting for Event objects using
- WaitMultipleObjects().
-
- When implementing a PA callback stream, we set up a high priority thread
- which waits on the MME buffer Events and drains/fills the buffers when
- they are ready.
-
- When implementing a PA blocking read/write stream, we simply wait on these
- Events (when necessary) inside the ReadStream() and WriteStream() functions.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <windows.h>
-#include <mmsystem.h>
-#ifndef UNDER_CE
-#include <process.h>
-#endif
-#include <assert.h>
-/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
-#ifndef __MWERKS__
-#include <malloc.h>
-#include <memory.h>
-#endif /* __MWERKS__ */
-
-#include "portaudio.h"
-#include "pa_trace.h"
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
-#include "pa_win_wmme.h"
-
-#include <pj/string.h>
-#include <pj/unicode.h>
-
-#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && \
- !defined(UNDER_CE)
-/* MSC version 6 and above */
-#pragma comment(lib, "winmm.lib")
-#endif
-
-/************************************************* Constants ********/
-
-#define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */
-
-#if PA_MME_USE_HIGH_DEFAULT_LATENCY_
- #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.4)
- #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (4)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (4)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (4)
- #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16)
- #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.3) /* Do not exceed unless user buffer exceeds */
- #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
-#else
- #define PA_MME_WIN_9X_DEFAULT_LATENCY_ (0.2)
- #define PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_ (2)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ (3)
- #define PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_ (2)
- #define PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_ (16)
- #define PA_MME_MAX_HOST_BUFFER_SECS_ (0.1) /* Do not exceed unless user buffer exceeds */
- #define PA_MME_MAX_HOST_BUFFER_BYTES_ (32 * 1024) /* Has precedence over PA_MME_MAX_HOST_BUFFER_SECS_, some drivers are known to crash with buffer sizes > 32k */
-#endif
-
-/* Use higher latency for NT because it is even worse at real-time
- operation than Win9x.
-*/
-#define PA_MME_WIN_NT_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_ * 2)
-#define PA_MME_WIN_WDM_DEFAULT_LATENCY_ (PA_MME_WIN_9X_DEFAULT_LATENCY_)
-
-
-#define PA_MME_MIN_TIMEOUT_MSEC_ (1000)
-
-static const pj_char_t constInputMapperSuffix_[] = PJ_T(" - Input");
-static const pj_char_t constOutputMapperSuffix_[] = PJ_T(" - Output");
-
-/********************************************************************/
-
-typedef struct PaWinMmeStream PaWinMmeStream; /* forward declaration */
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** stream,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-
-/* macros for setting last host error information */
-
-#ifdef UNICODE
-
-#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
- { \
- wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
- char mmeErrorText[ MAXERRORLENGTH ]; \
- waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
- WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
- mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
- PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
- }
-
-#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
- { \
- wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
- char mmeErrorText[ MAXERRORLENGTH ]; \
- waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
- WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
- mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
- PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
- }
-
-#else /* !UNICODE */
-
-#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
- { \
- char mmeErrorText[ MAXERRORLENGTH ]; \
- waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
- PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
- }
-
-#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
- { \
- char mmeErrorText[ MAXERRORLENGTH ]; \
- waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
- PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
- }
-
-#endif /* UNICODE */
-
-
-static void PaMme_SetLastSystemError( DWORD errorCode )
-{
- char *lpMsgBuf;
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- errorCode,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL
- );
- PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf );
- LocalFree( lpMsgBuf );
-}
-
-#define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \
- PaMme_SetLastSystemError( errorCode )
-
-
-/* PaError returning wrappers for some commonly used win32 functions
- note that we allow passing a null ptr to have no effect.
-*/
-
-static PaError CreateEventWithPaError( HANDLE *handle,
- LPSECURITY_ATTRIBUTES lpEventAttributes,
- BOOL bManualReset,
- BOOL bInitialState,
- LPCTSTR lpName )
-{
- PaError result = paNoError;
-
- *handle = NULL;
-
- *handle = CreateEvent( lpEventAttributes, bManualReset, bInitialState, lpName );
- if( *handle == NULL )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
- }
-
- return result;
-}
-
-
-static PaError ResetEventWithPaError( HANDLE handle )
-{
- PaError result = paNoError;
-
- if( handle )
- {
- if( ResetEvent( handle ) == 0 )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
- }
- }
-
- return result;
-}
-
-
-static PaError CloseHandleWithPaError( HANDLE handle )
-{
- PaError result = paNoError;
-
- if( handle )
- {
- if( CloseHandle( handle ) == 0 )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
- }
- }
-
- return result;
-}
-
-
-/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- int inputDeviceCount, outputDeviceCount;
-
- /** winMmeDeviceIds is an array of WinMme device ids.
- fields in the range [0, inputDeviceCount) are input device ids,
- and [inputDeviceCount, inputDeviceCount + outputDeviceCount) are output
- device ids.
- */
- UINT *winMmeDeviceIds;
-}
-PaWinMmeHostApiRepresentation;
-
-
-typedef struct
-{
- PaDeviceInfo inheritedDeviceInfo;
- DWORD dwFormats; /**<< standard formats bitmask from the WAVEINCAPS and WAVEOUTCAPS structures */
-}
-PaWinMmeDeviceInfo;
-
-
-/*************************************************************************
- * Returns recommended device ID.
- * On the PC, the recommended device can be specified by the user by
- * setting an environment variable. For example, to use device #1.
- *
- * set PA_RECOMMENDED_OUTPUT_DEVICE=1
- *
- * The user should first determine the available device ID by using
- * the supplied application "pa_devs".
- */
-#define PA_ENV_BUF_SIZE_ (32)
-#define PA_REC_IN_DEV_ENV_NAME_ ("PA_RECOMMENDED_INPUT_DEVICE")
-#define PA_REC_OUT_DEV_ENV_NAME_ ("PA_RECOMMENDED_OUTPUT_DEVICE")
-static PaDeviceIndex GetEnvDefaultDeviceID( char *envName )
-{
- PaDeviceIndex recommendedIndex = paNoDevice;
- DWORD hresult;
- char envbuf[PA_ENV_BUF_SIZE_];
-
-#ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */
-
- /* Let user determine default device by setting environment variable. */
- hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ );
- if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) )
- {
- recommendedIndex = atoi( envbuf );
- }
-#endif
-
- return recommendedIndex;
-}
-
-
-static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi )
-{
- PaDeviceIndex device;
-
- /* input */
- device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ );
- if( device != paNoDevice &&
- ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
- hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 )
- {
- hostApi->inheritedHostApiRep.info.defaultInputDevice = device;
- }
-
- /* output */
- device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ );
- if( device != paNoDevice &&
- ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
- hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 )
- {
- hostApi->inheritedHostApiRep.info.defaultOutputDevice = device;
- }
-}
-
-
-/** Convert external PA ID to a windows multimedia device ID
-*/
-static UINT LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device )
-{
- assert( device >= 0 && device < hostApi->inputDeviceCount + hostApi->outputDeviceCount );
-
- return hostApi->winMmeDeviceIds[ device ];
-}
-
-
-static PaError QueryInputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
-{
- MMRESULT mmresult;
-
- switch( mmresult = waveInOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
- {
- case MMSYSERR_NOERROR:
- return paNoError;
- case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
- return paDeviceUnavailable;
- case MMSYSERR_NODRIVER: /* No device driver is present. */
- return paDeviceUnavailable;
- case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
- return paInsufficientMemory;
- case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
- return paSampleFormatNotSupported;
-
- case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
- /* falls through */
- default:
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- return paUnanticipatedHostError;
- }
-}
-
-
-static PaError QueryOutputWaveFormatEx( int deviceId, WAVEFORMATEX *waveFormatEx )
-{
- MMRESULT mmresult;
-
- switch( mmresult = waveOutOpen( NULL, deviceId, waveFormatEx, 0, 0, WAVE_FORMAT_QUERY ) )
- {
- case MMSYSERR_NOERROR:
- return paNoError;
- case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
- return paDeviceUnavailable;
- case MMSYSERR_NODRIVER: /* No device driver is present. */
- return paDeviceUnavailable;
- case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
- return paInsufficientMemory;
- case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
- return paSampleFormatNotSupported;
-
- case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
- /* falls through */
- default:
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- return paUnanticipatedHostError;
- }
-}
-
-
-static PaError QueryFormatSupported( PaDeviceInfo *deviceInfo,
- PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*),
- int winMmeDeviceId, int channels, double sampleRate )
-{
- PaWinMmeDeviceInfo *winMmeDeviceInfo = (PaWinMmeDeviceInfo*)deviceInfo;
- WAVEFORMATEX waveFormatEx;
-
- if( sampleRate == 11025.0
- && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1M16))
- || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_1S16)) ) ){
-
- return paNoError;
- }
-
- if( sampleRate == 22050.0
- && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2M16))
- || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_2S16)) ) ){
-
- return paNoError;
- }
-
- if( sampleRate == 44100.0
- && ( (channels == 1 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4M16))
- || (channels == 2 && (winMmeDeviceInfo->dwFormats & WAVE_FORMAT_4S16)) ) ){
-
- return paNoError;
- }
-
- waveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
- waveFormatEx.nChannels = (WORD)channels;
- waveFormatEx.nSamplesPerSec = (DWORD)sampleRate;
- waveFormatEx.nAvgBytesPerSec = waveFormatEx.nSamplesPerSec * channels * sizeof(short);
- waveFormatEx.nBlockAlign = (WORD)(channels * sizeof(short));
- waveFormatEx.wBitsPerSample = 16;
- waveFormatEx.cbSize = 0;
-
- return waveFormatExQueryFunction( winMmeDeviceId, &waveFormatEx );
-}
-
-
-#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */
-static double defaultSampleRateSearchOrder_[] =
- { 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,
- 16000.0, 12000.0, 11025.0, 9600.0, 8000.0 };
-
-static void DetectDefaultSampleRate( PaWinMmeDeviceInfo *winMmeDeviceInfo, int winMmeDeviceId,
- PaError (*waveFormatExQueryFunction)(int, WAVEFORMATEX*), int maxChannels )
-{
- PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
- int i;
-
- deviceInfo->defaultSampleRate = 0.;
-
- for( i=0; i < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++i )
- {
- double sampleRate = defaultSampleRateSearchOrder_[ i ];
- PaError paerror = QueryFormatSupported( deviceInfo, waveFormatExQueryFunction, winMmeDeviceId, maxChannels, sampleRate );
- if( paerror == paNoError )
- {
- deviceInfo->defaultSampleRate = sampleRate;
- break;
- }
- }
-}
-
-
-static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
- PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeInputDeviceId, int *success )
-{
- PaError result = paNoError;
- char *deviceName; /* non-const ptr */
- MMRESULT mmresult;
- WAVEINCAPS wic;
- PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
- PJ_DECL_ANSI_TEMP_BUF(abuf,128)
-
- *success = 0;
-
- mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) );
- if( mmresult == MMSYSERR_NOMEM )
- {
- result = paInsufficientMemory;
- goto error;
- }
- else if( mmresult != MMSYSERR_NOERROR )
- {
- /* instead of returning paUnanticipatedHostError we return
- paNoError, but leave success set as 0. This allows
- Pa_Initialize to just ignore this device, without failing
- the entire initialisation process.
- */
- return paNoError;
- }
-
- if( winMmeInputDeviceId == WAVE_MAPPER )
- {
- /* Append I/O suffix to WAVE_MAPPER device. */
- deviceName = (char*)PaUtil_GroupAllocateMemory(
- winMmeHostApi->allocations,
- pj_native_strlen( wic.szPname ) + sizeof(pj_char_t) + sizeof(constInputMapperSuffix_) );
- if( !deviceName )
- {
- result = paInsufficientMemory;
- goto error;
- }
- strcpy( deviceName, PJ_NATIVE_TO_STRING(wic.szPname,abuf,sizeof(abuf)) );
- strcat( deviceName, PJ_NATIVE_TO_STRING(constInputMapperSuffix_,abuf,sizeof(abuf)) );
- }
- else
- {
- deviceName = (char*)PaUtil_GroupAllocateMemory(
- winMmeHostApi->allocations, pj_native_strlen( wic.szPname ) + sizeof(pj_char_t) );
- if( !deviceName )
- {
- result = paInsufficientMemory;
- goto error;
- }
- strcpy( deviceName, PJ_NATIVE_TO_STRING(wic.szPname,abuf,sizeof(abuf)) );
- }
- deviceInfo->name = deviceName;
-
- deviceInfo->maxInputChannels = wic.wChannels;
- /* Sometimes a device can return a rediculously large number of channels.
- * This happened with an SBLive card on a Windows ME box.
- * If that happens, then force it to 2 channels. PLB20010413
- */
- if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )
- {
- PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxInputChannels ));
- deviceInfo->maxInputChannels = 2;
- }
-
- winMmeDeviceInfo->dwFormats = wic.dwFormats;
-
- DetectDefaultSampleRate( winMmeDeviceInfo, winMmeInputDeviceId,
- QueryInputWaveFormatEx, deviceInfo->maxInputChannels );
-
- *success = 1;
-
-error:
- return result;
-}
-
-
-static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
- PaWinMmeDeviceInfo *winMmeDeviceInfo, UINT winMmeOutputDeviceId, int *success )
-{
- PaError result = paNoError;
- char *deviceName; /* non-const ptr */
- MMRESULT mmresult;
- WAVEOUTCAPS woc;
- PaDeviceInfo *deviceInfo = &winMmeDeviceInfo->inheritedDeviceInfo;
- PJ_DECL_ANSI_TEMP_BUF(abuf,128)
-
- *success = 0;
-
- mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) );
- if( mmresult == MMSYSERR_NOMEM )
- {
- result = paInsufficientMemory;
- goto error;
- }
- else if( mmresult != MMSYSERR_NOERROR )
- {
- /* instead of returning paUnanticipatedHostError we return
- paNoError, but leave success set as 0. This allows
- Pa_Initialize to just ignore this device, without failing
- the entire initialisation process.
- */
- return paNoError;
- }
-
- if( winMmeOutputDeviceId == WAVE_MAPPER )
- {
- /* Append I/O suffix to WAVE_MAPPER device. */
- deviceName = (char *)PaUtil_GroupAllocateMemory(
- winMmeHostApi->allocations, pj_native_strlen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) );
- if( !deviceName )
- {
- result = paInsufficientMemory;
- goto error;
- }
- strcpy( deviceName, PJ_NATIVE_TO_STRING(woc.szPname,abuf,sizeof(abuf)) );
- strcat( deviceName, PJ_NATIVE_TO_STRING(constOutputMapperSuffix_,abuf,sizeof(abuf)) );
- }
- else
- {
- deviceName = (char*)PaUtil_GroupAllocateMemory(
- winMmeHostApi->allocations, pj_native_strlen( woc.szPname ) + 1 );
- if( !deviceName )
- {
- result = paInsufficientMemory;
- goto error;
- }
- strcpy( deviceName, PJ_NATIVE_TO_STRING(woc.szPname,abuf,sizeof(abuf)) );
- }
- deviceInfo->name = deviceName;
-
- deviceInfo->maxOutputChannels = woc.wChannels;
- /* Sometimes a device can return a rediculously large number of channels.
- * This happened with an SBLive card on a Windows ME box.
- * It also happens on Win XP!
- */
- if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )
- {
- PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
- deviceInfo->maxOutputChannels = 2;
- }
-
- winMmeDeviceInfo->dwFormats = woc.dwFormats;
-
- DetectDefaultSampleRate( winMmeDeviceInfo, winMmeOutputDeviceId,
- QueryOutputWaveFormatEx, deviceInfo->maxOutputChannels );
-
- *success = 1;
-
-error:
- return result;
-}
-
-
-static void GetDefaultLatencies( PaTime *defaultLowLatency, PaTime *defaultHighLatency )
-{
- OSVERSIONINFO osvi;
- osvi.dwOSVersionInfoSize = sizeof( osvi );
- GetVersionEx( &osvi );
-
- /* Check for NT */
- if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
- {
- *defaultLowLatency = PA_MME_WIN_NT_DEFAULT_LATENCY_;
- }
- else if(osvi.dwMajorVersion >= 5)
- {
- *defaultLowLatency = PA_MME_WIN_WDM_DEFAULT_LATENCY_;
- }
- else
- {
- *defaultLowLatency = PA_MME_WIN_9X_DEFAULT_LATENCY_;
- }
-
- *defaultHighLatency = *defaultLowLatency * 2;
-}
-
-
-PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- int i;
- PaWinMmeHostApiRepresentation *winMmeHostApi;
- int inputDeviceCount, outputDeviceCount, maximumPossibleDeviceCount;
- PaWinMmeDeviceInfo *deviceInfoArray;
- int deviceInfoInitializationSucceeded;
- PaTime defaultLowLatency, defaultHighLatency;
-
- winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) );
- if( !winMmeHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- winMmeHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !winMmeHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- *hostApi = &winMmeHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paMME;
- (*hostApi)->info.name = "MME";
-
-
- /* initialise device counts and default devices under the assumption that
- there are no devices. These values are incremented below if and when
- devices are successfully initialized.
- */
- (*hostApi)->info.deviceCount = 0;
- (*hostApi)->info.defaultInputDevice = paNoDevice;
- (*hostApi)->info.defaultOutputDevice = paNoDevice;
- winMmeHostApi->inputDeviceCount = 0;
- winMmeHostApi->outputDeviceCount = 0;
-
-
- maximumPossibleDeviceCount = 0;
-
- inputDeviceCount = waveInGetNumDevs();
- if( inputDeviceCount > 0 )
- maximumPossibleDeviceCount += inputDeviceCount + 1; /* assume there is a WAVE_MAPPER */
-
- outputDeviceCount = waveOutGetNumDevs();
- if( outputDeviceCount > 0 )
- maximumPossibleDeviceCount += outputDeviceCount + 1; /* assume there is a WAVE_MAPPER */
-
-
- if( maximumPossibleDeviceCount > 0 ){
-
- (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleDeviceCount );
- if( !(*hostApi)->deviceInfos )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- /* allocate all device info structs in a contiguous block */
- deviceInfoArray = (PaWinMmeDeviceInfo*)PaUtil_GroupAllocateMemory(
- winMmeHostApi->allocations, sizeof(PaWinMmeDeviceInfo) * maximumPossibleDeviceCount );
- if( !deviceInfoArray )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- winMmeHostApi->winMmeDeviceIds = (UINT*)PaUtil_GroupAllocateMemory(
- winMmeHostApi->allocations, sizeof(int) * maximumPossibleDeviceCount );
- if( !winMmeHostApi->winMmeDeviceIds )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- GetDefaultLatencies( &defaultLowLatency, &defaultHighLatency );
-
- if( inputDeviceCount > 0 ){
- /* -1 is the WAVE_MAPPER */
- for( i = -1; i < inputDeviceCount; ++i ){
- UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
- PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
- PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
-
- deviceInfo->maxInputChannels = 0;
- deviceInfo->maxOutputChannels = 0;
-
- deviceInfo->defaultLowInputLatency = defaultLowLatency;
- deviceInfo->defaultLowOutputLatency = defaultLowLatency;
- deviceInfo->defaultHighInputLatency = defaultHighLatency;
- deviceInfo->defaultHighOutputLatency = defaultHighLatency;
-
- result = InitializeInputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,
- winMmeDeviceId, &deviceInfoInitializationSucceeded );
- if( result != paNoError )
- goto error;
-
- if( deviceInfoInitializationSucceeded ){
- if( (*hostApi)->info.defaultInputDevice == paNoDevice )
- (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
-
- winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;
- (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
-
- winMmeHostApi->inputDeviceCount++;
- (*hostApi)->info.deviceCount++;
- }
- }
- }
-
- if( outputDeviceCount > 0 ){
- /* -1 is the WAVE_MAPPER */
- for( i = -1; i < outputDeviceCount; ++i ){
- UINT winMmeDeviceId = (UINT)((i==-1) ? WAVE_MAPPER : i);
- PaWinMmeDeviceInfo *wmmeDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
- PaDeviceInfo *deviceInfo = &wmmeDeviceInfo->inheritedDeviceInfo;
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
-
- deviceInfo->maxInputChannels = 0;
- deviceInfo->maxOutputChannels = 0;
-
- deviceInfo->defaultLowInputLatency = defaultLowLatency;
- deviceInfo->defaultLowOutputLatency = defaultLowLatency;
- deviceInfo->defaultHighInputLatency = defaultHighLatency;
- deviceInfo->defaultHighOutputLatency = defaultHighLatency;
-
- result = InitializeOutputDeviceInfo( winMmeHostApi, wmmeDeviceInfo,
- winMmeDeviceId, &deviceInfoInitializationSucceeded );
- if( result != paNoError )
- goto error;
-
- if( deviceInfoInitializationSucceeded ){
- if( (*hostApi)->info.defaultOutputDevice == paNoDevice )
- (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
-
- winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = winMmeDeviceId;
- (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
-
- winMmeHostApi->outputDeviceCount++;
- (*hostApi)->info.deviceCount++;
- }
- }
- }
- }
-
-
- InitializeDefaultDeviceIdsFromEnv( winMmeHostApi );
-
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( winMmeHostApi )
- {
- if( winMmeHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
- PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
- }
-
- PaUtil_FreeMemory( winMmeHostApi );
- }
-
- return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
-
- if( winMmeHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
- PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
- }
-
- PaUtil_FreeMemory( winMmeHostApi );
-}
-
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
- PaDeviceInfo *inputDeviceInfo, *outputDeviceInfo;
- int inputChannelCount, outputChannelCount;
- int inputMultipleDeviceChannelCount, outputMultipleDeviceChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
- UINT winMmeInputDeviceId, winMmeOutputDeviceId;
- unsigned int i;
- PaError paerror;
-
- /* The calls to QueryFormatSupported below are intended to detect invalid
- sample rates. If we assume that the channel count and format are OK,
- then the only thing that could fail is the sample rate. This isn't
- strictly true, but I can't think of a better way to test that the
- sample rate is valid.
- */
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- inputStreamInfo = inputParameters->hostApiSpecificStreamInfo;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( inputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification
- && inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )
- {
- inputMultipleDeviceChannelCount = 0;
- for( i=0; i< inputStreamInfo->deviceCount; ++i )
- {
- inputMultipleDeviceChannelCount += inputStreamInfo->devices[i].channelCount;
-
- inputDeviceInfo = hostApi->deviceInfos[ inputStreamInfo->devices[i].device ];
-
- /* check that input device can support inputChannelCount */
- if( inputStreamInfo->devices[i].channelCount <= 0
- || inputStreamInfo->devices[i].channelCount > inputDeviceInfo->maxInputChannels )
- return paInvalidChannelCount;
-
- /* test for valid sample rate, see comment above */
- winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputStreamInfo->devices[i].device );
- paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputStreamInfo->devices[i].channelCount, sampleRate );
- if( paerror != paNoError )
- return paInvalidSampleRate;
- }
-
- if( inputMultipleDeviceChannelCount != inputChannelCount )
- return paIncompatibleHostApiSpecificStreamInfo;
- }
- else
- {
- if( inputStreamInfo && (inputStreamInfo->flags & paWinMmeUseMultipleDevices) )
- return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the input device */
-
- inputDeviceInfo = hostApi->deviceInfos[ inputParameters->device ];
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > inputDeviceInfo->maxInputChannels )
- return paInvalidChannelCount;
-
- /* test for valid sample rate, see comment above */
- winMmeInputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device );
- paerror = QueryFormatSupported( inputDeviceInfo, QueryInputWaveFormatEx, winMmeInputDeviceId, inputChannelCount, sampleRate );
- if( paerror != paNoError )
- return paInvalidSampleRate;
- }
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- outputStreamInfo = outputParameters->hostApiSpecificStreamInfo;
-
- /* all standard sample formats are supported by the buffer adapter,
- this implementation doesn't support any custom sample formats */
- if( outputSampleFormat & paCustomFormat )
- return paSampleFormatNotSupported;
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification
- && outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )
- {
- outputMultipleDeviceChannelCount = 0;
- for( i=0; i< outputStreamInfo->deviceCount; ++i )
- {
- outputMultipleDeviceChannelCount += outputStreamInfo->devices[i].channelCount;
-
- outputDeviceInfo = hostApi->deviceInfos[ outputStreamInfo->devices[i].device ];
-
- /* check that output device can support outputChannelCount */
- if( outputStreamInfo->devices[i].channelCount <= 0
- || outputStreamInfo->devices[i].channelCount > outputDeviceInfo->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* test for valid sample rate, see comment above */
- winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputStreamInfo->devices[i].device );
- paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputStreamInfo->devices[i].channelCount, sampleRate );
- if( paerror != paNoError )
- return paInvalidSampleRate;
- }
-
- if( outputMultipleDeviceChannelCount != outputChannelCount )
- return paIncompatibleHostApiSpecificStreamInfo;
- }
- else
- {
- if( outputStreamInfo && (outputStreamInfo->flags & paWinMmeUseMultipleDevices) )
- return paIncompatibleHostApiSpecificStreamInfo; /* paUseHostApiSpecificDeviceSpecification was not supplied as the output device */
-
- outputDeviceInfo = hostApi->deviceInfos[ outputParameters->device ];
-
- /* check that output device can support outputChannelCount */
- if( outputChannelCount > outputDeviceInfo->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* test for valid sample rate, see comment above */
- winMmeOutputDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device );
- paerror = QueryFormatSupported( outputDeviceInfo, QueryOutputWaveFormatEx, winMmeOutputDeviceId, outputChannelCount, sampleRate );
- if( paerror != paNoError )
- return paInvalidSampleRate;
- }
- }
-
- /*
- - if a full duplex stream is requested, check that the combination
- of input and output parameters is supported
-
- - check that the device supports sampleRate
-
- for mme all we can do is test that the input and output devices
- support the requested sample rate and number of channels. we
- cannot test for full duplex compatibility.
- */
-
- return paFormatIsSupported;
-}
-
-
-
-static void SelectBufferSizeAndCount( unsigned long baseBufferSize,
- unsigned long requestedLatency,
- unsigned long baseBufferCount, unsigned long minimumBufferCount,
- unsigned long maximumBufferSize, unsigned long *hostBufferSize,
- unsigned long *hostBufferCount )
-{
- unsigned long sizeMultiplier, bufferCount, latency;
- unsigned long nextLatency, nextBufferSize;
- int baseBufferSizeIsPowerOfTwo;
-
- sizeMultiplier = 1;
- bufferCount = baseBufferCount;
-
- /* count-1 below because latency is always determined by one less
- than the total number of buffers.
- */
- latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
-
- if( latency > requestedLatency )
- {
-
- /* reduce number of buffers without falling below suggested latency */
-
- nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);
- while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )
- {
- --bufferCount;
- nextLatency = (baseBufferSize * sizeMultiplier) * (bufferCount-2);
- }
-
- }else if( latency < requestedLatency ){
-
- baseBufferSizeIsPowerOfTwo = (! (baseBufferSize & (baseBufferSize - 1)));
- if( baseBufferSizeIsPowerOfTwo ){
-
- /* double size of buffers without exceeding requestedLatency */
-
- nextBufferSize = (baseBufferSize * (sizeMultiplier*2));
- nextLatency = nextBufferSize * (bufferCount-1);
- while( nextBufferSize <= maximumBufferSize
- && nextLatency < requestedLatency )
- {
- sizeMultiplier *= 2;
- nextBufferSize = (baseBufferSize * (sizeMultiplier*2));
- nextLatency = nextBufferSize * (bufferCount-1);
- }
-
- }else{
-
- /* increase size of buffers upto first excess of requestedLatency */
-
- nextBufferSize = (baseBufferSize * (sizeMultiplier+1));
- nextLatency = nextBufferSize * (bufferCount-1);
- while( nextBufferSize <= maximumBufferSize
- && nextLatency < requestedLatency )
- {
- ++sizeMultiplier;
- nextBufferSize = (baseBufferSize * (sizeMultiplier+1));
- nextLatency = nextBufferSize * (bufferCount-1);
- }
-
- if( nextLatency < requestedLatency )
- ++sizeMultiplier;
- }
-
- /* increase number of buffers until requestedLatency is reached */
-
- latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
- while( latency < requestedLatency )
- {
- ++bufferCount;
- latency = (baseBufferSize * sizeMultiplier) * (bufferCount-1);
- }
- }
-
- *hostBufferSize = baseBufferSize * sizeMultiplier;
- *hostBufferCount = bufferCount;
-}
-
-
-static void ReselectBufferCount( unsigned long bufferSize,
- unsigned long requestedLatency,
- unsigned long baseBufferCount, unsigned long minimumBufferCount,
- unsigned long *hostBufferCount )
-{
- unsigned long bufferCount, latency;
- unsigned long nextLatency;
-
- bufferCount = baseBufferCount;
-
- /* count-1 below because latency is always determined by one less
- than the total number of buffers.
- */
- latency = bufferSize * (bufferCount-1);
-
- if( latency > requestedLatency )
- {
- /* reduce number of buffers without falling below suggested latency */
-
- nextLatency = bufferSize * (bufferCount-2);
- while( bufferCount > minimumBufferCount && nextLatency >= requestedLatency )
- {
- --bufferCount;
- nextLatency = bufferSize * (bufferCount-2);
- }
-
- }else if( latency < requestedLatency ){
-
- /* increase number of buffers until requestedLatency is reached */
-
- latency = bufferSize * (bufferCount-1);
- while( latency < requestedLatency )
- {
- ++bufferCount;
- latency = bufferSize * (bufferCount-1);
- }
- }
-
- *hostBufferCount = bufferCount;
-}
-
-
-/* CalculateBufferSettings() fills the framesPerHostInputBuffer, hostInputBufferCount,
- framesPerHostOutputBuffer and hostOutputBufferCount parameters based on the values
- of the other parameters.
-*/
-
-static PaError CalculateBufferSettings(
- unsigned long *framesPerHostInputBuffer, unsigned long *hostInputBufferCount,
- unsigned long *framesPerHostOutputBuffer, unsigned long *hostOutputBufferCount,
- int inputChannelCount, PaSampleFormat hostInputSampleFormat,
- PaTime suggestedInputLatency, PaWinMmeStreamInfo *inputStreamInfo,
- int outputChannelCount, PaSampleFormat hostOutputSampleFormat,
- PaTime suggestedOutputLatency, PaWinMmeStreamInfo *outputStreamInfo,
- double sampleRate, unsigned long framesPerBuffer )
-{
- PaError result = paNoError;
- int effectiveInputChannelCount, effectiveOutputChannelCount;
- int hostInputFrameSize = 0;
- unsigned int i;
-
- if( inputChannelCount > 0 )
- {
- int hostInputSampleSize = Pa_GetSampleSize( hostInputSampleFormat );
- if( hostInputSampleSize < 0 )
- {
- result = hostInputSampleSize;
- goto error;
- }
-
- if( inputStreamInfo
- && ( inputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
- {
- /* set effectiveInputChannelCount to the largest number of
- channels on any one device.
- */
- effectiveInputChannelCount = 0;
- for( i=0; i< inputStreamInfo->deviceCount; ++i )
- {
- if( inputStreamInfo->devices[i].channelCount > effectiveInputChannelCount )
- effectiveInputChannelCount = inputStreamInfo->devices[i].channelCount;
- }
- }
- else
- {
- effectiveInputChannelCount = inputChannelCount;
- }
-
- hostInputFrameSize = hostInputSampleSize * effectiveInputChannelCount;
-
- if( inputStreamInfo
- && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
- {
- if( inputStreamInfo->bufferCount <= 0
- || inputStreamInfo->framesPerBuffer <= 0 )
- {
- result = paIncompatibleHostApiSpecificStreamInfo;
- goto error;
- }
-
- *framesPerHostInputBuffer = inputStreamInfo->framesPerBuffer;
- *hostInputBufferCount = inputStreamInfo->bufferCount;
- }
- else
- {
- unsigned long hostBufferSizeBytes, hostBufferCount;
- unsigned long minimumBufferCount = (outputChannelCount > 0)
- ? PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_
- : PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_HALF_DUPLEX_;
-
- unsigned long maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostInputFrameSize);
- if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
- maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;
-
- /* compute the following in bytes, then convert back to frames */
-
- SelectBufferSizeAndCount(
- ((framesPerBuffer == paFramesPerBufferUnspecified)
- ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
- : framesPerBuffer ) * hostInputFrameSize, /* baseBufferSize */
- ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
- 4, /* baseBufferCount */
- minimumBufferCount, maximumBufferSize,
- &hostBufferSizeBytes, &hostBufferCount );
-
- *framesPerHostInputBuffer = hostBufferSizeBytes / hostInputFrameSize;
- *hostInputBufferCount = hostBufferCount;
- }
- }
- else
- {
- *framesPerHostInputBuffer = 0;
- *hostInputBufferCount = 0;
- }
-
- if( outputChannelCount > 0 )
- {
- if( outputStreamInfo
- && ( outputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
- {
- if( outputStreamInfo->bufferCount <= 0
- || outputStreamInfo->framesPerBuffer <= 0 )
- {
- result = paIncompatibleHostApiSpecificStreamInfo;
- goto error;
- }
-
- *framesPerHostOutputBuffer = outputStreamInfo->framesPerBuffer;
- *hostOutputBufferCount = outputStreamInfo->bufferCount;
-
-
- if( inputChannelCount > 0 ) /* full duplex */
- {
- if( *framesPerHostInputBuffer != *framesPerHostOutputBuffer )
- {
- if( inputStreamInfo
- && ( inputStreamInfo->flags & paWinMmeUseLowLevelLatencyParameters ) )
- {
- /* a custom StreamInfo was used for specifying both input
- and output buffer sizes, the larger buffer size
- must be a multiple of the smaller buffer size */
-
- if( *framesPerHostInputBuffer < *framesPerHostOutputBuffer )
- {
- if( *framesPerHostOutputBuffer % *framesPerHostInputBuffer != 0 )
- {
- result = paIncompatibleHostApiSpecificStreamInfo;
- goto error;
- }
- }
- else
- {
- assert( *framesPerHostInputBuffer > *framesPerHostOutputBuffer );
- if( *framesPerHostInputBuffer % *framesPerHostOutputBuffer != 0 )
- {
- result = paIncompatibleHostApiSpecificStreamInfo;
- goto error;
- }
- }
- }
- else
- {
- /* a custom StreamInfo was not used for specifying the input buffer size,
- so use the output buffer size, and approximately the same latency. */
-
- *framesPerHostInputBuffer = *framesPerHostOutputBuffer;
- *hostInputBufferCount = (((unsigned long)(suggestedInputLatency * sampleRate)) / *framesPerHostInputBuffer) + 1;
-
- if( *hostInputBufferCount < PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_ )
- *hostInputBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
- }
- }
- }
- }
- else
- {
- unsigned long hostBufferSizeBytes, hostBufferCount;
- unsigned long minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
- unsigned long maximumBufferSize;
- int hostOutputFrameSize;
- int hostOutputSampleSize;
-
- hostOutputSampleSize = Pa_GetSampleSize( hostOutputSampleFormat );
- if( hostOutputSampleSize < 0 )
- {
- result = hostOutputSampleSize;
- goto error;
- }
-
- if( outputStreamInfo
- && ( outputStreamInfo->flags & paWinMmeUseMultipleDevices ) )
- {
- /* set effectiveOutputChannelCount to the largest number of
- channels on any one device.
- */
- effectiveOutputChannelCount = 0;
- for( i=0; i< outputStreamInfo->deviceCount; ++i )
- {
- if( outputStreamInfo->devices[i].channelCount > effectiveOutputChannelCount )
- effectiveOutputChannelCount = outputStreamInfo->devices[i].channelCount;
- }
- }
- else
- {
- effectiveOutputChannelCount = outputChannelCount;
- }
-
- hostOutputFrameSize = hostOutputSampleSize * effectiveOutputChannelCount;
-
- maximumBufferSize = (long) ((PA_MME_MAX_HOST_BUFFER_SECS_ * sampleRate) * hostOutputFrameSize);
- if( maximumBufferSize > PA_MME_MAX_HOST_BUFFER_BYTES_ )
- maximumBufferSize = PA_MME_MAX_HOST_BUFFER_BYTES_;
-
-
- /* compute the following in bytes, then convert back to frames */
-
- SelectBufferSizeAndCount(
- ((framesPerBuffer == paFramesPerBufferUnspecified)
- ? PA_MME_MIN_HOST_BUFFER_FRAMES_WHEN_UNSPECIFIED_
- : framesPerBuffer ) * hostOutputFrameSize, /* baseBufferSize */
- ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
- 4, /* baseBufferCount */
- minimumBufferCount,
- maximumBufferSize,
- &hostBufferSizeBytes, &hostBufferCount );
-
- *framesPerHostOutputBuffer = hostBufferSizeBytes / hostOutputFrameSize;
- *hostOutputBufferCount = hostBufferCount;
-
-
- if( inputChannelCount > 0 )
- {
- /* ensure that both input and output buffer sizes are the same.
- if they don't match at this stage, choose the smallest one
- and use that for input and output
- */
-
- if( *framesPerHostOutputBuffer != *framesPerHostInputBuffer )
- {
- if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
- {
- unsigned long framesPerHostBuffer = *framesPerHostInputBuffer;
-
- minimumBufferCount = PA_MME_MIN_HOST_OUTPUT_BUFFER_COUNT_;
- ReselectBufferCount(
- framesPerHostBuffer * hostOutputFrameSize, /* bufferSize */
- ((unsigned long)(suggestedOutputLatency * sampleRate)) * hostOutputFrameSize, /* suggestedLatency */
- 4, /* baseBufferCount */
- minimumBufferCount,
- &hostBufferCount );
-
- *framesPerHostOutputBuffer = framesPerHostBuffer;
- *hostOutputBufferCount = hostBufferCount;
- }
- else
- {
- unsigned long framesPerHostBuffer = *framesPerHostOutputBuffer;
-
- minimumBufferCount = PA_MME_MIN_HOST_INPUT_BUFFER_COUNT_FULL_DUPLEX_;
- ReselectBufferCount(
- framesPerHostBuffer * hostInputFrameSize, /* bufferSize */
- ((unsigned long)(suggestedInputLatency * sampleRate)) * hostInputFrameSize, /* suggestedLatency */
- 4, /* baseBufferCount */
- minimumBufferCount,
- &hostBufferCount );
-
- *framesPerHostInputBuffer = framesPerHostBuffer;
- *hostInputBufferCount = hostBufferCount;
- }
- }
- }
- }
- }
- else
- {
- *framesPerHostOutputBuffer = 0;
- *hostOutputBufferCount = 0;
- }
-
-error:
- return result;
-}
-
-
-typedef struct
-{
- HANDLE bufferEvent;
- void *waveHandles;
- unsigned int deviceCount;
- /* unsigned int channelCount; */
- WAVEHDR **waveHeaders; /* waveHeaders[device][buffer] */
- unsigned int bufferCount;
- unsigned int currentBufferIndex;
- unsigned int framesPerBuffer;
- unsigned int framesUsedInCurrentBuffer;
-}PaWinMmeSingleDirectionHandlesAndBuffers;
-
-/* prototypes for functions operating on PaWinMmeSingleDirectionHandlesAndBuffers */
-
-static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers );
-static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
- PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
- unsigned long bytesPerHostSample,
- double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
- unsigned int deviceCount, int isInput );
-static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError );
-static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
- unsigned long hostBufferCount,
- PaSampleFormat hostSampleFormat,
- unsigned long framesPerHostBuffer,
- PaWinMmeDeviceAndChannelCount *devices,
- int isInput );
-static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput );
-
-
-static void InitializeSingleDirectionHandlesAndBuffers( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
-{
- handlesAndBuffers->bufferEvent = 0;
- handlesAndBuffers->waveHandles = 0;
- handlesAndBuffers->deviceCount = 0;
- handlesAndBuffers->waveHeaders = 0;
- handlesAndBuffers->bufferCount = 0;
-}
-
-static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostApi,
- PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
- unsigned long bytesPerHostSample,
- double sampleRate, PaWinMmeDeviceAndChannelCount *devices,
- unsigned int deviceCount, int isInput )
-{
- PaError result;
- MMRESULT mmresult;
- unsigned long bytesPerFrame;
- WAVEFORMATEX wfx;
- signed int i;
-
- /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
- has already been called to zero some fields */
-
- result = CreateEventWithPaError( &handlesAndBuffers->bufferEvent, NULL, FALSE, FALSE, NULL );
- if( result != paNoError ) goto error;
-
- if( isInput )
- handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * deviceCount );
- else
- handlesAndBuffers->waveHandles = (void*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * deviceCount );
- if( !handlesAndBuffers->waveHandles )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- handlesAndBuffers->deviceCount = deviceCount;
-
- for( i = 0; i < (signed int)deviceCount; ++i )
- {
- if( isInput )
- ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] = 0;
- else
- ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] = 0;
- }
-
- wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nSamplesPerSec = (DWORD) sampleRate;
- wfx.cbSize = 0;
-
- for( i = 0; i < (signed int)deviceCount; ++i )
- {
- UINT winMmeDeviceId;
-
- winMmeDeviceId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, devices[i].device );
- wfx.nChannels = (WORD)devices[i].channelCount;
-
- bytesPerFrame = wfx.nChannels * bytesPerHostSample;
-
- wfx.nAvgBytesPerSec = (DWORD)(bytesPerFrame * sampleRate);
- wfx.nBlockAlign = (WORD)bytesPerFrame;
- wfx.wBitsPerSample = (WORD)((bytesPerFrame/wfx.nChannels) * 8);
-
- /* REVIEW: consider not firing an event for input when a full duplex
- stream is being used. this would probably depend on the
- neverDropInput flag. */
-
- if( isInput )
- mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
- (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
- else
- mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
- (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
-
- if( mmresult != MMSYSERR_NOERROR )
- {
- switch( mmresult )
- {
- case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
- result = paDeviceUnavailable;
- break;
- case MMSYSERR_NODRIVER: /* No device driver is present. */
- result = paDeviceUnavailable;
- break;
- case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
- result = paInsufficientMemory;
- break;
-
- case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
- /* falls through */
- case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
- /* falls through */
- default:
- result = paUnanticipatedHostError;
- if( isInput )
- {
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- }
- else
- {
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- }
- }
- goto error;
- }
- }
-
- return result;
-
-error:
- TerminateWaveHandles( handlesAndBuffers, isInput, 1 /* currentlyProcessingAnError */ );
-
- return result;
-}
-
-
-static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput, int currentlyProcessingAnError )
-{
- PaError result = paNoError;
- MMRESULT mmresult = 0;
- signed int i;
-
- if( handlesAndBuffers->waveHandles )
- {
- for( i = handlesAndBuffers->deviceCount-1; i >= 0; --i )
- {
- if( isInput )
- {
- if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] )
- mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] );
- }
- else
- {
- if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] )
- mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] );
- }
-
- if( mmresult != MMSYSERR_NOERROR &&
- !currentlyProcessingAnError ) /* don't update the error state if we're already processing an error */
- {
- result = paUnanticipatedHostError;
- if( isInput )
- {
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- }
- else
- {
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- }
- /* note that we don't break here, we try to continue closing devices */
- }
- }
-
- PaUtil_FreeMemory( handlesAndBuffers->waveHandles );
- handlesAndBuffers->waveHandles = 0;
- }
-
- if( handlesAndBuffers->bufferEvent )
- {
- result = CloseHandleWithPaError( handlesAndBuffers->bufferEvent );
- handlesAndBuffers->bufferEvent = 0;
- }
-
- return result;
-}
-
-
-static PaError InitializeWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers,
- unsigned long hostBufferCount,
- PaSampleFormat hostSampleFormat,
- unsigned long framesPerHostBuffer,
- PaWinMmeDeviceAndChannelCount *devices,
- int isInput )
-{
- PaError result = paNoError;
- MMRESULT mmresult;
- WAVEHDR *deviceWaveHeaders;
- signed int i, j;
-
- /* for error cleanup we expect that InitializeSingleDirectionHandlesAndBuffers()
- has already been called to zero some fields */
-
-
- /* allocate an array of pointers to arrays of wave headers, one array of
- wave headers per device */
- handlesAndBuffers->waveHeaders = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * handlesAndBuffers->deviceCount );
- if( !handlesAndBuffers->waveHeaders )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )
- handlesAndBuffers->waveHeaders[i] = 0;
-
- handlesAndBuffers->bufferCount = hostBufferCount;
-
- for( i = 0; i < (signed int)handlesAndBuffers->deviceCount; ++i )
- {
- int bufferBytes = Pa_GetSampleSize( hostSampleFormat ) *
- framesPerHostBuffer * devices[i].channelCount;
- if( bufferBytes < 0 )
- {
- result = paInternalError;
- goto error;
- }
-
- /* Allocate an array of wave headers for device i */
- deviceWaveHeaders = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*hostBufferCount );
- if( !deviceWaveHeaders )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- for( j=0; j < (signed int)hostBufferCount; ++j )
- deviceWaveHeaders[j].lpData = 0;
-
- handlesAndBuffers->waveHeaders[i] = deviceWaveHeaders;
-
- /* Allocate a buffer for each wave header */
- for( j=0; j < (signed int)hostBufferCount; ++j )
- {
- deviceWaveHeaders[j].lpData = (char *)PaUtil_AllocateMemory( bufferBytes );
- if( !deviceWaveHeaders[j].lpData )
- {
- result = paInsufficientMemory;
- goto error;
- }
- deviceWaveHeaders[j].dwBufferLength = bufferBytes;
- deviceWaveHeaders[j].dwUser = 0xFFFFFFFF; /* indicates that *PrepareHeader() has not yet been called, for error clean up code */
-
- if( isInput )
- {
- mmresult = waveInPrepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- goto error;
- }
- }
- else /* output */
- {
- mmresult = waveOutPrepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- goto error;
- }
- }
- deviceWaveHeaders[j].dwUser = devices[i].channelCount;
- }
- }
-
- return result;
-
-error:
- TerminateWaveHeaders( handlesAndBuffers, isInput );
-
- return result;
-}
-
-
-static void TerminateWaveHeaders( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers, int isInput )
-{
- signed int i, j;
- WAVEHDR *deviceWaveHeaders;
-
- if( handlesAndBuffers->waveHeaders )
- {
- for( i = handlesAndBuffers->deviceCount-1; i >= 0 ; --i )
- {
- deviceWaveHeaders = handlesAndBuffers->waveHeaders[i]; /* wave headers for device i */
- if( deviceWaveHeaders )
- {
- for( j = handlesAndBuffers->bufferCount-1; j >= 0; --j )
- {
- if( deviceWaveHeaders[j].lpData )
- {
- if( deviceWaveHeaders[j].dwUser != 0xFFFFFFFF )
- {
- if( isInput )
- waveInUnprepareHeader( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
- else
- waveOutUnprepareHeader( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], &deviceWaveHeaders[j], sizeof(WAVEHDR) );
- }
-
- PaUtil_FreeMemory( deviceWaveHeaders[j].lpData );
- }
- }
-
- PaUtil_FreeMemory( deviceWaveHeaders );
- }
- }
-
- PaUtil_FreeMemory( handlesAndBuffers->waveHeaders );
- handlesAndBuffers->waveHeaders = 0;
- }
-}
-
-
-
-/* PaWinMmeStream - a stream data structure specifically for this implementation */
-/* note that struct PaWinMmeStream is typedeffed to PaWinMmeStream above. */
-struct PaWinMmeStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- int primeStreamUsingCallback;
-
- PaWinMmeSingleDirectionHandlesAndBuffers input;
- PaWinMmeSingleDirectionHandlesAndBuffers output;
-
- /* Processing thread management -------------- */
- HANDLE abortEvent;
- HANDLE processingThread;
- DWORD processingThreadId;
-
- char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */
- int processingThreadPriority;
- int highThreadPriority;
- int throttledThreadPriority;
- unsigned long throttledSleepMsecs;
-
- int isStopped;
- volatile int isActive;
- volatile int stopProcessing; /* stop thread once existing buffers have been returned */
- volatile int abortProcessing; /* stop thread immediately */
-
- DWORD allBuffersDurationMs; /* used to calculate timeouts */
-};
-
-/* updates deviceCount if PaWinMmeUseMultipleDevices is used */
-
-static PaError ValidateWinMmeSpecificStreamInfo(
- const PaStreamParameters *streamParameters,
- const PaWinMmeStreamInfo *streamInfo,
- char *throttleProcessingThreadOnOverload,
- unsigned long *deviceCount )
-{
- if( streamInfo )
- {
- if( streamInfo->size != sizeof( PaWinMmeStreamInfo )
- || streamInfo->version != 1 )
- {
- return paIncompatibleHostApiSpecificStreamInfo;
- }
-
- if( streamInfo->flags & paWinMmeDontThrottleOverloadedProcessingThread )
- *throttleProcessingThreadOnOverload = 0;
-
- if( streamInfo->flags & paWinMmeUseMultipleDevices )
- {
- if( streamParameters->device != paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- *deviceCount = streamInfo->deviceCount;
- }
- }
-
- return paNoError;
-}
-
-static PaError RetrieveDevicesFromStreamParameters(
- struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *streamParameters,
- const PaWinMmeStreamInfo *streamInfo,
- PaWinMmeDeviceAndChannelCount *devices,
- unsigned long deviceCount )
-{
- PaError result = paNoError;
- unsigned int i;
- int totalChannelCount;
- PaDeviceIndex hostApiDevice;
-
- if( streamInfo && streamInfo->flags & paWinMmeUseMultipleDevices )
- {
- totalChannelCount = 0;
- for( i=0; i < deviceCount; ++i )
- {
- /* validate that the device number is within range */
- result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
- streamInfo->devices[i].device, hostApi );
- if( result != paNoError )
- return result;
-
- devices[i].device = hostApiDevice;
- devices[i].channelCount = streamInfo->devices[i].channelCount;
-
- totalChannelCount += devices[i].channelCount;
- }
-
- if( totalChannelCount != streamParameters->channelCount )
- {
- /* channelCount must match total channels specified by multiple devices */
- return paInvalidChannelCount; /* REVIEW use of this error code */
- }
- }
- else
- {
- devices[0].device = streamParameters->device;
- devices[0].channelCount = streamParameters->channelCount;
- }
-
- return result;
-}
-
-static PaError ValidateInputChannelCounts(
- struct PaUtilHostApiRepresentation *hostApi,
- PaWinMmeDeviceAndChannelCount *devices,
- unsigned long deviceCount )
-{
- unsigned int i;
-
- for( i=0; i < deviceCount; ++i )
- {
- if( devices[i].channelCount < 1 || devices[i].channelCount
- > hostApi->deviceInfos[ devices[i].device ]->maxInputChannels )
- return paInvalidChannelCount;
- }
-
- return paNoError;
-}
-
-static PaError ValidateOutputChannelCounts(
- struct PaUtilHostApiRepresentation *hostApi,
- PaWinMmeDeviceAndChannelCount *devices,
- unsigned long deviceCount )
-{
- unsigned int i;
-
- for( i=0; i < deviceCount; ++i )
- {
- if( devices[i].channelCount < 1 || devices[i].channelCount
- > hostApi->deviceInfos[ devices[i].device ]->maxOutputChannels )
- return paInvalidChannelCount;
- }
-
- return paNoError;
-}
-
-
-/* the following macros are intended to improve the readability of the following code */
-#define PA_IS_INPUT_STREAM_( stream ) ( stream ->input.waveHandles )
-#define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->output.waveHandles )
-#define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->input.waveHandles && stream ->output.waveHandles )
-#define PA_IS_HALF_DUPLEX_STREAM_( stream ) ( !(stream ->input.waveHandles && stream ->output.waveHandles) )
-
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result;
- PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
- PaWinMmeStream *stream = 0;
- int bufferProcessorIsInitialized = 0;
- int streamRepresentationIsInitialized = 0;
- PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
- double suggestedInputLatency, suggestedOutputLatency;
- PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
- unsigned long framesPerHostInputBuffer;
- unsigned long hostInputBufferCount;
- unsigned long framesPerHostOutputBuffer;
- unsigned long hostOutputBufferCount;
- unsigned long framesPerBufferProcessorCall=0;
- PaWinMmeDeviceAndChannelCount *inputDevices = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */
- unsigned long inputDeviceCount = 0;
- PaWinMmeDeviceAndChannelCount *outputDevices = 0;
- unsigned long outputDeviceCount = 0; /* contains all devices and channel counts as local host api ids, even when PaWinMmeUseMultipleDevices is not used */
- char throttleProcessingThreadOnOverload = 1;
-
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- suggestedInputLatency = inputParameters->suggestedLatency;
-
- inputDeviceCount = 1;
-
- /* validate input hostApiSpecificStreamInfo */
- inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
- result = ValidateWinMmeSpecificStreamInfo( inputParameters, inputStreamInfo,
- &throttleProcessingThreadOnOverload,
- &inputDeviceCount );
- if( result != paNoError ) return result;
-
- inputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * inputDeviceCount );
- if( !inputDevices ) return paInsufficientMemory;
-
- result = RetrieveDevicesFromStreamParameters( hostApi, inputParameters, inputStreamInfo, inputDevices, inputDeviceCount );
- if( result != paNoError ) return result;
-
- result = ValidateInputChannelCounts( hostApi, inputDevices, inputDeviceCount );
- if( result != paNoError ) return result;
-
- hostInputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
- }
- else
- {
- inputChannelCount = 0;
- inputSampleFormat = 0;
- suggestedInputLatency = 0.;
- inputStreamInfo = 0;
- hostInputSampleFormat = 0;
- }
-
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- suggestedOutputLatency = outputParameters->suggestedLatency;
-
- outputDeviceCount = 1;
-
- /* validate output hostApiSpecificStreamInfo */
- outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
- result = ValidateWinMmeSpecificStreamInfo( outputParameters, outputStreamInfo,
- &throttleProcessingThreadOnOverload,
- &outputDeviceCount );
- if( result != paNoError ) return result;
-
- outputDevices = (PaWinMmeDeviceAndChannelCount*)alloca( sizeof(PaWinMmeDeviceAndChannelCount) * outputDeviceCount );
- if( !outputDevices ) return paInsufficientMemory;
-
- result = RetrieveDevicesFromStreamParameters( hostApi, outputParameters, outputStreamInfo, outputDevices, outputDeviceCount );
- if( result != paNoError ) return result;
-
- result = ValidateOutputChannelCounts( hostApi, outputDevices, outputDeviceCount );
- if( result != paNoError ) return result;
-
- hostOutputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
- }
- else
- {
- outputChannelCount = 0;
- outputSampleFormat = 0;
- outputStreamInfo = 0;
- hostOutputSampleFormat = 0;
- suggestedOutputLatency = 0.;
- }
-
-
- /*
- IMPLEMENT ME:
- - alter sampleRate to a close allowable rate if possible / necessary
- */
-
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- return paInvalidFlag; /* unexpected platform specific flag */
-
-
- result = CalculateBufferSettings( &framesPerHostInputBuffer, &hostInputBufferCount,
- &framesPerHostOutputBuffer, &hostOutputBufferCount,
- inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo,
- outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo,
- sampleRate, framesPerBuffer );
- if( result != paNoError ) goto error;
-
-
- stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) );
- if( !stream )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- InitializeSingleDirectionHandlesAndBuffers( &stream->input );
- InitializeSingleDirectionHandlesAndBuffers( &stream->output );
-
- stream->abortEvent = 0;
- stream->processingThread = 0;
-
- stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload;
-
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- ( (streamCallback)
- ? &winMmeHostApi->callbackStreamInterface
- : &winMmeHostApi->blockingStreamInterface ),
- streamCallback, userData );
- streamRepresentationIsInitialized = 1;
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
-
- if( inputParameters && outputParameters ) /* full duplex */
- {
- if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
- {
- assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */
-
- framesPerBufferProcessorCall = framesPerHostInputBuffer;
- }
- else
- {
- assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 ); /* CalculateBufferSettings() should guarantee this condition */
-
- framesPerBufferProcessorCall = framesPerHostOutputBuffer;
- }
- }
- else if( inputParameters )
- {
- framesPerBufferProcessorCall = framesPerHostInputBuffer;
- }
- else if( outputParameters )
- {
- framesPerBufferProcessorCall = framesPerHostOutputBuffer;
- }
-
- stream->input.framesPerBuffer = framesPerHostInputBuffer;
- stream->output.framesPerBuffer = framesPerHostOutputBuffer;
-
- result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- inputChannelCount, inputSampleFormat, hostInputSampleFormat,
- outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerBuffer,
- framesPerBufferProcessorCall, paUtilFixedHostBufferSize,
- streamCallback, userData );
- if( result != paNoError ) goto error;
-
- bufferProcessorIsInitialized = 1;
-
- stream->streamRepresentation.streamInfo.inputLatency =
- (double)(PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor)
- +(framesPerHostInputBuffer * (hostInputBufferCount-1))) / sampleRate;
- stream->streamRepresentation.streamInfo.outputLatency =
- (double)(PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor)
- +(framesPerHostOutputBuffer * (hostOutputBufferCount-1))) / sampleRate;
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
- stream->primeStreamUsingCallback = ( (streamFlags&paPrimeOutputBuffersUsingStreamCallback) && streamCallback ) ? 1 : 0;
-
- /* time to sleep when throttling due to >100% cpu usage.
- -a quater of a buffer's duration */
- stream->throttledSleepMsecs =
- (unsigned long)(stream->bufferProcessor.framesPerHostBuffer *
- stream->bufferProcessor.samplePeriod * .25 * 1000);
-
- stream->isStopped = 1;
- stream->isActive = 0;
-
-
- /* for maximum compatibility with multi-device multichannel drivers,
- we first open all devices, then we prepare all buffers, finally
- we start all devices ( in StartStream() ). teardown in reverse order.
- */
-
- if( inputParameters )
- {
- result = InitializeWaveHandles( winMmeHostApi, &stream->input,
- stream->bufferProcessor.bytesPerHostInputSample, sampleRate,
- inputDevices, inputDeviceCount, 1 /* isInput */ );
- if( result != paNoError ) goto error;
- }
-
- if( outputParameters )
- {
- result = InitializeWaveHandles( winMmeHostApi, &stream->output,
- stream->bufferProcessor.bytesPerHostOutputSample, sampleRate,
- outputDevices, outputDeviceCount, 0 /* isInput */ );
- if( result != paNoError ) goto error;
- }
-
- if( inputParameters )
- {
- result = InitializeWaveHeaders( &stream->input, hostInputBufferCount,
- hostInputSampleFormat, framesPerHostInputBuffer, inputDevices, 1 /* isInput */ );
- if( result != paNoError ) goto error;
- }
-
- if( outputParameters )
- {
- result = InitializeWaveHeaders( &stream->output, hostOutputBufferCount,
- hostOutputSampleFormat, framesPerHostOutputBuffer, outputDevices, 0 /* not isInput */ );
- if( result != paNoError ) goto error;
-
- stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->output.bufferCount) / sampleRate);
- }
- else
- {
- stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->input.bufferCount) / sampleRate);
- }
-
-
- if( streamCallback )
- {
- /* abort event is only needed for callback streams */
- result = CreateEventWithPaError( &stream->abortEvent, NULL, TRUE, FALSE, NULL );
- if( result != paNoError ) goto error;
- }
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
-
- if( stream )
- {
- if( stream->abortEvent )
- CloseHandle( stream->abortEvent );
-
- TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );
- TerminateWaveHeaders( &stream->input, 1 /* isInput */ );
-
- TerminateWaveHandles( &stream->output, 0 /* not isInput */, 1 /* currentlyProcessingAnError */ );
- TerminateWaveHandles( &stream->input, 1 /* isInput */, 1 /* currentlyProcessingAnError */ );
-
- if( bufferProcessorIsInitialized )
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
-
- if( streamRepresentationIsInitialized )
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-
- PaUtil_FreeMemory( stream );
- }
-
- return result;
-}
-
-
-/* return non-zero if all current buffers are done */
-static int BuffersAreDone( WAVEHDR **waveHeaders, unsigned int deviceCount, int bufferIndex )
-{
- unsigned int i;
-
- for( i=0; i < deviceCount; ++i )
- {
- if( !(waveHeaders[i][ bufferIndex ].dwFlags & WHDR_DONE) )
- {
- return 0;
- }
- }
-
- return 1;
-}
-
-static int CurrentInputBuffersAreDone( PaWinMmeStream *stream )
-{
- return BuffersAreDone( stream->input.waveHeaders, stream->input.deviceCount, stream->input.currentBufferIndex );
-}
-
-static int CurrentOutputBuffersAreDone( PaWinMmeStream *stream )
-{
- return BuffersAreDone( stream->output.waveHeaders, stream->output.deviceCount, stream->output.currentBufferIndex );
-}
-
-
-/* return non-zero if any buffers are queued */
-static int NoBuffersAreQueued( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
-{
- unsigned int i, j;
-
- if( handlesAndBuffers->waveHandles )
- {
- for( i=0; i < handlesAndBuffers->bufferCount; ++i )
- {
- for( j=0; j < handlesAndBuffers->deviceCount; ++j )
- {
- if( !( handlesAndBuffers->waveHeaders[ j ][ i ].dwFlags & WHDR_DONE) )
- {
- return 0;
- }
- }
- }
- }
-
- return 1;
-}
-
-
-#define PA_CIRCULAR_INCREMENT_( current, max )\
- ( (((current) + 1) >= (max)) ? (0) : (current+1) )
-
-#define PA_CIRCULAR_DECREMENT_( current, max )\
- ( ((current) == 0) ? ((max)-1) : (current-1) )
-
-
-static signed long GetAvailableFrames( PaWinMmeSingleDirectionHandlesAndBuffers *handlesAndBuffers )
-{
- signed long result = 0;
- unsigned int i;
-
- if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, handlesAndBuffers->currentBufferIndex ) )
- {
- /* we could calculate the following in O(1) if we kept track of the
- last done buffer */
- result = handlesAndBuffers->framesPerBuffer - handlesAndBuffers->framesUsedInCurrentBuffer;
-
- i = PA_CIRCULAR_INCREMENT_( handlesAndBuffers->currentBufferIndex, handlesAndBuffers->bufferCount );
- while( i != handlesAndBuffers->currentBufferIndex )
- {
- if( BuffersAreDone( handlesAndBuffers->waveHeaders, handlesAndBuffers->deviceCount, i ) )
- {
- result += handlesAndBuffers->framesPerBuffer;
- i = PA_CIRCULAR_INCREMENT_( i, handlesAndBuffers->bufferCount );
- }
- else
- break;
- }
- }
-
- return result;
-}
-
-
-static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream )
-{
- PaError result = paNoError;
- MMRESULT mmresult;
- unsigned int i;
-
- for( i=0; i < stream->input.deviceCount; ++i )
- {
- mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[i],
- &stream->input.waveHeaders[i][ stream->input.currentBufferIndex ],
- sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- }
- }
-
- stream->input.currentBufferIndex =
- PA_CIRCULAR_INCREMENT_( stream->input.currentBufferIndex, stream->input.bufferCount );
-
- stream->input.framesUsedInCurrentBuffer = 0;
-
- return result;
-}
-
-
-static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream )
-{
- PaError result = paNoError;
- MMRESULT mmresult;
- unsigned int i;
-
- for( i=0; i < stream->output.deviceCount; ++i )
- {
- mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[i],
- &stream->output.waveHeaders[i][ stream->output.currentBufferIndex ],
- sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- }
- }
-
- stream->output.currentBufferIndex =
- PA_CIRCULAR_INCREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );
-
- stream->output.framesUsedInCurrentBuffer = 0;
-
- return result;
-}
-
-
-/* requeue all but the most recent input with the driver. Used for catching
- up after a total input buffer underrun */
-static PaError CatchUpInputBuffers( PaWinMmeStream *stream )
-{
- PaError result = paNoError;
- unsigned int i;
-
- for( i=0; i < stream->input.bufferCount - 1; ++i )
- {
- result = AdvanceToNextInputBuffer( stream );
- if( result != paNoError )
- break;
- }
-
- return result;
-}
-
-
-/* take the most recent output and duplicate it to all other output buffers
- and requeue them. Used for catching up after a total output buffer underrun.
-*/
-static PaError CatchUpOutputBuffers( PaWinMmeStream *stream )
-{
- PaError result = paNoError;
- unsigned int i, j;
- unsigned int previousBufferIndex =
- PA_CIRCULAR_DECREMENT_( stream->output.currentBufferIndex, stream->output.bufferCount );
-
- for( i=0; i < stream->output.bufferCount - 1; ++i )
- {
- for( j=0; j < stream->output.deviceCount; ++j )
- {
- if( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData
- != stream->output.waveHeaders[j][ previousBufferIndex ].lpData )
- {
- CopyMemory( stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].lpData,
- stream->output.waveHeaders[j][ previousBufferIndex ].lpData,
- stream->output.waveHeaders[j][ stream->output.currentBufferIndex ].dwBufferLength );
- }
- }
-
- result = AdvanceToNextOutputBuffer( stream );
- if( result != paNoError )
- break;
- }
-
- return result;
-}
-
-
-static DWORD WINAPI ProcessingThreadProc( void *pArg )
-{
- PaWinMmeStream *stream = (PaWinMmeStream *)pArg;
- HANDLE events[3];
- int eventCount = 0;
- DWORD result = paNoError;
- DWORD waitResult;
- DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
- int hostBuffersAvailable;
- signed int hostInputBufferIndex, hostOutputBufferIndex;
- PaStreamCallbackFlags statusFlags;
- int callbackResult;
- int done = 0;
- unsigned int channel, i;
- unsigned long framesProcessed;
-
- /* prepare event array for call to WaitForMultipleObjects() */
- if( stream->input.bufferEvent )
- events[eventCount++] = stream->input.bufferEvent;
- if( stream->output.bufferEvent )
- events[eventCount++] = stream->output.bufferEvent;
- events[eventCount++] = stream->abortEvent;
-
- statusFlags = 0; /** @todo support paInputUnderflow, paOutputOverflow and paNeverDropInput */
-
- /* loop until something causes us to stop */
- do{
- /* wait for MME to signal that a buffer is available, or for
- the PA abort event to be signaled.
-
- When this indicates that one or more buffers are available
- NoBuffersAreQueued() and Current*BuffersAreDone are used below to
- poll for additional done buffers. NoBuffersAreQueued() will fail
- to identify an underrun/overflow if the driver doesn't mark all done
- buffers prior to signalling the event. Some drivers do this
- (eg RME Digi96, and others don't eg VIA PC 97 input). This isn't a
- huge problem, it just means that we won't always be able to detect
- underflow/overflow.
- */
- waitResult = WaitForMultipleObjects( eventCount, events, FALSE /* wait all = FALSE */, timeout );
- if( waitResult == WAIT_FAILED )
- {
- result = paUnanticipatedHostError;
- /** @todo FIXME/REVIEW: can't return host error info from an asyncronous thread */
- done = 1;
- }
- else if( waitResult == WAIT_TIMEOUT )
- {
- /* if a timeout is encountered, continue */
- }
-
- if( stream->abortProcessing )
- {
- /* Pa_AbortStream() has been called, stop processing immediately */
- done = 1;
- }
- else if( stream->stopProcessing )
- {
- /* Pa_StopStream() has been called or the user callback returned
- non-zero, processing will continue until all output buffers
- are marked as done. The stream will stop immediately if it
- is input-only.
- */
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- if( NoBuffersAreQueued( &stream->output ) )
- done = 1; /* Will cause thread to return. */
- }
- else
- {
- /* input only stream */
- done = 1; /* Will cause thread to return. */
- }
- }
- else
- {
- hostBuffersAvailable = 1;
-
- /* process all available host buffers */
- do
- {
- hostInputBufferIndex = -1;
- hostOutputBufferIndex = -1;
-
- if( PA_IS_INPUT_STREAM_(stream) )
- {
- if( CurrentInputBuffersAreDone( stream ) )
- {
- if( NoBuffersAreQueued( &stream->input ) )
- {
- /** @todo
- if all of the other buffers are also ready then
- we discard all but the most recent. This is an
- input buffer overflow. FIXME: these buffers should
- be passed to the callback in a paNeverDropInput
- stream.
-
- note that it is also possible for an input overflow
- to happen while the callback is processing a buffer.
- that is handled further down.
- */
- result = CatchUpInputBuffers( stream );
- if( result != paNoError )
- done = 1;
-
- statusFlags |= paInputOverflow;
- }
-
- hostInputBufferIndex = stream->input.currentBufferIndex;
- }
- }
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- if( CurrentOutputBuffersAreDone( stream ) )
- {
- /* ok, we have an output buffer */
-
- if( NoBuffersAreQueued( &stream->output ) )
- {
- /*
- if all of the other buffers are also ready, catch up by copying
- the most recently generated buffer into all but one of the output
- buffers.
-
- note that this catch up code only handles the case where all
- buffers have been played out due to this thread not having
- woken up at all. a more common case occurs when this thread
- is woken up, processes one buffer, but takes too long, and as
- a result all the other buffers have become un-queued. that
- case is handled further down.
- */
-
- result = CatchUpOutputBuffers( stream );
- if( result != paNoError )
- done = 1;
-
- statusFlags |= paOutputUnderflow;
- }
-
- hostOutputBufferIndex = stream->output.currentBufferIndex;
- }
- }
-
-
- if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) ||
- (PA_IS_HALF_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) )
- {
- PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement inputBufferAdcTime */
-
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- /* set timeInfo.currentTime and calculate timeInfo.outputBufferDacTime
- from the current wave out position */
- MMTIME mmtime;
- double timeBeforeGetPosition, timeAfterGetPosition;
- double time;
- long framesInBufferRing;
- long writePosition;
- long playbackPosition;
- HWAVEOUT firstWaveOutDevice = ((HWAVEOUT*)stream->output.waveHandles)[0];
-
- mmtime.wType = TIME_SAMPLES;
- timeBeforeGetPosition = PaUtil_GetTime();
- waveOutGetPosition( firstWaveOutDevice, &mmtime, sizeof(MMTIME) );
- timeAfterGetPosition = PaUtil_GetTime();
-
- timeInfo.currentTime = timeAfterGetPosition;
-
- /* approximate time at which wave out position was measured
- as half way between timeBeforeGetPosition and timeAfterGetPosition */
- time = timeBeforeGetPosition + (timeAfterGetPosition - timeBeforeGetPosition) * .5;
-
- framesInBufferRing = stream->output.bufferCount * stream->bufferProcessor.framesPerHostBuffer;
- playbackPosition = mmtime.u.sample % framesInBufferRing;
-
- writePosition = stream->output.currentBufferIndex * stream->bufferProcessor.framesPerHostBuffer
- + stream->output.framesUsedInCurrentBuffer;
-
- if( playbackPosition >= writePosition ){
- timeInfo.outputBufferDacTime =
- time + ((double)( writePosition + (framesInBufferRing - playbackPosition) ) * stream->bufferProcessor.samplePeriod );
- }else{
- timeInfo.outputBufferDacTime =
- time + ((double)( writePosition - playbackPosition ) * stream->bufferProcessor.samplePeriod );
- }
- }
-
-
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
- PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, statusFlags );
-
- /* reset status flags once they have been passed to the buffer processor */
- statusFlags = 0;
-
- if( PA_IS_INPUT_STREAM_(stream) )
- {
- PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-
- channel = 0;
- for( i=0; i<stream->input.deviceCount; ++i )
- {
- /* we have stored the number of channels in the buffer in dwUser */
- int channelCount = stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;
-
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
- stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +
- stream->input.framesUsedInCurrentBuffer * channelCount *
- stream->bufferProcessor.bytesPerHostInputSample,
- channelCount );
-
-
- channel += channelCount;
- }
- }
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-
- channel = 0;
- for( i=0; i<stream->output.deviceCount; ++i )
- {
- /* we have stored the number of channels in the buffer in dwUser */
- int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
-
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
- stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
- stream->output.framesUsedInCurrentBuffer * channelCount *
- stream->bufferProcessor.bytesPerHostOutputSample,
- channelCount );
-
- channel += channelCount;
- }
- }
-
- callbackResult = paContinue;
- framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
-
- stream->input.framesUsedInCurrentBuffer += framesProcessed;
- stream->output.framesUsedInCurrentBuffer += framesProcessed;
-
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
- if( callbackResult == paContinue )
- {
- /* nothing special to do */
- }
- else if( callbackResult == paAbort )
- {
- stream->abortProcessing = 1;
- done = 1;
- /** @todo FIXME: should probably reset the output device immediately once the callback returns paAbort */
- result = paNoError;
- }
- else
- {
- /* User callback has asked us to stop with paComplete or other non-zero value */
- stream->stopProcessing = 1; /* stop once currently queued audio has finished */
- result = paNoError;
- }
-
-
- if( PA_IS_INPUT_STREAM_(stream)
- && stream->stopProcessing == 0 && stream->abortProcessing == 0
- && stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )
- {
- if( NoBuffersAreQueued( &stream->input ) )
- {
- /** @todo need to handle PaNeverDropInput here where necessary */
- result = CatchUpInputBuffers( stream );
- if( result != paNoError )
- done = 1;
-
- statusFlags |= paInputOverflow;
- }
-
- result = AdvanceToNextInputBuffer( stream );
- if( result != paNoError )
- done = 1;
- }
-
-
- if( PA_IS_OUTPUT_STREAM_(stream) && !stream->abortProcessing )
- {
- if( stream->stopProcessing &&
- stream->output.framesUsedInCurrentBuffer < stream->output.framesPerBuffer )
- {
- /* zero remaining samples in output output buffer and flush */
-
- stream->output.framesUsedInCurrentBuffer += PaUtil_ZeroOutput( &stream->bufferProcessor,
- stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-
- /* we send the entire buffer to the output devices, but we could
- just send a partial buffer, rather than zeroing the unused
- samples.
- */
- }
-
- if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )
- {
- /* check for underflow before enquing the just-generated buffer,
- but recover from underflow after enquing it. This ensures
- that the most recent audio segment is repeated */
- int outputUnderflow = NoBuffersAreQueued( &stream->output );
-
- result = AdvanceToNextOutputBuffer( stream );
- if( result != paNoError )
- done = 1;
-
- if( outputUnderflow && !done && !stream->stopProcessing )
- {
- /* Recover from underflow in the case where the
- underflow occured while processing the buffer
- we just finished */
-
- result = CatchUpOutputBuffers( stream );
- if( result != paNoError )
- done = 1;
-
- statusFlags |= paOutputUnderflow;
- }
- }
- }
-
- if( stream->throttleProcessingThreadOnOverload != 0 )
- {
- if( stream->stopProcessing || stream->abortProcessing )
- {
- if( stream->processingThreadPriority != stream->highThreadPriority )
- {
- SetThreadPriority( stream->processingThread, stream->highThreadPriority );
- stream->processingThreadPriority = stream->highThreadPriority;
- }
- }
- else if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. )
- {
- if( stream->processingThreadPriority != stream->throttledThreadPriority )
- {
- SetThreadPriority( stream->processingThread, stream->throttledThreadPriority );
- stream->processingThreadPriority = stream->throttledThreadPriority;
- }
-
- /* sleep to give other processes a go */
- Sleep( stream->throttledSleepMsecs );
- }
- else
- {
- if( stream->processingThreadPriority != stream->highThreadPriority )
- {
- SetThreadPriority( stream->processingThread, stream->highThreadPriority );
- stream->processingThreadPriority = stream->highThreadPriority;
- }
- }
- }
- }
- else
- {
- hostBuffersAvailable = 0;
- }
- }
- while( hostBuffersAvailable &&
- stream->stopProcessing == 0 &&
- stream->abortProcessing == 0 &&
- !done );
- }
- }
- while( !done );
-
- stream->isActive = 0;
-
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-
- PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-
- return result;
-}
-
-
-/*
- When CloseStream() is called, the multi-api layer ensures that
- the stream has already been stopped or aborted.
-*/
-static PaError CloseStream( PaStream* s )
-{
- PaError result;
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
- result = CloseHandleWithPaError( stream->abortEvent );
- if( result != paNoError ) goto error;
-
- TerminateWaveHeaders( &stream->output, 0 /* not isInput */ );
- TerminateWaveHeaders( &stream->input, 1 /* isInput */ );
-
- TerminateWaveHandles( &stream->output, 0 /* not isInput */, 0 /* not currentlyProcessingAnError */ );
- TerminateWaveHandles( &stream->input, 1 /* isInput */, 0 /* not currentlyProcessingAnError */ );
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- PaUtil_FreeMemory( stream );
-
-error:
- /** @todo REVIEW: what is the best way to clean up a stream if an error is detected? */
- return result;
-}
-
-
-static PaError StartStream( PaStream *s )
-{
- PaError result;
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
- MMRESULT mmresult;
- unsigned int i, j;
- int callbackResult;
- unsigned int channel;
- unsigned long framesProcessed;
- PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /** @todo implement this for stream priming */
-
- PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
-
- if( PA_IS_INPUT_STREAM_(stream) )
- {
- for( i=0; i<stream->input.bufferCount; ++i )
- {
- for( j=0; j<stream->input.deviceCount; ++j )
- {
- mmresult = waveInAddBuffer( ((HWAVEIN*)stream->input.waveHandles)[j], &stream->input.waveHeaders[j][i], sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- goto error;
- }
- }
- }
- stream->input.currentBufferIndex = 0;
- stream->input.framesUsedInCurrentBuffer = 0;
- }
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- for( i=0; i<stream->output.deviceCount; ++i )
- {
- if( (mmresult = waveOutPause( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- goto error;
- }
- }
-
- for( i=0; i<stream->output.bufferCount; ++i )
- {
- if( stream->primeStreamUsingCallback )
- {
-
- stream->output.framesUsedInCurrentBuffer = 0;
- do{
-
- PaUtil_BeginBufferProcessing( &stream->bufferProcessor,
- &timeInfo,
- paPrimingOutput | ((stream->input.bufferCount > 0 ) ? paInputUnderflow : 0));
-
- if( stream->input.bufferCount > 0 )
- PaUtil_SetNoInput( &stream->bufferProcessor );
-
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
-
- channel = 0;
- for( j=0; j<stream->output.deviceCount; ++j )
- {
- /* we have stored the number of channels in the buffer in dwUser */
- int channelCount = stream->output.waveHeaders[j][i].dwUser;
-
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
- stream->output.waveHeaders[j][i].lpData +
- stream->output.framesUsedInCurrentBuffer * channelCount *
- stream->bufferProcessor.bytesPerHostOutputSample,
- channelCount );
-
- /* we have stored the number of channels in the buffer in dwUser */
- channel += channelCount;
- }
-
- callbackResult = paContinue;
- framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
- stream->output.framesUsedInCurrentBuffer += framesProcessed;
-
- if( callbackResult != paContinue )
- {
- /** @todo fix this, what do we do if callback result is non-zero during stream
- priming?
-
- for complete: play out primed waveHeaders as usual
- for abort: clean up immediately.
- */
- }
-
- }while( stream->output.framesUsedInCurrentBuffer != stream->output.framesPerBuffer );
-
- }
- else
- {
- for( j=0; j<stream->output.deviceCount; ++j )
- {
- ZeroMemory( stream->output.waveHeaders[j][i].lpData, stream->output.waveHeaders[j][i].dwBufferLength );
- }
- }
-
- /* we queue all channels of a single buffer frame (accross all
- devices, because some multidevice multichannel drivers work
- better this way */
- for( j=0; j<stream->output.deviceCount; ++j )
- {
- mmresult = waveOutWrite( ((HWAVEOUT*)stream->output.waveHandles)[j], &stream->output.waveHeaders[j][i], sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- goto error;
- }
- }
- }
- stream->output.currentBufferIndex = 0;
- stream->output.framesUsedInCurrentBuffer = 0;
- }
-
-
- stream->isStopped = 0;
- stream->isActive = 1;
- stream->stopProcessing = 0;
- stream->abortProcessing = 0;
-
- result = ResetEventWithPaError( stream->input.bufferEvent );
- if( result != paNoError ) goto error;
-
- result = ResetEventWithPaError( stream->output.bufferEvent );
- if( result != paNoError ) goto error;
-
-
- if( stream->streamRepresentation.streamCallback )
- {
- /* callback stream */
-
- result = ResetEventWithPaError( stream->abortEvent );
- if( result != paNoError ) goto error;
-
- /* Create thread that waits for audio buffers to be ready for processing. */
- stream->processingThread = CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId );
- if( !stream->processingThread )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
- goto error;
- }
-
- /** @todo could have mme specific stream parameters to allow the user
- to set the callback thread priorities */
- stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL;
- stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL;
-
- if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
- goto error;
- }
- stream->processingThreadPriority = stream->highThreadPriority;
- }
- else
- {
- /* blocking read/write stream */
-
- }
-
- if( PA_IS_INPUT_STREAM_(stream) )
- {
- for( i=0; i < stream->input.deviceCount; ++i )
- {
- mmresult = waveInStart( ((HWAVEIN*)stream->input.waveHandles)[i] );
- PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- goto error;
- }
- }
- }
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- for( i=0; i < stream->output.deviceCount; ++i )
- {
- if( (mmresult = waveOutRestart( ((HWAVEOUT*)stream->output.waveHandles)[i] )) != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- goto error;
- }
- }
- }
-
- return result;
-
-error:
- /** @todo FIXME: implement recovery as best we can
- This should involve rolling back to a state as-if this function had never been called
- */
- return result;
-}
-
-
-static PaError StopStream( PaStream *s )
-{
- PaError result = paNoError;
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
- int timeout;
- DWORD waitResult;
- MMRESULT mmresult;
- signed int hostOutputBufferIndex;
- unsigned int channel, waitCount, i;
-
- /** @todo
- REVIEW: the error checking in this function needs review. the basic
- idea is to return from this function in a known state - for example
- there is no point avoiding calling waveInReset just because
- the thread times out.
- */
-
- if( stream->processingThread )
- {
- /* callback stream */
-
- /* Tell processing thread to stop generating more data and to let current data play out. */
- stream->stopProcessing = 1;
-
- /* Calculate timeOut longer than longest time it could take to return all buffers. */
- timeout = (int)(stream->allBuffersDurationMs * 1.5);
- if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
- timeout = PA_MME_MIN_TIMEOUT_MSEC_;
-
- PA_DEBUG(("WinMME StopStream: waiting for background thread.\n"));
-
- waitResult = WaitForSingleObject( stream->processingThread, timeout );
- if( waitResult == WAIT_TIMEOUT )
- {
- /* try to abort */
- stream->abortProcessing = 1;
- SetEvent( stream->abortEvent );
- waitResult = WaitForSingleObject( stream->processingThread, timeout );
- if( waitResult == WAIT_TIMEOUT )
- {
- PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n"));
- result = paTimedOut;
- }
- }
-
- CloseHandle( stream->processingThread );
- stream->processingThread = NULL;
- }
- else
- {
- /* blocking read / write stream */
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- if( stream->output.framesUsedInCurrentBuffer > 0 )
- {
- /* there are still unqueued frames in the current buffer, so flush them */
-
- hostOutputBufferIndex = stream->output.currentBufferIndex;
-
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor,
- stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-
- channel = 0;
- for( i=0; i<stream->output.deviceCount; ++i )
- {
- /* we have stored the number of channels in the buffer in dwUser */
- int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
-
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
- stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
- stream->output.framesUsedInCurrentBuffer * channelCount *
- stream->bufferProcessor.bytesPerHostOutputSample,
- channelCount );
-
- channel += channelCount;
- }
-
- PaUtil_ZeroOutput( &stream->bufferProcessor,
- stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-
- /* we send the entire buffer to the output devices, but we could
- just send a partial buffer, rather than zeroing the unused
- samples.
- */
- AdvanceToNextOutputBuffer( stream );
- }
-
-
- timeout = (stream->allBuffersDurationMs / stream->output.bufferCount) + 1;
- if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
- timeout = PA_MME_MIN_TIMEOUT_MSEC_;
-
- waitCount = 0;
- while( !NoBuffersAreQueued( &stream->output ) && waitCount <= stream->output.bufferCount )
- {
- /* wait for MME to signal that a buffer is available */
- waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );
- if( waitResult == WAIT_FAILED )
- {
- break;
- }
- else if( waitResult == WAIT_TIMEOUT )
- {
- /* keep waiting */
- }
-
- ++waitCount;
- }
- }
- }
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- for( i =0; i < stream->output.deviceCount; ++i )
- {
- mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- }
- }
- }
-
- if( PA_IS_INPUT_STREAM_(stream) )
- {
- for( i=0; i < stream->input.deviceCount; ++i )
- {
- mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );
- if( mmresult != MMSYSERR_NOERROR )
- {
- result = paUnanticipatedHostError;
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- }
- }
- }
-
- stream->isStopped = 1;
- stream->isActive = 0;
-
- return result;
-}
-
-
-static PaError AbortStream( PaStream *s )
-{
- PaError result = paNoError;
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
- int timeout;
- DWORD waitResult;
- MMRESULT mmresult;
- unsigned int i;
-
- /** @todo
- REVIEW: the error checking in this function needs review. the basic
- idea is to return from this function in a known state - for example
- there is no point avoiding calling waveInReset just because
- the thread times out.
- */
-
- if( stream->processingThread )
- {
- /* callback stream */
-
- /* Tell processing thread to abort immediately */
- stream->abortProcessing = 1;
- SetEvent( stream->abortEvent );
- }
-
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- for( i =0; i < stream->output.deviceCount; ++i )
- {
- mmresult = waveOutReset( ((HWAVEOUT*)stream->output.waveHandles)[i] );
- if( mmresult != MMSYSERR_NOERROR )
- {
- PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
- return paUnanticipatedHostError;
- }
- }
- }
-
- if( PA_IS_INPUT_STREAM_(stream) )
- {
- for( i=0; i < stream->input.deviceCount; ++i )
- {
- mmresult = waveInReset( ((HWAVEIN*)stream->input.waveHandles)[i] );
- if( mmresult != MMSYSERR_NOERROR )
- {
- PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
- return paUnanticipatedHostError;
- }
- }
- }
-
-
- if( stream->processingThread )
- {
- /* callback stream */
-
- PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n"));
-
- /* Calculate timeOut longer than longest time it could take to return all buffers. */
- timeout = (int)(stream->allBuffersDurationMs * 1.5);
- if( timeout < PA_MME_MIN_TIMEOUT_MSEC_ )
- timeout = PA_MME_MIN_TIMEOUT_MSEC_;
-
- waitResult = WaitForSingleObject( stream->processingThread, timeout );
- if( waitResult == WAIT_TIMEOUT )
- {
- PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n"));
- return paTimedOut;
- }
-
- CloseHandle( stream->processingThread );
- stream->processingThread = NULL;
- }
-
- stream->isStopped = 1;
- stream->isActive = 0;
-
- return result;
-}
-
-
-static PaError IsStreamStopped( PaStream *s )
-{
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
- return stream->isStopped;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
- return stream->isActive;
-}
-
-
-static PaTime GetStreamTime( PaStream *s )
-{
- (void) s; /* unused parameter */
-
- return PaUtil_GetTime();
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaError result = paNoError;
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
- void *userBuffer;
- unsigned long framesRead = 0;
- unsigned long framesProcessed;
- signed int hostInputBufferIndex;
- DWORD waitResult;
- DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
- unsigned int channel, i;
-
- if( PA_IS_INPUT_STREAM_(stream) )
- {
- /* make a local copy of the user buffer pointer(s). this is necessary
- because PaUtil_CopyInput() advances these pointers every time
- it is called.
- */
- if( stream->bufferProcessor.userInputIsInterleaved )
- {
- userBuffer = buffer;
- }
- else
- {
- userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.inputChannelCount );
- if( !userBuffer )
- return paInsufficientMemory;
- for( i = 0; i<stream->bufferProcessor.inputChannelCount; ++i )
- ((void**)userBuffer)[i] = ((void**)buffer)[i];
- }
-
- do{
- if( CurrentInputBuffersAreDone( stream ) )
- {
- if( NoBuffersAreQueued( &stream->input ) )
- {
- /** @todo REVIEW: consider what to do if the input overflows.
- do we requeue all of the buffers? should we be running
- a thread to make sure they are always queued? */
-
- result = paInputOverflowed;
- }
-
- hostInputBufferIndex = stream->input.currentBufferIndex;
-
- PaUtil_SetInputFrameCount( &stream->bufferProcessor,
- stream->input.framesPerBuffer - stream->input.framesUsedInCurrentBuffer );
-
- channel = 0;
- for( i=0; i<stream->input.deviceCount; ++i )
- {
- /* we have stored the number of channels in the buffer in dwUser */
- int channelCount = stream->input.waveHeaders[i][ hostInputBufferIndex ].dwUser;
-
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
- stream->input.waveHeaders[i][ hostInputBufferIndex ].lpData +
- stream->input.framesUsedInCurrentBuffer * channelCount *
- stream->bufferProcessor.bytesPerHostInputSample,
- channelCount );
-
- channel += channelCount;
- }
-
- framesProcessed = PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, frames - framesRead );
-
- stream->input.framesUsedInCurrentBuffer += framesProcessed;
- if( stream->input.framesUsedInCurrentBuffer == stream->input.framesPerBuffer )
- {
- result = AdvanceToNextInputBuffer( stream );
- if( result != paNoError )
- break;
- }
-
- framesRead += framesProcessed;
-
- }else{
- /* wait for MME to signal that a buffer is available */
- waitResult = WaitForSingleObject( stream->input.bufferEvent, timeout );
- if( waitResult == WAIT_FAILED )
- {
- result = paUnanticipatedHostError;
- break;
- }
- else if( waitResult == WAIT_TIMEOUT )
- {
- /* if a timeout is encountered, continue,
- perhaps we should give up eventually
- */
- }
- }
- }while( framesRead < frames );
- }
- else
- {
- result = paCanNotReadFromAnOutputOnlyStream;
- }
-
- return result;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaError result = paNoError;
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
- const void *userBuffer;
- unsigned long framesWritten = 0;
- unsigned long framesProcessed;
- signed int hostOutputBufferIndex;
- DWORD waitResult;
- DWORD timeout = (unsigned long)(stream->allBuffersDurationMs * 0.5);
- unsigned int channel, i;
-
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- {
- /* make a local copy of the user buffer pointer(s). this is necessary
- because PaUtil_CopyOutput() advances these pointers every time
- it is called.
- */
- if( stream->bufferProcessor.userOutputIsInterleaved )
- {
- userBuffer = buffer;
- }
- else
- {
- userBuffer = alloca( sizeof(void*) * stream->bufferProcessor.outputChannelCount );
- if( !userBuffer )
- return paInsufficientMemory;
- for( i = 0; i<stream->bufferProcessor.outputChannelCount; ++i )
- ((const void**)userBuffer)[i] = ((const void**)buffer)[i];
- }
-
- do{
- if( CurrentOutputBuffersAreDone( stream ) )
- {
- if( NoBuffersAreQueued( &stream->output ) )
- {
- /** @todo REVIEW: consider what to do if the output
- underflows. do we requeue all the existing buffers with
- zeros? should we run a separate thread to keep the buffers
- enqueued at all times? */
-
- result = paOutputUnderflowed;
- }
-
- hostOutputBufferIndex = stream->output.currentBufferIndex;
-
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor,
- stream->output.framesPerBuffer - stream->output.framesUsedInCurrentBuffer );
-
- channel = 0;
- for( i=0; i<stream->output.deviceCount; ++i )
- {
- /* we have stored the number of channels in the buffer in dwUser */
- int channelCount = stream->output.waveHeaders[i][ hostOutputBufferIndex ].dwUser;
-
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
- stream->output.waveHeaders[i][ hostOutputBufferIndex ].lpData +
- stream->output.framesUsedInCurrentBuffer * channelCount *
- stream->bufferProcessor.bytesPerHostOutputSample,
- channelCount );
-
- channel += channelCount;
- }
-
- framesProcessed = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames - framesWritten );
-
- stream->output.framesUsedInCurrentBuffer += framesProcessed;
- if( stream->output.framesUsedInCurrentBuffer == stream->output.framesPerBuffer )
- {
- result = AdvanceToNextOutputBuffer( stream );
- if( result != paNoError )
- break;
- }
-
- framesWritten += framesProcessed;
- }
- else
- {
- /* wait for MME to signal that a buffer is available */
- waitResult = WaitForSingleObject( stream->output.bufferEvent, timeout );
- if( waitResult == WAIT_FAILED )
- {
- result = paUnanticipatedHostError;
- break;
- }
- else if( waitResult == WAIT_TIMEOUT )
- {
- /* if a timeout is encountered, continue,
- perhaps we should give up eventually
- */
- }
- }
- }while( framesWritten < frames );
- }
- else
- {
- result = paCanNotWriteToAnInputOnlyStream;
- }
-
- return result;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
- if( PA_IS_INPUT_STREAM_(stream) )
- return GetAvailableFrames( &stream->input );
- else
- return paCanNotReadFromAnOutputOnlyStream;
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaWinMmeStream *stream = (PaWinMmeStream*)s;
-
- if( PA_IS_OUTPUT_STREAM_(stream) )
- return GetAvailableFrames( &stream->output );
- else
- return paCanNotWriteToAnInputOnlyStream;
-}
-
-
-/* NOTE: the following functions are MME-stream specific, and are called directly
- by client code. We need to check for many more error conditions here because
- we don't have the benefit of pa_front.c's parameter checking.
-*/
-
-static PaError GetWinMMEStreamPointer( PaWinMmeStream **stream, PaStream *s )
-{
- PaError result;
- PaUtilHostApiRepresentation *hostApi;
- PaWinMmeHostApiRepresentation *winMmeHostApi;
-
- result = PaUtil_ValidateStreamPointer( s );
- if( result != paNoError )
- return result;
-
- result = PaUtil_GetHostApiRepresentation( &hostApi, paMME );
- if( result != paNoError )
- return result;
-
- winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
-
- /* note, the following would be easier if there was a generic way of testing
- that a stream belongs to a specific host API */
-
- if( PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->callbackStreamInterface
- || PA_STREAM_REP( s )->streamInterface == &winMmeHostApi->blockingStreamInterface )
- {
- /* s is a WinMME stream */
- *stream = (PaWinMmeStream *)s;
- return paNoError;
- }
- else
- {
- return paIncompatibleStreamHostApi;
- }
-}
-
-
-int PaWinMME_GetStreamInputHandleCount( PaStream* s )
-{
- PaWinMmeStream *stream;
- PaError result = GetWinMMEStreamPointer( &stream, s );
-
- if( result == paNoError )
- return (PA_IS_INPUT_STREAM_(stream)) ? stream->input.deviceCount : 0;
- else
- return result;
-}
-
-
-HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* s, int handleIndex )
-{
- PaWinMmeStream *stream;
- PaError result = GetWinMMEStreamPointer( &stream, s );
-
- if( result == paNoError
- && PA_IS_INPUT_STREAM_(stream)
- && handleIndex >= 0
- && (unsigned int)handleIndex < stream->input.deviceCount )
- return ((HWAVEIN*)stream->input.waveHandles)[handleIndex];
- else
- return 0;
-}
-
-
-int PaWinMME_GetStreamOutputHandleCount( PaStream* s)
-{
- PaWinMmeStream *stream;
- PaError result = GetWinMMEStreamPointer( &stream, s );
-
- if( result == paNoError )
- return (PA_IS_OUTPUT_STREAM_(stream)) ? stream->output.deviceCount : 0;
- else
- return result;
-}
-
-
-HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* s, int handleIndex )
-{
- PaWinMmeStream *stream;
- PaError result = GetWinMMEStreamPointer( &stream, s );
-
- if( result == paNoError
- && PA_IS_OUTPUT_STREAM_(stream)
- && handleIndex >= 0
- && (unsigned int)handleIndex < stream->output.deviceCount )
- return ((HWAVEOUT*)stream->output.waveHandles)[handleIndex];
- else
- return 0;
-}
-
-
-
-
-
diff --git a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.h b/pjmedia/src/pjmedia/portaudio/pa_win_wmme.h
deleted file mode 100644
index 1a71633a..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_win_wmme.h
+++ /dev/null
@@ -1,160 +0,0 @@
-#ifndef PA_WIN_WMME_H
-#define PA_WIN_WMME_H
-/*
- * $Id: pa_win_wmme.h,v 1.1.2.14 2004/02/20 14:16:53 rossbencina Exp $
- * PortAudio Portable Real-Time Audio Library
- * MME specific extensions
- *
- * 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.
- *
- * 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.
- *
- * 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.
- *
- */
-
-/** @file
- @brief WMME-specific PortAudio API extension header file.
-*/
-
-
-#include "portaudio.h"
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-#define paWinMmeUseLowLevelLatencyParameters (0x01)
-#define paWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */
-
-
-/* By default, the mme implementation drops the processing thread's priority
- to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100%
- This flag disables any priority throttling. The processing thread will always
- run at THREAD_PRIORITY_TIME_CRITICAL.
-*/
-#define paWinMmeDontThrottleOverloadedProcessingThread (0x08)
-
-
-typedef struct PaWinMmeDeviceAndChannelCount{
- PaDeviceIndex device;
- int channelCount;
-}PaWinMmeDeviceAndChannelCount;
-
-
-typedef struct PaWinMmeStreamInfo{
- unsigned long size; /**< sizeof(PaWinMmeStreamInfo) */
- PaHostApiTypeId hostApiType; /**< paMME */
- unsigned long version; /**< 1 */
-
- unsigned long flags;
-
- /* low-level latency setting support
- These settings control the number and size of host buffers in order
- to set latency. They will be used instead of the generic parameters
- to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters
- flag.
-
- If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters
- are supplied for both input and output in a full duplex stream, then the
- input and output framesPerBuffer must be the same, or the larger of the
- two must be a multiple of the smaller, otherwise a
- paIncompatibleHostApiSpecificStreamInfo error will be returned from
- Pa_OpenStream().
- */
- unsigned long framesPerBuffer;
- unsigned long bufferCount; /* formerly numBuffers */
-
- /* multiple devices per direction support
- If flags contains the PaWinMmeUseMultipleDevices flag,
- this functionality will be used, otherwise the device parameter to
- Pa_OpenStream() will be used instead.
- If devices are specified here, the corresponding device parameter
- to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification,
- otherwise an paInvalidDevice error will result.
- The total number of channels accross all specified devices
- must agree with the corresponding channelCount parameter to
- Pa_OpenStream() otherwise a paInvalidChannelCount error will result.
- */
- PaWinMmeDeviceAndChannelCount *devices;
- unsigned long deviceCount;
-
-}PaWinMmeStreamInfo;
-
-
-/** Retrieve the number of wave in handles used by a PortAudio WinMME stream.
- Returns zero if the stream is output only.
-
- @return A non-negative value indicating the number of wave in handles
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- @see PaWinMME_GetStreamInputHandle
-*/
-int PaWinMME_GetStreamInputHandleCount( PaStream* stream );
-
-
-/** Retrieve a wave in handle used by a PortAudio WinMME stream.
-
- @param stream The stream to query.
- @param handleIndex The zero based index of the wave in handle to retrieve. This
- should be in the range [0, PaWinMME_GetStreamInputHandle(stream)-1].
-
- @return A valid wave in handle, or NULL if an error occurred.
-
- @see PaWinMME_GetStreamInputHandle
-*/
-HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex );
-
-
-/** Retrieve the number of wave out handles used by a PortAudio WinMME stream.
- Returns zero if the stream is input only.
-
- @return A non-negative value indicating the number of wave out handles
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- @see PaWinMME_GetStreamOutputHandle
-*/
-int PaWinMME_GetStreamOutputHandleCount( PaStream* stream );
-
-
-/** Retrieve a wave out handle used by a PortAudio WinMME stream.
-
- @param stream The stream to query.
- @param handleIndex The zero based index of the wave out handle to retrieve.
- This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1].
-
- @return A valid wave out handle, or NULL if an error occurred.
-
- @see PaWinMME_GetStreamOutputHandleCount
-*/
-HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PA_WIN_WMME_H */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c b/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c
deleted file mode 100644
index 3a33540b..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.c
+++ /dev/null
@@ -1,1167 +0,0 @@
-#include "pa_x86_plain_converters.h"
-
-#include "pa_converters.h"
-#include "pa_dither.h"
-
-/*
- plain intel assemby versions of standard pa converter functions.
-
- the main reason these versions are faster than the equivalent C versions
- is that float -> int casting is expensive in C on x86 because the rounding
- mode needs to be changed for every cast. these versions only set
- the rounding mode once outside the loop.
-
- small additional speed gains are made by the way that clamping is
- implemented.
-
-TODO:
- o- inline dither code
- o- implement Dither only (no-clip) versions
- o- implement int8 and uint8 versions
- o- test thouroughly
-
- o- the packed 24 bit functions could benefit from unrolling and avoiding
- byte and word sized register access.
-*/
-
-/* -------------------------------------------------------------------------- */
-
-/*
-#define PA_CLIP_( val, min, max )\
- { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
-*/
-
-/*
- the following notes were used to determine whether a floating point
- value should be saturated (ie >1 or <-1) by loading it into an integer
- register. these should be rewritten so that they make sense.
-
- an ieee floating point value
-
- 1.xxxxxxxxxxxxxxxxxxxx?
-
-
- is less than or equal to 1 and greater than or equal to -1 either:
-
- if the mantissa is 0 and the unbiased exponent is 0
-
- OR
-
- if the unbiased exponent < 0
-
- this translates to:
-
- if the mantissa is 0 and the biased exponent is 7F
-
- or
-
- if the biased exponent is less than 7F
-
-
- therefore the value is greater than 1 or less than -1 if
-
- the mantissa is not 0 and the biased exponent is 7F
-
- or
-
- if the biased exponent is greater than 7F
-
-
- in other words, if we mask out the sign bit, the value is
- greater than 1 or less than -1 if its integer representation is greater than:
-
- 0 01111111 0000 0000 0000 0000 0000 000
-
- 0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000
-*/
-
-/* -------------------------------------------------------------------------- */
-
-static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/
-static const double int32Scaler_ = 0x7FFFFFFF;
-static const double ditheredInt32Scaler_ = 0x7FFFFFFE;
-static const double int24Scaler_ = 0x7FFFFF;
-static const double ditheredInt24Scaler_ = 0x7FFFFE;
-static const double int16Scaler_ = 0x7FFF;
-static const double ditheredInt16Scaler_ = 0x7FFE;
-
-#define PA_DITHER_BITS_ (15)
-/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
-#define PA_FLOAT_DITHER_SCALE_ (1.0 / ((1<<PA_DITHER_BITS_)-1))
-static const float const_float_dither_scale_ = (float) PA_FLOAT_DITHER_SCALE_;
-#define PA_DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
- (void)ditherGenerator; // unused parameter
-
- while( count-- )
- {
- // REVIEW
- double scaled = *src * 0x7FFFFFFF;
- *dest = (signed long) scaled;
-
- src += sourceStride;
- dest += destinationStride;
- }
-*/
-
- short savedFpuControlWord;
-
- (void) ditherGenerator; /* unused parameter */
-
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32 and int32
- mov eax, sourceStride
- imul eax, edx
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi
-
- mov edi, destinationBuffer
-
- mov ebx, destinationStride
- imul ebx, edx
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld int32Scaler_ // stack: (int)0x7FFFFFFF
-
- Float32_To_Int32_loop:
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF
- /*
- note: we could store to a temporary qword here which would cause
- wraparound distortion instead of int indefinite 0x10. that would
- be more work, and given that not enabling clipping is only advisable
- when you know that your signal isn't going to clip it isn't worth it.
- */
- fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF
-
- add edi, ebx // increment destination ptr
- //lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int32_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
- (void) ditherGenerator; // unused parameter
-
- while( count-- )
- {
- // REVIEW
- double scaled = *src * 0x7FFFFFFF;
- PA_CLIP_( scaled, -2147483648., 2147483647. );
- *dest = (signed long) scaled;
-
- src += sourceStride;
- dest += destinationStride;
- }
-*/
-
- short savedFpuControlWord;
-
- (void) ditherGenerator; /* unused parameter */
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32 and int32
- mov eax, sourceStride
- imul eax, edx
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi
-
- mov edi, destinationBuffer
-
- mov ebx, destinationStride
- imul ebx, edx
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld int32Scaler_ // stack: (int)0x7FFFFFFF
-
- Float32_To_Int32_Clip_loop:
-
- mov edx, dword ptr [esi] // load floating point value into integer register
-
- and edx, 0x7FFFFFFF // mask off sign
- cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
-
- jg Float32_To_Int32_Clip_clamp
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF
- fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF
- jmp Float32_To_Int32_Clip_stored
-
- Float32_To_Int32_Clip_clamp:
- mov edx, dword ptr [esi] // load floating point value into integer register
- shr edx, 31 // move sign bit into bit 0
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- add edx, 0x7FFFFFFF // convert to maximum range integers
- mov dword ptr [edi], edx
-
- Float32_To_Int32_Clip_stored:
-
- //add edi, ebx // increment destination ptr
- lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int32_Clip_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int32_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
- /*
- float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
-
- while( count-- )
- {
- // REVIEW
- double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- // use smaller scaler to prevent overflow when we add the dither
- double dithered = ((double)*src * (2147483646.0)) + dither;
- PA_CLIP_( dithered, -2147483648., 2147483647. );
- *dest = (signed long) dithered;
-
-
- src += sourceStride;
- dest += destinationStride;
- }
- */
-
- short savedFpuControlWord;
-
- // spill storage:
- signed long sourceByteStride;
- signed long highpassedDither;
-
- // dither state:
- unsigned long ditherPrevious = ditherGenerator->previous;
- unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
- unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32 and int32
- mov eax, sourceStride
- imul eax, edx
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi
-
- mov edi, destinationBuffer
-
- mov ebx, destinationStride
- imul ebx, edx
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld ditheredInt32Scaler_ // stack: int scaler
-
- Float32_To_Int32_DitherClip_loop:
-
- mov edx, dword ptr [esi] // load floating point value into integer register
-
- and edx, 0x7FFFFFFF // mask off sign
- cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
-
- jg Float32_To_Int32_DitherClip_clamp
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, int scaler
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
-
- /*
- // call PaUtil_GenerateFloatTriangularDither with C calling convention
- mov sourceByteStride, eax // save eax
- mov sourceEnd, ecx // save ecx
- push ditherGenerator // pass ditherGenerator parameter on stack
- call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
- pop edx // clear parameter off stack
- mov ecx, sourceEnd // restore ecx
- mov eax, sourceByteStride // restore eax
- */
-
- // generate dither
- mov sourceByteStride, eax // save eax
- mov edx, 196314165
- mov eax, ditherRandSeed1
- mul edx // eax:edx = eax * 196314165
- //add eax, 907633515
- lea eax, [eax+907633515]
- mov ditherRandSeed1, eax
- mov edx, 196314165
- mov eax, ditherRandSeed2
- mul edx // eax:edx = eax * 196314165
- //add eax, 907633515
- lea eax, [eax+907633515]
- mov edx, ditherRandSeed1
- shr edx, PA_DITHER_SHIFT_
- mov ditherRandSeed2, eax
- shr eax, PA_DITHER_SHIFT_
- //add eax, edx // eax -> current
- lea eax, [eax+edx]
- mov edx, ditherPrevious
- neg edx
- lea edx, [eax+edx] // highpass = current - previous
- mov highpassedDither, edx
- mov ditherPrevious, eax // previous = current
- mov eax, sourceByteStride // restore eax
- fild highpassedDither
- fmul const_float_dither_scale_
- // end generate dither, dither signal in st(0)
-
- faddp st(1), st(0) // stack: dither + value*(int scaler), int scaler
- fistp dword ptr [edi] // pop st(0) into dest, stack: int scaler
- jmp Float32_To_Int32_DitherClip_stored
-
- Float32_To_Int32_DitherClip_clamp:
- mov edx, dword ptr [esi] // load floating point value into integer register
- shr edx, 31 // move sign bit into bit 0
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- add edx, 0x7FFFFFFF // convert to maximum range integers
- mov dword ptr [edi], edx
-
- Float32_To_Int32_DitherClip_stored:
-
- //add edi, ebx // increment destination ptr
- lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int32_DitherClip_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-
- ditherGenerator->previous = ditherPrevious;
- ditherGenerator->randSeed1 = ditherRandSeed1;
- ditherGenerator->randSeed2 = ditherRandSeed2;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
-
- (void) ditherGenerator; // unused parameter
-
- while( count-- )
- {
- // convert to 32 bit and drop the low 8 bits
- double scaled = *src * 0x7FFFFFFF;
- temp = (signed long) scaled;
-
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 24);
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-*/
-
- short savedFpuControlWord;
-
- signed long tempInt32;
-
- (void) ditherGenerator; /* unused parameter */
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32
- mov eax, sourceStride
- imul eax, edx
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi
-
- mov edi, destinationBuffer
-
- mov edx, 3 // sizeof int24
- mov ebx, destinationStride
- imul ebx, edx
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld int24Scaler_ // stack: (int)0x7FFFFF
-
- Float32_To_Int24_loop:
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, (int)0x7FFFFF
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF
- fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF
- mov edx, tempInt32
-
- mov byte ptr [edi], DL
- shr edx, 8
- //mov byte ptr [edi+1], DL
- //mov byte ptr [edi+2], DH
- mov word ptr [edi+1], DX
-
- //add edi, ebx // increment destination ptr
- lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int24_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
-
- (void) ditherGenerator; // unused parameter
-
- while( count-- )
- {
- // convert to 32 bit and drop the low 8 bits
- double scaled = *src * 0x7FFFFFFF;
- PA_CLIP_( scaled, -2147483648., 2147483647. );
- temp = (signed long) scaled;
-
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 24);
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-*/
-
- short savedFpuControlWord;
-
- signed long tempInt32;
-
- (void) ditherGenerator; /* unused parameter */
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32
- mov eax, sourceStride
- imul eax, edx
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi
-
- mov edi, destinationBuffer
-
- mov edx, 3 // sizeof int24
- mov ebx, destinationStride
- imul ebx, edx
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld int24Scaler_ // stack: (int)0x7FFFFF
-
- Float32_To_Int24_Clip_loop:
-
- mov edx, dword ptr [esi] // load floating point value into integer register
-
- and edx, 0x7FFFFFFF // mask off sign
- cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
-
- jg Float32_To_Int24_Clip_clamp
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, (int)0x7FFFFF
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF
- fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF
- mov edx, tempInt32
- jmp Float32_To_Int24_Clip_store
-
- Float32_To_Int24_Clip_clamp:
- mov edx, dword ptr [esi] // load floating point value into integer register
- shr edx, 31 // move sign bit into bit 0
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- add edx, 0x7FFFFF // convert to maximum range integers
-
- Float32_To_Int24_Clip_store:
-
- mov byte ptr [edi], DL
- shr edx, 8
- //mov byte ptr [edi+1], DL
- //mov byte ptr [edi+2], DH
- mov word ptr [edi+1], DX
-
- //add edi, ebx // increment destination ptr
- lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int24_Clip_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int24_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
-
- while( count-- )
- {
- // convert to 32 bit and drop the low 8 bits
-
- // FIXME: the dither amplitude here appears to be too small by 8 bits
- double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- // use smaller scaler to prevent overflow when we add the dither
- double dithered = ((double)*src * (2147483646.0)) + dither;
- PA_CLIP_( dithered, -2147483648., 2147483647. );
-
- temp = (signed long) dithered;
-
- dest[0] = (unsigned char)(temp >> 8);
- dest[1] = (unsigned char)(temp >> 16);
- dest[2] = (unsigned char)(temp >> 24);
-
- src += sourceStride;
- dest += destinationStride * 3;
- }
-*/
-
- short savedFpuControlWord;
-
- // spill storage:
- signed long sourceByteStride;
- signed long highpassedDither;
-
- // dither state:
- unsigned long ditherPrevious = ditherGenerator->previous;
- unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
- unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
-
- signed long tempInt32;
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32
- mov eax, sourceStride
- imul eax, edx
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi
-
- mov edi, destinationBuffer
-
- mov edx, 3 // sizeof int24
- mov ebx, destinationStride
- imul ebx, edx
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld ditheredInt24Scaler_ // stack: int scaler
-
- Float32_To_Int24_DitherClip_loop:
-
- mov edx, dword ptr [esi] // load floating point value into integer register
-
- and edx, 0x7FFFFFFF // mask off sign
- cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
-
- jg Float32_To_Int24_DitherClip_clamp
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, int scaler
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
-
- /*
- // call PaUtil_GenerateFloatTriangularDither with C calling convention
- mov sourceByteStride, eax // save eax
- mov sourceEnd, ecx // save ecx
- push ditherGenerator // pass ditherGenerator parameter on stack
- call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
- pop edx // clear parameter off stack
- mov ecx, sourceEnd // restore ecx
- mov eax, sourceByteStride // restore eax
- */
-
- // generate dither
- mov sourceByteStride, eax // save eax
- mov edx, 196314165
- mov eax, ditherRandSeed1
- mul edx // eax:edx = eax * 196314165
- //add eax, 907633515
- lea eax, [eax+907633515]
- mov ditherRandSeed1, eax
- mov edx, 196314165
- mov eax, ditherRandSeed2
- mul edx // eax:edx = eax * 196314165
- //add eax, 907633515
- lea eax, [eax+907633515]
- mov edx, ditherRandSeed1
- shr edx, PA_DITHER_SHIFT_
- mov ditherRandSeed2, eax
- shr eax, PA_DITHER_SHIFT_
- //add eax, edx // eax -> current
- lea eax, [eax+edx]
- mov edx, ditherPrevious
- neg edx
- lea edx, [eax+edx] // highpass = current - previous
- mov highpassedDither, edx
- mov ditherPrevious, eax // previous = current
- mov eax, sourceByteStride // restore eax
- fild highpassedDither
- fmul const_float_dither_scale_
- // end generate dither, dither signal in st(0)
-
- faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler
- fistp tempInt32 // pop st(0) into tempInt32, stack: int scaler
- mov edx, tempInt32
- jmp Float32_To_Int24_DitherClip_store
-
- Float32_To_Int24_DitherClip_clamp:
- mov edx, dword ptr [esi] // load floating point value into integer register
- shr edx, 31 // move sign bit into bit 0
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- add edx, 0x7FFFFF // convert to maximum range integers
-
- Float32_To_Int24_DitherClip_store:
-
- mov byte ptr [edi], DL
- shr edx, 8
- //mov byte ptr [edi+1], DL
- //mov byte ptr [edi+2], DH
- mov word ptr [edi+1], DX
-
- //add edi, ebx // increment destination ptr
- lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int24_DitherClip_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-
- ditherGenerator->previous = ditherPrevious;
- ditherGenerator->randSeed1 = ditherRandSeed1;
- ditherGenerator->randSeed2 = ditherRandSeed2;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; // unused parameter
-
- while( count-- )
- {
-
- short samp = (short) (*src * (32767.0f));
- *dest = samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-*/
-
- short savedFpuControlWord;
-
- (void) ditherGenerator; /* unused parameter */
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32
- mov eax, sourceStride
- imul eax, edx // source byte stride
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi // source end ptr = count * source byte stride + source ptr
-
- mov edi, destinationBuffer
-
- mov edx, 2 // sizeof int16
- mov ebx, destinationStride
- imul ebx, edx // destination byte stride
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld int16Scaler_ // stack: (int)0x7FFF
-
- Float32_To_Int16_loop:
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, (int)0x7FFF
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF
- fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF
-
- add edi, ebx // increment destination ptr
- //lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int16_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_Clip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; // unused parameter
-
- while( count-- )
- {
- long samp = (signed long) (*src * (32767.0f));
- PA_CLIP_( samp, -0x8000, 0x7FFF );
- *dest = (signed short) samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-*/
-
- short savedFpuControlWord;
-
- (void) ditherGenerator; /* unused parameter */
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32
- mov eax, sourceStride
- imul eax, edx // source byte stride
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi // source end ptr = count * source byte stride + source ptr
-
- mov edi, destinationBuffer
-
- mov edx, 2 // sizeof int16
- mov ebx, destinationStride
- imul ebx, edx // destination byte stride
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld int16Scaler_ // stack: (int)0x7FFF
-
- Float32_To_Int16_Clip_loop:
-
- mov edx, dword ptr [esi] // load floating point value into integer register
-
- and edx, 0x7FFFFFFF // mask off sign
- cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
-
- jg Float32_To_Int16_Clip_clamp
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, (int)0x7FFF
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF
- fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF
- jmp Float32_To_Int16_Clip_stored
-
- Float32_To_Int16_Clip_clamp:
- mov edx, dword ptr [esi] // load floating point value into integer register
- shr edx, 31 // move sign bit into bit 0
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- add dx, 0x7FFF // convert to maximum range integers
- mov word ptr [edi], dx // store clamped into into dest
-
- Float32_To_Int16_Clip_stored:
-
- add edi, ebx // increment destination ptr
- //lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int16_Clip_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void Float32_To_Int16_DitherClip(
- void *destinationBuffer, signed int destinationStride,
- void *sourceBuffer, signed int sourceStride,
- unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
-{
-/*
- float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- (void)ditherGenerator; // unused parameter
-
- while( count-- )
- {
-
- float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
- // use smaller scaler to prevent overflow when we add the dither
- float dithered = (*src * (32766.0f)) + dither;
- signed long samp = (signed long) dithered;
- PA_CLIP_( samp, -0x8000, 0x7FFF );
- *dest = (signed short) samp;
-
- src += sourceStride;
- dest += destinationStride;
- }
-*/
-
- short savedFpuControlWord;
-
- // spill storage:
- signed long sourceByteStride;
- signed long highpassedDither;
-
- // dither state:
- unsigned long ditherPrevious = ditherGenerator->previous;
- unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
- unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
-
- __asm{
- // esi -> source ptr
- // eax -> source byte stride
- // edi -> destination ptr
- // ebx -> destination byte stride
- // ecx -> source end ptr
- // edx -> temp
-
- mov esi, sourceBuffer
-
- mov edx, 4 // sizeof float32
- mov eax, sourceStride
- imul eax, edx // source byte stride
-
- mov ecx, count
- imul ecx, eax
- add ecx, esi // source end ptr = count * source byte stride + source ptr
-
- mov edi, destinationBuffer
-
- mov edx, 2 // sizeof int16
- mov ebx, destinationStride
- imul ebx, edx // destination byte stride
-
- fwait
- fstcw savedFpuControlWord
- fldcw fpuControlWord_
-
- fld ditheredInt16Scaler_ // stack: int scaler
-
- Float32_To_Int16_DitherClip_loop:
-
- mov edx, dword ptr [esi] // load floating point value into integer register
-
- and edx, 0x7FFFFFFF // mask off sign
- cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
-
- jg Float32_To_Int16_DitherClip_clamp
-
- // load unscaled value into st(0)
- fld dword ptr [esi] // stack: value, int scaler
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
-
- /*
- // call PaUtil_GenerateFloatTriangularDither with C calling convention
- mov sourceByteStride, eax // save eax
- mov sourceEnd, ecx // save ecx
- push ditherGenerator // pass ditherGenerator parameter on stack
- call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
- pop edx // clear parameter off stack
- mov ecx, sourceEnd // restore ecx
- mov eax, sourceByteStride // restore eax
- */
-
- // generate dither
- mov sourceByteStride, eax // save eax
- mov edx, 196314165
- mov eax, ditherRandSeed1
- mul edx // eax:edx = eax * 196314165
- //add eax, 907633515
- lea eax, [eax+907633515]
- mov ditherRandSeed1, eax
- mov edx, 196314165
- mov eax, ditherRandSeed2
- mul edx // eax:edx = eax * 196314165
- //add eax, 907633515
- lea eax, [eax+907633515]
- mov edx, ditherRandSeed1
- shr edx, PA_DITHER_SHIFT_
- mov ditherRandSeed2, eax
- shr eax, PA_DITHER_SHIFT_
- //add eax, edx // eax -> current
- lea eax, [eax+edx] // current = randSeed1>>x + randSeed2>>x
- mov edx, ditherPrevious
- neg edx
- lea edx, [eax+edx] // highpass = current - previous
- mov highpassedDither, edx
- mov ditherPrevious, eax // previous = current
- mov eax, sourceByteStride // restore eax
- fild highpassedDither
- fmul const_float_dither_scale_
- // end generate dither, dither signal in st(0)
-
- faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler
- fistp word ptr [edi] // store scaled int into dest, stack: int scaler
- jmp Float32_To_Int16_DitherClip_stored
-
- Float32_To_Int16_DitherClip_clamp:
- mov edx, dword ptr [esi] // load floating point value into integer register
- shr edx, 31 // move sign bit into bit 0
- add esi, eax // increment source ptr
- //lea esi, [esi+eax]
- add dx, 0x7FFF // convert to maximum range integers
- mov word ptr [edi], dx // store clamped into into dest
-
- Float32_To_Int16_DitherClip_stored:
-
- add edi, ebx // increment destination ptr
- //lea edi, [edi+ebx]
-
- cmp esi, ecx // has src ptr reached end?
- jne Float32_To_Int16_DitherClip_loop
-
- ffree st(0)
- fincstp
-
- fwait
- fnclex
- fldcw savedFpuControlWord
- }
-
- ditherGenerator->previous = ditherPrevious;
- ditherGenerator->randSeed1 = ditherRandSeed1;
- ditherGenerator->randSeed2 = ditherRandSeed2;
-}
-
-/* -------------------------------------------------------------------------- */
-
-void PaUtil_InitializeX86PlainConverters( void )
-{
- paConverters.Float32_To_Int32 = Float32_To_Int32;
- paConverters.Float32_To_Int32_Clip = Float32_To_Int32_Clip;
- paConverters.Float32_To_Int32_DitherClip = Float32_To_Int32_DitherClip;
-
- paConverters.Float32_To_Int24 = Float32_To_Int24;
- paConverters.Float32_To_Int24_Clip = Float32_To_Int24_Clip;
- paConverters.Float32_To_Int24_DitherClip = Float32_To_Int24_DitherClip;
-
- paConverters.Float32_To_Int16 = Float32_To_Int16;
- paConverters.Float32_To_Int16_Clip = Float32_To_Int16_Clip;
- paConverters.Float32_To_Int16_DitherClip = Float32_To_Int16_DitherClip;
-}
-
-/* -------------------------------------------------------------------------- */
diff --git a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h b/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h
deleted file mode 100644
index f56c710f..00000000
--- a/pjmedia/src/pjmedia/portaudio/pa_x86_plain_converters.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef PA_X86_PLAIN_CONVERTERS_H
-#define PA_X86_PLAIN_CONVERTERS_H
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/**
- @brief Install optimised converter functions suitable for all IA32 processors
-*/
-void PaUtil_InitializeX86PlainConverters( void );
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PA_X86_PLAIN_CONVERTERS_H */
diff --git a/pjmedia/src/pjmedia/portaudio/portaudio.h b/pjmedia/src/pjmedia/portaudio/portaudio.h
deleted file mode 100644
index 432372ce..00000000
--- a/pjmedia/src/pjmedia/portaudio/portaudio.h
+++ /dev/null
@@ -1,1122 +0,0 @@
-#ifndef PORTAUDIO_H
-#define PORTAUDIO_H
-/*
- * $Id: portaudio.h,v 1.5.2.50 2004/12/13 11:50:40 rossbencina Exp $
- * PortAudio Portable Real-Time Audio Library
- * PortAudio API Header File
- * Latest version available at: http://www.portaudio.com/
- *
- * Copyright (c) 1999-2002 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.
- *
- * 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.
- *
- * 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.
- */
-
-/** @file
- @brief The PortAudio API.
-*/
-
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-
-/** Retrieve the release number of the currently running PortAudio build,
- eg 1900.
-*/
-int Pa_GetVersion( void );
-
-
-/** Retrieve a textual description of the current PortAudio build,
- eg "PortAudio V19-devel 13 October 2002".
-*/
-const char* Pa_GetVersionText( void );
-
-
-/** Error codes returned by PortAudio functions.
- Note that with the exception of paNoError, all PaErrorCodes are negative.
-*/
-
-typedef int PaError;
-typedef enum PaErrorCode
-{
- paNoError = 0,
-
- paNotInitialized = -1000, /* blp: changed from -10000 */
- paUnanticipatedHostError,
- paInvalidChannelCount,
- paInvalidSampleRate,
- paInvalidDevice,
- paInvalidFlag,
- paSampleFormatNotSupported,
- paBadIODeviceCombination,
- paInsufficientMemory,
- paBufferTooBig,
- paBufferTooSmall,
- paNullCallback,
- paBadStreamPtr,
- paTimedOut,
- paInternalError,
- paDeviceUnavailable,
- paIncompatibleHostApiSpecificStreamInfo,
- paStreamIsStopped,
- paStreamIsNotStopped,
- paInputOverflowed,
- paOutputUnderflowed,
- paHostApiNotFound,
- paInvalidHostApi,
- paCanNotReadFromACallbackStream, /**< @todo review error code name */
- paCanNotWriteToACallbackStream, /**< @todo review error code name */
- paCanNotReadFromAnOutputOnlyStream, /**< @todo review error code name */
- paCanNotWriteToAnInputOnlyStream, /**< @todo review error code name */
- paIncompatibleStreamHostApi
-} PaErrorCode;
-
-
-/** Translate the supplied PortAudio error code into a human readable
- message.
-*/
-const char *Pa_GetErrorText( PaError errorCode );
-
-
-/** Library initialization function - call this before using PortAudio.
- This function initialises internal data structures and prepares underlying
- host APIs for use. This function MUST be called before using any other
- PortAudio API functions.
-
- If Pa_Initialize() is called multiple times, each successful
- call must be matched with a corresponding call to Pa_Terminate().
- Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not
- required to be fully nested.
-
- Note that if Pa_Initialize() returns an error code, Pa_Terminate() should
- NOT be called.
-
- @return paNoError if successful, otherwise an error code indicating the cause
- of failure.
-
- @see Pa_Terminate
-*/
-PaError Pa_Initialize( void );
-
-
-/** Library termination function - call this when finished using PortAudio.
- This function deallocates all resources allocated by PortAudio since it was
- initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has
- been called multiple times, each call must be matched with a corresponding call
- to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically
- close any PortAudio streams that are still open.
-
- Pa_Terminate() MUST be called before exiting a program which uses PortAudio.
- Failure to do so may result in serious resource leaks, such as audio devices
- not being available until the next reboot.
-
- @return paNoError if successful, otherwise an error code indicating the cause
- of failure.
-
- @see Pa_Initialize
-*/
-PaError Pa_Terminate( void );
-
-
-
-/** The type used to refer to audio devices. Values of this type usually
- range from 0 to (Pa_DeviceCount-1), and may also take on the PaNoDevice
- and paUseHostApiSpecificDeviceSpecification values.
-
- @see Pa_DeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification
-*/
-typedef int PaDeviceIndex;
-
-
-/** A special PaDeviceIndex value indicating that no device is available,
- or should be used.
-
- @see PaDeviceIndex
-*/
-#define paNoDevice ((PaDeviceIndex)-1)
-
-
-/** A special PaDeviceIndex value indicating that the device(s) to be used
- are specified in the host api specific stream info structure.
-
- @see PaDeviceIndex
-*/
-#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2)
-
-
-/* Host API enumeration mechanism */
-
-/** The type used to enumerate to host APIs at runtime. Values of this type
- range from 0 to (Pa_GetHostApiCount()-1).
-
- @see Pa_GetHostApiCount
-*/
-typedef int PaHostApiIndex;
-
-
-/** Retrieve the number of available host APIs. Even if a host API is
- available it may have no devices available.
-
- @return A non-negative value indicating the number of available host APIs
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- @see PaHostApiIndex
-*/
-PaHostApiIndex Pa_GetHostApiCount( void );
-
-
-/** Retrieve the index of the default host API. The default host API will be
- the lowest common denominator host API on the current platform and is
- unlikely to provide the best performance.
-
- @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1)
- indicating the default host API index or, a PaErrorCode (which are always
- negative) if PortAudio is not initialized or an error is encountered.
-*/
-PaHostApiIndex Pa_GetDefaultHostApi( void );
-
-
-/** Unchanging unique identifiers for each supported host API. This type
- is used in the PaHostApiInfo structure. The values are guaranteed to be
- unique and to never change, thus allowing code to be written that
- conditionally uses host API specific extensions.
-
- New type ids will be allocated when support for a host API reaches
- "public alpha" status, prior to that developers should use the
- paInDevelopment type id.
-
- @see PaHostApiInfo
-*/
-typedef enum PaHostApiTypeId
-{
- paInDevelopment=0, /* use while developing support for a new host API */
- paDirectSound=1,
- paMME=2,
- paASIO=3,
- paSoundManager=4,
- paCoreAudio=5,
- paOSS=7,
- paALSA=8,
- paAL=9,
- paBeOS=10,
- paWDMKS=11,
- paJACK=12
-} PaHostApiTypeId;
-
-
-/** A structure containing information about a particular host API. */
-
-typedef struct PaHostApiInfo
-{
- /** this is struct version 1 */
- int structVersion;
- /** The well known unique identifier of this host API @see PaHostApiTypeId */
- PaHostApiTypeId type;
- /** A textual description of the host API for display on user interfaces. */
- const char *name;
-
- /** The number of devices belonging to this host API. This field may be
- used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate
- all devices for this host API.
- @see Pa_HostApiDeviceIndexToDeviceIndex
- */
- int deviceCount;
-
- /** The the default input device for this host API. The value will be a
- device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice
- if no default input device is available.
- */
- PaDeviceIndex defaultInputDevice;
-
- /** The the default output device for this host API. The value will be a
- device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice
- if no default output device is available.
- */
- PaDeviceIndex defaultOutputDevice;
-
-} PaHostApiInfo;
-
-
-/** Retrieve a pointer to a structure containing information about a specific
- host Api.
-
- @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1)
-
- @return A pointer to an immutable PaHostApiInfo structure describing
- a specific host API. If the hostApi parameter is out of range or an error
- is encountered, the function returns NULL.
-
- The returned structure is owned by the PortAudio implementation and must not
- be manipulated or freed. The pointer is only guaranteed to be valid between
- calls to Pa_Initialize() and Pa_Terminate().
-*/
-const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi );
-
-
-/** Convert a static host API unique identifier, into a runtime
- host API index.
-
- @param type A unique host API identifier belonging to the PaHostApiTypeId
- enumeration.
-
- @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or,
- a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- The paHostApiNotFound error code indicates that the host API specified by the
- type parameter is not available.
-
- @see PaHostApiTypeId
-*/
-PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type );
-
-
-/** Convert a host-API-specific device index to standard PortAudio device index.
- This function may be used in conjunction with the deviceCount field of
- PaHostApiInfo to enumerate all devices for the specified host API.
-
- @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1)
-
- @param hostApiDeviceIndex A valid per-host device index in the range
- 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1)
-
- @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1)
- or, a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-
- A paInvalidHostApi error code indicates that the host API index specified by
- the hostApi parameter is out of range.
-
- A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter
- is out of range.
-
- @see PaHostApiInfo
-*/
-PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi,
- int hostApiDeviceIndex );
-
-
-
-/** Structure used to return information about a host error condition.
-*/
-typedef struct PaHostErrorInfo{
- PaHostApiTypeId hostApiType; /**< the host API which returned the error code */
- long errorCode; /**< the error code returned */
- const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */
-}PaHostErrorInfo;
-
-
-/** Return information about the last host error encountered. The error
- information returned by Pa_GetLastHostErrorInfo() will never be modified
- asyncronously by errors occurring in other PortAudio owned threads
- (such as the thread that manages the stream callback.)
-
- This function is provided as a last resort, primarily to enhance debugging
- by providing clients with access to all available error information.
-
- @return A pointer to an immutable structure constaining information about
- the host error. The values in this structure will only be valid if a
- PortAudio function has previously returned the paUnanticipatedHostError
- error code.
-*/
-const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void );
-
-
-
-/* Device enumeration and capabilities */
-
-/** Retrieve the number of available devices. The number of available devices
- may be zero.
-
- @return A non-negative value indicating the number of available devices or,
- a PaErrorCode (which are always negative) if PortAudio is not initialized
- or an error is encountered.
-*/
-PaDeviceIndex Pa_GetDeviceCount( void );
-
-
-/** Retrieve the index of the default input device. The result can be
- used in the inputDevice parameter to Pa_OpenStream().
-
- @return The default input device index for the default host API, or paNoDevice
- if no default input device is available or an error was encountered.
-*/
-PaDeviceIndex Pa_GetDefaultInputDevice( void );
-
-
-/** Retrieve the index of the default output device. The result can be
- used in the outputDevice parameter to Pa_OpenStream().
-
- @return The default output device index for the defualt host API, or paNoDevice
- if no default output device is available or an error was encountered.
-
- @note
- On the PC, the user can specify a default device by
- setting an environment variable. For example, to use device #1.
-<pre>
- set PA_RECOMMENDED_OUTPUT_DEVICE=1
-</pre>
- The user should first determine the available device ids by using
- the supplied application "pa_devs".
-*/
-PaDeviceIndex Pa_GetDefaultOutputDevice( void );
-
-
-/** The type used to represent monotonic time in seconds that can be used
- for syncronisation. The type is used for the outTime argument to the
- PaStreamCallback and as the result of Pa_GetStreamTime().
-
- @see PaStreamCallback, Pa_GetStreamTime
-*/
-typedef double PaTime;
-
-
-/** A type used to specify one or more sample formats. Each value indicates
- a possible format for sound data passed to and from the stream callback,
- Pa_ReadStream and Pa_WriteStream.
-
- The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8
- and aUInt8 are usually implemented by all implementations.
-
- The floating point representation (paFloat32) uses +1.0 and -1.0 as the
- maximum and minimum respectively.
-
- paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
-
- The paNonInterleaved flag indicates that a multichannel buffer is passed
- as a set of non-interleaved pointers.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo
- @see paFloat32, paInt16, paInt32, paInt24, paInt8
- @see paUInt8, paCustomFormat, paNonInterleaved
-*/
-typedef unsigned long PaSampleFormat;
-
-
-#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */
-#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */
-#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */
-#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */
-#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */
-#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */
-#define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */
-
-#define paNonInterleaved ((PaSampleFormat) 0x80000000)
-
-/** A structure providing information and capabilities of PortAudio devices.
- Devices may support input, output or both input and output.
-*/
-typedef struct PaDeviceInfo
-{
- int structVersion; /* this is struct version 2 */
- const char *name;
- PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
-
- int maxInputChannels;
- int maxOutputChannels;
-
- /* Default latency values for interactive performance. */
- PaTime defaultLowInputLatency;
- PaTime defaultLowOutputLatency;
- /* Default latency values for robust non-interactive applications (eg. playing sound files). */
- PaTime defaultHighInputLatency;
- PaTime defaultHighOutputLatency;
-
- double defaultSampleRate;
-} PaDeviceInfo;
-
-
-/** Retrieve a pointer to a PaDeviceInfo structure containing information
- about the specified device.
- @return A pointer to an immutable PaDeviceInfo structure. If the device
- parameter is out of range the function returns NULL.
-
- @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1)
-
- @note PortAudio manages the memory referenced by the returned pointer,
- the client must not manipulate or free the memory. The pointer is only
- guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate().
-
- @see PaDeviceInfo, PaDeviceIndex
-*/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );
-
-
-/** Parameters for one direction (input or output) of a stream.
-*/
-typedef struct PaStreamParameters
-{
- /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1)
- specifying the device to be used or the special constant
- paUseHostApiSpecificDeviceSpecification which indicates that the actual
- device(s) to use are specified in hostApiSpecificStreamInfo.
- This field must not be set to paNoDevice.
- */
- PaDeviceIndex device;
-
- /** The number of channels of sound to be delivered to the
- stream callback or accessed by Pa_ReadStream() or Pa_WriteStream().
- It can range from 1 to the value of maxInputChannels in the
- PaDeviceInfo record for the device specified by the device parameter.
- */
- int channelCount;
-
- /** The sample format of the buffer provided to the stream callback,
- a_ReadStream() or Pa_WriteStream(). It may be any of the formats described
- by the PaSampleFormat enumeration.
- */
- PaSampleFormat sampleFormat;
-
- /** The desired latency in seconds. Where practical, implementations should
- configure their latency based on these parameters, otherwise they may
- choose the closest viable latency instead. Unless the suggested latency
- is greater than the absolute upper limit for the device implementations
- shouldround the suggestedLatency up to the next practial value - ie to
- provide an equal or higher latency than suggestedLatency whereever possibe.
- Actual latency values for an open stream may be retrieved using the
- inputLatency and outputLatency fields of the PaStreamInfo structure
- returned by Pa_GetStreamInfo().
- @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo
- */
- PaTime suggestedLatency;
-
- /** An optional pointer to a host api specific data structure
- containing additional information for device setup and/or stream processing.
- hostApiSpecificStreamInfo is never required for correct operation,
- if not used it should be set to NULL.
- */
- void *hostApiSpecificStreamInfo;
-
-} PaStreamParameters;
-
-
-/** Return code for Pa_IsFormatSupported indicating success. */
-#define paFormatIsSupported (0)
-
-/** Determine whether it would be possible to open a stream with the specified
- parameters.
-
- @param inputParameters A structure that describes the input parameters used to
- open a stream. The suggestedLatency field is ignored. See PaStreamParameters
- for a description of these parameters. inputParameters must be NULL for
- output-only streams.
-
- @param outputParameters A structure that describes the output parameters used
- to open a stream. The suggestedLatency field is ignored. See PaStreamParameters
- for a description of these parameters. outputParameters must be NULL for
- input-only streams.
-
- @param sampleRate The required sampleRate. For full-duplex streams it is the
- sample rate for both input and output
-
- @return Returns 0 if the format is supported, and an error code indicating why
- the format is not supported otherwise. The constant paFormatIsSupported is
- provided to compare with the return value for success.
-
- @see paFormatIsSupported, PaStreamParameters
-*/
-PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-
-
-
-/* Streaming types and functions */
-
-
-/**
- A single PaStream can provide multiple channels of real-time
- streaming audio input and output to a client application. A stream
- provides access to audio hardware represented by one or more
- PaDevices. Depending on the underlying Host API, it may be possible
- to open multiple streams using the same device, however this behavior
- is implementation defined. Portable applications should assume that
- a PaDevice may be simultaneously used by at most one PaStream.
-
- Pointers to PaStream objects are passed between PortAudio functions that
- operate on streams.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream,
- Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive,
- Pa_GetStreamTime, Pa_GetStreamCpuLoad
-
-*/
-typedef void PaStream;
-
-
-/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream()
- or Pa_OpenDefaultStream() to indicate that the stream callback will
- accept buffers of any size.
-*/
-#define paFramesPerBufferUnspecified (0)
-
-
-/** Flags used to control the behavior of a stream. They are passed as
- parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be
- ORed together.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream
- @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput,
- paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags
-*/
-typedef unsigned long PaStreamFlags;
-
-/** @see PaStreamFlags */
-#define paNoFlag ((PaStreamFlags) 0)
-
-/** Disable default clipping of out of range samples.
- @see PaStreamFlags
-*/
-#define paClipOff ((PaStreamFlags) 0x00000001)
-
-/** Disable default dithering.
- @see PaStreamFlags
-*/
-#define paDitherOff ((PaStreamFlags) 0x00000002)
-
-/** Flag requests that where possible a full duplex stream will not discard
- overflowed input samples without calling the stream callback. This flag is
- only valid for full duplex callback streams and only when used in combination
- with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using
- this flag incorrectly results in a paInvalidFlag error being returned from
- Pa_OpenStream and Pa_OpenDefaultStream.
-
- @see PaStreamFlags, paFramesPerBufferUnspecified
-*/
-#define paNeverDropInput ((PaStreamFlags) 0x00000004)
-
-/** Call the stream callback to fill initial output buffers, rather than the
- default behavior of priming the buffers with zeros (silence). This flag has
- no effect for input-only and blocking read/write streams.
-
- @see PaStreamFlags
-*/
-#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008)
-
-/** A mask specifying the platform specific bits.
- @see PaStreamFlags
-*/
-#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000)
-
-/**
- Timing information for the buffers passed to the stream callback.
-*/
-typedef struct PaStreamCallbackTimeInfo{
- PaTime inputBufferAdcTime;
- PaTime currentTime;
- PaTime outputBufferDacTime;
-} PaStreamCallbackTimeInfo;
-
-
-/**
- Flag bit constants for the statusFlags to PaStreamCallback.
-
- @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow,
- paPrimingOutput
-*/
-typedef unsigned long PaStreamCallbackFlags;
-
-/** In a stream opened with paFramesPerBufferUnspecified, indicates that
- input data is all silence (zeros) because no real data is available. In a
- stream opened without paFramesPerBufferUnspecified, it indicates that one or
- more zero samples have been inserted into the input buffer to compensate
- for an input underflow.
- @see PaStreamCallbackFlags
-*/
-#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001)
-
-/** In a stream opened with paFramesPerBufferUnspecified, indicates that data
- prior to the first sample of the input buffer was discarded due to an
- overflow, possibly because the stream callback is using too much CPU time.
- Otherwise indicates that data prior to one or more samples in the
- input buffer was discarded.
- @see PaStreamCallbackFlags
-*/
-#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002)
-
-/** Indicates that output data (or a gap) was inserted, possibly because the
- stream callback is using too much CPU time.
- @see PaStreamCallbackFlags
-*/
-#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004)
-
-/** Indicates that output data will be discarded because no room is available.
- @see PaStreamCallbackFlags
-*/
-#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008)
-
-/** Some of all of the output data will be used to prime the stream, input
- data may be zero.
- @see PaStreamCallbackFlags
-*/
-#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010)
-
-/**
- Allowable return values for the PaStreamCallback.
- @see PaStreamCallback
-*/
-typedef enum PaStreamCallbackResult
-{
- paContinue=0,
- paComplete=1,
- paAbort=2
-} PaStreamCallbackResult;
-
-
-/**
- Functions of type PaStreamCallback are implemented by PortAudio clients.
- They consume, process or generate audio in response to requests from an
- active PortAudio stream.
-
- @param input and @param output are arrays of interleaved samples,
- the format, packing and number of channels used by the buffers are
- determined by parameters to Pa_OpenStream().
-
- @param frameCount The number of sample frames to be processed by
- the stream callback.
-
- @param timeInfo The time in seconds when the first sample of the input
- buffer was received at the audio input, the time in seconds when the first
- sample of the output buffer will begin being played at the audio output, and
- the time in seconds when the stream callback was called.
- See also Pa_GetStreamTime()
-
- @param statusFlags Flags indicating whether input and/or output buffers
- have been inserted or will be dropped to overcome underflow or overflow
- conditions.
-
- @param userData The value of a user supplied pointer passed to
- Pa_OpenStream() intended for storing synthesis data etc.
-
- @return
- The stream callback should return one of the values in the
- PaStreamCallbackResult enumeration. To ensure that the callback continues
- to be called, it should return paContinue (0). Either paComplete or paAbort
- can be returned to finish stream processing, after either of these values is
- returned the callback will not be called again. If paAbort is returned the
- stream will finish as soon as possible. If paComplete is returned, the stream
- will continue until all buffers generated by the callback have been played.
- This may be useful in applications such as soundfile players where a specific
- duration of output is required. However, it is not necessary to utilise this
- mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also
- be used to stop the stream. The callback must always fill the entire output
- buffer irrespective of its return value.
-
- @see Pa_OpenStream, Pa_OpenDefaultStream
-
- @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call
- PortAudio API functions from within the stream callback.
-*/
-typedef int PaStreamCallback(
- const void *input, void *output,
- unsigned long frameCount,
- const PaStreamCallbackTimeInfo* timeInfo,
- PaStreamCallbackFlags statusFlags,
- void *userData );
-
-
-/** Opens a stream for either input, output or both.
-
- @param stream The address of a PaStream pointer which will receive
- a pointer to the newly opened stream.
-
- @param inputParameters A structure that describes the input parameters used by
- the opened stream. See PaStreamParameters for a description of these parameters.
- inputParameters must be NULL for output-only streams.
-
- @param outputParameters A structure that describes the output parameters used by
- the opened stream. See PaStreamParameters for a description of these parameters.
- outputParameters must be NULL for input-only streams.
-
- @param sampleRate The desired sampleRate. For full-duplex streams it is the
- sample rate for both input and output
-
- @param framesPerBuffer The number of frames passed to the stream callback
- function, or the preferred block granularity for a blocking read/write stream.
- The special value paFramesPerBufferUnspecified (0) may be used to request that
- the stream callback will recieve an optimal (and possibly varying) number of
- frames based on host requirements and the requested latency settings.
- Note: With some host APIs, the use of non-zero framesPerBuffer for a callback
- stream may introduce an additional layer of buffering which could introduce
- additional latency. PortAudio guarantees that the additional latency
- will be kept to the theoretical minimum however, it is strongly recommended
- that a non-zero framesPerBuffer value only be used when your algorithm
- requires a fixed number of frames per stream callback.
-
- @param streamFlags Flags which modify the behaviour of the streaming process.
- This parameter may contain a combination of flags ORed together. Some flags may
- only be relevant to certain buffer formats.
-
- @param streamCallback A pointer to a client supplied function that is responsible
- for processing and filling input and output buffers. If this parameter is NULL
- the stream will be opened in 'blocking read/write' mode. In blocking mode,
- the client can receive sample data using Pa_ReadStream and write sample data
- using Pa_WriteStream, the number of samples that may be read or written
- without blocking is returned by Pa_GetStreamReadAvailable and
- Pa_GetStreamWriteAvailable respectively.
-
- @param userData A client supplied pointer which is passed to the stream callback
- function. It could for example, contain a pointer to instance data necessary
- for processing the audio buffers. This parameter is ignored if streamCallback
- is NULL.
-
- @return
- Upon success Pa_OpenStream() returns paNoError and places a pointer to a
- valid PaStream in the stream argument. The stream is inactive (stopped).
- If a call to Pa_OpenStream() fails, a non-zero error code is returned (see
- PaError for possible error codes) and the value of stream is invalid.
-
- @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream,
- Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable
-*/
-PaError Pa_OpenStream( PaStream** stream,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-
-
-/** A simplified version of Pa_OpenStream() that opens the default input
- and/or output devices.
-
- @param stream The address of a PaStream pointer which will receive
- a pointer to the newly opened stream.
-
- @param numInputChannels The number of channels of sound that will be supplied
- to the stream callback or returned by Pa_ReadStream. It can range from 1 to
- the value of maxInputChannels in the PaDeviceInfo record for the default input
- device. If 0 the stream is opened as an output-only stream.
-
- @param numOutputChannels The number of channels of sound to be delivered to the
- stream callback or passed to Pa_WriteStream. It can range from 1 to the value
- of maxOutputChannels in the PaDeviceInfo record for the default output dvice.
- If 0 the stream is opened as an output-only stream.
-
- @param sampleFormat The sample format of both the input and output buffers
- provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream.
- sampleFormat may be any of the formats described by the PaSampleFormat
- enumeration.
-
- @param sampleRate Same as Pa_OpenStream parameter of the same name.
- @param framesPerBuffer Same as Pa_OpenStream parameter of the same name.
- @param streamCallback Same as Pa_OpenStream parameter of the same name.
- @param userData Same as Pa_OpenStream parameter of the same name.
-
- @return As for Pa_OpenStream
-
- @see Pa_OpenStream, PaStreamCallback
-*/
-PaError Pa_OpenDefaultStream( PaStream** stream,
- int numInputChannels,
- int numOutputChannels,
- PaSampleFormat sampleFormat,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamCallback *streamCallback,
- void *userData );
-
-
-/** Closes an audio stream. If the audio stream is active it
- discards any pending buffers as if Pa_AbortStream() had been called.
-*/
-PaError Pa_CloseStream( PaStream *stream );
-
-
-/** Functions of type PaStreamFinishedCallback are implemented by PortAudio
- clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback
- function. Once registered they are called when the stream becomes inactive
- (ie once a call to Pa_StopStream() will not block).
- A stream will become inactive after the stream callback returns non-zero,
- or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio
- output, if the stream callback returns paComplete, or Pa_StopStream is called,
- the stream finished callback will not be called until all generated sample data
- has been played.
-
- @param userData The userData parameter supplied to Pa_OpenStream()
-
- @see Pa_SetStreamFinishedCallback
-*/
-typedef void PaStreamFinishedCallback( void *userData );
-
-
-/** Register a stream finished callback function which will be called when the
- stream becomes inactive. See the description of PaStreamFinishedCallback for
- further details about when the callback will be called.
-
- @param stream a pointer to a PaStream that is in the stopped state - if the
- stream is not stopped, the stream's finished callback will remain unchanged
- and an error code will be returned.
-
- @param streamFinishedCallback a pointer to a function with the same signature
- as PaStreamFinishedCallback, that will be called when the stream becomes
- inactive. Passing NULL for this parameter will un-register a previously
- registered stream finished callback function.
-
- @return on success returns paNoError, otherwise an error code indicating the cause
- of the error.
-
- @see PaStreamFinishedCallback
-*/
-PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback );
-
-
-/** Commences audio processing.
-*/
-PaError Pa_StartStream( PaStream *stream );
-
-
-/** Terminates audio processing. It waits until all pending
- audio buffers have been played before it returns.
-*/
-PaError Pa_StopStream( PaStream *stream );
-
-
-/** Terminates audio processing immediately without waiting for pending
- buffers to complete.
-*/
-PaError Pa_AbortStream( PaStream *stream );
-
-
-/** Determine whether the stream is stopped.
- A stream is considered to be stopped prior to a successful call to
- Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream.
- If a stream callback returns a value other than paContinue the stream is NOT
- considered to be stopped.
-
- @return Returns one (1) when the stream is stopped, zero (0) when
- the stream is running or, a PaErrorCode (which are always negative) if
- PortAudio is not initialized or an error is encountered.
-
- @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive
-*/
-PaError Pa_IsStreamStopped( PaStream *stream );
-
-
-/** Determine whether the stream is active.
- A stream is active after a successful call to Pa_StartStream(), until it
- becomes inactive either as a result of a call to Pa_StopStream() or
- Pa_AbortStream(), or as a result of a return value other than paContinue from
- the stream callback. In the latter case, the stream is considered inactive
- after the last buffer has finished playing.
-
- @return Returns one (1) when the stream is active (ie playing or recording
- audio), zero (0) when not playing or, a PaErrorCode (which are always negative)
- if PortAudio is not initialized or an error is encountered.
-
- @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped
-*/
-PaError Pa_IsStreamActive( PaStream *stream );
-
-
-
-/** A structure containing unchanging information about an open stream.
- @see Pa_GetStreamInfo
-*/
-
-typedef struct PaStreamInfo
-{
- /** this is struct version 1 */
- int structVersion;
-
- /** The input latency of the stream in seconds. This value provides the most
- accurate estimate of input latency available to the implementation. It may
- differ significantly from the suggestedLatency value passed to Pa_OpenStream().
- The value of this field will be zero (0.) for output-only streams.
- @see PaTime
- */
- PaTime inputLatency;
-
- /** The output latency of the stream in seconds. This value provides the most
- accurate estimate of output latency available to the implementation. It may
- differ significantly from the suggestedLatency value passed to Pa_OpenStream().
- The value of this field will be zero (0.) for input-only streams.
- @see PaTime
- */
- PaTime outputLatency;
-
- /** The sample rate of the stream in Hertz (samples per second). In cases
- where the hardware sample rate is inaccurate and PortAudio is aware of it,
- the value of this field may be different from the sampleRate parameter
- passed to Pa_OpenStream(). If information about the actual hardware sample
- rate is not available, this field will have the same value as the sampleRate
- parameter passed to Pa_OpenStream().
- */
- double sampleRate;
-
-} PaStreamInfo;
-
-
-/** Retrieve a pointer to a PaStreamInfo structure containing information
- about the specified stream.
- @return A pointer to an immutable PaStreamInfo structure. If the stream
- parameter invalid, or an error is encountered, the function returns NULL.
-
- @param stream A pointer to an open stream previously created with Pa_OpenStream.
-
- @note PortAudio manages the memory referenced by the returned pointer,
- the client must not manipulate or free the memory. The pointer is only
- guaranteed to be valid until the specified stream is closed.
-
- @see PaStreamInfo
-*/
-const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream );
-
-
-/** Determine the current time for the stream according to the same clock used
- to generate buffer timestamps. This time may be used for syncronising other
- events to the audio stream, for example synchronizing audio to MIDI.
-
- @return The stream's current time in seconds, or 0 if an error occurred.
-
- @see PaTime, PaStreamCallback
-*/
-PaTime Pa_GetStreamTime( PaStream *stream );
-
-
-/** Retrieve CPU usage information for the specified stream.
- The "CPU Load" is a fraction of total CPU time consumed by a callback stream's
- audio processing routines including, but not limited to the client supplied
- stream callback. This function does not work with blocking read/write streams.
-
- This function may be called from the stream callback function or the
- application.
-
- @return
- A floating point value, typically between 0.0 and 1.0, where 1.0 indicates
- that the stream callback is consuming the maximum number of CPU cycles possible
- to maintain real-time operation. A value of 0.5 would imply that PortAudio and
- the stream callback was consuming roughly 50% of the available CPU time. The
- return value may exceed 1.0. A value of 0.0 will always be returned for a
- blocking read/write stream, or if an error occurrs.
-*/
-double Pa_GetStreamCpuLoad( PaStream* stream );
-
-
-/** Read samples from an input stream. The function doesn't return until
- the entire buffer has been filled - this may involve waiting for the operating
- system to supply the data.
-
- @param stream A pointer to an open stream previously created with Pa_OpenStream.
-
- @param buffer A pointer to a buffer of sample frames. The buffer contains
- samples in the format specified by the inputParameters->sampleFormat field
- used to open the stream, and the number of channels specified by
- inputParameters->numChannels. If non-interleaved samples were requested,
- buffer is a pointer to the first element of an array of non-interleaved
- buffer pointers, one for each channel.
-
- @param frames The number of frames to be read into buffer. This parameter
- is not constrained to a specific range, however high performance applications
- will want to match this parameter to the framesPerBuffer parameter used
- when opening the stream.
-
- @return On success PaNoError will be returned, or PaInputOverflowed if input
- data was discarded by PortAudio after the previous call and before this call.
-*/
-PaError Pa_ReadStream( PaStream* stream,
- void *buffer,
- unsigned long frames );
-
-
-/** Write samples to an output stream. This function doesn't return until the
- entire buffer has been consumed - this may involve waiting for the operating
- system to consume the data.
-
- @param stream A pointer to an open stream previously created with Pa_OpenStream.
-
- @param buffer A pointer to a buffer of sample frames. The buffer contains
- samples in the format specified by the outputParameters->sampleFormat field
- used to open the stream, and the number of channels specified by
- outputParameters->numChannels. If non-interleaved samples were requested,
- buffer is a pointer to the first element of an array of non-interleaved
- buffer pointers, one for each channel.
-
- @param frames The number of frames to be written from buffer. This parameter
- is not constrained to a specific range, however high performance applications
- will want to match this parameter to the framesPerBuffer parameter used
- when opening the stream.
-
- @return On success PaNoError will be returned, or paOutputUnderflowed if
- additional output data was inserted after the previous call and before this
- call.
-*/
-PaError Pa_WriteStream( PaStream* stream,
- const void *buffer,
- unsigned long frames );
-
-
-/** Retrieve the number of frames that can be read from the stream without
- waiting.
-
- @return Returns a non-negative value representing the maximum number of frames
- that can be read from the stream without blocking or busy waiting or, a
- PaErrorCode (which are always negative) if PortAudio is not initialized or an
- error is encountered.
-*/
-signed long Pa_GetStreamReadAvailable( PaStream* stream );
-
-
-/** Retrieve the number of frames that can be written to the stream without
- waiting.
-
- @return Returns a non-negative value representing the maximum number of frames
- that can be written to the stream without blocking or busy waiting or, a
- PaErrorCode (which are always negative) if PortAudio is not initialized or an
- error is encountered.
-*/
-signed long Pa_GetStreamWriteAvailable( PaStream* stream );
-
-
-/* Miscellaneous utilities */
-
-
-/** Retrieve the size of a given sample format in bytes.
-
- @return The size in bytes of a single sample in the specified format,
- or paSampleFormatNotSupported if the format is not supported.
-*/
-PaError Pa_GetSampleSize( PaSampleFormat format );
-
-
-/** Put the caller to sleep for at least 'msec' milliseconds. This function is
- provided only as a convenience for authors of portable code (such as the tests
- and examples in the PortAudio distribution.)
-
- The function may sleep longer than requested so don't rely on this for accurate
- musical timing.
-*/
-void Pa_Sleep( long msec );
-
-
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* PORTAUDIO_H */
diff --git a/pjmedia/src/pjmedia/portaudio/ringbuffer.c b/pjmedia/src/pjmedia/portaudio/ringbuffer.c
deleted file mode 100644
index c66ec613..00000000
--- a/pjmedia/src/pjmedia/portaudio/ringbuffer.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * $Id$
- * ringbuffer.c
- * Ring Buffer utility..
- *
- * Author: Phil Burk, http://www.softsynth.com
- * modified for SMP safety on Mac OS X by Bjorn Roche
- * also, alowed 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 hostapi_src
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include "ringbuffer.h"
-#include <string.h>
-
-/*
- * We can undefine this, to turn off memory barriers, but that
- * is only useful if we know we don't need to be MP safe or
- * we are interested in doing some kind of tests.
- */
-#define MPSAFE
-
-/****************
- * First, we'll define some memory barrier primitives based on the system.
- * right now only OS X and FreeBSD 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:
- *
- * FullMemoryBarrier()
- * ReadMemoryBarrier()
- * WriteMemoryBarrier()
- *
- ****************/
-
-#if 1
-# define FullMemoryBarrier()
-# define ReadMemoryBarrier()
-# define WriteMemoryBarrier()
-#elif 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.
- The asm volatile may be redundant with the memory barrier, but
- until I have proof of that, I'm leaving it. */
-# define FullMemoryBarrier() do{ asm volatile("":::"memory"); OSMemoryBarrier(); }while(false)
-# define ReadMemoryBarrier() do{ asm volatile("":::"memory"); OSMemoryBarrier(); }while(false)
-# define WriteMemoryBarrier() do{ asm volatile("":::"memory"); OSMemoryBarrier(); }while(false)
-#else
-# error Memory Barriers not defined on this system or system unknown
-#endif
-
-/***************************************************************************
- * Initialize FIFO.
- * numBytes must be power of 2, returns -1 if not.
- */
-long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
-{
- if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */
- rbuf->bufferSize = numBytes;
- rbuf->buffer = (char *)dataPtr;
- RingBuffer_Flush( rbuf );
- rbuf->bigMask = (numBytes*2)-1;
- rbuf->smallMask = (numBytes)-1;
- return 0;
-}
-/***************************************************************************
-** Return number of bytes available for reading. */
-long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
-{
-#ifdef MPSAFE
- ReadMemoryBarrier();
-#endif
- return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
-}
-/***************************************************************************
-** Return number of bytes available for writing. */
-long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )
-{
- /* Since we are calling RingBuffer_GetReadAvailable, we don't need an aditional MB */
- return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
-}
-
-/***************************************************************************
-** Clear buffer. Should only be called when buffer is NOT being read. */
-void RingBuffer_Flush( RingBuffer *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 RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
- void **dataPtr1, long *sizePtr1,
- void **dataPtr2, long *sizePtr2 )
-{
- long index;
- long available = RingBuffer_GetWriteAvailable( 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 RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
-{
-#ifdef MPSAFE
- /* we need to ensure that previous writes are seen before we update the write index */
- WriteMemoryBarrier();
- return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
-#else
- return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
-#endif
-}
-
-/***************************************************************************
-** 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 RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
- void **dataPtr1, long *sizePtr1,
- void **dataPtr2, long *sizePtr2 )
-{
- long index;
- long available = RingBuffer_GetReadAvailable( 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 RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
-{
-#ifdef MPSAFE
- /* we need to ensure that previous writes are always seen before updating the index. */
- WriteMemoryBarrier();
- return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
-#else
- return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
-#endif
-}
-
-/***************************************************************************
-** Return bytes written. */
-long RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes )
-{
- long size1, size2, numWritten;
- void *data1, *data2;
- numWritten = RingBuffer_GetWriteRegions( 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 );
- }
- RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
- return numWritten;
-}
-
-/***************************************************************************
-** Return bytes read. */
-long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
-{
- long size1, size2, numRead;
- void *data1, *data2;
- numRead = RingBuffer_GetReadRegions( 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 );
- }
- RingBuffer_AdvanceReadIndex( rbuf, numRead );
- return numRead;
-}
diff --git a/pjmedia/src/pjmedia/portaudio/ringbuffer.h b/pjmedia/src/pjmedia/portaudio/ringbuffer.h
deleted file mode 100644
index 816520e3..00000000
--- a/pjmedia/src/pjmedia/portaudio/ringbuffer.h
+++ /dev/null
@@ -1,117 +0,0 @@
-#ifndef _RINGBUFFER_H
-#define _RINGBUFFER_H
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-/*
- * $Id$
- * ringbuffer.h
- * 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 hostapi_src
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include "ringbuffer.h"
-#include <string.h>
-
-typedef struct
-{
- long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
- long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
- long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
- long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
- long smallMask; /* Used for fitting indices to buffer. */
- char * buffer;
-}
-RingBuffer;
-/*
- * Initialize Ring Buffer.
- * numBytes must be power of 2, returns -1 if not.
- */
-long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
-
-/* Clear buffer. Should only be called when buffer is NOT being read. */
-void RingBuffer_Flush( RingBuffer *rbuf );
-
-/* Return number of bytes available for writing. */
-long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
-/* Return number of bytes available for read. */
-long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
-/* Return bytes written. */
-long RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes );
-/* Return bytes read. */
-long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
-
-/* 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 RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
- void **dataPtr1, long *sizePtr1,
- void **dataPtr2, long *sizePtr2 );
-long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
-
-/* 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 RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
- void **dataPtr1, long *sizePtr1,
- void **dataPtr2, long *sizePtr2 );
-
-long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* _RINGBUFFER_H */