diff --git a/libs/portaudio/Makefile.am b/libs/portaudio/Makefile.am deleted file mode 100644 index d8fe856ba79ed1bbdc8c635c54260b6cbc87710b..0000000000000000000000000000000000000000 --- a/libs/portaudio/Makefile.am +++ /dev/null @@ -1,62 +0,0 @@ -noinst_LTLIBRARIES = libportaudio.la -libportaudio_la_CFLAGS = $(PORTAUDIO_CFLAGS) -Ipa_common/ -libportaudio_la_LIBADD = $(PORTAUDIO) $(PORTAUDIO_LIBS) -libportaudio_la_CXXFLAGS = $(PORTAUDIO_CFLAGS) -libportaudio_la_CPPFLAGS = $(PORTAUDIO_CPPFLAGS) - -if ENABLE_OSS -OSS=pa_unix_oss/pa_unix_oss.c -else -OSS= -endif - -if ENABLE_UNIX -UNIX=pa_unix/pa_unix_hostapis.c pa_unix/pa_unix_util.c -else -UNIX= -endif - -if ENABLE_DARWIN -DARWIN=pa_mac/pa_mac_hostapis.c pa_unix/pa_unix_util.c pa_mac_core/pa_mac_core.c -else -DARWIN= -endif - -if ENABLE_ALSA -ALSA=pa_linux_alsa/pa_linux_alsa.c -else -ALSA= -endif - -if ENABLE_JACK -JACK=pa_jack/pa_jack.c pablio/ringbuffer.c -else -JACK= -endif - -#if ENABLE_ASIO -#ASIO=pa_asio/iasiothiscallresolver.cpp $(ASIODIR)/host/asiodrivers.c $(ASIODIR)/common/asio.c $(ASIODIR)/host/mac/asioshlib.c -#else -ASIO= -#endif - -PLATFORM_SOURCES=$(OSS) $(UNIX) $(ALSA) $(DARWIN) $(JACK) $(ASIO) - -noinst_HEADERS = pa_common/portaudio.h \ -pa_common/pa_allocation.h pa_common/pa_dither.h pa_common/pa_process.h pa_common/pa_types.h \ -pa_common/pa_converters.h pa_common/pa_endianness.h pa_common/pa_stream.h pa_common/pa_util.h \ -pa_common/pa_cpuload.h pa_common/pa_hostapi.h pa_common/pa_trace.h pa_common/portaudio.h \ -pa_unix/pa_unix_util.h pa_linux_alsa/pa_linux_alsa.h \ -pablio/ringbuffer.h - -libportaudio_la_SOURCES = $(PLATFORM_SOURCES) \ - pa_common/pa_allocation.c \ - pa_common/pa_converters.c \ - pa_common/pa_cpuload.c \ - pa_common/pa_dither.c \ - pa_common/pa_front.c \ - pa_common/pa_process.c \ - pa_common/pa_skeleton.c \ - pa_common/pa_stream.c \ - pa_common/pa_trace.c - diff --git a/libs/portaudio/pa_asio/iasiothiscallresolver.h b/libs/portaudio/pa_asio/iasiothiscallresolver.h deleted file mode 100644 index 2ecfed799aece45fa32ee15140f30705de9b5ec0..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_asio/iasiothiscallresolver.h +++ /dev/null @@ -1,197 +0,0 @@ -// **************************************************************************** -// File: IASIOThiscallResolver.h -// Description: The IASIOThiscallResolver class implements the IASIO -// interface and acts as a proxy to the real IASIO interface by -// calling through its vptr table using the thiscall calling -// convention. To put it another way, we interpose -// IASIOThiscallResolver between ASIO SDK code and the driver. -// This is necessary because most non-Microsoft compilers don't -// implement the thiscall calling convention used by IASIO. -// -// iasiothiscallresolver.cpp contains the background of this -// problem plus a technical description of the vptr -// manipulations. -// -// In order to use this mechanism one simply has to add -// iasiothiscallresolver.cpp to the list of files to compile -// and #include <iasiothiscallresolver.h> -// -// Note that this #include must come after the other ASIO SDK -// #includes, for example: -// -// #include <windows.h> -// #include <asiosys.h> -// #include <asio.h> -// #include <asiodrivers.h> -// #include <iasiothiscallresolver.h> -// -// Actually the important thing is to #include -// <iasiothiscallresolver.h> after <asio.h>. We have -// incorporated a test to enforce this ordering. -// -// The code transparently takes care of the interposition by -// using macro substitution to intercept calls to ASIOInit() -// and ASIOExit(). We save the original ASIO global -// "theAsioDriver" in our "that" variable, and then set -// "theAsioDriver" to equal our IASIOThiscallResolver instance. -// -// Whilst this method of resolving the thiscall problem requires -// the addition of #include <iasiothiscallresolver.h> to client -// code it has the advantage that it does not break the terms -// of the ASIO licence by publishing it. We are NOT modifying -// any Steinberg code here, we are merely implementing the IASIO -// interface in the same way that we would need to do if we -// wished to provide an open source ASIO driver. -// -// For compilation with MinGW -lole32 needs to be added to the -// linker options. For BORLAND, linking with Import32.lib is -// sufficient. -// -// The dependencies are with: CoInitialize, CoUninitialize, -// CoCreateInstance, CLSIDFromString - used by asiolist.cpp -// and are required on Windows whether ThiscallResolver is used -// or not. -// -// Searching for the above strings in the root library path -// of your compiler should enable the correct libraries to be -// identified if they aren't immediately obvious. -// -// Note that the current implementation of IASIOThiscallResolver -// is not COM compliant - it does not correctly implement the -// IUnknown interface. Implementing it is not necessary because -// it is not called by parts of the ASIO SDK which call through -// theAsioDriver ptr. The IUnknown methods are implemented as -// assert(false) to ensure that the code fails if they are -// ever called. -// Restrictions: None. Public Domain & Open Source distribute freely -// You may use IASIOThiscallResolver commercially as well as -// privately. -// You the user assume the responsibility for the use of the -// files, binary or text, and there is no guarantee or warranty, -// expressed or implied, including but not limited to the -// implied warranties of merchantability and fitness for a -// particular purpose. You assume all responsibility and agree -// to hold no entity, copyright holder or distributors liable -// for any loss of data or inaccurate representations of data -// as a result of using IASIOThiscallResolver. -// Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from -// Andrew Baldwin, and volatile for whole gcc asm blocks, -// both for compatibility with newer gcc versions. Cleaned up -// Borland asm to use one less register. -// 1.3 Switched to including assert.h for better compatibility. -// Wrapped entire .h and .cpp contents with a check for -// _MSC_VER to provide better compatibility with MS compilers. -// Changed Singleton implementation to use static instance -// instead of freestore allocated instance. Removed ASIOExit -// macro as it is no longer needed. -// 1.2 Removed semicolons from ASIOInit and ASIOExit macros to -// allow them to be embedded in expressions (if statements). -// Cleaned up some comments. Removed combase.c dependency (it -// doesn't compile with BCB anyway) by stubbing IUnknown. -// 1.1 Incorporated comments from Ross Bencina including things -// such as changing name from ThiscallResolver to -// IASIOThiscallResolver, tidying up the constructor, fixing -// a bug in IASIOThiscallResolver::ASIOExit() and improving -// portability through the use of conditional compilation -// 1.0 Initial working version. -// Created: 6/09/2003 -// Authors: Fraser Adams -// Ross Bencina -// Rene G. Ceballos -// Martin Fay -// Antti Silvast -// Andrew Baldwin -// -// **************************************************************************** - - -#ifndef included_iasiothiscallresolver_h -#define included_iasiothiscallresolver_h - -// We only need IASIOThiscallResolver at all if we are on Win32. For other -// platforms we simply bypass the IASIOThiscallResolver definition to allow us -// to be safely #include'd whatever the platform to keep client code portable -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) - - -// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver -// is not used. -#if !defined(_MSC_VER) - - -// The following is in order to ensure that this header is only included after -// the other ASIO headers (except for the case of iasiothiscallresolver.cpp). -// We need to do this because IASIOThiscallResolver works by eclipsing the -// original definition of ASIOInit() with a macro (see below). -#if !defined(iasiothiscallresolver_sourcefile) - #if !defined(__ASIO_H) - #error iasiothiscallresolver.h must be included AFTER asio.h - #endif -#endif - -#include <windows.h> -#include <asiodrvr.h> /* From ASIO SDK */ - - -class IASIOThiscallResolver : public IASIO { -private: - IASIO* that_; // Points to the real IASIO - - static IASIOThiscallResolver instance; // Singleton instance - - // Constructors - declared private so construction is limited to - // our Singleton instance - IASIOThiscallResolver(); - IASIOThiscallResolver(IASIO* that); -public: - - // Methods from the IUnknown interface. We don't fully implement IUnknown - // because the ASIO SDK never calls these methods through theAsioDriver ptr. - // These methods are implemented as assert(false). - virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv); - virtual ULONG STDMETHODCALLTYPE AddRef(); - virtual ULONG STDMETHODCALLTYPE Release(); - - // Methods from the IASIO interface, implemented as forwarning calls to that. - virtual ASIOBool init(void *sysHandle); - virtual void getDriverName(char *name); - virtual long getDriverVersion(); - virtual void getErrorMessage(char *string); - virtual ASIOError start(); - virtual ASIOError stop(); - virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels); - virtual ASIOError getLatencies(long *inputLatency, long *outputLatency); - virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity); - virtual ASIOError canSampleRate(ASIOSampleRate sampleRate); - virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate); - virtual ASIOError setSampleRate(ASIOSampleRate sampleRate); - virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources); - virtual ASIOError setClockSource(long reference); - virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp); - virtual ASIOError getChannelInfo(ASIOChannelInfo *info); - virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks); - virtual ASIOError disposeBuffers(); - virtual ASIOError controlPanel(); - virtual ASIOError future(long selector,void *opt); - virtual ASIOError outputReady(); - - // Class method, see ASIOInit() macro below. - static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit -}; - - -// Replace calls to ASIOInit with our interposing version. -// This macro enables us to perform thiscall resolution simply by #including -// <iasiothiscallresolver.h> after the asio #includes (this file _must_ be -// included _after_ the asio #includes) - -#define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name)) - - -#endif /* !defined(_MSC_VER) */ - -#endif /* Win32 */ - -#endif /* included_iasiothiscallresolver_h */ - - diff --git a/libs/portaudio/pa_asio/pa_asio.h b/libs/portaudio/pa_asio/pa_asio.h deleted file mode 100644 index 573930572423c5b08dd942ba87fc968664569312..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_asio/pa_asio.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef PA_ASIO_H -#define PA_ASIO_H -/* - * $Id$ - * PortAudio Portable Real-Time Audio Library - * ASIO 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 ASIO-specific PortAudio API extension header file. -*/ - - -#include "portaudio.h" - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - - -/** Retrieve legal latency settings for the specificed device, in samples. - - @param device The global index of the device about which the query is being made. - @param minLatency A pointer to the location which will recieve the minimum latency value. - @param maxLatency A pointer to the location which will recieve the maximum latency value. - @param preferredLatency A pointer to the location which will recieve the preferred latency value. - @param granularity A pointer to the location which will recieve the granularity. This value - determines which values between minLatency and maxLatency are available. ie the step size, - if granularity is -1 then available latency settings are powers of two. - - @see ASIOGetBufferSize in the ASIO SDK. - - @todo This function should have a better name, any suggestions? -*/ -PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device, - long *minLatency, long *maxLatency, long *preferredLatency, long *granularity ); - - -/** Display the ASIO control panel for the specified device. - - @param device The global index of the device whose control panel is to be displayed. - @param systemSpecific On Windows, the calling application's main window handle, - on Macintosh this value should be zero. -*/ -PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific ); - - - - -/** Retrieve a pointer to a string containing the name of the specified - input channel. The string is valid until Pa_Terminate is called. - - The string will be no longer than 32 characters including the null terminator. -*/ -PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex, - const char** channelName ); - - -/** Retrieve a pointer to a string containing the name of the specified - input channel. The string is valid until Pa_Terminate is called. - - The string will be no longer than 32 characters including the null terminator. -*/ -PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex, - const char** channelName ); - - -#define paAsioUseChannelSelectors (0x01) - -typedef struct PaAsioStreamInfo{ - unsigned long size; /**< sizeof(PaAsioStreamInfo) */ - PaHostApiTypeId hostApiType; /**< paASIO */ - unsigned long version; /**< 1 */ - - unsigned long flags; - - /* Support for opening only specific channels of an ASIO device. - If the paAsioUseChannelSelectors flag is set, channelSelectors is a - pointer to an array of integers specifying the device channels to use. - When used, the length of the channelSelectors array must match the - corresponding channelCount parameter to Pa_OpenStream() otherwise a - crash may result. - The values in the selectors array must specify channels within the - range of supported channels for the device or paInvalidChannelCount will - result. - */ - int *channelSelectors; -}PaAsioStreamInfo; - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* PA_ASIO_H */ diff --git a/libs/portaudio/pa_common/pa_allocation.c b/libs/portaudio/pa_common/pa_allocation.c deleted file mode 100644 index 98239c48f00400932a826763f1b87c39cacabc0a..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_allocation.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_allocation.h b/libs/portaudio/pa_common/pa_allocation.h deleted file mode 100644 index 5bcfe75a67674da671de89962c866b6fc5c46285..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_allocation.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef PA_ALLOCATION_H -#define PA_ALLOCATION_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_converters.c b/libs/portaudio/pa_common/pa_converters.c deleted file mode 100644 index 39f83e481943297ad8bc67edd21712487d316a9d..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_converters.c +++ /dev/null @@ -1,1926 +0,0 @@ -/* - * $Id$ - * 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; - PaInt32 *dest = (PaInt32*)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 = (PaInt32) 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; - PaInt32 *dest = (PaInt32*)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 = (PaInt32) 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; - PaInt32 *dest = (PaInt32*)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 = (PaInt32) 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; - PaInt32 *dest = (PaInt32*)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 = (PaInt32) 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; - PaInt32 temp; - - (void) ditherGenerator; /* unused parameter */ - - while( count-- ) - { - /* convert to 32 bit and drop the low 8 bits */ - double scaled = *src * 0x7FFFFFFF; - temp = (PaInt32) 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; - PaInt32 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 = (PaInt32) 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; - PaInt32 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 = (PaInt32) 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; - PaInt32 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 = (PaInt32) 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; - PaInt16 *dest = (PaInt16*)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; - PaInt16 *dest = (PaInt16*)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 = (PaInt16) 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; - PaInt16 *dest = (PaInt16*)destinationBuffer; - (void)ditherGenerator; /* unused parameter */ - - while( count-- ) - { -#ifdef PA_USE_C99_LRINTF - long samp = lrintf((*src * (32767.0f)) -0.5f); -#else - long samp = (PaInt32) (*src * (32767.0f)); -#endif - PA_CLIP_( samp, -0x8000, 0x7FFF ); - *dest = (PaInt16) 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; - PaInt16 *dest = (PaInt16*)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; - PaInt32 samp = (PaInt32) dithered; - PA_CLIP_( samp, -0x8000, 0x7FFF ); -#ifdef PA_USE_C99_LRINTF - *dest = lrintf(samp-0.5f); -#else - *dest = (PaInt16) 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; - PaInt32 samp = (PaInt32) 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-- ) - { - PaInt32 samp = (PaInt32)(*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; - PaInt32 samp = (PaInt32) 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 ) -{ - PaInt32 *src = (PaInt32*)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 ) -{ - PaInt32 *src = (PaInt32*)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 ) -{ - PaInt32 *src = (PaInt32*)sourceBuffer; - PaInt16 *dest = (PaInt16*)destinationBuffer; - (void)ditherGenerator; /* unused parameter */ - - while( count-- ) - { - *dest = (PaInt16) ((*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 ) -{ - PaInt32 *src = (PaInt32*)sourceBuffer; - PaInt16 *dest = (PaInt16*)destinationBuffer; - PaInt32 dither; - - while( count-- ) - { - /* REVIEW */ - dither = PaUtil_Generate16BitTriangularDither( ditherGenerator ); - *dest = (PaInt16) ((((*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 ) -{ - PaInt32 *src = (PaInt32*)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 ) -{ - PaInt32 *src = (PaInt32*)sourceBuffer; - signed char *dest = (signed char*)destinationBuffer; - PaInt32 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 ) -{ - PaInt32 *src = (PaInt32*)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 ) -{ - PaInt32 *src = (PaInt32*)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; - PaInt32 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; - PaInt32 *dest = (PaInt32*) destinationBuffer; - PaInt32 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; - PaInt16 *dest = (PaInt16*)destinationBuffer; - - PaInt16 temp; - - (void) ditherGenerator; /* unused parameter */ - - while( count-- ) - { - -#if defined(PA_LITTLE_ENDIAN) - /* src[0] is discarded */ - temp = (((PaInt16)src[1])); - temp = temp | (PaInt16)(((PaInt16)src[2]) << 8); -#elif defined(PA_BIG_ENDIAN) - /* src[2] is discarded */ - temp = (PaInt16)(((PaInt16)src[0]) << 8); - temp = temp | (((PaInt16)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 ) -{ - PaInt16 *src = (PaInt16*)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 ) -{ - PaInt16 *src = (PaInt16*)sourceBuffer; - PaInt32 *dest = (PaInt32*)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 ) -{ - PaInt16 *src = (PaInt16*) sourceBuffer; - unsigned char *dest = (unsigned char*)destinationBuffer; - PaInt16 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 ) -{ - PaInt16 *src = (PaInt16*)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 ) -{ - PaInt16 *src = (PaInt16*)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 ) -{ - PaInt16 *src = (PaInt16*)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 ) -{ - PaInt16 *src = (PaInt16*)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; - PaInt32 *dest = (PaInt32*)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; - PaInt16 *dest = (PaInt16*)destinationBuffer; - (void)ditherGenerator; /* unused parameter */ - - while( count-- ) - { - (*dest) = (PaInt16)((*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; - PaInt32 *dest = (PaInt32*)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; - PaInt16 *dest = (PaInt16*)destinationBuffer; - (void)ditherGenerator; /* unused parameter */ - - while( count-- ) - { - (*dest) = (PaInt16)((*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; - - (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/libs/portaudio/pa_common/pa_converters.h b/libs/portaudio/pa_common/pa_converters.h deleted file mode 100644 index 1d83c990bb48f3355801019aa914062d982bbefd..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_converters.h +++ /dev/null @@ -1,254 +0,0 @@ -#ifndef PA_CONVERTERS_H -#define PA_CONVERTERS_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_cpuload.c b/libs/portaudio/pa_common/pa_cpuload.c deleted file mode 100644 index ee2147dc33fdfbda07255729acd5d8b79560f8e0..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_cpuload.c +++ /dev/null @@ -1,96 +0,0 @@ -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_cpuload.h b/libs/portaudio/pa_common/pa_cpuload.h deleted file mode 100644 index 131ad10bd30f706048328f6fe08430fbe7ca0197..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_cpuload.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef PA_CPULOAD_H -#define PA_CPULOAD_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_dither.c b/libs/portaudio/pa_common/pa_dither.c deleted file mode 100644 index d44a060cd20312368973143e278d170556e77a3b..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_dither.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_dither.h b/libs/portaudio/pa_common/pa_dither.h deleted file mode 100644 index 148db275fb8b77c3dbd51e19ae68cd537e5d08d9..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_dither.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef PA_DITHER_H -#define PA_DITHER_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_endianness.h b/libs/portaudio/pa_common/pa_endianness.h deleted file mode 100644 index 3a573929b36edbf657441b868039bfee700e6752..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_endianness.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef PA_ENDIANNESS_H -#define PA_ENDIANNESS_H -/* - * $Id$ - * 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 */ - - -#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/libs/portaudio/pa_common/pa_front.c b/libs/portaudio/pa_common/pa_front.c deleted file mode 100644 index 3b4a026b5524e31fa88d9f87cda7bf1c1fdd0ebc..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_front.c +++ /dev/null @@ -1,1976 +0,0 @@ -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_hostapi.h b/libs/portaudio/pa_common/pa_hostapi.h deleted file mode 100644 index fec4e4871bbd7bce7a46237a139fee10644bdc8b..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_hostapi.h +++ /dev/null @@ -1,244 +0,0 @@ -#ifndef PA_HOSTAPI_H -#define PA_HOSTAPI_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_process.c b/libs/portaudio/pa_common/pa_process.c deleted file mode 100644 index 837bbef35b66bf1fcfee2e60fc75008b8f7cde76..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_process.c +++ /dev/null @@ -1,1763 +0,0 @@ -/* - * $Id$ - * 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; - - if( streamFlags & paNeverDropInput ) - { - /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */ - if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) || - framesPerUserBuffer != paFramesPerBufferUnspecified ) - return paInvalidFlag; - } - - /* 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 ); - assert( data != NULL ); - - 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 ) - { - PaUtil_SetOutputChannel( bp, channel + i, p, channelCount ); - p += bp->bytesPerHostOutputSample; - } -} - - -void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data ) -{ - assert( channel < bp->outputChannelCount ); - - PaUtil_SetOutputChannel( bp, channel, data, 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 ); - assert( data != NULL ); - - 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 ) - { - PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount ); - p += bp->bytesPerHostOutputSample; - } -} - - -void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp, - unsigned int channel, void *data ) -{ - assert( channel < bp->outputChannelCount ); - - PaUtil_Set2ndOutputChannel( bp, channel, data, 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 ) - { - assert( hostOutputChannels[i].data != NULL ); - 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/libs/portaudio/pa_common/pa_process.h b/libs/portaudio/pa_common/pa_process.h deleted file mode 100644 index 8d13d903a4428416ec1d176f8afc548509006bb4..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_process.h +++ /dev/null @@ -1,741 +0,0 @@ -#ifndef PA_PROCESS_H -#define PA_PROCESS_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_skeleton.c b/libs/portaudio/pa_common/pa_skeleton.c deleted file mode 100644 index 51f95c8a3201d5605baf89dece660c402e8c9a7e..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_skeleton.c +++ /dev/null @@ -1,807 +0,0 @@ -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_stream.c b/libs/portaudio/pa_common/pa_stream.c deleted file mode 100644 index e820671bc1c5b0daf47b364d94ff0d8471f8f8d3..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_stream.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_stream.h b/libs/portaudio/pa_common/pa_stream.h deleted file mode 100644 index aaf89cf210c6f02367b1fbc57176c73a7d64b930..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_stream.h +++ /dev/null @@ -1,196 +0,0 @@ -#ifndef PA_STREAM_H -#define PA_STREAM_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_trace.c b/libs/portaudio/pa_common/pa_trace.c deleted file mode 100644 index 6619d423af4a3106418d331cae8b74fcbc35280c..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_trace.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * $Id$ - * 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[PA_MAX_TRACE_RECORDS]; -static int traceIntArray[PA_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] ); - } - PaUtil_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/libs/portaudio/pa_common/pa_trace.h b/libs/portaudio/pa_common/pa_trace.h deleted file mode 100644 index 256c3e6911bf887d76b5a36d9ed9a972ab34f81f..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_trace.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef PA_TRACE_H -#define PA_TRACE_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/pa_types.h b/libs/portaudio/pa_common/pa_types.h deleted file mode 100644 index 343dc8cf8a69284ef906fe62c7e76f7a3eb8fb35..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/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/libs/portaudio/pa_common/pa_util.h b/libs/portaudio/pa_common/pa_util.h deleted file mode 100644 index 4d060d814a7f95891c45e5eb5b251e25af230109..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/pa_util.h +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef PA_UTIL_H -#define PA_UTIL_H -/* - * $Id$ - * 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/libs/portaudio/pa_common/portaudio.h b/libs/portaudio/pa_common/portaudio.h deleted file mode 100644 index ac071d7eac66743eb495fdeb69a25d0195ec784d..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_common/portaudio.h +++ /dev/null @@ -1,1123 +0,0 @@ - -#ifndef PORTAUDIO_H -#define PORTAUDIO_H -/* - * $Id$ - * 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 = -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/libs/portaudio/pa_jack/pa_jack.c b/libs/portaudio/pa_jack/pa_jack.c deleted file mode 100644 index 17bf3d371bcd1937232f9f495536d03af5197165..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_jack/pa_jack.c +++ /dev/null @@ -1,1714 +0,0 @@ -/* - * $Id$ - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * JACK Implementation by Joshua Haberman - * - * Copyright (c) 2004 Stefan Westerfeld <stefan@space.twc.de> - * Copyright (c) 2004 Arve Knudsen <aknuds-1@broadpark.no> - * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com> - * - * 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 <string.h> -#include <regex.h> -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <sys/types.h> -#include <unistd.h> -#include <errno.h> /* EBUSY */ -#include <signal.h> /* sig_atomic_t */ -#include <math.h> -#include <semaphore.h> - -#include <jack/types.h> -#include <jack/jack.h> - -#include "pa_util.h" -#include "pa_hostapi.h" -#include "pa_stream.h" -#include "pa_process.h" -#include "pa_allocation.h" -#include "pa_cpuload.h" -#include "../pablio/ringbuffer.c" - -static int aErr_; -static PaError paErr_; /* For use with ENSURE_PA */ -static pthread_t mainThread_; -static char *jackErr_ = NULL; - -#define STRINGIZE_HELPER(expr) #expr -#define STRINGIZE(expr) STRINGIZE_HELPER(expr) - -/* Check PaError */ -#define ENSURE_PA(expr) \ - do { \ - if( (paErr_ = (expr)) < paNoError ) \ - { \ - if( (paErr_) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ - { \ - assert( jackErr_ ); \ - PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \ - } \ - PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ - result = paErr_; \ - goto error; \ - } \ - } while( 0 ) - -#define UNLESS(expr, code) \ - do { \ - if( (expr) == 0 ) \ - { \ - if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ - { \ - assert( jackErr_ ); \ - PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \ - } \ - 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 ); - -/* - * Functions that directly map to the PortAudio stream interface - */ - -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 GetStreamInputLatency( PaStream *stream );*/ -/*static PaTime GetStreamOutputLatency( PaStream *stream );*/ -static PaTime GetStreamTime( PaStream *stream ); -static double GetStreamCpuLoad( PaStream* stream ); - - -/* - * Data specific to this API - */ - -struct PaJackStream; - -typedef struct -{ - PaUtilHostApiRepresentation commonHostApiRep; - PaUtilStreamInterface callbackStreamInterface; - PaUtilStreamInterface blockingStreamInterface; - - PaUtilAllocationGroup *deviceInfoMemory; - - jack_client_t *jack_client; - int jack_buffer_size; - PaHostApiIndex hostApiIndex; - - pthread_mutex_t mtx; - pthread_cond_t cond; - unsigned long inputBase, outputBase; - - /* For dealing with the process thread */ - volatile int xrun; /* Received xrun notification from JACK? */ - struct PaJackStream * volatile toAdd, * volatile toRemove; - struct PaJackStream *processQueue; - volatile sig_atomic_t jackIsDown; -} -PaJackHostApiRepresentation; - -/* PaJackStream - a stream data structure specifically for this implementation */ - -typedef struct PaJackStream -{ - PaUtilStreamRepresentation streamRepresentation; - PaUtilBufferProcessor bufferProcessor; - PaUtilCpuLoadMeasurer cpuLoadMeasurer; - PaJackHostApiRepresentation *hostApi; - - /* our input and output ports */ - jack_port_t **local_input_ports; - jack_port_t **local_output_ports; - - /* the input and output ports of the client we are connecting to */ - jack_port_t **remote_input_ports; - jack_port_t **remote_output_ports; - - int num_incoming_connections; - int num_outgoing_connections; - - jack_client_t *jack_client; - - /* The stream is running if it's still producing samples. - * The stream is active if samples it produced are still being heard. - */ - volatile sig_atomic_t is_running; - volatile sig_atomic_t is_active; - /* Used to signal processing thread that stream should start or stop, respectively */ - volatile sig_atomic_t doStart, doStop, doAbort; - - jack_nframes_t t0; - - PaUtilAllocationGroup *stream_memory; - - /* These are useful in the process callback */ - - int callbackResult; - int isSilenced; - int xrun; - - /* These are useful for the blocking API */ - - int isBlockingStream; - RingBuffer inFIFO; - RingBuffer outFIFO; - volatile sig_atomic_t data_available; - sem_t data_semaphore; - int bytesPerFrame; - int samplesPerFrame; - - struct PaJackStream *next; -} -PaJackStream; - -#define TRUE 1 -#define FALSE 0 - -/* - * Functions specific to this API - */ - -static int JackCallback( jack_nframes_t frames, void *userData ); - - -/* - * - * Implementation - * - */ - -/* ---- blocking emulation layer ---- */ - -/* Allocate buffer. */ -static PaError BlockingInitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame ) -{ - long numBytes = numFrames * bytesPerFrame; - char *buffer = (char *) malloc( numBytes ); - if( buffer == NULL ) return paInsufficientMemory; - memset( buffer, 0, numBytes ); - return (PaError) RingBuffer_Init( rbuf, numBytes, buffer ); -} - -/* Free buffer. */ -static PaError BlockingTermFIFO( RingBuffer *rbuf ) -{ - if( rbuf->buffer ) free( rbuf->buffer ); - rbuf->buffer = NULL; - return paNoError; -} - -static int -BlockingCallback( const void *inputBuffer, - void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData ) -{ - struct PaJackStream *stream = (PaJackStream *)userData; - long numBytes = stream->bytesPerFrame * framesPerBuffer; - - /* This may get called with NULL inputBuffer during initial setup. */ - if( inputBuffer != NULL ) - { - RingBuffer_Write( &stream->inFIFO, inputBuffer, numBytes ); - } - if( outputBuffer != NULL ) - { - int numRead = RingBuffer_Read( &stream->outFIFO, outputBuffer, numBytes ); - /* Zero out remainder of buffer if we run out of data. */ - memset( (char *)outputBuffer + numRead, 0, numBytes - numRead ); - } - - if( !stream->data_available ) - { - stream->data_available = 1; - sem_post( &stream->data_semaphore ); - } - return paContinue; -} - -static PaError -BlockingBegin( PaJackStream *stream, int minimum_buffer_size ) -{ - long doRead = 0; - long doWrite = 0; - PaError result = paNoError; - long numFrames; - - doRead = stream->local_input_ports != NULL; - doWrite = stream->local_output_ports != NULL; - /* <FIXME> */ - stream->samplesPerFrame = 2; - stream->bytesPerFrame = sizeof(float) * stream->samplesPerFrame; - /* </FIXME> */ - numFrames = 32; - while (numFrames < minimum_buffer_size) - numFrames *= 2; - - if( doRead ) - { - ENSURE_PA( BlockingInitFIFO( &stream->inFIFO, numFrames, stream->bytesPerFrame ) ); - } - if( doWrite ) - { - long numBytes; - - ENSURE_PA( BlockingInitFIFO( &stream->outFIFO, numFrames, stream->bytesPerFrame ) ); - - /* Make Write FIFO appear full initially. */ - numBytes = RingBuffer_GetWriteAvailable( &stream->outFIFO ); - RingBuffer_AdvanceWriteIndex( &stream->outFIFO, numBytes ); - } - - stream->data_available = 0; - sem_init( &stream->data_semaphore, 0, 0 ); - -error: - return result; -} - -static void -BlockingEnd( PaJackStream *stream ) -{ - BlockingTermFIFO( &stream->inFIFO ); - BlockingTermFIFO( &stream->outFIFO ); - - sem_destroy( &stream->data_semaphore ); -} - -static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames ) -{ - PaError result = paNoError; - PaJackStream *stream = (PaJackStream *)s; - - long bytesRead; - char *p = (char *) data; - long numBytes = stream->bytesPerFrame * numFrames; - while( numBytes > 0 ) - { - bytesRead = RingBuffer_Read( &stream->inFIFO, p, numBytes ); - numBytes -= bytesRead; - p += bytesRead; - if( numBytes > 0 ) - { - /* see write for an explanation */ - if( stream->data_available ) - stream->data_available = 0; - else - sem_wait( &stream->data_semaphore ); - } - } - - return result; -} - -static PaError BlockingWriteStream( PaStream* s, const void *data, unsigned long numFrames ) -{ - PaError result = paNoError; - PaJackStream *stream = (PaJackStream *)s; - long bytesWritten; - char *p = (char *) data; - long numBytes = stream->bytesPerFrame * numFrames; - while( numBytes > 0 ) - { - bytesWritten = RingBuffer_Write( &stream->outFIFO, p, numBytes ); - numBytes -= bytesWritten; - p += bytesWritten; - if( numBytes > 0 ) - { - /* we use the following algorithm: - * (1) write data - * (2) if some data didn't fit into the ringbuffer, set data_available to 0 - * to indicate to the audio that if space becomes available, we want to know - * (3) retry to write data (because it might be that between (1) and (2) - * new space in the buffer became available) - * (4) if this failed, we are sure that the buffer is really empty and - * we will definitely receive a notification when it becomes available - * thus we can safely sleep - * - * if the algorithm bailed out in step (3) before, it leaks a count of 1 - * on the semaphore; however, it doesn't matter, because if we block in (4), - * we also do it in a loop - */ - if( stream->data_available ) - stream->data_available = 0; - else - sem_wait( &stream->data_semaphore ); - } - } - - return result; -} - -static signed long -BlockingGetStreamReadAvailable( PaStream* s ) -{ - PaJackStream *stream = (PaJackStream *)s; - - int bytesFull = RingBuffer_GetReadAvailable( &stream->inFIFO ); - return bytesFull / stream->bytesPerFrame; -} - -static signed long -BlockingGetStreamWriteAvailable( PaStream* s ) -{ - PaJackStream *stream = (PaJackStream *)s; - - int bytesEmpty = RingBuffer_GetWriteAvailable( &stream->outFIFO ); - return bytesEmpty / stream->bytesPerFrame; -} - -static PaError -BlockingWaitEmpty( PaStream *s ) -{ - PaJackStream *stream = (PaJackStream *)s; - - while( RingBuffer_GetReadAvailable( &stream->outFIFO ) > 0 ) - { - stream->data_available = 0; - sem_wait( &stream->data_semaphore ); - } - return 0; -} - -/* ---- jack driver ---- */ - -/* BuildDeviceList(): - * - * The process of determining a list of PortAudio "devices" from - * JACK's client/port system is fairly involved, so it is separated - * into its own routine. - */ - -static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi ) -{ - /* Utility macros for the repetitive process of allocating memory */ - - /* ... MALLOC: allocate memory as part of the device list - * allocation group */ -#define MALLOC(size) \ - (PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, (size) )) - - /* JACK has no concept of a device. To JACK, there are clients - * which have an arbitrary number of ports. To make this - * intelligible to PortAudio clients, we will group each JACK client - * into a device, and make each port of that client a channel */ - - PaError result = paNoError; - PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep; - - const char **jack_ports = NULL; - char **client_names = NULL; - char *regex_pattern = alloca( jack_client_name_size() + 3 ); - int port_index, client_index, i; - double globalSampleRate; - regex_t port_regex; - unsigned long numClients = 0, numPorts = 0; - char *tmp_client_name = alloca( jack_client_name_size() ); - - commonApi->info.defaultInputDevice = paNoDevice; - commonApi->info.defaultOutputDevice = paNoDevice; - commonApi->info.deviceCount = 0; - - /* Parse the list of ports, using a regex to grab the client names */ - ASSERT_CALL( regcomp( &port_regex, "^[^:]*", REG_EXTENDED ), 0 ); - - /* since we are rebuilding the list of devices, free all memory - * associated with the previous list */ - PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory ); - - /* We can only retrieve the list of clients indirectly, by first - * asking for a list of all ports, then parsing the port names - * according to the client_name:port_name convention (which is - * enforced by jackd) - * A: If jack_get_ports returns NULL, there's nothing for us to do */ - UNLESS( (jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 )) && jack_ports[0], paNoError ); - /* Find number of ports */ - while( jack_ports[numPorts] ) - ++numPorts; - /* At least there will be one port per client :) */ - UNLESS( client_names = alloca( numPorts * sizeof (char *) ), paInsufficientMemory ); - - /* Build a list of clients from the list of ports */ - for( numClients = 0, port_index = 0; jack_ports[port_index] != NULL; port_index++ ) - { - int client_seen = FALSE; - regmatch_t match_info; - const char *port = jack_ports[port_index]; - - /* extract the client name from the port name, using a regex - * that parses the clientname:portname syntax */ - UNLESS( !regexec( &port_regex, port, 1, &match_info, 0 ), paInternalError ); - assert(match_info.rm_eo - match_info.rm_so < jack_client_name_size()); - memcpy( tmp_client_name, port + match_info.rm_so, - match_info.rm_eo - match_info.rm_so ); - tmp_client_name[match_info.rm_eo - match_info.rm_so] = '\0'; - - /* do we know about this port's client yet? */ - for( i = 0; i < numClients; i++ ) - { - if( strcmp( tmp_client_name, client_names[i] ) == 0 ) - client_seen = TRUE; - } - - if (client_seen) - continue; /* A: Nothing to see here, move along */ - - UNLESS( client_names[numClients] = (char*)MALLOC(strlen(tmp_client_name) + 1), paInsufficientMemory ); - - /* The alsa_pcm client should go in spot 0. If this - * is the alsa_pcm client AND we are NOT about to put - * it in spot 0 put it in spot 0 and move whatever - * was already in spot 0 to the end. */ - if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && numClients > 0 ) - { - /* alsa_pcm goes in spot 0 */ - strcpy( client_names[ numClients ], client_names[0] ); - strcpy( client_names[0], tmp_client_name ); - } - else - { - /* put the new client at the end of the client list */ - strcpy( client_names[ numClients ], tmp_client_name ); - } - ++numClients; - } - - /* Now we have a list of clients, which will become the list of - * PortAudio devices. */ - - /* there is one global sample rate all clients must conform to */ - - globalSampleRate = jack_get_sample_rate( jackApi->jack_client ); - UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)MALLOC( sizeof(PaDeviceInfo*) * - numClients ), paInsufficientMemory ); - - assert( commonApi->info.deviceCount == 0 ); - - /* Create a PaDeviceInfo structure for every client */ - for( client_index = 0; client_index < numClients; client_index++ ) - { - PaDeviceInfo *curDevInfo; - const char **clientPorts = NULL; - - UNLESS( curDevInfo = (PaDeviceInfo*)MALLOC( sizeof(PaDeviceInfo) ), paInsufficientMemory ); - UNLESS( curDevInfo->name = (char*)MALLOC( strlen(client_names[client_index]) + 1 ), paInsufficientMemory ); - strcpy( (char *)curDevInfo->name, client_names[client_index] ); - - curDevInfo->structVersion = 2; - curDevInfo->hostApi = jackApi->hostApiIndex; - - /* JACK is very inflexible: there is one sample rate the whole - * system must run at, and all clients must speak IEEE float. */ - curDevInfo->defaultSampleRate = globalSampleRate; - - /* To determine how many input and output channels are available, - * we re-query jackd with more specific parameters. */ - - sprintf( regex_pattern, "%s:.*", client_names[client_index] ); - - /* ... what are your output ports (that we could input from)? */ - clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, - NULL, JackPortIsOutput); - curDevInfo->maxInputChannels = 0; - curDevInfo->defaultLowInputLatency = 0.; - curDevInfo->defaultHighInputLatency = 0.; - if( clientPorts ) - { - jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] ); - curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency = - jack_port_get_latency( p ) / globalSampleRate; - - for( i = 0; clientPorts[i] != NULL; i++) - { - /* The number of ports returned is the number of output channels. - * We don't care what they are, we just care how many */ - curDevInfo->maxInputChannels++; - } - free(clientPorts); - } - - /* ... what are your input ports (that we could output to)? */ - clientPorts = jack_get_ports( jackApi->jack_client, regex_pattern, - NULL, JackPortIsInput); - curDevInfo->maxOutputChannels = 0; - curDevInfo->defaultLowOutputLatency = 0.; - curDevInfo->defaultHighOutputLatency = 0.; - if( clientPorts ) - { - jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] ); - curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency = - jack_port_get_latency( p ) / globalSampleRate; - - for( i = 0; clientPorts[i] != NULL; i++) - { - /* The number of ports returned is the number of input channels. - * We don't care what they are, we just care how many */ - curDevInfo->maxOutputChannels++; - } - free(clientPorts); - } - - /* Add this client to the list of devices */ - commonApi->deviceInfos[client_index] = curDevInfo; - ++commonApi->info.deviceCount; - if( commonApi->info.defaultInputDevice == paNoDevice && curDevInfo->maxInputChannels > 0 ) - commonApi->info.defaultInputDevice = client_index; - if( commonApi->info.defaultOutputDevice == paNoDevice && curDevInfo->maxOutputChannels > 0 ) - commonApi->info.defaultOutputDevice = client_index; - } - -error: - regfree( &port_regex ); - free( jack_ports ); - return result; -} -#undef MALLOC - -static void UpdateSampleRate( PaJackStream *stream, double sampleRate ) -{ - /* XXX: Maybe not the cleanest way of going about this? */ - stream->cpuLoadMeasurer.samplingPeriod = stream->bufferProcessor.samplePeriod = 1. / sampleRate; - stream->streamRepresentation.streamInfo.sampleRate = sampleRate; -} - -static void JackErrorCallback( const char *msg ) -{ - if( pthread_self() == mainThread_ ) - { - assert( msg ); - free( jackErr_ ); - jackErr_ = malloc( strlen( msg ) ); - sprintf( jackErr_, msg ); - } -} - -static void JackOnShutdown( void *arg ) -{ - PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg; - PaJackStream *stream = jackApi->processQueue; - - PA_DEBUG(( "%s: JACK server is shutting down\n", __FUNCTION__ )); - for( ; stream; stream = stream->next ) - { - stream->is_active = 0; - } - - /* Make sure that the main thread doesn't get stuck waiting on the condition */ - ASSERT_CALL( pthread_mutex_lock( &jackApi->mtx ), 0 ); - jackApi->jackIsDown = 1; - ASSERT_CALL( pthread_cond_signal( &jackApi->cond ), 0 ); - ASSERT_CALL( pthread_mutex_unlock( &jackApi->mtx ), 0 ); - -} - -static int JackSrCb( jack_nframes_t nframes, void *arg ) -{ - PaJackHostApiRepresentation *jackApi = (PaJackHostApiRepresentation *)arg; - double sampleRate = (double)nframes; - PaJackStream *stream = jackApi->processQueue; - - /* Update all streams in process queue */ - PA_DEBUG(( "%s: Acting on change in JACK samplerate: %f\n", __FUNCTION__, sampleRate )); - for( ; stream; stream = stream->next ) - { - if( stream->streamRepresentation.streamInfo.sampleRate != sampleRate ) - { - PA_DEBUG(( "%s: Updating samplerate\n", __FUNCTION__ )); - UpdateSampleRate( stream, sampleRate ); - } - } - - return 0; -} - -static int JackXRunCb(void *arg) { - PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)arg; - assert( hostApi ); - hostApi->xrun = TRUE; - PA_DEBUG(( "%s: JACK signalled xrun\n", __FUNCTION__ )); - return 0; -} - -PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, - PaHostApiIndex hostApiIndex ) -{ - PaError result = paNoError; - PaJackHostApiRepresentation *jackHostApi; - int activated = 0; - char *clientName; - int written; - *hostApi = NULL; /* Initialize to NULL */ - - UNLESS( jackHostApi = (PaJackHostApiRepresentation*) - PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory ); - jackHostApi->deviceInfoMemory = NULL; - - mainThread_ = pthread_self(); - ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 ); - ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 ); - - /* Try to become a client of the JACK server. If we cannot do - * this, then this API cannot be used. */ - - clientName = alloca( jack_client_name_size() ); - written = snprintf( clientName, jack_client_name_size(), "PortAudio-%d", getpid() ); - assert( written < jack_client_name_size() ); - jackHostApi->jack_client = jack_client_new( clientName ); - if( jackHostApi->jack_client == NULL ) - { - /* the V19 development docs say that if an implementation - * detects that it cannot be used, it should return a NULL - * interface and paNoError */ - result = paNoError; - goto error; - } - - UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); - jackHostApi->hostApiIndex = hostApiIndex; - - *hostApi = &jackHostApi->commonHostApiRep; - (*hostApi)->info.structVersion = 1; - (*hostApi)->info.type = paJACK; - (*hostApi)->info.name = "JACK Audio Connection Kit"; - - /* Build a device list by querying the JACK server */ - - ENSURE_PA( BuildDeviceList( jackHostApi ) ); - - /* Register functions */ - - (*hostApi)->Terminate = Terminate; - (*hostApi)->OpenStream = OpenStream; - (*hostApi)->IsFormatSupported = IsFormatSupported; - - PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface, - CloseStream, StartStream, - StopStream, AbortStream, - IsStreamStopped, IsStreamActive, - GetStreamTime, GetStreamCpuLoad, - PaUtil_DummyRead, PaUtil_DummyWrite, - PaUtil_DummyGetReadAvailable, - PaUtil_DummyGetWriteAvailable ); - - PaUtil_InitializeStreamInterface( &jackHostApi->blockingStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, PaUtil_DummyGetCpuLoad, - BlockingReadStream, BlockingWriteStream, - BlockingGetStreamReadAvailable, BlockingGetStreamWriteAvailable ); - - jackHostApi->inputBase = jackHostApi->outputBase = 0; - jackHostApi->xrun = 0; - jackHostApi->toAdd = jackHostApi->toRemove = NULL; - jackHostApi->processQueue = NULL; - jackHostApi->jackIsDown = 0; - - jack_on_shutdown( jackHostApi->jack_client, JackOnShutdown, jackHostApi ); - jack_set_error_function( JackErrorCallback ); - jackHostApi->jack_buffer_size = jack_get_buffer_size ( jackHostApi->jack_client ); - UNLESS( !jack_set_sample_rate_callback( jackHostApi->jack_client, JackSrCb, jackHostApi ), paUnanticipatedHostError ); - UNLESS( !jack_set_xrun_callback( jackHostApi->jack_client, JackXRunCb, jackHostApi ), paUnanticipatedHostError ); - UNLESS( !jack_set_process_callback( jackHostApi->jack_client, JackCallback, jackHostApi ), paUnanticipatedHostError ); - UNLESS( !jack_activate( jackHostApi->jack_client ), paUnanticipatedHostError ); - activated = 1; - - return result; - -error: - if( activated ) - ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); - - if( jackHostApi ) - { - if( jackHostApi->jack_client ) - ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); - - if( jackHostApi->deviceInfoMemory ) - { - PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); - PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); - } - - PaUtil_FreeMemory( jackHostApi ); - } - return result; -} - - -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) -{ - PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; - - /* note: this automatically disconnects all ports, since a deactivated - * client is not allowed to have any ports connected */ - ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); - - ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 ); - ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 ); - - ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); - - if( jackHostApi->deviceInfoMemory ) - { - PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); - PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); - } - - PaUtil_FreeMemory( jackHostApi ); - - free( jackErr_ ); -} - -static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ) -{ - int inputChannelCount = 0, outputChannelCount = 0; - 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; - } - - /* - The following check is not necessary for JACK. - - - if a full duplex stream is requested, check that the combination - of input and output parameters is supported - - - 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 - */ - - /* check that the device supports sampleRate */ - -#define ABS(x) ( (x) > 0 ? (x) : -(x) ) - if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 ) - return paInvalidSampleRate; -#undef ABS - - return paFormatIsSupported; -} - -/* Basic stream initialization */ -static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentation *hostApi, int numInputChannels, - int numOutputChannels ) -{ - PaError result = paNoError; - assert( stream ); - - memset( stream, 0, sizeof (PaJackStream) ); - UNLESS( stream->stream_memory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); - stream->jack_client = hostApi->jack_client; - stream->hostApi = hostApi; - - if( numInputChannels > 0 ) - { - UNLESS( stream->local_input_ports = - (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), - paInsufficientMemory ); - memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels ); - UNLESS( stream->remote_output_ports = - (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), - paInsufficientMemory ); - memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels ); - } - if( numOutputChannels > 0 ) - { - UNLESS( stream->local_output_ports = - (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), - paInsufficientMemory ); - memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); - UNLESS( stream->remote_input_ports = - (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), - paInsufficientMemory ); - memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); - } - - stream->num_incoming_connections = numInputChannels; - stream->num_outgoing_connections = numOutputChannels; - -error: - return result; -} - -/*! - * Free resources associated with stream, and eventually stream itself. - * - * Frees allocated memory, and closes opened pcms. - */ -static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentation, int terminateBufferProcessor ) -{ - int i; - assert( stream ); - - if( stream->isBlockingStream ) - BlockingEnd( stream ); - - for( i = 0; i < stream->num_incoming_connections; ++i ) - { - if( stream->local_input_ports[i] ) - ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 ); - } - for( i = 0; i < stream->num_outgoing_connections; ++i ) - { - if( stream->local_output_ports[i] ) - ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 ); - } - - if( terminateStreamRepresentation ) - PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); - if( terminateBufferProcessor ) - PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); - - if( stream->stream_memory ) - { - PaUtil_FreeAllAllocations( stream->stream_memory ); - PaUtil_DestroyAllocationGroup( stream->stream_memory ); - } - PaUtil_FreeMemory( stream ); -} - -static PaError WaitCondition( PaJackHostApiRepresentation *hostApi ) -{ - PaError result = paNoError; - int err = 0; - PaTime pt = PaUtil_GetTime(); - struct timespec ts; - - ts.tv_sec = (time_t) floor( pt + 1 ); - ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000); - /* XXX: Best enclose in loop, in case of spurious wakeups? */ - err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts ); - - /* Make sure we didn't time out */ - UNLESS( err != ETIMEDOUT, paTimedOut ); - UNLESS( !err, paInternalError ); - -error: - return result; -} - -static PaError AddStream( PaJackStream *stream ) -{ - PaError result = paNoError; - PaJackHostApiRepresentation *hostApi = stream->hostApi; - /* Add to queue of streams that should be processed */ - ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); - if( !hostApi->jackIsDown ) - { - hostApi->toAdd = stream; - /* Unlock mutex and await signal from processing thread */ - result = WaitCondition( stream->hostApi ); - } - ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); - ENSURE_PA( result ); - - UNLESS( !hostApi->jackIsDown, paDeviceUnavailable ); - -error: - return result; -} - -/* Remove stream from processing queue */ -static PaError RemoveStream( PaJackStream *stream ) -{ - PaError result = paNoError; - PaJackHostApiRepresentation *hostApi = stream->hostApi; - - /* Add to queue over streams that should be processed */ - ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); - if( !hostApi->jackIsDown ) - { - hostApi->toRemove = stream; - /* Unlock mutex and await signal from processing thread */ - result = WaitCondition( stream->hostApi ); - } - ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); - ENSURE_PA( result ); - -error: - return result; -} - -/* Add stream to processing queue */ -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; - PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; - PaJackStream *stream = NULL; - char *port_string = alloca( jack_port_name_size() ); - unsigned long regexSz = jack_client_name_size() + 3; - char *regex_pattern = alloca( regexSz ); - const char **jack_ports = NULL; - /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */ - int i; - int inputChannelCount, outputChannelCount; - const double jackSr = jack_get_sample_rate( jackHostApi->jack_client ); - PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; - int bpInitialized = 0, srInitialized = 0; /* Initialized buffer processor and stream representation? */ - unsigned long ofs; - - /* validate platform specific flags */ - if( (streamFlags & paPlatformSpecificFlags) != 0 ) - return paInvalidFlag; /* unexpected platform specific flag */ - if( (streamFlags & paPrimeOutputBuffersUsingStreamCallback) != 0 ) - { - streamFlags &= ~paPrimeOutputBuffersUsingStreamCallback; - /*return paInvalidFlag;*/ /* This implementation does not support buffer priming */ - } - - if( framesPerBuffer != paFramesPerBufferUnspecified ) - { - /* Jack operates with power of two buffers, and we don't support non-integer buffer adaption (yet) */ - /*UNLESS( !(framesPerBuffer & (framesPerBuffer - 1)), paBufferTooBig );*/ /* TODO: Add descriptive error code? */ - } - - /* Preliminary checks */ - - 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; - } - - /* ... check that the sample rate exactly matches the ONE acceptable rate - * A: This rate isn't necessarily constant though? */ - -#define ABS(x) ( (x) > 0 ? (x) : -(x) ) - if( ABS(sampleRate - jackSr) > 1 ) - return paInvalidSampleRate; -#undef ABS - - UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory ); - ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) ); - - /* the blocking emulation, if necessary */ - stream->isBlockingStream = !streamCallback; - if( stream->isBlockingStream ) - { - float latency = 0.001; /* 1ms is the absolute minimum we support */ - int minimum_buffer_frames = 0; - - if( inputParameters && inputParameters->suggestedLatency > latency ) - latency = inputParameters->suggestedLatency; - else if( outputParameters && outputParameters->suggestedLatency > latency ) - latency = outputParameters->suggestedLatency; - - /* the latency the user asked for indicates the minimum buffer size in frames */ - minimum_buffer_frames = (int) (latency * jack_get_sample_rate( jackHostApi->jack_client )); - - /* we also need to be able to store at least three full jack buffers to avoid dropouts */ - if( jackHostApi->jack_buffer_size * 3 > minimum_buffer_frames ) - minimum_buffer_frames = jackHostApi->jack_buffer_size * 3; - - /* setup blocking API data structures (FIXME: can fail) */ - BlockingBegin( stream, minimum_buffer_frames ); - - /* install our own callback for the blocking API */ - streamCallback = BlockingCallback; - userData = stream; - - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &jackHostApi->blockingStreamInterface, streamCallback, userData ); - } - else - { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &jackHostApi->callbackStreamInterface, streamCallback, userData ); - } - srInitialized = 1; - PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, jackSr ); - - /* create the JACK ports. We cannot connect them until audio - * processing begins */ - - /* Register a unique set of ports for this stream - * TODO: Robust allocation of new port names */ - - ofs = jackHostApi->inputBase; - for( i = 0; i < inputChannelCount; i++ ) - { - snprintf( port_string, jack_port_name_size(), "in_%lu", ofs + i ); - UNLESS( stream->local_input_ports[i] = jack_port_register( - jackHostApi->jack_client, port_string, - JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ), paInsufficientMemory ); - } - jackHostApi->inputBase += inputChannelCount; - - ofs = jackHostApi->outputBase; - for( i = 0; i < outputChannelCount; i++ ) - { - snprintf( port_string, jack_port_name_size(), "out_%lu", ofs + i ); - UNLESS( stream->local_output_ports[i] = jack_port_register( - jackHostApi->jack_client, port_string, - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ), paInsufficientMemory ); - } - jackHostApi->outputBase += outputChannelCount; - - /* look up the jack_port_t's for the remote ports. We could do - * this at stream start time, but doing it here ensures the - * name lookup only happens once. */ - - if( inputChannelCount > 0 ) - { - int err = 0; - - /* ... remote output ports (that we input from) */ - snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name ); - UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, - NULL, JackPortIsOutput ), paUnanticipatedHostError ); - for( i = 0; i < inputChannelCount && jack_ports[i]; i++ ) - { - if( (stream->remote_output_ports[i] = jack_port_by_name( - jackHostApi->jack_client, jack_ports[i] )) == NULL ) - { - err = 1; - break; - } - } - free( jack_ports ); - UNLESS( !err, paInsufficientMemory ); - - /* Fewer ports than expected? */ - UNLESS( i == inputChannelCount, paInternalError ); - } - - if( outputChannelCount > 0 ) - { - int err = 0; - - /* ... remote input ports (that we output to) */ - snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name ); - UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, - NULL, JackPortIsInput ), paUnanticipatedHostError ); - for( i = 0; i < outputChannelCount && jack_ports[i]; i++ ) - { - if( (stream->remote_input_ports[i] = jack_port_by_name( - jackHostApi->jack_client, jack_ports[i] )) == 0 ) - { - err = 1; - break; - } - } - free( jack_ports ); - UNLESS( !err , paInsufficientMemory ); - - /* Fewer ports than expected? */ - UNLESS( i == outputChannelCount, paInternalError ); - } - - ENSURE_PA( PaUtil_InitializeBufferProcessor( - &stream->bufferProcessor, - inputChannelCount, - inputSampleFormat, - paFloat32, /* hostInputSampleFormat */ - outputChannelCount, - outputSampleFormat, - paFloat32, /* hostOutputSampleFormat */ - jackSr, - streamFlags, - framesPerBuffer, - 0, /* Ignored */ - paUtilUnknownHostBufferSize, /* Buffer size may vary on JACK's discretion */ - streamCallback, - userData ) ); - bpInitialized = 1; - - if( stream->num_incoming_connections > 0 ) - stream->streamRepresentation.streamInfo.inputLatency = (jack_port_get_latency( stream->remote_output_ports[0] ) - - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ - + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor )) / sampleRate; - if( stream->num_outgoing_connections > 0 ) - stream->streamRepresentation.streamInfo.outputLatency = (jack_port_get_latency( stream->remote_input_ports[0] ) - - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ - + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor )) / sampleRate; - - stream->streamRepresentation.streamInfo.sampleRate = jackSr; - stream->t0 = jack_frame_time( jackHostApi->jack_client ); /* A: Time should run from Pa_OpenStream */ - - ENSURE_PA( AddStream( stream ) ); /* Add to queue over opened streams */ - - *s = (PaStream*)stream; - - return result; - -error: - if( stream ) - CleanUpStream( stream, srInitialized, bpInitialized ); - - 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 = paNoError; - PaJackStream *stream = (PaJackStream*)s; - - /* Remove this stream from the processing queue */ - ENSURE_PA( RemoveStream( stream ) ); - -error: - CleanUpStream( stream, 1, 1 ); - return result; -} - -static PaError RealProcess( PaJackStream *stream, jack_nframes_t frames ) -{ - PaError result = paNoError; - PaStreamCallbackTimeInfo timeInfo = {0,0,0}; - int chn; - int framesProcessed; - const double sr = jack_get_sample_rate( stream->jack_client ); /* Shouldn't change during the process callback */ - PaStreamCallbackFlags cbFlags = 0; - - /* If the user has returned !paContinue from the callback we'll want to flush the internal buffers, - * when these are empty we can finally mark the stream as inactive */ - if( stream->callbackResult != paContinue && - PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) - { - stream->is_active = 0; - if( stream->streamRepresentation.streamFinishedCallback ) - stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); - PA_DEBUG(( "%s: Callback finished\n", __FUNCTION__ )); - - goto end; - } - - timeInfo.currentTime = (jack_frame_time( stream->jack_client ) - stream->t0) / sr; - if( stream->num_incoming_connections > 0 ) - timeInfo.inputBufferAdcTime = timeInfo.currentTime - jack_port_get_latency( stream->remote_output_ports[0] ) - / sr; - if( stream->num_outgoing_connections > 0 ) - timeInfo.outputBufferDacTime = timeInfo.currentTime + jack_port_get_latency( stream->remote_input_ports[0] ) - / sr; - - PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); - - if( stream->xrun ) - { - /* XXX: Any way to tell which of these occurred? */ - cbFlags = paOutputUnderflow | paInputOverflow; - stream->xrun = FALSE; - } - PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, - cbFlags ); - - if( stream->num_incoming_connections > 0 ) - PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames ); - if( stream->num_outgoing_connections > 0 ) - PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames ); - - for( chn = 0; chn < stream->num_incoming_connections; chn++ ) - { - jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) - jack_port_get_buffer( stream->local_input_ports[chn], - frames ); - - PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor, - chn, - channel_buf ); - } - - for( chn = 0; chn < stream->num_outgoing_connections; chn++ ) - { - jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) - jack_port_get_buffer( stream->local_output_ports[chn], - frames ); - - PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor, - chn, - channel_buf ); - } - - framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, - &stream->callbackResult ); - /* We've specified a host buffer size mode where every frame should be consumed by the buffer processor */ - assert( framesProcessed == frames ); - - PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); - -end: - return result; -} - -/* Alter the processing queue if necessary */ -static PaError UpdateQueue( PaJackHostApiRepresentation *hostApi ) -{ - PaError result = paNoError; - int queueModified = 0; - const double jackSr = jack_get_sample_rate( hostApi->jack_client ); - int err; - - if( (err = pthread_mutex_trylock( &hostApi->mtx )) != 0 ) - { - assert( err == EBUSY ); - return paNoError; - } - - if( hostApi->toAdd ) - { - if( hostApi->processQueue ) - { - PaJackStream *node = hostApi->processQueue; - /* Advance to end of queue */ - while( node->next ) - node = node->next; - - node->next = hostApi->toAdd; - } - else - hostApi->processQueue = (PaJackStream *)hostApi->toAdd; - - /* If necessary, update stream state */ - if( hostApi->toAdd->streamRepresentation.streamInfo.sampleRate != jackSr ) - UpdateSampleRate( hostApi->toAdd, jackSr ); - - hostApi->toAdd = NULL; - queueModified = 1; - } - if( hostApi->toRemove ) - { - int removed = 0; - PaJackStream *node = hostApi->processQueue, *prev = NULL; - assert( hostApi->processQueue ); - - while( node ) - { - if( node == hostApi->toRemove ) - { - if( prev ) - prev->next = node->next; - else - hostApi->processQueue = (PaJackStream *)node->next; - - removed = 1; - break; - } - - prev = node; - node = node->next; - } - UNLESS( removed, paInternalError ); - hostApi->toRemove = NULL; - PA_DEBUG(( "%s: Removed stream from processing queue\n", __FUNCTION__ )); - queueModified = 1; - } - - if( queueModified ) - { - /* Signal that we've done what was asked of us */ - ASSERT_CALL( pthread_cond_signal( &hostApi->cond ), 0 ); - } - -error: - ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); - - return result; -} - -static int JackCallback( jack_nframes_t frames, void *userData ) -{ - PaError result = paNoError; - PaJackHostApiRepresentation *hostApi = (PaJackHostApiRepresentation *)userData; - PaJackStream *stream = NULL; - int xrun = hostApi->xrun; - hostApi->xrun = 0; - - assert( hostApi ); - - ENSURE_PA( UpdateQueue( hostApi ) ); - - /* Process each stream */ - stream = hostApi->processQueue; - for( ; stream; stream = stream->next ) - { - if( xrun ) /* Don't override if already set */ - stream->xrun = 1; - - /* See if this stream is to be started */ - if( stream->doStart ) - { - /* If we can't obtain a lock, we'll try next time */ - int err = pthread_mutex_trylock( &stream->hostApi->mtx ); - if( !err ) - { - if( stream->doStart ) /* Could potentially change before obtaining the lock */ - { - stream->is_active = 1; - stream->doStart = 0; - PA_DEBUG(( "%s: Starting stream\n", __FUNCTION__ )); - ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); - stream->callbackResult = paContinue; - stream->isSilenced = 0; - } - - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); - } - else - assert( err == EBUSY ); - } - else if( stream->doStop || stream->doAbort ) /* Should we stop/abort stream? */ - { - if( stream->callbackResult == paContinue ) /* Ok, make it stop */ - { - PA_DEBUG(( "%s: Stopping stream\n", __FUNCTION__ )); - stream->callbackResult = stream->doStop ? paComplete : paAbort; - } - } - - if( stream->is_active ) - ENSURE_PA( RealProcess( stream, frames ) ); - /* If we have just entered inactive state, silence output */ - if( !stream->is_active && !stream->isSilenced ) - { - int i; - - /* Silence buffer after entering inactive state */ - PA_DEBUG(( "Silencing the output\n" )); - for( i = 0; i < stream->num_outgoing_connections; ++i ) - { - jack_default_audio_sample_t *buffer = jack_port_get_buffer( stream->local_output_ports[i], frames ); - memset( buffer, 0, sizeof (jack_default_audio_sample_t) * frames ); - } - - stream->isSilenced = 1; - } - - if( stream->doStop || stream->doAbort ) - { - /* See if RealProcess has acted on the request */ - if( !stream->is_active ) /* Ok, signal to the main thread that we've carried out the operation */ - { - /* If we can't obtain a lock, we'll try next time */ - int err = pthread_mutex_trylock( &stream->hostApi->mtx ); - if( !err ) - { - stream->doStop = stream->doAbort = 0; - ASSERT_CALL( pthread_cond_signal( &stream->hostApi->cond ), 0 ); - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); - } - else - assert( err == EBUSY ); - } - } - } - - return 0; -error: - return -1; -} - -static PaError StartStream( PaStream *s ) -{ - PaError result = paNoError; - PaJackStream *stream = (PaJackStream*)s; - int i; - - /* Ready the processor */ - PaUtil_ResetBufferProcessor( &stream->bufferProcessor ); - - /* connect the ports */ - - /* NOTE: I would rather use jack_port_connect which uses jack_port_t's - * instead of port names, but it is not implemented yet. */ - if( stream->num_incoming_connections > 0 ) - { - for( i = 0; i < stream->num_incoming_connections; i++ ) - UNLESS( jack_connect( stream->jack_client, - jack_port_name( stream->remote_output_ports[i] ), - jack_port_name( stream->local_input_ports[i] ) ) == 0, paUnanticipatedHostError ); - } - - if( stream->num_outgoing_connections > 0 ) - { - for( i = 0; i < stream->num_outgoing_connections; i++ ) - UNLESS( jack_connect( stream->jack_client, - jack_port_name( stream->local_output_ports[i] ), - jack_port_name( stream->remote_input_ports[i] ) ) == 0, paUnanticipatedHostError ); - } - - stream->xrun = FALSE; - - /* Enable processing */ - - ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); - stream->doStart = 1; - - /* Wait for stream to be started */ - result = WaitCondition( stream->hostApi ); - /* - do - { - err = pthread_cond_timedwait( &stream->hostApi->cond, &stream->hostApi->mtx, &ts ); - } while( !stream->is_active && !err ); - */ - if( result != paNoError ) /* Something went wrong, call off the stream start */ - { - stream->doStart = 0; - stream->is_active = 0; /* Cancel any processing */ - } - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); - - ENSURE_PA( result ); - - stream->is_running = TRUE; - PA_DEBUG(( "%s: Stream started\n", __FUNCTION__ )); - -error: - return result; -} - -static PaError RealStop( PaJackStream *stream, int abort ) -{ - PaError result = paNoError; - int i; - - if( stream->isBlockingStream ) - BlockingWaitEmpty ( stream ); - - ASSERT_CALL( pthread_mutex_lock( &stream->hostApi->mtx ), 0 ); - if( abort ) - stream->doAbort = 1; - else - stream->doStop = 1; - - /* Wait for stream to be stopped */ - result = WaitCondition( stream->hostApi ); - ASSERT_CALL( pthread_mutex_unlock( &stream->hostApi->mtx ), 0 ); - ENSURE_PA( result ); - - UNLESS( !stream->is_active, paInternalError ); - - PA_DEBUG(( "%s: Stream stopped\n", __FUNCTION__ )); - -error: - stream->is_running = FALSE; - - /* Disconnect ports belonging to this stream */ - - if( !stream->hostApi->jackIsDown ) /* XXX: Well? */ - { - if( stream->num_incoming_connections > 0 ) - { - for( i = 0; i < stream->num_incoming_connections; i++ ) - UNLESS( !jack_disconnect( stream->jack_client, - jack_port_name( stream->remote_output_ports[i] ), - jack_port_name( stream->local_input_ports[i] ) ), paUnanticipatedHostError ); - } - if( stream->num_outgoing_connections > 0 ) - { - for( i = 0; i < stream->num_outgoing_connections; i++ ) - UNLESS( !jack_disconnect( stream->jack_client, - jack_port_name( stream->local_output_ports[i] ), - jack_port_name( stream->remote_input_ports[i] ) ), paUnanticipatedHostError ); - } - } - - return result; -} - -static PaError StopStream( PaStream *s ) -{ - assert(s); - return RealStop( (PaJackStream *)s, 0 ); -} - -static PaError AbortStream( PaStream *s ) -{ - assert(s); - return RealStop( (PaJackStream *)s, 1 ); -} - -static PaError IsStreamStopped( PaStream *s ) -{ - PaJackStream *stream = (PaJackStream*)s; - return !stream->is_running; -} - - -static PaError IsStreamActive( PaStream *s ) -{ - PaJackStream *stream = (PaJackStream*)s; - return stream->is_active; -} - - -static PaTime GetStreamTime( PaStream *s ) -{ - PaJackStream *stream = (PaJackStream*)s; - - /* A: Is this relevant?? --> TODO: what if we're recording-only? */ - return (jack_frame_time( stream->jack_client ) - stream->t0) / (PaTime)jack_get_sample_rate( stream->jack_client ); -} - - -static double GetStreamCpuLoad( PaStream* s ) -{ - PaJackStream *stream = (PaJackStream*)s; - return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); -} diff --git a/libs/portaudio/pa_linux_alsa/pa_linux_alsa.c b/libs/portaudio/pa_linux_alsa/pa_linux_alsa.c deleted file mode 100644 index 283c3e9fe328af35817eb2dbce67e092820e157e..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_linux_alsa/pa_linux_alsa.c +++ /dev/null @@ -1,3379 +0,0 @@ -/* - * $Id$ - * 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/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 ENSURE_SYSTEM_(expr, success) \ - do { \ - if( UNLIKELY( (aErr_ = (expr)) != success ) ) \ - { \ - /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \ - if( pthread_self() != callbackThread_ ) \ - { \ - PaUtil_SetLastHostErrorInfo( paALSA, aErr_, strerror( aErr_ ) ); \ - } \ - PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \ - result = paUnanticipatedHostError; \ - goto error; \ - } \ - } while( 0 ); - -#define ASSERT_CALL_(expr, success) \ - aErr_ = (expr); \ - assert( success == aErr_ ); - -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 ); - ENSURE_SYSTEM_( 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? */ - PA_DEBUG(( "Canceled callback thread\n" )); - } - ENSURE_SYSTEM_( pthread_join( th->callbackThread, &pret ), 0 ); - - if( pret && pret != PTHREAD_CANCELED ) - { - if( exitResult ) - *exitResult = *(PaError *) pret; - free( pret ); - } - -error: - return result; -} - -/** Lock a pthread_mutex_t. - * - * @concern ThreadCancellation We're disabling thread cancellation while the thread is holding a lock, so mutexes are - * properly unlocked at termination time. - */ -static PaError LockMutex( pthread_mutex_t *mtx ) -{ - PaError result = paNoError; - int oldState; - - ENSURE_SYSTEM_( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 ); - ENSURE_SYSTEM_( pthread_mutex_lock( mtx ), 0 ); - -error: - return result; -} - -/** Unlock a pthread_mutex_t. - * - * @concern ThreadCancellation Thread cancellation is enabled again after the mutex is properly unlocked. - */ -static PaError UnlockMutex( pthread_mutex_t *mtx ) -{ - PaError result = paNoError; - int oldState; - - ENSURE_SYSTEM_( pthread_mutex_unlock( mtx ), 0 ); - ENSURE_SYSTEM_( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 ); - -error: - 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; - ENSURE_SYSTEM_( 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 */ - if( NULL == snd_config ) - { - /* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */ - ENSURE_( snd_config_update(), paUnanticipatedHostError ); - PA_DEBUG(( "Updating snd_config\n" )); - } - assert( snd_config ); - 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: - /* No particular action */ - goto end; -} - -/* 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 ); - PA_UNLESS( streamInfo->deviceString != NULL, paInvalidDevice ); - - /* Skip further checking */ - return paNoError; - } - - 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; - - PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName )); - 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 ); - - /* PaAlsaStream_Configure 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; /* 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 ) - { - PA_DEBUG(( "\nStream in error, terminating\n\n" )); - 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; - - LockMutex( &stream->stateMtx ); - 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_( UnlockMutex( &stream->stateMtx ), paNoError ); - - 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) */ - PA_ENSURE( LockMutex( &stream->startMtx ) ); - - /* 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 ); - } - PA_ENSURE( UnlockMutex( &stream->startMtx ) ); - - 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, ×tamp ); - 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; - - PA_ENSURE( LockMutex( &stream->stateMtx ) ); - PA_ENSURE( AlsaStop( stream, 0 ) ); - PA_ENSURE( AlsaStart( stream, 0 ) ); - - PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ )); - -error: - PA_ENSURE( UnlockMutex( &stream->stateMtx ) ); - - 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 ); - /*PA_DEBUG(("capture: %lu, playback: %lu, combined: %lu\n", captureFrames, playbackFrames, *available));*/ - } - 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. Output is normally preferred over capture however, so capture frames may be - * discarded to avoid overrun unless paNeverDropInput is 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 ) - { - /* Drop input, a period's worth */ - assert( self->capture.ready ); - PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerBuffer, - *framesAvail ), &xrun ); - *framesAvail = 0; - self->capture.ready = 0; - } - } - else if( self->capture.pcm ) - assert( self->capture.ready ); - else - assert( self->playback.ready ); - } - -end: -error: - if( xrun ) - { - /* Recover from the xrun state */ - PA_ENSURE( PaAlsaStream_HandleXrun( self ) ); - *framesAvail = 0; - } - else - { - PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError ); - } - *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; - - if( *xrunOccurred ) - { - *numFrames = 0; - return result; - } - /* If we got here at least one of the pcm's should be marked ready */ - PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError ); - - /* 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 ); */ - if( commonFrames > *numFrames ) - { - /* Hmmm ... how come there are more frames available than we requested!? Blah. */ - PA_DEBUG(( "%s: Common available frames are reported to be more than number requested: %lu, %lu, callbackMode: %d\n", __FUNCTION__, - commonFrames, *numFrames, self->callbackMode )); - if( self->capture.pcm ) - { - PA_DEBUG(( "%s: captureFrames: %lu, capture.ready: %d\n", __FUNCTION__, captureFrames, self->capture.ready )); - } - if( self->playback.pcm ) - { - PA_DEBUG(( "%s: playbackFrames: %lu, playback.ready: %d\n", __FUNCTION__, playbackFrames, self->playback.ready )); - } - - commonFrames = 0; - goto end; - } - - /* 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 ); - assert( self->capture.pcm != NULL ); - PA_DEBUG(( "%s: Setting output buffers to NULL\n", __FUNCTION__ )); - 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 - { - PA_ENSURE( LockMutex( &stream->startMtx ) ); - PA_ENSURE( AlsaStart( stream, 0 ) ); /* Buffer will be zeroed */ - ENSURE_SYSTEM_( pthread_cond_signal( &stream->startCond ), 0 ); - PA_ENSURE( UnlockMutex( &stream->startMtx ) ); - - 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; - } - - /* Start stream after one period of samples worth */ - - /* Frames residing in buffer */ - PA_ENSURE( err = GetStreamWriteAvailable( stream ) ); - framesAvail = err; - hwAvail = stream->playback.bufferSize - framesAvail; - - 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/libs/portaudio/pa_linux_alsa/pa_linux_alsa.h b/libs/portaudio/pa_linux_alsa/pa_linux_alsa.h deleted file mode 100644 index b9d43c9291c20c5088b654bc83566821a0969409..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_linux_alsa/pa_linux_alsa.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef PA_LINUX_ALSA_H -#define PA_LINUX_ALSA_H - -/* - * $Id$ - * 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/libs/portaudio/pa_mac/pa_mac_hostapis.c b/libs/portaudio/pa_mac/pa_mac_hostapis.c deleted file mode 100644 index f8306c302f4c5a669eb64e419ded5a3a91440c7d..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_mac/pa_mac_hostapis.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * $Id$ - * 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 -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/libs/portaudio/pa_mac_core/pa_mac_core.c b/libs/portaudio/pa_mac_core/pa_mac_core.c deleted file mode 100644 index 020b5aeb4bb734fd69dad4f6bdb94edbee200bcd..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_mac_core/pa_mac_core.c +++ /dev/null @@ -1,896 +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. - * - * 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 <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; - case kAudioHardwareUnsupportedOperationError: - result = paInternalError; break; - case kAudioDeviceUnsupportedFormatError: - result = paSampleFormatNotSupported; break; - case kAudioDevicePermissionsError: - result = paDeviceUnavailable; break; - default: - result = paInternalError; - } - - return result; -} - -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; - } -} - -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; - } -} - -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); - } -} - -// This is not for input-only streams, this is for streams where the input device is different from the output device -// TODO: This needs to store the output data in a buffer, to be written to the device the next time AudioOutputProc is called -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); - clientData->callback(clientData->inputBuffer, NULL, frameCount, timeInfo, paNoFlag, clientData->userData); - - PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount ); -} - -// 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 ); -} - -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; -} \ No newline at end of file diff --git a/libs/portaudio/pa_mac_sm/pa_mac_sm.c b/libs/portaudio/pa_mac_sm/pa_mac_sm.c deleted file mode 100644 index 7a8e03009d25cf823c729c795708a21f3be9090b..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_mac_sm/pa_mac_sm.c +++ /dev/null @@ -1,1656 +0,0 @@ -/* - * $Id$ - * Portable Audio I/O Library for Macintosh - * - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2000 Phil Burk - * - * Special thanks to Chris Rolfe for his many helpful suggestions, bug fixes, - * and code contributions. - * Thanks also to Tue Haste Andersen, Alberto Ricci, Nico Wald, - * Roelf Toxopeus and Tom Erbe for testing the code and making - * numerous suggestions. - * - * 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 - PLB20010415 - ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID - PLB20010415 - Device Scan was crashing for anything other than siBadSoundInDevice, but some Macs may return other errors! - PLB20010420 - Fix TIMEOUT in record mode. - PLB20010420 - Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON - PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni. - PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. - PLB20011009 - Use NewSndCallBackUPP() for CARBON - PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the - variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will - give lower latency when virtual memory is turned off. - Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug. - PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated. - Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer. - Added PA_MAX_USAGE_ALLOWED to prevent Mac form hanging when CPU load approaches 100%. - PLB20020424 - Fixed return value in Pa_StreamTime -*/ - -/* -COMPATIBILITY -This Macintosh implementation is designed for use with Mac OS 7, 8 and -9 on PowerMacs, and OS X if compiled with CARBON - -OUTPUT -A circular array of CmpSoundHeaders is used as a queue. For low latency situations -there will only be two small buffers used. For higher latency, more and larger buffers -may be used. -To play the sound we use SndDoCommand() with bufferCmd. Each buffer is followed -by a callbackCmd which informs us when the buffer has been processsed. - -INPUT -The SndInput Manager SPBRecord call is used for sound input. If only -input is used, then the PA user callback is called from the Input completion proc. -For full-duplex, or output only operation, the PA callback is called from the -HostBuffer output completion proc. In that case, input sound is passed to the -callback by a simple FIFO. - -TODO: -O- Add support for native sample data formats other than int16. -O- Review buffer sizing. Should it be based on result of siDeviceBufferInfo query? -O- Determine default devices somehow. -*/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <memory.h> -#include <math.h> - -/* Mac specific includes */ -#include "OSUtils.h" -#include <MacTypes.h> -#include <Math64.h> -#include <Errors.h> -#include <Sound.h> -#include <SoundInput.h> -#include <SoundComponents.h> -#include <Devices.h> -#include <DateTimeUtils.h> -#include <Timer.h> -#include <Gestalt.h> - -#include "portaudio.h" -#include "pa_host.h" -#include "pa_trace.h" - -#ifndef FALSE - #define FALSE (0) - #define TRUE (!FALSE) -#endif - -/* #define TARGET_API_MAC_CARBON (1) */ - -/* - * Define maximum CPU load that will be allowed. User callback will - * be skipped if load exceeds this limit. This is to prevent the Mac - * from hanging when the CPU is hogged by the sound thread. - * On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ). - */ -#define PA_MAX_USAGE_ALLOWED (0.92) - -/* Debugging output macros. */ -#define PRINT(x) { printf x; fflush(stdout); } -#define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) /**/ -#define DBUGX(x) /* PRINT(x) /**/ - -#define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */ -#define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */ -#define PA_MIN_NUM_HOST_BUFFERS (2) -#define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */ -#define PA_MAX_DEVICE_INFO (32) - -/* Conversions for 16.16 fixed point code. */ -#define DoubleToUnsignedFixed(x) ((UnsignedFixed) ((x) * 65536.0)) -#define UnsignedFixedToDouble(fx) (((double)(fx)) * (1.0/(1<<16))) - -/************************************************************************************/ -/****************** Structures ******************************************************/ -/************************************************************************************/ -/* Use for passing buffers from input callback to output callback for processing. */ -typedef struct MultiBuffer -{ - char *buffers[PA_MAX_NUM_HOST_BUFFERS]; - int numBuffers; - int nextWrite; - int nextRead; -} -MultiBuffer; - -/* Define structure to contain all Macintosh specific data. */ -typedef struct PaHostSoundControl -{ - UInt64 pahsc_EntryCount; - double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */ - - /* Use char instead of Boolean for atomic operation. */ - volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */ - volatile char pahsc_StopRecording; /* Signal sent to background. */ - volatile char pahsc_IfInsideCallback; - /* Input */ - SPB pahsc_InputParams; - SICompletionUPP pahsc_InputCompletionProc; - MultiBuffer pahsc_InputMultiBuffer; - int32 pahsc_BytesPerInputHostBuffer; - int32 pahsc_InputRefNum; - /* Output */ - CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS]; - int32 pahsc_BytesPerOutputHostBuffer; - SndChannelPtr pahsc_Channel; - SndCallBackUPP pahsc_OutputCompletionProc; - int32 pahsc_NumOutsQueued; - int32 pahsc_NumOutsPlayed; - PaTimestamp pahsc_NumFramesDone; - UInt64 pahsc_WhenFramesDoneIncremented; - /* Init Time -------------- */ - int32 pahsc_NumHostBuffers; - int32 pahsc_FramesPerHostBuffer; - int32 pahsc_UserBuffersPerHostBuffer; - int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */ -} -PaHostSoundControl; - -/* Mac specific device information. */ -typedef struct internalPortAudioDevice -{ - long pad_DeviceRefNum; - long pad_DeviceBufferSize; - Component pad_Identifier; - PaDeviceInfo pad_Info; -} -internalPortAudioDevice; - -/************************************************************************************/ -/****************** Data ************************************************************/ -/************************************************************************************/ -static int sNumDevices = 0; -static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 }; -static int32 sPaHostError = 0; -static int sDefaultOutputDeviceID; -static int sDefaultInputDeviceID; - -/************************************************************************************/ -/****************** Prototypes ******************************************************/ -/************************************************************************************/ -static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr ); -static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ); -static PaError PaMac_RecordNext( internalPortAudioStream *past ); -static void PaMac_StartLoadCalculation( internalPortAudioStream *past ); -static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate ); -static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ); -static PaError PaMac_ScanInputDevices( void ); -static PaError PaMac_ScanOutputDevices( void ); -static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad ); -static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad ); -static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader ); -static void PaMac_EndLoadCalculation( internalPortAudioStream *past ); -static void PaMac_PlayNext ( internalPortAudioStream *past, int index ); -static long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index ); -static pascal void PaMac_InputCompletionProc(SPBPtr recParams); -static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCmd); -static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index ); -long PaHost_GetTotalBufferFrames( internalPortAudioStream *past ); -static int Mac_IsVirtualMemoryOn( void ); -static void PToCString(unsigned char* inString, char* outString); -char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf ); -char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf ); -int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf ); -int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf ); -int MultiBuffer_IsWriteable( MultiBuffer *mbuf ); -int MultiBuffer_IsReadable( MultiBuffer *mbuf ); -void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf ); -void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf ); - -/************************************************************************* -** Simple FIFO index control for multiple buffers. -** Read and Write indices range from 0 to 2N-1. -** This allows us to distinguish between full and empty. -*/ -char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf ) -{ - return mbuf->buffers[mbuf->nextWrite % mbuf->numBuffers]; -} -char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf ) -{ - return mbuf->buffers[mbuf->nextRead % mbuf->numBuffers]; -} -int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf ) -{ - return mbuf->nextRead % mbuf->numBuffers; -} -int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf ) -{ - return mbuf->nextWrite % mbuf->numBuffers; -} - -int MultiBuffer_IsWriteable( MultiBuffer *mbuf ) -{ - int bufsFull = mbuf->nextWrite - mbuf->nextRead; - if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers); - return (bufsFull < mbuf->numBuffers); -} -int MultiBuffer_IsReadable( MultiBuffer *mbuf ) -{ - int bufsFull = mbuf->nextWrite - mbuf->nextRead; - if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers); - return (bufsFull > 0); -} -void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf ) -{ - int temp = mbuf->nextRead + 1; - mbuf->nextRead = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp; -} -void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf ) -{ - int temp = mbuf->nextWrite + 1; - mbuf->nextWrite = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp; -} - -/************************************************************************* -** String Utility by Chris Rolfe -*/ -static void PToCString(unsigned char* inString, char* outString) -{ - long i; - for(i=0; i<inString[0]; i++) /* convert Pascal to C string */ - outString[i] = inString[i+1]; - outString[i]=0; -} - -/*************************************************************************/ -PaError PaHost_Term( void ) -{ - int i; - PaDeviceInfo *dev; - double *rates; - /* Free any allocated sample rate arrays. */ - for( i=0; i<sNumDevices; i++ ) - { - dev = &sDevices[i].pad_Info; - rates = (double *) dev->sampleRates; - if( (rates != NULL) ) free( rates ); /* MEM_011 */ - dev->sampleRates = NULL; - if( dev->name != NULL ) free( (void *) dev->name ); /* MEM_010 */ - dev->name = NULL; - } - sNumDevices = 0; - return paNoError; -} - -/************************************************************************* - PaHost_Init() is the library initialization function - call this before - using the library. -*/ -PaError PaHost_Init( void ) -{ - PaError err; - NumVersionVariant version; - - version.parts = SndSoundManagerVersion(); - DBUG(("SndSoundManagerVersion = 0x%x\n", version.whole)); - - /* Have we already initialized the device info? */ - err = (PaError) Pa_CountDevices(); - if( err < 0 ) return err; - else return paNoError; -} - -/************************************************************************* - PaMac_ScanOutputDevices() queries the properties of all output devices. -*/ -static PaError PaMac_ScanOutputDevices( void ) -{ - PaError err; - Component identifier=0; - ComponentDescription criteria = { kSoundOutputDeviceType, 0, 0, 0, 0 }; - long numComponents, i; - - /* Search the system linked list for output components */ - numComponents = CountComponents (&criteria); - identifier = 0; - sDefaultOutputDeviceID = sNumDevices; /* FIXME - query somehow */ - for (i = 0; i < numComponents; i++) - { - /* passing nil returns first matching component. */ - identifier = FindNextComponent( identifier, &criteria); - sDevices[sNumDevices].pad_Identifier = identifier; - - /* Set up for default OUTPUT devices. */ - err = PaMac_QueryOutputDeviceInfo( identifier, &sDevices[sNumDevices] ); - if( err < 0 ) return err; - else sNumDevices++; - - } - - return paNoError; -} - -/************************************************************************* - PaMac_ScanInputDevices() queries the properties of all input devices. -*/ -static PaError PaMac_ScanInputDevices( void ) -{ - Str255 deviceName; - int count; - Handle iconHandle; - PaError err; - OSErr oserr; - count = 1; - sDefaultInputDeviceID = sNumDevices; /* FIXME - query somehow */ /* PLB20010415 - was setting sDefaultOutputDeviceID */ - while(true) - { - /* Thanks Chris Rolfe and Alberto Ricci for this trick. */ - oserr = SPBGetIndexedDevice(count++, deviceName, &iconHandle); - DBUG(("PaMac_ScanInputDevices: SPBGetIndexedDevice returned %d\n", oserr )); -#if 1 - /* PLB20010415 - was giving error for anything other than siBadSoundInDevice, but some Macs may return other errors! */ - if(oserr != noErr) break; /* Some type of error is expected when count > devices */ -#else - if(oserr == siBadSoundInDevice) - { /* it's expected when count > devices */ - oserr = noErr; - break; - } - if(oserr != noErr) - { - ERR_RPT(("ERROR: SPBGetIndexedDevice(%d,,) returned %d\n", count-1, oserr )); - sPaHostError = oserr; - return paHostError; - } -#endif - DisposeHandle(iconHandle); /* Don't need the icon */ - - err = PaMac_QueryInputDeviceInfo( deviceName, &sDevices[sNumDevices] ); - DBUG(("PaMac_ScanInputDevices: PaMac_QueryInputDeviceInfo returned %d\n", err )); - if( err < 0 ) return err; - else if( err == 1 ) sNumDevices++; - } - - return paNoError; -} - -/* Sample rate info returned by using siSampleRateAvailable selector in SPBGetDeviceInfo() */ -/* Thanks to Chris Rolfe for help with this query. */ -#pragma options align=mac68k -typedef struct -{ - int16 numRates; - UnsignedFixed (**rates)[]; /* Handle created by SPBGetDeviceInfo */ -} -SRateInfo; -#pragma options align=reset - -/************************************************************************* -** PaMac_QueryOutputDeviceInfo() -** Query information about a named output device. -** Clears contents of ipad and writes info based on queries. -** Return one if OK, -** zero if device cannot be used, -** or negative error. -*/ -static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad ) -{ - int len; - OSErr err; - PaDeviceInfo *dev = &ipad->pad_Info; - SRateInfo srinfo = {0}; - int numRates; - ComponentDescription tempD; - Handle nameH=nil, infoH=nil, iconH=nil; - - memset( ipad, 0, sizeof(internalPortAudioDevice) ); - - dev->structVersion = 1; - dev->maxInputChannels = 0; - dev->maxOutputChannels = 2; - dev->nativeSampleFormats = paInt16; /* FIXME - query to see if 24 or 32 bit data can be handled. */ - - /* Get sample rates supported. */ - err = GetSoundOutputInfo(identifier, siSampleRateAvailable, (Ptr) &srinfo); - if(err != noErr) - { - ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetSoundOutputInfo siSampleRateAvailable returned %d\n", err )); - goto error; - } - numRates = srinfo.numRates; - DBUG(("PaMac_QueryOutputDeviceInfo: srinfo.numRates = 0x%x\n", srinfo.numRates )); - if( numRates == 0 ) - { - dev->numSampleRates = -1; - numRates = 2; - } - else - { - dev->numSampleRates = numRates; - } - dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates ); - /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */ - DisposeHandle((Handle) srinfo.rates); - - /* Device name */ - /* we pass an existing handle for the component name; - we don't care about the info (type, subtype, etc.) or icon, so set them to nil */ - infoH = nil; - iconH = nil; - nameH = NewHandle(0); - if(nameH == nil) return paInsufficientMemory; - err = GetComponentInfo(identifier, &tempD, nameH, infoH, iconH); - if (err) - { - ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetComponentInfo returned %d\n", err )); - goto error; - } - len = (*nameH)[0] + 1; - dev->name = (char *) malloc(len); /* MEM_010 */ - if( dev->name == NULL ) - { - DisposeHandle(nameH); - return paInsufficientMemory; - } - else - { - PToCString((unsigned char *)(*nameH), (char *) dev->name); - DisposeHandle(nameH); - } - - DBUG(("PaMac_QueryOutputDeviceInfo: dev->name = %s\n", dev->name )); - return paNoError; - -error: - sPaHostError = err; - return paHostError; - -} - -/************************************************************************* -** PaMac_QueryInputDeviceInfo() -** Query information about a named input device. -** Clears contents of ipad and writes info based on queries. -** Return one if OK, -** zero if device cannot be used, -** or negative error. -*/ -static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad ) -{ - PaError result = paNoError; - int len; - OSErr err; - long mRefNum = 0; - long tempL; - int16 tempS; - Fixed tempF; - PaDeviceInfo *dev = &ipad->pad_Info; - SRateInfo srinfo = {0}; - int numRates; - - memset( ipad, 0, sizeof(internalPortAudioDevice) ); - dev->maxOutputChannels = 0; - - /* Open device based on name. If device is in use, it may not be able to open in write mode. */ - err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum); - if (err) - { - /* If device is in use, it may not be able to open in write mode so try read mode. */ - err = SPBOpenDevice( deviceName, siReadPermission, &mRefNum); - if (err) - { - ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBOpenDevice returned %d\n", err )); - sPaHostError = err; - return paHostError; - } - } - - /* Define macros for printing out device info. */ -#define PrintDeviceInfo(selector,var) \ - err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \ - if (err) { \ - DBUG(("query %s failed\n", #selector )); \ - }\ - else { \ - DBUG(("query %s = 0x%x\n", #selector, var )); \ - } - - PrintDeviceInfo( siContinuous, tempS ); - PrintDeviceInfo( siAsync, tempS ); - PrintDeviceInfo( siNumberChannels, tempS ); - PrintDeviceInfo( siSampleSize, tempS ); - PrintDeviceInfo( siSampleRate, tempF ); - PrintDeviceInfo( siChannelAvailable, tempS ); - PrintDeviceInfo( siActiveChannels, tempL ); - PrintDeviceInfo( siDeviceBufferInfo, tempL ); - - err = SPBGetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL); - if (err == 0) DBUG(("%s = 0x%x\n", "siActiveChannels", tempL )); - /* Can we use this device? */ - err = SPBGetDeviceInfo(mRefNum, siAsync, (Ptr) &tempS); - if (err) - { - ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siAsync returned %d\n", err )); - goto error; - } - if( tempS == 0 ) goto useless; /* Does not support async recording so forget about it. */ - - err = SPBGetDeviceInfo(mRefNum, siChannelAvailable, (Ptr) &tempS); - if (err) - { - ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siChannelAvailable returned %d\n", err )); - goto error; - } - dev->maxInputChannels = tempS; - - /* Get sample rates supported. */ - err = SPBGetDeviceInfo(mRefNum, siSampleRateAvailable, (Ptr) &srinfo); - if (err) - { - ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleRateAvailable returned %d\n", err )); - goto error; - } - - numRates = srinfo.numRates; - DBUG(("numRates = 0x%x\n", numRates )); - if( numRates == 0 ) - { - dev->numSampleRates = -1; - numRates = 2; - } - else - { - dev->numSampleRates = numRates; - } - dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates ); - /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */ - DisposeHandle((Handle) srinfo.rates); - - /* Get size of device buffer. */ - err = SPBGetDeviceInfo(mRefNum, siDeviceBufferInfo, (Ptr) &tempL); - if (err) - { - ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siDeviceBufferInfo returned %d\n", err )); - goto error; - } - ipad->pad_DeviceBufferSize = tempL; - DBUG(("siDeviceBufferInfo = %d\n", tempL )); - - /* Set format based on sample size. */ - err = SPBGetDeviceInfo(mRefNum, siSampleSize, (Ptr) &tempS); - if (err) - { - ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleSize returned %d\n", err )); - goto error; - } - switch( tempS ) - { - case 0x0020: - dev->nativeSampleFormats = paInt32; /* FIXME - warning, code probably won't support this! */ - break; - case 0x0010: - default: /* FIXME - What about other formats? */ - dev->nativeSampleFormats = paInt16; - break; - } - DBUG(("nativeSampleFormats = %d\n", dev->nativeSampleFormats )); - - /* Device name */ - len = deviceName[0] + 1; /* Get length of Pascal string */ - dev->name = (char *) malloc(len); /* MEM_010 */ - if( dev->name == NULL ) - { - result = paInsufficientMemory; - goto cleanup; - } - PToCString(deviceName, (char *) dev->name); - DBUG(("deviceName = %s\n", dev->name )); - result = (PaError) 1; - /* All done so close up device. */ -cleanup: - if( mRefNum ) SPBCloseDevice(mRefNum); - return result; - -error: - if( mRefNum ) SPBCloseDevice(mRefNum); - sPaHostError = err; - return paHostError; - -useless: - if( mRefNum ) SPBCloseDevice(mRefNum); - return (PaError) 0; -} - -/************************************************************************* -** Allocate a double array and fill it with listed sample rates. -*/ -static double * PaMac_GetSampleRatesFromHandle ( int numRates, Handle h ) -{ - OSErr err = noErr; - SInt8 hState; - int i; - UnsignedFixed *fixedRates; - double *rates = (double *) malloc( numRates * sizeof(double) ); /* MEM_011 */ - if( rates == NULL ) return NULL; - /* Save and restore handle state as suggested by TechNote at: - http://developer.apple.com/technotes/tn/tn1122.html - */ - hState = HGetState (h); - if (!(err = MemError ())) - { - HLock (h); - if (!(err = MemError ( ))) - { - fixedRates = (UInt32 *) *h; - for( i=0; i<numRates; i++ ) - { - rates[i] = UnsignedFixedToDouble(fixedRates[i]); - } - - HSetState (h,hState); - err = MemError ( ); - } - } - if( err ) - { - free( rates ); - ERR_RPT(("Error in PaMac_GetSampleRatesFromHandle = %d\n", err )); - } - return rates; -} - -/*************************************************************************/ -int Pa_CountDevices() -{ - PaError err; - DBUG(("Pa_CountDevices()\n")); - /* If no devices, go find some. */ - if( sNumDevices <= 0 ) - { - err = PaMac_ScanOutputDevices(); - if( err != paNoError ) goto error; - err = PaMac_ScanInputDevices(); - if( err != paNoError ) goto error; - } - return sNumDevices; - -error: - PaHost_Term(); - DBUG(("Pa_CountDevices: returns %d\n", err )); - return err; - -} - -/*************************************************************************/ -const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) -{ - if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL; - return &sDevices[id].pad_Info; -} -/*************************************************************************/ -PaDeviceID Pa_GetDefaultInputDeviceID( void ) -{ - return sDefaultInputDeviceID; -} - -/*************************************************************************/ -PaDeviceID Pa_GetDefaultOutputDeviceID( void ) -{ - return sDefaultOutputDeviceID; -} - -/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/ -static void PaMac_StartLoadCalculation( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - UnsignedWide widePad; - if( pahsc == NULL ) return; - /* Query system timer for usage analysis and to prevent overuse of CPU. */ - Microseconds( &widePad ); - pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad ); -} - -/****************************************************************************** -** Measure fractional CPU load based on real-time it took to calculate -** buffers worth of output. -*/ -/**************************************************************************/ -static void PaMac_EndLoadCalculation( internalPortAudioStream *past ) -{ - UnsignedWide widePad; - UInt64 currentCount; - long usecsElapsed; - double newUsage; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; - - /* Measure CPU utilization during this callback. Note that this calculation - ** assumes that we had the processor the whole time. - */ -#define LOWPASS_COEFFICIENT_0 (0.95) -#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) - Microseconds( &widePad ); - currentCount = UnsignedWideToUInt64( widePad ); - - usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount); - - /* Use inverse because it is faster than the divide. */ - newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer; - - past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + - (LOWPASS_COEFFICIENT_1 * newUsage); - -} - -/*********************************************************************** -** Called by Pa_StartStream() -*/ -PaError PaHost_StartInput( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - pahsc->pahsc_IsRecording = 0; - pahsc->pahsc_StopRecording = 0; - pahsc->pahsc_InputMultiBuffer.nextWrite = 0; - pahsc->pahsc_InputMultiBuffer.nextRead = 0; - return PaMac_RecordNext( past ); -} - -/*********************************************************************** -** Called by Pa_StopStream(). -** May be called during error recovery or cleanup code -** so protect against NULL pointers. -*/ -PaError PaHost_StopInput( internalPortAudioStream *past, int abort ) -{ - int32 timeOutMsec; - PaError result = paNoError; - OSErr err = 0; - long mRefNum; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; - - (void) abort; - - mRefNum = pahsc->pahsc_InputRefNum; - - DBUG(("PaHost_StopInput: mRefNum = %d\n", mRefNum )); - if( mRefNum ) - { - DBUG(("PaHost_StopInput: pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording )); - if( pahsc->pahsc_IsRecording ) - { - /* PLB20010420 - Fix TIMEOUT in record mode. */ - pahsc->pahsc_StopRecording = 1; /* Request that we stop recording. */ - err = SPBStopRecording(mRefNum); - DBUG(("PaHost_StopInput: then pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording )); - - /* Calculate timeOut longer than longest time it could take to play one buffer. */ - timeOutMsec = (int32) ((1500.0 * pahsc->pahsc_FramesPerHostBuffer) / past->past_SampleRate); - /* Keep querying sound channel until it is no longer busy playing. */ - while( !err && pahsc->pahsc_IsRecording && (timeOutMsec > 0)) - { - Pa_Sleep(20); - timeOutMsec -= 20; - } - if( timeOutMsec <= 0 ) - { - ERR_RPT(("PaHost_StopInput: timed out!\n")); - return paTimedOut; - } - } - } - if( err ) - { - sPaHostError = err; - result = paHostError; - } - - DBUG(("PaHost_StopInput: finished.\n", mRefNum )); - return result; -} - -/***********************************************************************/ -static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader ) -{ - sndHeader->numChannels = past->past_NumOutputChannels; - sndHeader->sampleRate = DoubleToUnsignedFixed(past->past_SampleRate); - sndHeader->loopStart = 0; - sndHeader->loopEnd = 0; - sndHeader->encode = cmpSH; - sndHeader->baseFrequency = kMiddleC; - sndHeader->markerChunk = nil; - sndHeader->futureUse2 = nil; - sndHeader->stateVars = nil; - sndHeader->leftOverSamples = nil; - sndHeader->compressionID = 0; - sndHeader->packetSize = 0; - sndHeader->snthID = 0; - sndHeader->sampleSize = 8 * sizeof(int16); // FIXME - might be 24 or 32 bits some day; - sndHeader->sampleArea[0] = 0; - sndHeader->format = kSoundNotCompressed; -} - -static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone ) -{ - UnsignedWide now; - Microseconds( &now ); - pahsc->pahsc_NumFramesDone = framesDone; - pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now ); -} - -/***********************************************************************/ -PaError PaHost_StartOutput( internalPortAudioStream *past ) -{ - SndCommand pauseCommand; - SndCommand resumeCommand; - int i; - OSErr error; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paInternalError; - if( pahsc->pahsc_Channel == NULL ) return paInternalError; - - past->past_StopSoon = 0; - past->past_IsActive = 1; - pahsc->pahsc_NumOutsQueued = 0; - pahsc->pahsc_NumOutsPlayed = 0; - - SetFramesDone( pahsc, 0.0 ); - - /* Pause channel so it does not do back ground processing while we are still filling the queue. */ - pauseCommand.cmd = pauseCmd; - pauseCommand.param1 = pauseCommand.param2 = 0; - error = SndDoCommand (pahsc->pahsc_Channel, &pauseCommand, true); - if (noErr != error) goto exit; - - /* Queue all of the buffers so we start off full. */ - for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++) - { - PaMac_PlayNext( past, i ); - } - - /* Resume channel now that the queue is full. */ - resumeCommand.cmd = resumeCmd; - resumeCommand.param1 = resumeCommand.param2 = 0; - error = SndDoImmediate( pahsc->pahsc_Channel, &resumeCommand ); - if (noErr != error) goto exit; - - return paNoError; -exit: - past->past_IsActive = 0; - sPaHostError = error; - ERR_RPT(("Error in PaHost_StartOutput: SndDoCommand returned %d\n", error )); - return paHostError; -} - -/*******************************************************************/ -long PaHost_GetTotalBufferFrames( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - return (long) (pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer); -} - -/*********************************************************************** -** Called by Pa_StopStream(). -** May be called during error recovery or cleanup code -** so protect against NULL pointers. -*/ -PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ) -{ - int32 timeOutMsec; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; - if( pahsc->pahsc_Channel == NULL ) return paNoError; - - DBUG(("PaHost_StopOutput()\n")); - if( past->past_IsActive == 0 ) return paNoError; - - /* Set flags for callback function to see. */ - if( abort ) past->past_StopNow = 1; - past->past_StopSoon = 1; - /* Calculate timeOut longer than longest time it could take to play all buffers. */ - timeOutMsec = (int32) ((1500.0 * PaHost_GetTotalBufferFrames( past )) / past->past_SampleRate); - /* Keep querying sound channel until it is no longer busy playing. */ - while( past->past_IsActive && (timeOutMsec > 0)) - { - Pa_Sleep(20); - timeOutMsec -= 20; - } - if( timeOutMsec <= 0 ) - { - ERR_RPT(("PaHost_StopOutput: timed out!\n")); - return paTimedOut; - } - else return paNoError; -} - -/***********************************************************************/ -PaError PaHost_StartEngine( internalPortAudioStream *past ) -{ - (void) past; /* Prevent unused variable warnings. */ - return paNoError; -} - -/***********************************************************************/ -PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ) -{ - (void) past; /* Prevent unused variable warnings. */ - (void) abort; /* Prevent unused variable warnings. */ - return paNoError; -} -/***********************************************************************/ -PaError PaHost_StreamActive( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - return (PaError) ( past->past_IsActive + pahsc->pahsc_IsRecording ); -} -int Mac_IsVirtualMemoryOn( void ) -{ - long attr; - OSErr result = Gestalt( gestaltVMAttr, &attr ); - DBUG(("gestaltVMAttr : 0x%x\n", attr )); - return ((attr >> gestaltVMHasPagingControl ) & 1); -} - -/******************************************************************* -* Determine number of host Buffers -* and how many User Buffers we can put into each host buffer. -*/ -static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - int32 minNumBuffers; - int32 minFramesPerHostBuffer; - int32 minTotalFrames; - int32 userBuffersPerHostBuffer; - int32 framesPerHostBuffer; - int32 numHostBuffers; - - minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer; - minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; - DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); - - /* Determine number of user buffers based on minimum latency. */ - /* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the - ** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will - ** gove lower latency when virtual memory is turned off. */ - /* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */ - minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate ); - - past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers; - DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); - minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer; - - /* We cannot make the buffers too small because they may not get serviced quickly enough. */ - if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer ) - { - userBuffersPerHostBuffer = - (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) / - past->past_FramesPerUserBuffer; - } - else - { - userBuffersPerHostBuffer = 1; - } - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; - - /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */ - numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; - /* Make sure we have enough host buffers. */ - if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS) - { - numHostBuffers = PA_MIN_NUM_HOST_BUFFERS; - } - else - { - /* If we have too many host buffers, try to put more user buffers in a host buffer. */ - while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) - { - userBuffersPerHostBuffer += 1; - framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer; - numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer; - } - } - - pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer; - pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer; - pahsc->pahsc_NumHostBuffers = numHostBuffers; - DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers )); - DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer )); - DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); -} - -/*******************************************************************/ -PaError PaHost_OpenStream( internalPortAudioStream *past ) -{ - OSErr err; - PaError result = paHostError; - PaHostSoundControl *pahsc; - int i; - /* Allocate and initialize host data. */ - pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); - if( pahsc == NULL ) - { - return paInsufficientMemory; - } - past->past_DeviceData = (void *) pahsc; - - /* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */ - if( (past->past_NumInputChannels > 0) && Mac_IsVirtualMemoryOn() ) - { - pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER; - } - else - { - pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER; - } - - PaHost_CalcNumHostBuffers( past ); - - /* Setup constants for CPU load measurement. */ - pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer); - - /* ------------------ OUTPUT */ - if( past->past_NumOutputChannels > 0 ) - { - /* Create sound channel to which we can send commands. */ - pahsc->pahsc_Channel = 0L; - err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */ - if(err != 0) - { - ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err )); - goto error; - } - - /* Install our callback function pointer straight into the sound channel structure */ - /* Use new CARBON name for callback procedure. */ -#if TARGET_API_MAC_CARBON - pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc); -#else - pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc); -#endif - - pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc; - - pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16); - for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++) - { - char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer); - if (buf == NULL) - { - ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer )); - goto memerror; - } - - PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] ); - pahsc->pahsc_SoundHeaders[i].samplePtr = buf; - pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer; - - } - } -#ifdef SUPPORT_AUDIO_CAPTURE - /* ------------------ INPUT */ - /* Use double buffer scheme that matches output. */ - if( past->past_NumInputChannels > 0 ) - { - int16 tempS; - long tempL; - Fixed tempF; - long mRefNum; - unsigned char noname = 0; /* FIXME - use real device names. */ -#if TARGET_API_MAC_CARBON - pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc); -#else - pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc); -#endif - pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16); - for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++) - { - char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer); - if ( buf == NULL ) - { - ERR_RPT(("PaHost_OpenStream: could not allocate input buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer )); - goto memerror; - } - pahsc->pahsc_InputMultiBuffer.buffers[i] = buf; - } - pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers; - - err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum); /* FIXME - use name so we get selected device */ - // FIXME err = SPBOpenDevice( (const unsigned char *) sDevices[past->past_InputDeviceID].pad_Info.name, siWritePermission, &mRefNum); - if (err) goto error; - pahsc->pahsc_InputRefNum = mRefNum; - DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum )); - - /* Set input device characteristics. */ - tempS = 1; - err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS); - if (err) - { - ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err )); - goto error; - } - - tempL = 0x03; - err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL); - if (err) - { - DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err )); - } - - /* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */ - tempS = past->past_NumInputChannels; - err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS); - if (err) - { - ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err )); - goto error; - } - - tempF = ((unsigned long)past->past_SampleRate) << 16; - err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF); - if (err) - { - ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err )); - goto error; - } - - /* Setup record-parameter block */ - pahsc->pahsc_InputParams.inRefNum = mRefNum; - pahsc->pahsc_InputParams.milliseconds = 0; // not used - pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc; - pahsc->pahsc_InputParams.interruptRoutine = 0; - pahsc->pahsc_InputParams.userLong = (long) past; - pahsc->pahsc_InputParams.unused1 = 0; - } -#endif /* SUPPORT_AUDIO_CAPTURE */ - DBUG(("PaHost_OpenStream: complete.\n")); - return paNoError; - -error: - PaHost_CloseStream( past ); - ERR_RPT(("PaHost_OpenStream: sPaHostError = 0x%x.\n", err )); - sPaHostError = err; - return paHostError; - -memerror: - PaHost_CloseStream( past ); - return paInsufficientMemory; -} - -/*********************************************************************** -** Called by Pa_CloseStream(). -** May be called during error recovery or cleanup code -** so protect against NULL pointers. -*/ -PaError PaHost_CloseStream( internalPortAudioStream *past ) -{ - PaError result = paNoError; - OSErr err = 0; - int i; - PaHostSoundControl *pahsc; - - DBUG(("PaHost_CloseStream( 0x%x )\n", past )); - - if( past == NULL ) return paBadStreamPtr; - - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return paNoError; - - if( past->past_NumOutputChannels > 0 ) - { - /* TRUE means flush now instead of waiting for quietCmd to be processed. */ - if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE); - { - for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++) - { - Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr; - if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer ); - } - } - } - - if( past->past_NumInputChannels > 0 ) - { - if( pahsc->pahsc_InputRefNum ) - { - err = SPBCloseDevice(pahsc->pahsc_InputRefNum); - pahsc->pahsc_InputRefNum = 0; - if( err ) - { - sPaHostError = err; - result = paHostError; - } - } - { - for (i = 0; i<pahsc->pahsc_InputMultiBuffer.numBuffers; i++) - { - Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i]; - if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer ); - } - } - } - - past->past_DeviceData = NULL; - PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); - - DBUG(("PaHost_CloseStream: complete.\n", past )); - return result; -} -/*************************************************************************/ -int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ) -{ -/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording. -** This routine doesn't have enough information to determine the best value -** and is being depracated. */ - return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate ); -} -/*************************************************************************/ -static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate ) -{ - int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer; - int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost; - if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS; - (void) sampleRate; - return numBufs; -} - -/*************************************************************************/ -void Pa_Sleep( int32 msec ) -{ - EventRecord event; - int32 sleepTime, endTime; - /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */ - sleepTime = ((msec * 60) + 999) / 1000; - if( sleepTime < 1 ) sleepTime = 1; - endTime = TickCount() + sleepTime; - do - { - DBUGX(("Sleep for %d ticks.\n", sleepTime )); - /* Use WaitNextEvent() to sleep without getting events. */ - /* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent - * Mac OSX crash. Thanks Dominic Mazzoni. */ - WaitNextEvent( 0, &event, sleepTime, NULL ); - sleepTime = endTime - TickCount(); - } - while( sleepTime > 0 ); -} -/*************************************************************************/ -int32 Pa_GetHostError( void ) -{ - int32 err = sPaHostError; - sPaHostError = 0; - return err; -} - -/************************************************************************* - * Allocate memory that can be accessed in real-time. - * This may need to be held in physical memory so that it is not - * paged to virtual memory. - * This call MUST be balanced with a call to PaHost_FreeFastMemory(). - */ -void *PaHost_AllocateFastMemory( long numBytes ) -{ - void *addr = NewPtrClear( numBytes ); - if( (addr == NULL) || (MemError () != 0) ) return NULL; - -#if (TARGET_API_MAC_CARBON == 0) - if( HoldMemory( addr, numBytes ) != noErr ) - { - DisposePtr( (Ptr) addr ); - return NULL; - } -#endif - return addr; -} - -/************************************************************************* - * Free memory that could be accessed in real-time. - * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). - */ -void PaHost_FreeFastMemory( void *addr, long numBytes ) -{ - if( addr == NULL ) return; -#if TARGET_API_MAC_CARBON - (void) numBytes; -#else - UnholdMemory( addr, numBytes ); -#endif - DisposePtr( (Ptr) addr ); -} - -/*************************************************************************/ -PaTimestamp Pa_StreamTime( PortAudioStream *stream ) -{ - PaTimestamp framesDone1; - PaTimestamp framesDone2; - UInt64 whenIncremented; - UnsignedWide now; - UInt64 now64; - long microsElapsed; - long framesElapsed; - - PaHostSoundControl *pahsc; - internalPortAudioStream *past = (internalPortAudioStream *) stream; - if( past == NULL ) return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - -/* Capture information from audio thread. - * We have to be careful that we don't get interrupted in the middle. - * So we grab the pahsc_NumFramesDone twice and make sure it didn't change. - */ - do - { - framesDone1 = pahsc->pahsc_NumFramesDone; - whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented; - framesDone2 = pahsc->pahsc_NumFramesDone; - } while( framesDone1 != framesDone2 ); - - /* Calculate how many microseconds have elapsed and convert to frames. */ - Microseconds( &now ); - now64 = UnsignedWideToUInt64( now ); - microsElapsed = U64Subtract( now64, whenIncremented ); - framesElapsed = microsElapsed * past->past_SampleRate * 0.000001; - - return framesDone1 + framesElapsed; -} - -/************************************************************************** -** Callback for Input, SPBRecord() -*/ -int gRecordCounter = 0; -int gPlayCounter = 0; -pascal void PaMac_InputCompletionProc(SPBPtr recParams) -{ - PaError result = paNoError; - int finished = 1; - internalPortAudioStream *past; - PaHostSoundControl *pahsc; - - gRecordCounter += 1; /* debug hack to see if engine running */ - - /* Get our PA data from Mac structure. */ - past = (internalPortAudioStream *) recParams->userLong; - if( past == NULL ) return; - - if( past->past_Magic != PA_MAGIC ) - { - AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past ); - AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic ); - goto error; - } - pahsc = (PaHostSoundControl *) past->past_DeviceData; - past->past_NumCallbacks += 1; - - /* Have we been asked to stop recording? */ - if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error; - - /* If there are no output channels, then we need to call the user callback function from here. - * Otherwise we will call the user code during the output completion routine. - */ - if(past->past_NumOutputChannels == 0) - { - SetFramesDone( pahsc, - pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); - result = PaMac_CallUserLoop( past, NULL ); - } - - /* Did user code ask us to stop? If not, issue another recording request. */ - if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) ) - { - result = PaMac_RecordNext( past ); - if( result != paNoError ) pahsc->pahsc_IsRecording = 0; - } - else goto error; - - return; - -error: - pahsc->pahsc_IsRecording = 0; - pahsc->pahsc_StopRecording = 0; - return; -} - -/*********************************************************************** -** Called by either input or output completion proc. -** Grabs input data if any present, and calls PA conversion code, -** that in turn calls user code. -*/ -static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr ) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - int16 *inPtr = NULL; - int i; - - - /* Advance read index for sound input FIFO here, independantly of record/write process. */ - if(past->past_NumInputChannels > 0) - { - if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) ) - { - inPtr = (int16 *) MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer ); - MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer ); - } - } - - /* Call user code enough times to fill buffer. */ - if( (inPtr != NULL) || (outPtr != NULL) ) - { - PaMac_StartLoadCalculation( past ); /* CPU usage */ - -#ifdef PA_MAX_USAGE_ALLOWED - /* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */ - if( past->past_Usage > PA_MAX_USAGE_ALLOWED ) - { - past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer; - } - else -#endif - { - - for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ ) - { - result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr ); - if( result != 0) - { - /* Recording might be in another process, so tell it to stop with a flag. */ - pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording; - break; - } - /* Advance sample pointers. */ - if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels; - if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels; - } - } - - PaMac_EndLoadCalculation( past ); - } - return result; -} - -/*********************************************************************** -** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager. -*/ -static PaError PaMac_RecordNext( internalPortAudioStream *past ) -{ - PaError result = paNoError; - OSErr err; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - /* Get pointer to next buffer to record into. */ - pahsc->pahsc_InputParams.bufferPtr = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer ); - - /* Advance write index if there is room. Otherwise keep writing same buffer. */ - if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) ) - { - MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer ); - } - - AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr ); - AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite ); - - /* Setup parameters and issue an asynchronous recording request. */ - pahsc->pahsc_InputParams.bufferLength = pahsc->pahsc_BytesPerInputHostBuffer; - pahsc->pahsc_InputParams.count = pahsc->pahsc_BytesPerInputHostBuffer; - err = SPBRecord(&pahsc->pahsc_InputParams, true); - if( err ) - { - AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err ); - sPaHostError = err; - result = paHostError; - } - else - { - pahsc->pahsc_IsRecording = 1; - } - return result; -} - -/************************************************************************** -** Callback for Output Playback() -** Return negative error, 0 to continue, 1 to stop. -*/ -long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index ) -{ - PaHostSoundControl *pahsc; - long result = 0; - int finished = 1; - char *outPtr; - - gPlayCounter += 1; /* debug hack */ - - past->past_NumCallbacks += 1; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return -1; - /* Are we nested?! */ - if( pahsc->pahsc_IfInsideCallback ) return 0; - pahsc->pahsc_IfInsideCallback = 1; - /* Get pointer to buffer to fill. */ - outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr; - /* Combine with any sound input, and call user callback. */ - result = PaMac_CallUserLoop( past, (int16 *) outPtr ); - - pahsc->pahsc_IfInsideCallback = 0; - return result; -} - -/************************************************************************************* -** Called by SoundManager when ready for another buffer. -*/ -static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd) -{ - internalPortAudioStream *past; - PaHostSoundControl *pahsc; - (void) theChannel; - (void) theCallBackCmd; - - /* Get our data from Mac structure. */ - past = (internalPortAudioStream *) theCallBackCmd->param2; - if( past == NULL ) return; - - pahsc = (PaHostSoundControl *) past->past_DeviceData; - pahsc->pahsc_NumOutsPlayed += 1; - - SetFramesDone( pahsc, - pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer ); - - PaMac_BackgroundManager( past, theCallBackCmd->param1 ); -} - -/*******************************************************************/ -static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index ) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - /* Has someone asked us to abort by calling Pa_AbortStream()? */ - if( past->past_StopNow ) - { - SndCommand command; - /* Clear the queue of any pending commands. */ - command.cmd = flushCmd; - command.param1 = command.param2 = 0; - SndDoImmediate( pahsc->pahsc_Channel, &command ); - /* Then stop currently playing buffer, if any. */ - command.cmd = quietCmd; - SndDoImmediate( pahsc->pahsc_Channel, &command ); - past->past_IsActive = 0; - } - /* Has someone asked us to stop by calling Pa_StopStream() - * OR has a user callback returned '1' to indicate finished. - */ - else if( past->past_StopSoon ) - { - if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 ) - { - past->past_IsActive = 0; /* We're finally done. */ - } - } - else - { - PaMac_PlayNext( past, index ); - } - return result; -} - -/************************************************************************************* -** Fill next buffer with sound and queue it for playback. -*/ -static void PaMac_PlayNext ( internalPortAudioStream *past, int index ) -{ - OSErr error; - long result; - SndCommand playCmd; - SndCommand callbackCmd; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - - /* If this was the last buffer, or abort requested, then just be done. */ - if ( past->past_StopSoon ) goto done; - - /* Load buffer with sound. */ - result = PaMac_FillNextOutputBuffer ( past, index ); - if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */ - else if( result < 0 ) goto done; - - /* Play the next buffer. */ - playCmd.cmd = bufferCmd; - playCmd.param1 = 0; - playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ]; - error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true ); - if( error != noErr ) goto gotError; - - /* Ask for a callback when it is done. */ - callbackCmd.cmd = callBackCmd; - callbackCmd.param1 = index; - callbackCmd.param2 = (long)past; - error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true ); - if( error != noErr ) goto gotError; - pahsc->pahsc_NumOutsQueued += 1; - - return; - -gotError: - sPaHostError = error; -done: - return; -} diff --git a/libs/portaudio/pa_unix/pa_unix_hostapis.c b/libs/portaudio/pa_unix/pa_unix_hostapis.c deleted file mode 100644 index 8494753c62979a3d1d71f3d03e506232bbd0cfb5..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_unix/pa_unix_hostapis.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * $Id$ - * 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_OSS - PaOSS_Initialize, -#endif - -#ifdef PA_USE_ALSA - PaAlsa_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/libs/portaudio/pa_unix/pa_unix_util.c b/libs/portaudio/pa_unix/pa_unix_util.c deleted file mode 100644 index f8cab4021c78afc6c5de2680ca47665f354992f0..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_unix/pa_unix_util.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * $Id$ - * 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/libs/portaudio/pa_unix/pa_unix_util.h b/libs/portaudio/pa_unix/pa_unix_util.h deleted file mode 100644 index 01dda01e5f775e8ece5906ffdc29b08057c25519..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_unix/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/libs/portaudio/pa_unix_oss/pa_unix_oss.c b/libs/portaudio/pa_unix_oss/pa_unix_oss.c deleted file mode 100644 index dce05caf6f665e010a81a96b72f8ff8e20736851..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_unix_oss/pa_unix_oss.c +++ /dev/null @@ -1,1923 +0,0 @@ -/* - * $Id$ - * 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 <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 __FreeBSD__ -# include <sys/soundcard.h> -# define DEVICE_NAME_BASE "/dev/dsp" -#elif defined __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/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, 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 ); - /* TODO: Handle condition where number of frames read doesn't equal number of frames requested */ - -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 ); - /* TODO: Handle condition where number of frames written doesn't equal number of frames requested */ - -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, outLatency; - - /* 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 ); - PA_ENSURE( 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, 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/libs/portaudio/pa_unix_oss/recplay.c b/libs/portaudio/pa_unix_oss/recplay.c deleted file mode 100644 index 9d4c78cfa3073a7367c7d3d24dcc5db63e556728..0000000000000000000000000000000000000000 --- a/libs/portaudio/pa_unix_oss/recplay.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * recplay.c - * Phil Burk - * Minimal record and playback test. - * - */ -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> -#ifndef __STDC__ -/* #include <getopt.h> */ -#endif /* __STDC__ */ -#include <fcntl.h> -#ifdef __STDC__ -#include <string.h> -#else /* __STDC__ */ -#include <strings.h> -#endif /* __STDC__ */ -#include <sys/soundcard.h> - -#define NUM_BYTES (64*1024) -#define BLOCK_SIZE (4*1024) - -#define AUDIO "/dev/dsp" - -char buffer[NUM_BYTES]; - -int audioDev = 0; - -main (int argc, char *argv[]) -{ - int numLeft; - char *ptr; - int num; - int samplesize; - - /********** RECORD ********************/ - /* Open audio device. */ - audioDev = open (AUDIO, O_RDONLY, 0); - if (audioDev == -1) - { - perror (AUDIO); - exit (-1); - } - - /* Set to 16 bit samples. */ - samplesize = 16; - ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); - if (samplesize != 16) - { - perror("Unable to set the sample size."); - exit(-1); - } - - /* Record in blocks */ - printf("Begin recording.\n"); - numLeft = NUM_BYTES; - ptr = buffer; - while( numLeft >= BLOCK_SIZE ) - { - if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 ) - { - perror (AUDIO); - exit (-1); - } - else - { - printf("Read %d bytes\n", num); - ptr += num; - numLeft -= num; - } - } - - close( audioDev ); - - /********** PLAYBACK ********************/ - /* Open audio device for writing. */ - audioDev = open (AUDIO, O_WRONLY, 0); - if (audioDev == -1) - { - perror (AUDIO); - exit (-1); - } - - /* Set to 16 bit samples. */ - samplesize = 16; - ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize); - if (samplesize != 16) - { - perror("Unable to set the sample size."); - exit(-1); - } - - /* Play in blocks */ - printf("Begin playing.\n"); - numLeft = NUM_BYTES; - ptr = buffer; - while( numLeft >= BLOCK_SIZE ) - { - if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 ) - { - perror (AUDIO); - exit (-1); - } - else - { - printf("Wrote %d bytes\n", num); - ptr += num; - numLeft -= num; - } - } - - close( audioDev ); -} diff --git a/libs/portaudio/pablio/ringbuffer.c b/libs/portaudio/pablio/ringbuffer.c deleted file mode 100644 index 16031fef67d663137db8dcfa7085b9800e7258d0..0000000000000000000000000000000000000000 --- a/libs/portaudio/pablio/ringbuffer.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * $Id$ - * ringbuffer.c - * Ring Buffer utility.. - * - * Author: Phil Burk, http://www.softsynth.com - * - * This program uses the PortAudio Portable Audio Library. - * For more information see: 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. - * - */ -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include "ringbuffer.h" -#include <string.h> - -/*************************************************************************** - * 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 ) -{ - return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask ); -} -/*************************************************************************** -** Return number of bytes available for writing. */ -long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ) -{ - 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 ) -{ - return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask; -} - -/*************************************************************************** -** Get address of region(s) from which we can read data. -** If the region is contiguous, size2 will be zero. -** If non-contiguous, size2 will be the size of second region. -** Returns room available to be written or numBytes, whichever is smaller. -*/ -long 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 ) -{ - return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask; -} - -/*************************************************************************** -** Return bytes written. */ -long RingBuffer_Write( RingBuffer *rbuf, 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/libs/portaudio/pablio/ringbuffer.h b/libs/portaudio/pablio/ringbuffer.h deleted file mode 100644 index 91cc7e405e8d0df425da1f4852c79fff65e539db..0000000000000000000000000000000000000000 --- a/libs/portaudio/pablio/ringbuffer.h +++ /dev/null @@ -1,100 +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 - * - * This program is distributed with the PortAudio Portable Audio Library. - * For more information see: 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. - * - */ -#include <stdio.h> -#include <stdlib.h> -#include <math.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, 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 */