Changeset 333 for portaudio/trunk/docs
- Timestamp:
- 07/26/02 15:35:31 (8 years ago)
- Location:
- portaudio/trunk/docs
- Files:
-
- 3 deleted
- 1 edited
-
PaStreamStateDiagram.gif (deleted)
-
pa_drivermodel.c.txt (deleted)
-
pa_drivermodel.h.txt (deleted)
-
proposals.html (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
portaudio/trunk/docs/proposals.html
r205 r333 22 22 <P><A href="http://www.portaudio.com/">PortAudio Home Page</A></P> 23 23 24 <P>Updated: June 12, 2002 </P> 25 <H2>Introduction</H2> 26 <P>This document describes modifications to the PortAudio API currently being considered by the developer community. It is intended to capture the current state of discussions. The authors are the various members of the PortAudio community and are too numerous to mention. Please refer to the mailing list archives to see who said what. </P> 27 <P>We are still at the design stage with all of these proposals - if you think something is missing, could be improved, or would just like to comment please do so on the PortAudio mailing list.</P> 28 <P> <A HREF="http://techweb.rfa.org/mailman/listinfo/portaudio">http://techweb.rfa.org/mailman/listinfo/portaudio</A> </P> 29 <H2>Contents</H2> 24 <P>Updated: July 27, 2002 </P> 25 <H2>The Proposals Have Moved</H2> 30 26 31 <UL> 32 <LI><A HREF="#Underflow">PortAudioCallback Underflow/Overflow Handling</A> </LI> 33 <LI><A HREF="#ImproveDeviceFormatQuerySystem">Improve Device Format Query System</A> * </LI> 34 <LI><A HREF="#Latency">Improve Latency Mechanisms</A> </LI> 35 <LI><A HREF="#AllowCallbackVariableFramesPerBuffer">Allow Callbacks to Accept Variable framesPerBuffer</A> * </LI> 36 <LI><A HREF="#Blocking">Blocking Read/Write API</A> </LI> 37 <LI><A HREF="#Interleaved">Non-Interleaved Buffers</A> </LI> 38 <LI><A HREF="#MultipleDriverModels">Support for Multiple Host APIs in a Single PortAudio Build</A> |C| </LI> 39 <LI><A HREF="#DriverModelSpecificPa_OpenStream">Host API Specific Pa_OpenStream() Parameters</A> |C| </LI> 40 <LI><A HREF="#Error">Handling of Host API Specific Error Codes</A> * </LI> 41 <LI><A HREF="#StreamStates">Clarify Stream State Machine and State Querying Functions</A> </LI> 42 <LI><A HREF="#RenamePa_GetCPULoad">Rename Pa_GetCPULoad(), PaDeviceID etc. for Consistency</A> </LI> 43 <LI><A HREF="#AdditionalPa_TerminateBehaviour">Additional Pa_Terminate() Behaviour</A> </LI> 44 <LI><A HREF="#CodingStyleGuidelines">Coding Style Guidelines</A> * </LI> 45 <LI><A HREF="#ReviseInternalHostAPI">Revise Internal Host API</A> *</LI> 27 <p>All PortAudio Enhancement Proposal documentation has moved. On the web site, it is now located at: 28 <A HREF="http://www.portaudio.com/docs/proposals">http://www.portaudio.com/docs/proposals</A> 46 29 47 </UL> 30 On the CVS server it is now located in a module named "pa_proposals". 31 </p> 48 32 49 33 50 51 <I><P>The proposals above which are marked with a * are under construction, those marked with |</I>C<I>| are essentially complete but require community approval or comment before they are considered complete. The remaining proposals are essentially complete and will be implemented as-is unless significant objections are raised.</P> 52 </I><H2>Status </H2> 53 <P>This document describes proposals that range in complexity from clarifications of existing API functionality, through to renaming API functions for consistency, through to significant feature additions. Due to the interdependency of many of the proposed changes, we plan to introduce all API changes simultaneously as part of release 19.</P> 54 <P>The developer community is in the process of reviewing all proposals. Most proposals are defined in sufficient detail to implement, however some completed proposals are dependent on proposals that are still under construction. Of the remaining unfinished proposals, only <A HREF="#ImproveDeviceFormatQuerySystem">Improve Device Format Query System</A>, <A HREF="#Latency">Improve Latency Mechanisms</A>, <A HREF="#AllowCallbackVariableFramesPerBuffer">Allow Callbacks to Accept Variable framesPerBuffer</A>, and <A HREF="#Error">Handling of Host-Specific Error Codes</A> require significant attention. Both the <A HREF="#CodingStyleGuidelines">Coding Style Guidelines</A> and <A HREF="#ReviseInternalHostAPI">Revise Internal Host API</A> proposals only effect implementors and do not effect the API definition itself. Refinement of these proposals is desirable but not critical to the development of release 19. Interested readers are advised to consult the Dependencies section of each proposal for more detailed information.</P> 55 <H2>Client Impact</H2> 56 <P>Some of the proposed changes will break existing client code. Usually these breakages involve renaming of constant identifiers or function calls. In a small number of cases additional parameters will be added to existing API functions. Concerned readers are advised to consult the Impact Analysis section of each proposal for further details.</P> 57 <P>____________</P> 58 <H2>PortAudioCallback <A NAME="Underflow"></A>Underflow/Overflow Handling</H2> 59 <H4>Status</H4> 60 <P>This proposal is sufficiently well defined to be implemented</P> 61 <H4>Background</H4> 62 <P>There are conditions where a full-duplex stream needs to generate output but doesn't have any input available, or where it has too much input so some input needs to be discarded (not passed to the output.) There is also the case where output is needed, but the callback has (transiently) consumed so much CPU time that output has to be generated without the callback being called.</P> 63 <P>Currently (V17) the PortAudioCallback Function handles these underflow/overflow conditions by passing NULL buffer pointers to the callback. This can happen if the output is pre-rolled and there is not yet any input data. It can also happen if the input underflows. </P> 64 <P>A number of concerns have been raised about the current system: For PortAudio to discard input just because it is not needed for output is considered unacceptable for some recording applications. Passing of NULL buffer pointers has been deemed to be too error prone and requires too much housekeeping for simple programs. </P> 65 <P>See <A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-October/000222.html">http://techweb.rfa.org/pipermail/portaudio/2001-October/000222.html</A> and subsequent messages in various threads.</P> 66 <P>This proposal seeks to keep the PortAudioCallback as simple as possible for ease-of-use while providing full access to overflow/underflow information, and all input and output sample data when clients require it.</P> 67 <H4>Proposal</H4> 68 <P>For streams providing input, the inputBuffer parameter will always point to a valid memory location containing framesPerBuffer frames of sample data in the requested format. The inputBuffer parameter will be NULL for output only streams. Similarly, the outputBuffer parameter will be NULL for input only streams, otherwise it will point to a valid memory location containing framesPerBuffer frames of sample data.</P> 69 <P>A new parameter will be added to the PortAudioCallback Function that gives the status of the data as bit flags. </P> 70 <PRE> 71 typedef int (PortAudioCallback)( 72 void *inputBuffer, void *outputBuffer, 73 unsigned long framesPerBuffer, 74 PaTimestamp outTime, 75 unsigned long statusFlags, 76 void *userData );</PRE> 77 <P>These bits may be set in the statusFlags parameter. </P> 78 <PRE> 79 #define paInputUnderflow (1<<0) /* Input data is all zeros because no real data is available. */ 80 #define paInputOverflow (1<<1) /* Input data was discarded by PortAudio */ 81 #define paOutputUnderflow (1<<2) /* Output data was inserted by PortAudio because the callback is using too much CPU */ 82 #define paOutputOverflow (1<<3) /* Output data will be ignored because no room is available. */</PRE> 83 <P>New rules will govern when the PortAudioCallback is called:</P> 84 85 <UL> 86 <LI>For input-only streams, the callback will be called for every available input buffer. If the callback takes too long to complete and input samples have to be discarded the paInputOverflow flag will be set the next time the callback is called. An input-only stream will never be called with the paInputUnderflow flag set. </LI> 87 <LI>For output-only streams, the callback will be called whenever an output buffer needs to be filled, except when doing so would cause the stream to fall further behind real-time due to CPULoad being too high. In such cases PortAudio will insert silence or repeat the previous buffer to the output and the paOutputUnderflow bit will be set next time the callback is called. An output-only stream will never be called with the paOutputOverflow flag set. </LI> 88 <LI>By default, a full duplex stream will behave according to the same rules as an output-only stream. If input is not available, the paInputUnderflow bit will be set and the input buffers will contain zeros. In the case of an input buffer overflow, PortAudio will discard input - in such cases the input samples will <B>not</B> be passed to a callback, and paInputOverflow will be set next time the callback is called to generate more output. A full-duplex stream in default mode will never be called with the paOutputOverflow flag set. </LI> 89 <LI>A new mode flag to Pa_OpenStream(), <I>paNeverDropInput</I> specifies that a full duplex stream will not discard overflowed input samples without calling the callback. When an input buffer overflow occurs, the callback will be passed an input buffer containing valid data and a valid output buffer pointer, the paOutputOverflow flag will be set, when the callback completes the output buffer will be discarded.</LI></UL> 90 91 <P>Note that the default full-duplex mode is intended to cover most common uses of PortAudio, where the client wants a simple audio streaming interface, and is happy to let PortAudio handle buffer underflow/overflow conditions when they occur.</P> 92 <H4>Impact Analysis</H4> 93 <P>This proposal involves adding a new statusFlags parameter to PortAudioCallback. This will require all clients to update their callback declarations accordingly. Clients who previously checked for NULL buffers will be able to remove such checks. Only clients who whish to take advantage of the callback flags, or the new <I>paNeverDropInput</I> mode will require significant changes.</P> 94 <P>____________</P> 95 <H2><A NAME="ImproveDeviceFormatQuerySystem">Improve Device Format Query System</A></H2> 96 <H4>Status</H4> 97 <P>This proposal is open for discussion.</P> 98 <H4>Background</H4> 99 <P>It has been noted that the current method (Pa_GetDeviceInfo()) of querying devices for supported sample formats, channels and sample rates is weak. It does not cleanly differentiate between 'PortAudio supported' formats and 'native' formats, and it is incapable of representing formats where the parameters are interdependent (eg where full duplex is only supported for certain sample rates.) We have also found that a static structure is not a good match for many host APIs where format discovery is performed by polling the driver. Even if a sound card supports arbitrary sample rates, the host API may only allow a client to poll to see whether a rate is available rather than providing the available rate ranges.</P> 100 <P>It has been noted that most (platform specific) audio APIs do a pretty bad job of allowing for device capability querying. Even the better APIs (ALSA is perhaps one) don't necessarily provide accurate information. This proposal should seek to maximise the amount of information that can be extracted from existing APIs while remaining expressive enough to take full advantage of APIs with more advanced capability querying systems should they become available in the future.</P> 101 <H4>Proposal</H4> 102 <P>A number of options are being considered with regard to supplying clients with format information:</P> 103 <P>Use PaDeviceInfo only for representing information that can be expressed without querying the host API multiple times, or only check for "standard" formats, or leave it unchanged.</P> 104 <P>And/Or</P> 105 <P>Add a Pa_IsFormatSupported() function:</P> 106 <PRE>Pa_IsFormatSupported( PaDeviceIndex inputDevice, 107 int numInputChannels, 108 PaSampleFormat inputSampleFormat, 109 void *inputDriverInfo, 110 PaDeviceIndex outputDevice, 111 int numOutputChannels, 112 PaSampleFormat outputSampleFormat, 113 void *outputDriverInfo, 114 double sampleRate );</PRE> 115 <P>At a minimum this call would need to return values indicating whether the requested format(s) are supported natively, or will undergo conversion by PortAudio. The result could be a set of flags indicating:</P> 116 117 <UL> 118 <LI>Input byte order (native/converted) </LI> 119 <LI>Input sample format (native/converted) </LI> 120 <LI>Output byte order (native/converted) </LI> 121 <LI>Output sample format (native/converted)</LI></UL> 122 123 <P>There also needs to be a method for accommodating host-API-specific return flags.</P> 124 <H4>Discussion</H4> 125 <P>At present it seems desirable to retain Pa_GetDeviceInfo() and the PaDeviceInfo structure. At a minimum PaDeviceInfo needs to contain name and host API type code fields:</P> 126 <PRE>typedef struct{ 127 int structVersion; 128 const char *name; 129 PaHostApiTypeCode hostApi; 130 } PaDeviceInfo;</PRE> 131 <P>It was suggested that we could do things the way MME does: if Pa_OpenStream() is called with a NULL stream parameter then the stream isn't opened, but it is checked to see if the device supports the specified format - if the format is supported then paNoError would be returned, otherwise an error code would be returned. However, this has been ruled to be unsatisfactory, since querying for supported formats is really a different function from opening a stream.</P> 132 <H4>Impact Analysis</H4> 133 <P>This proposal will provide clients with more expressive methods for querying device capabilities, which should improve the utility of PortAudio. It is not yet clear what the full impact of this proposal will be.</P> 134 <P>____________</P> 135 <H2><A NAME="Latency"></A>Improve Latency Mechanisms</H2> 136 <H4>Status</H4> 137 <P>This proposal is open for discussion.</P> 138 <H4>Background</H4> 139 <P>The current mechanism for setting latency is not considered optimal by all clients of the API. There seems to be some tension between using the framesPerBuffer parameter of Pa_OpenStream as a latency control parameter and as a specifier for the number of frames supplied to the callback. Specifying latency as a single millisecond value would be more user friendly for some users, however some host APIs need latency to be tuned by specifying buffer sizes and number of buffers. Additionally, it not clear whether separate input and output buffer counts would allow tuning of lower latencies in some circumstances.</P> 140 <P>A related issue is the need to improve the interface available to determine default latency parameters. The most recent proposal is documented below, however there is still some debate as to whether this is satisfactory. </P> 141 <P>See this thread: <A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-October/000196.html">http://techweb.rfa.org/pipermail/portaudio/2001-October/000196.html</A> </P> 142 <H4>Proposal</H4> 143 <P>The numBuffers parameter to Pa_OpenStream() could be removed, and replaced by two new parameters inputLatencyFrames and outputLatencyFrames. These parameters allow clients to fine-tune latency in a portable manner. PortAudio implementations should select buffer sizes based on these parameters, if this is not possible they may choose the closest viable buffer size and latency instead. In such cases the PortAudio implementations should round-up (ie always provide equal or higher latency than requested.) </P> 144 <P>The special latency value of 0 indicates that the implementation should use the default latency values, this will produce the same behavior as passing 0 for numBuffers in existing PortAudio implementations. Clients may retrieve recommended safe latency settings using the following two functions:</P> 145 <PRE> 146 unsigned long Pa_GetRecommendedLowLatencyFrames( PaDeviceIndex deviceID ); /* For interactive performance. */ 147 unsigned long Pa_GetRecommendedHighLatencyFrames( PaDeviceIndex deviceID ); /* For playing sound files. */ 148 </PRE> 149 <P> </P> 150 <P>Currently, when numBuffers>0, Pa_OpenStream will constrain the actual numBuffers so that the latency is within a valid range determined by the host API, or an environment variables such as PA_MIN_LATENCY_MSEC. Propose changing the behavior so that the requested value is honored as much as possible. This will allow the user to override the minimum if they know their system can handle it. This might be used, for example on patched Linux kernels</P> 151 <P>In addition to the portable latency setting mechanism just described, implementations may use the inputDriverInfo and outputDriverInfo Pa_OpenStream() parameters to provide host API specific latency setting mechanisms which directly reflect the underlying buffer passing scheme. For example, the MME driverInfo structure would provide a way to directly set the bufferSize and numberOfBuffers parameters for input and output. When driverInfo structures are passed to Pa_OpenStream(), using 0 values for their API specific latency settings should cause PortAudio to use Pa_OpenStream()'s latencySamples parameters.</P> 152 <P>In cases where Host API specific latency parameters may be limited to certain allowable ranges (buffer sizes in ASIO for example) a method for querying these limits should be provided. This will consist of host-API specific query functions declared in a host-api specific header file. These header files will also contain the declaration of the host API specific driverInfo structure.</P> 153 <P>The following two functions have been proposed to retrieve the estimated input and output latency of a stream. Both return the estimated latency in ms.</P> 154 <PRE> 155 /* the following would operate directly on streams */ 156 double Pa_StreamInputLatency( PaStream *stream ); 157 double Pa_StreamOutputLatency( PaStream *stream ); 158 </PRE> 159 <P>The Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) function will be removed, as it's functionality is fulfilled by the get recommended latency functions.</P> 160 <H4>Discussion</H4> 161 <P>This proposal provides both a high level mechanism for portable latency tuning, and suggests method for providing a host-API specific latency tuning interface. The provision of both default latency settings (via 0 valued latencySamples parameters) and query functions for recommended latency settings provide the needed flexibility for simple, and portable applications.</P> 162 <P>It is not clear whether a 0 latencySamples parameter produces the same latency as returned by Pa_GetRecommendedHighLatencySamples() or whether there is a separate default latency value, in which case there should also be a Pa_GetDefaultLatencySamples() function.</P> 163 <P>It is unclear whether the Pa_StreamInputLatency() and Pa_StreamOutputLatency() functions are needed, whether they relate directly to this proposal, and how they will be effected by the yet to be documented <U>Improve Callback Timestamp Information</U> proposal. </P> 164 <P>Should we provide a way of notifying the client if the latencySamples parameters have not been accurately honored?</P> 165 <H4>Impact Analysis</H4> 166 <P>This proposal will require all clients to alter their calls to Pa_OpenStream(). Clients who passed a 0 value for numBuffers will not need to significantly alter their code. Clients who manipulated numBuffers will need to either use the latencySamples parameters, or the host API specific interfaces, as they become available.</P> 167 <P>____________</P> 168 <H2><A NAME="AllowCallbackVariableFramesPerBuffer"></A>Allow Callbacks to Accept Variable framesPerBuffer</H2> 169 <H4>Status</H4> 170 <P>This proposal is under construction.</P> 171 <B><P>Background</B><BR> 172 <BR> 173 Some devices prefer, or even require, a particular value for framesPerBuffer. Some applications also prefer a particular buffer size because they may, for example, be doing FFTs. If possible, an integral number of application buffers can be fit into a device buffer. If an integral number of application buffers cannot be fit into an application buffer then some system for adapting between them is required. Stephane Letz implemented a block adapter for the ASIO implementation that could perhaps be made part of a utility library for PortAudio.<BR> 174 <BR> 175 Adapting between different block size, unfortunately, involves extra memory movement and should be avoided. One way to avoid this is to allow an application to say "I can handle any value for framesPerBuffer". An example would be a simple algorithm like the one in "pa_tests/pa_fuzz.c". Its callback function could easily work with any value for FramesPerBuffer.<BR> 176 <BR> 177 <B>Proposal</B><BR> 178 <BR> 179 Pa_OpenStream() should be able to accept a zero value for framesPerBuffer. When framesPerBuffer is zero, the implementation can choose any value that it thinks will work best given the other constraints. That value will be passed to the user callback.<BR> 180 <BR> 181 To make the code more obvious, this constant could be used:<BR> 182 <BR> 183 #define paFramesPerBufferUnspecified (0)<BR> 184 <BR> 185 In order to find out what value the implementation chose, and also to help the application determine the actual latency, the following calls could be added:<BR> 186 <BR> 187 int Pa_GetFramesPerBuffer( PaStream* stream );<BR> 188 int Pa_GetNumOutputBuffers( PaStream* stream );<BR> 189 int Pa_GetNumInputBuffers( PaStream* stream );</P> 190 <H4>Impact Analysis</H4> 191 <P>This proposal will not effect existing client code, since all clients will currently specify a non-zero framesPerBuffer parameter. Clients whose code can operate with a flexible number of framesPerBuffer may benefit from improved efficiency in some cases simply by specifying paFramesPerBufferUnspecified.</P> 192 <P>____________</P> 193 <H2><A NAME="Blocking"></A>Blocking Read/Write API</H2> 194 <H4>Status</H4> 195 <P>This proposal is sufficiently well defined to be implemented.</P> 196 <H4>Background</H4> 197 <P>Many PortAudio users have requested a blocking read()/write() API that will be supported in addition to the current callback based API. A blocking Read/Write API would allow a more natural style of multi-threaded programming, and facilitate single-threaded reactive applications, while insulating clients from platform-specific thread synchronisation facilities. </P> 198 <P>A blocking read/write API would also be useful when binding PortAudio to languages that don't easily support callbacks such as Python, Java, Lisp and Smalltalk. However in this case it has been noted that a blocking API is not sufficient - the host language also needs to support native threads to interact efficiently with blocking. Dannenberg observes that native thread support cannot be added without major redesign (based on a study of Python and Squeak), but given blocking calls, there are several ways to structure programs using non-native threads.</P> 199 <P>Adding a blocking Read/Write interface to PortAudio has been discussed on a number of occasions, including the following threads:</P> 200 <P><A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-August/000063.html">http://techweb.rfa.org/pipermail/portaudio/2001-August/000063.html</A> a long thread about blocking calls.</P> 201 <P><A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-August/000137.html">http://techweb.rfa.org/pipermail/portaudio/2001-August/000137.html</A> this is Roger Dannenberg's proposal and a subsequent discussion</P> 202 <P><A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-August/000144.html">http://techweb.rfa.org/pipermail/portaudio/2001-August/000144.html</A> is a thread discussing using blocking APIs with other languages</P> 203 <H4>Proposal</H4> 204 <P>If a NULL callback parameter is passed to Pa_OpenStream() then the stream will be opened in blocking mode. This enables users to call Pa_WriteStream() and Pa_ReadStream() to read and write sample data. (The PaErrorNum item "paNullCallback" becomes obsolete.)</P> 205 <P>Pa_WriteStream() writes a buffer of frames to a stream. The length of the buffer is arbitrary and specified by the frames parameter. Pa_WriteStream() returns when all samples have been copied from buffer. If necessary, Pa_WriteStream() will wait until buffer space becomes available. (Waiting on Unix will be the by-product of an I/O system call, waiting in Win32 will be implemented by waiting on an Event object, and waiting on MacOS 9 will probably require a busy wait.) High performance applications will want to match the length of the buffer to framesPerBuffer, but this is not a requirement.</P> 206 <P>The buffer parameter has the same semantics and format as the inputbuffer and outputbuffer parameters of a PortAudioCallback function. In particular, non-interleaved data is handled in the same way.</P> 207 <PRE>PaError Pa_WriteStream( PaStream* stream, 208 void *buffer, 209 unsigned long frames );</PRE> 210 <P>Pa_ReadStream() is similar, but it reads rather than writes.</P> 211 <PRE> 212 PaError Pa_ReadStream( PaStream* stream, 213 void *buffer, 214 unsigned long frames );</PRE> 215 <P>Pa_ReadStream() returns <I>paInputUnderflow</I> if input data was discarded by PortAudio after the previous call and before this call. Pa_WriteStream() returns <I>paOutputUnderflow</I> if output data was inserted after the previous call and before this call. The mode flag <I>paNeverDropInput</I> is ignored because Pa_ReadStream() and Pa_WriteStream() are not synchronized.</P> 216 <P>There are two functions to determine the number of frames available for writing and reading. These functions may be called to determine whether calls to Pa_WriteStream() or Pa_ReadStream() will return immediately or will wait. The return value, if non-negative, is the maximum number of frames that can be written or read without blocking or busy waiting. A negative value is a PaErrorNum.</P> 217 <PRE>long Pa_StreamWriteAvailable( PaStream* stream ); 218 219 long Pa_StreamReadAvailable( PaStream* stream );</PRE> 220 <P>The stream functions Pa_CloseStream(), Pa_StartStream(), Pa_StopStream(), Pa_AbortStream(), and Pa_StreamTime() work with the blocking API as well as with callbacks. Pa_StreamCPULoad() does not work with the blocking API and will return 0 when called on a blocking stream. PortAudio might be extended to give applications access to the internal routines that compute Pa_StreamCPULoad(). Applications using blocking calls could then bracket audio computation with these calls to determine the CPU load. (This additional functionality is not being proposed here.)</P> 221 <H4>Discussion</H4> 222 <P>A rejected alternative is to allow Pa_WriteStream() and Pa_ReadStream() to return the number of frames actually written or read so that a Mac implementation could return immediately and avoid blocking. This would require applications to be prepared to handle partial read/writes. It seems simpler and more consistent to use "Available" to determine in advance whether blocking or busy waiting will occur if that is a concern. Also, note that data is almost certainly copied; however, it seems likely that the copy will be folded into any format conversion.</P> 223 <P>Implementations may want to provide a way for applications to be notified when data can be written or read. For example, one might want to know the file ID of an ALSA or OSS stream for use in a select() system call. Since this sort of information will be platform-specific and non-portable, no interface is defined here, but implementations can include a device-model-specific access function. If applications commonly need this information, we can think about how to make this more standardized.</P> 224 <H4>Implementation Notes</H4> 225 <P>Implementing blocking i/o will be quite simple for host APIs which are natively blocking-based. Under Windows (MME), the arrival of a buffer will signal an Event passed to waveOutOpen(). Pa_WriteStream() and Pa_ReadStream() will do all the work (no server threads necessary). Writes will make waveOutWrite calls. When no buffer is available, the writer will wait on the event and try again. Reading is similar. On the Mac, a double-buffer scheme can be set up where the Mac callbacks pick up data placed in buffers by Pa_WriteStream(). The double-buffer adds to the latency. Alternatively (and preferably) callbacks can be used only for notification, and Pa_WriteStream() can issue all the calls to write samples.</P> 226 <P>PABLIO currently contains a busy-wait ring buffer in "ringbuffer.c" which is generic, used in many projects and is pretty solid. This code could be a useful starting point for implementing the new blocking API on some platforms.</P> 227 <P>Pa_WriteStream() and Pa_ReadStream() are not thread safe. Applications wanting to call these from multiple threads should manage their own mutual exclusion. <I>[Roger: Is any of PortAudio thread safe? I don't think so. This is good because it avoids many system calls for mutual exclusion.]</P> 228 </I><P>At one time it was suggested that implementations only implement blocking calls and that callbacks would be required to implement callbacks in terms of the blocking API. The current direction is that this decision should be made independently for each host API.</P> 229 <H4>Impact Analysis</H4> 230 <P>This proposal would extend the functionality of PortAudio without requiring any changes to client code with the exception that the PaErrorNum paNullCallback will no longer be defined. As noted above, implementation complexity is dependent on the target platform.</P> 231 <P>____________</P> 232 <H2>Non-<A NAME="Interleaved"></A>Interleaved Buffers</H2> 233 <H4>Status</H4> 234 <P>This proposal is sufficiently well defined to be implemented. No objections have been raised.</P> 235 <H4>Background</H4> 236 <P><A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-October/000210.html">http://techweb.rfa.org/pipermail/portaudio/2001-October/000210.html</A></P> 237 <P>Some native APIs use non-interleaved buffers, particularly those that support N>2 channels. Additionally, many client applications use non-interleaved buffers internally. In order to avoid adding unnecessary overhead, PortAudio should support both interleaved and non-interleaved buffers on all platforms. </P> 238 <P>The current PortAudio/ASIO implementation works as follows : ASIO native buffers are non-interleaved and the de-interleaving, format conversion and copying the data into PortAudio interleaved buffers is done in one loop. But if PortAudio supported non-interleaved buffers then we could use efficient vector operations even for native buffer <==> port audio buffers transfers. </P> 239 <H4>Proposal</H4> 240 <P>A new sample format could be defined: </P> 241 <PRE>#define paNonInterleaved ((PaSampleFormat) (1<<31)) </PRE> 242 <P>This could be used as a modifier flag to the buffer format fields of Pa_OpenStream(). When present, this flag would indicate that non-interleaved buffers would be passed to the callback. When not present, interleaved buffers would be used as is currently always the case. For example, the following code would open an interleaved stream:</P> 243 <PRE> 244 Pa_OpenStream(&stream, 245 paNoDevice, 246 0, 247 paFloat32 248 NULL, 249 Pa_GetDefaultOutputDevice(), 250 2, 251 paFloat32, 252 NULL, 253 SAMPLE_RATE, 254 FRAMES_PER_BUFFER, 255 0, 256 paClipOff, 257 patestCallback, 258 &data );</PRE> 259 <P>And the following code would open a non-interleaved stream:</P> 260 <PRE> 261 Pa_OpenStream(&stream, 262 paNoDevice, 263 0, 264 paFloat32|paNonInterleaved, 265 NULL, 266 Pa_GetDefaultOutputDevice(), 267 2, 268 paFloat32|paNonInterleaved, 269 NULL, 270 SAMPLE_RATE, 271 FRAMES_PER_BUFFER, 272 0, 273 paClipOff, 274 patestCallback, 275 &data );</PRE> 276 <P>In the user callback, the application would be passed a pointer to an array of buffers. The left and right buffers of a non-interleaved stream could be accessed as follows: </P> 277 <PRE> 278 float *left = ((float **) inputBuffer)[0]; 279 float *right = ((float **) inputBuffer)[1];</PRE> 280 <P>This new sample format could also be used to interrogate the host API to see if it supports interleaved or non-interleaved buffers. This would be achieved by reading the nativeSampleFormats field of the PaDeviceInfo structure. </P> 281 <H4>Impact Analysis</H4> 282 <P>This proposal extends the functionality of PortAudio without any impact on existing client code. It will require new conversion functions and all existing PortAudio implementations will have to be modified to reference these new conversion functions.</P> 283 <P>____________</P> 284 <H2><A NAME="MultipleDriverModels">Support For Multiple Host APIs</A> in a Single Build</H2> 285 <H4>Status</H4> 286 <P>This proposal is currently being discussed. Its final form depends on a number of other unfinished proposals.</P> 287 <H4>Dependencies </H4> 288 <P>The API changes described in this proposal are independent of all other proposals. However, changes to the host error mechanism defined in <A HREF="#Error">Handling of Host-Specific Error Codes</A>, and the addition of new API functions due to the <A HREF="#Blocking">Blocking Read/Write API</A> proposal may effect the implementation of this proposal. Changes to the API defined by the <A HREF="#ImproveDeviceFormatQuerySystem">Improve Device Format Query System</A> and the <A HREF="#Latency">Improve the Latency Setting Mechanism</A> proposals will need to be multi-host-API capable. </P> 289 <H4>Background</H4> 290 <P>As the number of supported host APIs on each platform grows (WMME, ASIO, and DirectSound under Windows for example) client applications need to be able to select between different host APIs at run-time. At least four platforms supported by PortAudio have multiple host audio APIs. At present PortAudio allows clients to link in support for at most one host API.</P> 291 <P>This proposal is based this email: <A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-December/000308.html">http://techweb.rfa.org/pipermail/portaudio/2001-December/000308.html</A></P> 292 <H4>Requirements</H4> 293 <P>It will be necessary to supply clients with a method of displaying a textual description of the host API for each PortAudio device.</P> 294 <P>Some PortAudio functions do not operate on PortAudioStreams, but rather they operate on or return the global state of the PortAudio library as a whole. If multiple host APIs were present, some of these functions would have different implementations, or would return different values depending on which host API they applied to. These functions include:</P> 295 <PRE> int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ); 296 PaDeviceID Pa_GetDefaultInputDeviceID( void ); 297 PaDeviceID Pa_GetDefaultOutputDeviceID( void ); 298 </PRE> 299 <P>Note that Pa_CountDevices() could also be interpreted as applying to a specific host API.</P> 300 <P>PortAudio currently defines a per-host-API extension mechanism via the inputDriverInfo and outputDriverInfo parameters to Pa_OpenStream(). For code to take advantage of host-API-specific extensions when multiple host APIs are present there needs to be a way to establish which (statically identified) host API is associated with each device. This is because host-API -specific extensions must only be used in combination with devices supplied by that host API.</P> 301 <P>PortAudio should present clients with all of the devices made available by each host API. This means that some physical devices may be accessible though multiple host APIs. Since it will not be possible to open a full duplex stream with input and output devices from different host APIs, some clients may want to enumerate the available host APIs and only display devices from one host API at a time.</P> 302 <P>Introducing a new PortAudioHostAPI abstraction could fulfil the above requirements. At a minimum, this abstraction would need to have the following attributes:</P> 303 304 <UL> 305 <LI>A textual description for display on user interfaces </LI> 306 <LI>Functions for querying default device ids and latency parameters for each host API </LI> 307 <LI>A unique identifier for each host API published in portaudio.h for use in code which takes advantage of host API specific extensions</LI></UL> 308 309 <P>Additionally, the following features could be present:</P> 310 311 <UL> 312 <LI>A method for querying the default PortAudioHostAPI (perhaps the "best" host API which has more than 0 devices available) </LI> 313 <LI>A method for enumerating 'currently available' PortAudioHostAPIs. 'Currently available' could be interpreted as meaning the host APIs linked into the current PortAudio implementation, or it could mean the host APIs which currently have more than zero devices available. </LI> 314 <LI>A method of enumerating PortAudioDevices independently for each available PortAudioHostAPI</LI></UL> 315 316 <H4>Proposal</H4> 317 <P>This proposal consists of the 7 modifications to the PortAudio API listed below.</P> 318 <P>1. Define a new PaHostApiTypeId enumeration, with fixed values for each host API:</P> 319 <PRE> 320 /* 321 The PaHostApiTypeId enumeration contains constants for uniquely 322 Identifying each host API supported by PortAudio. This type 323 is used in the PaHostApiInfo structure below. Host API type ids 324 are guaranteed to never change, thus allowing code to be written that 325 conditionally uses host API specific extensions. 326 New type ids will only be allocated when support for a host API 327 model reaches "public alpha" status, prior to that developers should 328 use the paInDevelopment type id. 329 */ 330 331 typedef enum { 332 paInDevelopment=0, /* use while developing support for a new host API */ 333 paWin32DirectSound=1, 334 paWin32MME=2, 335 paWin32ASIO=3, 336 paMacOSSoundManager=4, 337 paMacOSCoreAudio=5, 338 paMacOSASIO=6, 339 paOSS=7, 340 paALSA=8, 341 paIRIXAL=9, 342 paBeOS=10 343 }PaHostApiTypeId ;</PRE> 344 <P>2. Define a method for enumerating host APIs:</P> 345 <PRE> 346 /* 347 Host API enumeration mechanism. 348 349 Host API indicies range from 0 to Pa_CountHostApis()-1. 350 351 Pa_GetDefaultHostApi() returns the index of the default host api. 352 The default host API is the lowest common denominator 353 Host API on the current platform and is unlikely to provide 354 the best performance. 355 */ 356 357 typedef int PaHostApiIndex; 358 359 PaHostApiIndex Pa_CountHostApis (); 360 361 PaHostApiIndex Pa_GetDefaultHostApi(); 362 </PRE> 363 <P>3. Provide a method for retrieving information about a given host API:</P> 364 <PRE> 365 /* 366 Pa_GetHostApiInfo() returns a pointer to an immutable 367 PaHostApiInfo structure referring to the host API specified by hostApi. 368 If hostApi is out of range the function returns NULL. The returned structure 369 is owned by the PortAudio implementation and must not be manipulated or 370 freed. The pointer is only guaranteed to be valid between calls 371 to Pa_Initialize() and Pa_Terminate(). 372 */ 373 374 const PaHostApiInfo * Pa_GetHostApiInfo(PaHostApiIndex hostApi); 375 376 struct{ 377 int structVersion; 378 PaHostApiTypeId typeId; /* the well known unique identifier of this host API */ 379 const char *name; /* a textual description of the host API for display on user interfaces */ 380 }PaHostApiInfo; 381 </PRE> 382 <P>4. Add a new field to PaDeviceInfo to identify the host API type:</P> 383 <PRE> 384 struct{ 385 ... 386 PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/ 387 ... 388 }PaDeviceInfo;</PRE> 389 <P>This would enable the following two code fragments to be written.</P> 390 <PRE> 391 /* obtain the user-readable name of a device's host API */ 392 Pa_GetHostApiInfo( deviceInfo->hostApi )->name; 393 394 /* implement special behavior for a specific host API */ 395 if( Pa_GetHostApiInfo( deviceInfo->hostApi )->typeId == paWin32MME ){ 396 InitialiseWmmeSpecificDeviceInfo(); 397 }</PRE> 398 <P>5. Provide methods for finding per-host API default devices and latency settings:</P> 399 <PRE> 400 PaDeviceIndex Pa_HostApiDefaultInputDevice( PaHostApiIndex hostApi ); 401 PaDeviceIndex Pa_HostApiDefaultOutputDevice( PaHostApiIndex hostApi ); 402 int Pa_HostApiMinNumBuffers(PaHostApiIndex hostApi, int framesPerBuffer, double sampleRate );</PRE> 403 <P>6. Provide functions for enumerating devices on a per-host-API basis. Note that this functionality is provided in addition to the current Pa_CountDevices() and Pa_GetDeviceInfo() functions:</P> 404 <PRE> 405 PaDeviceIndex Pa_HostApiCountDevices( PaHostApiIndex hostApi ); 406 PaDeviceIndex Pa_HostAPIGetDeviceID( PaHostApiIndex hostApi, PaDeviceIndex perHostApiIndex );</PRE> 407 <P>7. Re-implement the following existing functions to use the default host API. This would be a backwards compatible change except for Pa_GetMinNumBuffers() which gains an extra parameter.</P> 408 <PRE> 409 PaDeviceIndex Pa_GetDefaultInputDevice( void ); /* returns the default device id for the default host API */ 410 PaDeviceIndex Pa_GetDefaultOutputDevice( void ); 411 412 int Pa_GetMinNumBuffers( PaDeviceIndex id, int framesPerBuffer, double sampleRate );</PRE> 413 <P>Note that Pa_GetMinNumBuffers() takes a device id, not a host API id. This minimises the need for clients to be aware of the multiple host API extensions. </P> 414 <H4>Discussion</H4> 415 <P>The main disadvantage of this proposal it that it may make the API seem more complex for new users.</P> 416 <P>There is concern that this proposal is too complex, and that the simpler solution of simply adding a hostAPI string to the device info structure of each device would be sufficient. It is true that the simple solution would allow clients to duplicate the functionality of this proposal, provided hostAPI strings were published and guaranteed not to change in the future. However, the bulk of the functionality included in this proposal will need to be implemented internally to facilitate multiple host API support anyway. This proposal is based on the assumption that it is better to expose such functionality in the PortAudio API rather than require clients to reimplement what is already present internally. </P> 417 <P>There has been discussion about supporting "pluggable" host APIs - the general idea is that a client application could link against PortAudio and PortAudio would load the available Host APIs at run-time using "PortAudio Host API Plugins." Some people consider this to be an overly complex solution, and no significant advantages over a monolithic PortAudio dll have been submitted yet. Some people would like PortAudio to always be able to be statically linked with multiple host API support. The ability to load additional host APIs at runtime is considered desirable so long as the basic multiple host API mechanism does not require dynamic linking.</P> 418 <P>The overhead (both processor and memory) of the Multiple Host API support should be minimised on platforms which don't have multiple host APIs (such as BeOS and some handheld devices.) However, the multiple host API support will still be used on all platoforms, so as to reduce the burden on implementers if a second API becomes available, and also to allow reuse of common code in the multiple host API layer across all implementations.</P> 419 <H4>Implementation Notes</H4> 420 <P>The implementation will follow the methodology currently employed in PortMIDI described here: <A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-December/000295.html">http://techweb.rfa.org/pipermail/portaudio/2001-December/000295.html</A></P> 421 <P>An implementation of the host API neutral "Façade" of this proposal exists here: </P> 422 <P><A HREF="http://www.portaudio.com/docs/pa_drivermodel.c.txt">http://www.portaudio.com/docs/pa_drivermodel.c.txt</A></P> 423 <P><A HREF="http://www.portaudio.com/docs/pa_drivermodel.h.txt">http://www.portaudio.com/docs/pa_drivermodel.h.txt</A></P> 424 <P>This proposal will involve the changes described below. Note that the string <HA> will be replaced with a host API tag for each implementation.</P> 425 <P>Each host API will have it's own Initialize function which PortAudio will call in response to client calls to Pa_Initialize and Pa_Terminate respectively. This will be the only identifier each host API implementation will be required to expose.</P> 426 <PRE>PaError Pa<HA>_Initialize( PaImplementation **impl );</PRE> 427 <P>PaImplementation is an internal data structure containing a set of function pointers for globally relevant functions: (function pointer type declarations omitted for simplicity:)</P> 428 <PRE>struct{ 429 fptr terminate; /* takes the PaImplementation* returned by initialize */ 430 fptr getHostAPIInfo; 431 fptr getHostError; 432 fptr getHostErrorText; 433 fptr countDevices; 434 fptr getDefaultInputDeviceID; 435 fptr getDefaultOutputDeviceID; 436 fptr getDeviceInfo; 437 fptr openStream; 438 fptr getMinNumBuffers; 439 } PaImplementation;</PRE> 440 <P>The function pointers in PaImplementation will point to the corresponding functions in current PortAudio implementations. The new multiple host API support code will take care of mapping per-host API device ids onto a single homogenous device id range. A significant advantage of this scheme is that it will require very little change to existing PortAudio implementations.</P> 441 <P>A new PaStreamImplementation internal data structure will be defined to contain function pointers to implementations of the stream functions for each host API. This structure will be placed at the head of implementation-specific data structures returned as PortAudioStream* in current implementations.</P> 442 <PRE>struct{ 443 unsigned long magic; 444 fptr close; 445 fptr start; 446 fptr stop; 447 fptr abort; 448 fptr read; 449 fptr write; 450 fptr readAvailable; 451 fptr writeAvailable; 452 fptr active; 453 fptr time; 454 fptr cpuLoad; 455 } PaStreamImplementation;</PRE> 456 <P>Magic contains a unique bit pattern which should be set by implementations when a stream is opened, and cleared when it is closed. This technique will allow implementations to perform some degree of validation on PortAudioStream* passed to PortAudio.</P> 457 <H4>Impact Analysis</H4> 458 <P>This proposal will significantly improve the utility of PortAudio by allowing clients to support multiple host APIs in a single executable. </P> 459 <P>The only required change for existing clients will be to insert an extra deviceID parameter into calls to Pa_GetMinNumBuffers().</P> 460 <P>Since multiple host APIs may return devices with the same names, a minimum requirement for clients who want to be "multiple host API aware" will be to ensure that the appropriate host API name is displayed alongside device names in the user interface.</P> 461 <P>____________</P> 462 <H2><A NAME="DriverModelSpecificPa_OpenStream">Host API Specific Pa_OpenStream() Parameters</A></H2> 463 <H4>Status</H4> 464 <P>This proposal is essentially complete, but is pending the final definition of PaHostApiTypeId (see below.) </P> 465 <H4>Dependencies</H4> 466 <P>If the PaHostApiSpecificStreamInfo structure defined in this proposal includes a PaHostApiTypeId host API identifier, then this proposal depends on the <A HREF="#MultipleDriverModels">Support for Multiple Host APIs in a Single PortAudio Build</A> proposal to define the form of the identifier.</P> 467 <H4>Background</H4> 468 <P>Pa_OpenStream has always had the inputDriverInfo and outputDriverInfo parameters, which were defined to support passing host API specific information to PortAudio implementations. Currently these parameters are defined as void* and are not used by any implementation. Two uses of inputDriverInfo and outputDriverInfo are planned for the near future: passing device names to OSS drivers, and passing additional device ids for opening multichannel soundcards under MME.</P> 469 <H4>Proposal</H4> 470 <P>The following structure could be defined and be placed at the head of all data structures passed to the inputDriverInfo and outputDriverInfo parameters of Pa_OpenStream:</P> 471 <PRE>struct{ 472 unsigned long size; /* size of whole structure including this header */ 473 PaHostApiTypeId hostApiType; /* host API for which this data is intended */ 474 unsigned long version; /* structure version */ 475 }PaHostApiSpecificStreamInfo;</PRE> 476 <P>The following host API specific extensions should be placed in separate header files rather than being placed in portaudio.h</P> 477 <P>___</P> 478 <P>The following structure is proposed for passing device names to the OSS implementation:</P> 479 <PRE>struct{ 480 PaHostApiSpecificStreamInfo header; 481 char *deviceName; 482 }PaOSSSpecificStreamInfo;</PRE> 483 <P>A pointer to this structure could be passed to Pa_OpenStream() to request that a device other than the default dsp device be opened. This structure could be used for opening input and/or output devices.</P> 484 <P>___</P> 485 <P>The following structure is proposed for passing multiple interleaved device ids to the MME implementation in order to open a multichannel stream with some soundcards that support multichannel operation via multiple stereo (or other number of channels) interleaved devices. When this structure is passed, the MME implementation would ignore the deviceId parameters passed directly to Pa_OpenStream(), however it would not ignore the channelCount parameters.</P> 486 <P>#define paWMMEPassMultipleInterleavedBuffers 0x01 /* a flag */</P> 487 <PRE>struct{ 488 PaHostApiSpecificStreamInfo header; 489 int *devicesAndChannelCounts; /* interleaved devices and channelCounts */ 490 int deviceCount; 491 int flags; 492 }PaMMESpecificStreamInfo;</PRE> 493 <P>The deviceIdsAndChannelCounts field points to an array of ints containing multiple {deviceId, channelCount} pairs. The number of integer elements in the array must be two times the value of the deviceCount field. Specified deviceIds must have a host API type of Windows MME. Currently only one flag is defined: paWMMEPassMultipleInterleavedBuffers, this can be used to request that the raw, multiple interleaved buffers be passed to the callback.</P> 494 <H4>Discussion</H4> 495 <P>The type of the inputDriverInfo and outputDriverInfo parameters could be changed to PaHostAPISpecificStreamInfo* however this may cause more trouble that it's worth.</P> 496 <P>The PaMMESpecificStreamInfo functionality may require the common buffer conversion functions defined in the <A HREF="#ReviseInternalHostAPI">Revise Internal Host API</A> proposal to support (multiple interleave <==> unified interleave) and (multiple interleave <==> non-interleaved) conversions.</P> 497 <H4>Impact Analysis</H4> 498 <P>This proposal provides access to new platform-specific extensions. No existing client code will be modified. Only implementations that implement the extensions will be effected.</P> 499 <P>____________</P> 500 <H2><A NAME="Error"></A>Handling of Host API Specific Error Codes</H2> 501 <H4>Status</H4> 502 <P>This proposal is sufficiently well defined to be implemented immediately. However, the possibility of extending the scope of this proposal has been discussed in this thread: <A HREF="http://techweb.rfa.org/pipermail/portaudio/2002-January/000358.html">http://techweb.rfa.org/pipermail/portaudio/2002-January/000358.html</A></P> 503 <H4>Background</H4> 504 <P>Currently the PaHostError error code is used to notify clients that a platform-specific error condition occurred. This is considered ambiguous and difficult to work with. </P> 505 <H4>Proposal</H4> 506 <P>PortAudio should seek to avoid returning ambiguous paHostError error codes, and instead translate to portable PortAudio error codes. In the case of the pa_win_mme implementation this means translating the following MME error codes:</P> 507 <P>MMSYSERR_ALLOCATED to paDeviceBusy (new) <BR> 508 MMSYSERR_BADDEVICEID to paInvalidDeviceId (already defined) <BR> 509 MMSYSERR_NODRIVER to paDriverMissing (new) <BR> 510 MMSYSERR_NOMEM to paInsufficientMemory (already defined) <BR> 511 WAVERR_BADFORMAT to paSampleFormatNotSupported (already defined) </P> 512 <H4>Discussion</H4> 513 <P>It is suggested that all implementations should be audited for their use of PaHostError.</P> 514 <P>There was some concern about polluting the PortAudio error code namespace with platform-specific error codes, and of the potential overhead of including platform specific error strings on other platforms. Another suggestion has been to add a Pa_GetHostErrorText() function.</P> 515 <P>If all error codes are mapped to PortAudio error codes do we need a PaHostError code and the Pa_GetHostErrorCode() function?</P> 516 <P>A suggestion has been made to extend Pa_GetErrorText() so that it retrieved host API specific error strings when a host error occurs.</P> 517 <H4>Impact Analysis</H4> 518 <P>This proposal improves the quality of PortAudio diagnostics. Client code that depends on paHostError code to flag certain conditions may be effected.</P> 519 <P>____________</P> 520 <H2><A NAME="StreamStates">Clarify Stream State Machine and State Querying Functions</A></H2> 521 <H4>Status</H4> 522 <P> 523 This proposal is sufficiently well defined to be implemented. 524 </P> 525 526 <H4>Background</H4> 527 <P> 528 Interaction between Pa_StartStream(), Pa_StopStream() and Pa_AbortStream(), and the ability to stop a stream 529 by returning non-zero from the callback function was never clearly documented. After returning non-zero from the callback it was not clear whether the stream was stopped (meaning that Pa_StartStream() could be called immediately) or whether the Stream was in some intermediate state, requiring Pa_StopStream() to be called prior to being Started again. The availability of Pa_StreamActive() implied the latter case, but it was never documented. 530 </P> 531 <P> 532 In order for the common infrastructure to manage some stream state transitions (such as automatically stopping an active stream when closing it) a function to query whether the stream is stopped is required. 533 </P> 534 <P> 535 It has been suggested that it should be possible for the callback return value to indicate whether a stream should 536 stop immediately or that it should stop after all queued buffers have been played (current behavior.) Thus providing similar behavior to Pa_StopStream()/Pa_AbortStream() from the callback. 537 </P> 538 <P> 539 This proposal documents the previously implicit state machine for PortAudio Streams and provides a new accessor function for determining whether the stream is stopped. It also defines 3 new constants which can be used as return values from the callback. 540 </P> 541 542 <H4>Proposal</H4> 543 <P> 544 PortAudio streams will function according to the following state machine: 545 </P> 546 <P> 547 <IMG src="PaStreamStateDiagram.gif"> 548 </P> 549 <P> 550 A new function Pa_IsStreamStopped() will be added to allow clients to determine whether the Stream is in the Stopped state. 551 <P> 552 <P> 553 New error codes paStreamIsStopped and paStreamIsNotStopped will be added (see below for usage.) 554 </P> 555 <P>Stream functions will interact with the state machine as follows:</P> 556 557 <PRE> 558 Pa_OpenStream() -> creates a stream in the Stopped state 559 Pa_CloseStream() -> always closes a stream, 560 if the stream is not Stopped it will be automatically 561 aborted using Pa_AbortStream() before being closed. 562 563 In the Stopped state: 564 Pa_StartStream() -> transitions to Active state 565 Pa_StopStream() -> returns paStreamIsStopped error 566 Pa_AbortStream()-> returns paStreamIsStopped error 567 Pa_IsStreamStopped() -> returns one (1), or error code 568 Pa_IsStreamActive() -> returns zero (0), or error code 569 570 In the Active state: 571 Pa_StartStream() -> returns paStreamIsNotStopped error 572 Pa_StopStream() -> stops calling the callback and blocks until 573 all buffers have been played 574 : transitions to Stopped state 575 Pa_AbortStream()-> if possible, discards all queued buffers instead of 576 waiting for them to be played, otherwise same as Pa_StopStream() 577 : transitions to Stopped state 578 Pa_IsStreamStopped() -> returns zero (0), or error code 579 Pa_IsStreamActive() -> returns one (1), or error code 580 581 In the Callback Finished state: 582 Pa_StartStream() -> returns paStreamIsNotStopped error 583 Pa_StopStream() -> transitions to Stopped state 584 Pa_AbortStream()-> transitions to Stopped state 585 Pa_IsStreamStopped() -> returns zero (0), or error code 586 Pa_IsStreamActive() -> returns zero (0), or error code 587 </PRE> 588 589 <P> 590 Three new constants: paContinue(0), paComplete(1) and paAbort(2) will be defined for use as return values from the callback. Both paComplete and paAbort cause PortAudio to stop calling the callback. paComplete will cause a transition to the Callback Finished state once all buffers have been played, paAbort indicates that PortAudio may to attempt to cancel pending buffers before transitioning to the Callback Finished state. Note that returning any other non-zero value from the callback will have the same effect as returning paComplete, for maximum backwards compatibility. 591 </P> 592 593 <H5>A Note About Stop and Abort Behavior</H5> 594 <P> 595 As the host may buffer samples, it is possible for a perceptible delay to arise between the callback generating samples and them being heard. Sometimes it is desirable to wait for all generated samples to be played before closing a stream - for example when waiting for the end of a soundfile to complete playbeck. At other times it may be desirable to stop the stream as quickly as possible, without necessarily waiting for all queued samples to be played. This latter situation can occur when exiting an application or closing a document - providing good interactive performance to the end-user may necessitate aborting the stream rather than pausing for a significant period waiting for the queued samples to complete. These two use-cases are respectively addressed by the Pa_StopStream() and Pa_AbortStream() functions, and by the paComplete and paAbort callback return values. 596 </P> 597 <P> 598 It has been noted that not all host APIs support the cancellation of already queued samples or buffers, thus making it impossible to usefully implement Pa_AbortStream. In such cases, Pa_AbortStream() will have the same behavior as Pa_StopStream(), and returning paAbort from the callback will have the behavior as returning paComplete. 599 </P> 600 601 602 <H4>Discussion</H4> 603 <P>The multi-host-API common infrastructure requires a function like Pa_IsStreamStopped() so that it can automatically call Pa_AbortStream() if Pa_CloseStream() is called on an Active stream. The availability of this state information may also be used to implement error results when actions are not valid for the current stream state (calling Pa_StartStream() on a Active stream for example.)</P> 604 605 <H4>Impact Analysis</H4> 606 <P> 607 Clients who currently return 2 from the callback will need to change the callback return value to paFinish to retain the expected behavior. 608 </P> 609 610 <P>____________</P> 611 <H2><A NAME="RenamePa_GetCPULoad">Rename Pa_GetCPULoad(), PaDeviceID etc. for Consistency</A></H2> 612 <H4>Status</H4> 613 <P>Proposal is sufficiently well defined to be implemented. No objections have been raised.</P> 614 <H4>Background</H4> 615 <P> 616 PortAudio functions that return global information typically have names of the form Pa_Get*() (eg. Pa_GetDeviceInfo). However functions retrieving information from a stream do not currently follow this convention (Pa_StreamActive() and Pa_StreamTime()), additionally the Pa_GetCPULoad() function operates on a stream, but does not contain stream in its name. 617 </P> 618 <P>PortAudio functions and parameter names that operate on integer identifiers use the string ID (all uppercase.) The paInvalidDeviceId error code is an exception to this convention.</P> 619 <H4>Proposal</H4> 620 <p>Rename the stream accessor functions as follows:</p> 621 <pre> 622 Pa_StreamActive() -> Pa_IsStreamActive() 623 Pa_StreamTime() -> Pa_GetStreamTime() 624 Pa_GetCPULoad() -> Pa_GetStreamCpuLoad() 625 </pre> 626 <p>Note that CPU becomes Cpu, the convention of only capitalising the first letter of an acronym has been adopted in other proposals too.</p> 627 628 <p>Rename device identifier types and functions as follows:</p> 629 <pre> 630 paInvalidDeviceId -> paInvalidDevice 631 PaDeviceID -> PaDeviceIndex 632 Pa_GetDefaultInputDeviceID() -> Pa_GetDefaultInputDevice() 633 Pa_GetDefaultOutputDeviceID() -> Pa_GetDefaultOutputDevice() 634 </pre> 635 <p>The use of the term index in PaDeviceIndex clearly denotes that the types has values within a closed range and may be incremented or decremented to access adjacent values. The ommission of "Index" from paInvalidDevice and the Pa_GetDefault* functions is justified by the fact that the only public representation of a device is its index. 636 </p> 637 <H4>Impact Analysis</H4> 638 <P>This proposal improves the consistency of the naming scheme making the API easier to learn and remember. All clients which currently call Pa_GetCPULoad(), Pa_StreamTime(), Pa_StreamActive(), Pa_GetDefaultInputDeviceID(), or Pa_GetDefaultOutputDeviceID() will need to alter their code by renaming the function call. Clients who explicitly check for the paInvalidDeviceId error code, or use the PaDeviceID type will have to edit the spelling of these identifiers.</P> 639 <P>____________</P> 640 <H2><A NAME="AdditionalPa_TerminateBehaviour">Additional Pa_Terminate() Behaviour</A></H2> 641 <H4>Status</H4> 642 <P>This proposal is sufficiently well defined to be implemented. </P> 643 <H4>Background</H4> 644 <P>Some host APIs (eg ASIO, MME and DirectSound under Windows NT) can require a reboot to free devices when they are not closed properly (due to a program not calling Pa_Close() either in error, or due to a crash.) As a quality of implementation issue PortAudio should seek to avoid such circumstances.</P> 645 <H4>Proposal</H4> 646 <P>The definition of Pa_Terminate() should be extended as follows:</P> 647 <PRE>/* 648 Pa_Terminate() is the library termination function - call this after 649 using the library. This function deallocates all resources allocated 650 by PortAudio since it was initializied using Pa_Initialize(). Any open 651 PortAudioStreams are closed. 652 653 Pa_Terminate() MUST be called before exiting a program which 654 uses PortAudio. Failure to do so may result in serious resource 655 leaks, such as audio devices not being available until the next reboot. 656 */ 657 PaError Pa_Terminate( void );</PRE> 658 <H4>Implementation Notes</H4> 659 <P>One possible implementation strategy would be to add a "next" member to the internal stream data structure thus making it a linked list node, which could be linked into a list of all open streams.</P> 660 <H4>Discussion</H4> 661 <P>Some concerns have been raised about the overhead involved in PortAudio having to keep track of which streams are currently open. </P> 662 <P>There has been some discussion about the behavior of nesting multiple calls to Pa_Initialize() and Pa_Terminate() - there is no intention of changing the current behaviour, which is that PortAudio has two states: "Initialized" and "Uninitialized" - in the Initialized state, Pa_Initialize() does nothing and returns an error, in the Uninitialized state Pa_Terminate() does nothing and returns an error.</P> 663 <H4>Impact Analysis</H4> 664 <P>This proposal changes the termination behaviour of PortAudio to reduce the likelihood of resource leaks.</P> 665 <P>On Windows, the new Pa_Terminate() behaviour would allow users who want full protection against device leakage to install a global Win32 exception handler that calls Pa_Terminate() before exiting when a crash occurs. Similar techniques (using SIGNAL handlers perhaps?) may be possible on other platforms where necessary.</P> 666 <P>____________</P> 667 <H2><A NAME="CodingStyleGuidelines">Coding Style Guidelines</A></H2> 668 <H4>Status</H4> 669 <P>This proposal is under construction. Further suggestions and comments would be extremely welcome.</P> 670 <H4>Background</H4> 671 <P>Since the PortAudio code is commonly edited on many different platforms using different editors it has been suggested that some conventions be adopted to improve readability and consistency. The general opinion is that the definition of such conventions, and their enforcement shouldn't be too extreme. There are also a number of unspoken implementation standards that could be usefully written down. This proposal consists of a list of mechanical formatting conventions, and a list of "quality of implementation" conventions. When completed this proposal will packaged with the distribution and placed on the web site as "Coding Style Guidelines for PortAudio Implementors."</P> 672 <H4>Proposal</H4> 673 <P>The following formatting conventions should be adhered to in all PortAudio code:</P> 674 675 <UL> 676 <LI>TABs should not be used in .c and .h files; instead 4 spaces should be used. Makefiles should continue to use TABs since this is required by Make </LI> 677 <LI>Adopt a consistent set of rules for placement of braces (see note regarding Astyle below) </LI> 678 <LI>Adopt a consistent policy for line-end characters. This could be 'use CR on Mac, CRLF on Windows and LF on Unix' or it could be 'use Unix style new-lines in all source files.</LI></UL> 679 680 <P>AStyle ( <A HREF="http://astyle.sourceforge.net/">http://astyle.sourceforge.net/</A> ) has been proposed as helpful tool for cleaning code, however we haven't yet decided whether to use it on an ongoing basis. Once our style guidelines have been established it is expected that contributors of each implementation will take responsibility for keeping their code clean, as an automated tool applied by someone unfamiliar with the code will probably just mess things up.</P> 681 <P>In addition to the formatting conventions noted above, the following "quality of implementation" coding guidelines are being proposed to establish a quality baseline for our implementations:</P> 682 683 <UL> 684 <LI>All code should be written in C++-compatible plain ANSI-C (i.e. no // comments). The following guideline has been proposed: should compile silently with both "gcc -ansi -pedantic -Wall" and "g++ -ansi -pedantic -Wall" </LI> 685 <LI>Think of PortAudio as a heavyweight library rather than a lightweight wrapper. Always code defensively. Efficiency is important where it matters (eg in real-time callbacks) but safety is important everywhere. </LI> 686 <LI>All parameters passed to PortAudio by the user should be validated, and error codes returned where necessary. All reasonable efforts should be made to minimise the risk of a crash resulting from passing incorrect parameters to PortAudio. </LI> 687 <LI>Error handling should be complete. Every host function that can return an error condition should have its status checked. PortAudio may attempt to recover from errors, but generally error codes should be returned to the client. </LI> 688 <LI>In almost all cases, a PortAudio error code should be preferred to returning PaHostError. If a new PortAudio error code is needed it should be discussed with the maintainer to coordinate updating port_audio.h </LI> 689 <LI>PortAudio code should not cause resource leaks. After Pa_Terminate() is called, implementations should guarantee that all dynamically allocated resources have been freed. </LI> 690 <LI>The definition of the PortAudio API should minimise "implementation defined behaviour". For example, calling functions such as Pa_Initialize() after PortAudio is initialised, or Pa_Terminate() after PortAudio has been terminated should have well defined behaviour. (In this example, both calls should be safe and simply return an error code.) </LI> 691 <LI>Minimise dependence on ANSI C runtime on platforms where it would have to be loaded separately (eg on Win32 prefer Win32 API functions such as GlobalAlloc() to ANSI C functions such as malloc().) <I>(Ross: this may be problematic, since some portable parts of the implementation may need to allocate memory -- perhaps we should define our own internal memory allocation functions.)</LI></UL> 692 693 </I><P>It has been suggested that we make an effort to minimise the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some possible guidelines in this regard are:</P> 694 695 <UL> 696 <LI>Implementations should avoid exporting any symbols except where absolutely necessary. Specifically, global data must be declared statically. We will need a naming convention for non-public global symbols, such as internal functions defined in one module and used in another. </LI> 697 <LI>Implementations should minimise their use of static data. </LI></UL> 698 699 <H4>Discussion</H4> 700 <P>There will always be time to improve these guidelines, however we are making a concerted effort to document some standards before the next round of changes are implemented.</P> 701 <H4>Impact Analysis</H4> 702 <P>This proposal will require all existing code to be reviewed and possibly revised. This is not expected to be a "big-bang" operation. Rather it is envisaged that this will be a long term, ongoing process aimed at improving the quality of the PortAudio codebase. </P> 703 <P>____________</P> 704 <H2><A NAME="ReviseInternalHostAPI">Revise Internal Host API</A></H2> 705 <H4>Status</H4> 706 <P>This proposal is under construction. Ideally, someone should go through all of the existing implementations and identify code that could be factored into a common library (parameter validation code for example.)</P> 707 <H4>Dependencies</H4> 708 <P>This proposal is dependent on the <A HREF="#MultipleDriverModels">Support for Multiple Host APIs in a Single PortAudio Build</A> proposal, and the <A HREF="#Interleaved">Non-Interleaved Buffers</A> proposal. The proposed conversion functions may be dependent on the MME multichannel via stereo pairs extension which is part of the <A HREF="#DriverModelSpecificPa_OpenStream">Host API Specific Pa_OpenStream() Parameters</A> proposal.</P> 709 <H4>Background</H4> 710 <P>PortAudio defines a set of helper functions that all implementations share. It is envisaged that these internal functions will need to be revised in response to the changes proposed in this document. It would also be beneficial to take this opportunity to refactor any other common code fragments that could be shared by multiple implementations.</P> 711 <P>A refactoring of the buffer data conversion functions was proposed here: <A HREF="http://techweb.rfa.org/pipermail/portaudio/2001-November/000244.html">http://techweb.rfa.org/pipermail/portaudio/2001-November/000244.html</A> However the proposal below is not quite the same. A significant benefit of formally specifying the interface to the buffer conversion functions is that it would facilitate the creation of optimised assembly language versions for different platforms.</P> 712 <H4>Proposal</H4> 713 <P>A common set of buffer conversion functions should be defined and shared by all implementations. The buffer conversion functions should handle all permutations of:</P> 714 715 <UL> 716 <LI>Sample format </LI> 717 <LI>Channels </LI> 718 <LI>Interleave / Non-interleave </LI> 719 <LI>Endianness </LI> 720 <LI>Channel compensation</LI></UL> 721 722 <P>"Channel-compensation" is necessary when certain devices require a higher number of channels than the user requests. With the Midiman Delta1010, for example, the device always needs to be fed 10 channels of output and you must read 12 channels of input (at least under ALSA without the "plug" interface).</P> 723 <P>The conversion functions could look something like:</P> 724 <PRE>void ConversionFunction_DestType_DestInterleave_SrcType_SrcInterleave_ ( void *dest, int destChannels, void *src, int srcChannels, int frames );</PRE> 725 <P>The dest and src parameters have the same format as those supplied to the PortAudio client callback.</P> 726 <P>Rather than have each implementation call these conversion functions directly, a 'factory function' could be implemented that returns a pointer to a conversion function based on parameters specifying the format of the source and destination buffers. This factory function could be called as needed when a stream is opened. The conversion functions could then be made static and hidden from the rest of PortAudio. The 'factory function' could have the following form:</P> 727 <PRE>enum PaEndiannes { paBigEndian, paSmallEndian, paHostEndian }; 728 729 PaBufferConversionFunction* Pa_GetBufferConversionFunction( 730 PaSampleFormat destFormat, int destChannels, PaEndianness destEndianness, 731 PaSampleFormat srcFormat, int srcChannels, PaEndianness srcEndianness );</PRE> 732 <P>Note that the interleave/deinterleave status is encoded in the destFormat and srcFormat parameters. paHostEndian is used to represent the endianness of the current platform since some host APIs (eg ASIO) allow the driver to use samples in a different endianness from the host endianness. Another alternative is to encode sample endianness in PaSampleFormat - this would allow clients to write sample data of either endianness to PortAudio (e.g. soundfile playback direct from file) and benefit from PortAudio's byte swapping code.</P> 733 <P>The redundant use of channel parameters in both the conversion functions and the factory function is intentional and would allow channel-optimised conversion functions to be supplied for common cases such as 16-bit stereo.</P> 734 <H4>Discussion</H4> 735 <P>This proposal currently only addresses buffer conversion functions, however it is important to identify other common code fragments that could be placed in the shared PortAudio library.</P> 736 <P>This proposal has not yet addressed the fact that the conversion functions also need to handle clipping and dithering.</P> 737 <P>It is not clear whether additional conversion functions will be needed to accommodate the MME interleaved stereo pairs for multichannel devices proposal.</P> 738 <P>It hasn't been established whether PortAudio will be extended to support all PaSampleFormats on all devices.</P> 739 <P>It isn't clear whether paCustomFormat is viable under this proposal, or how it would be accommodated.</P> 740 <P>When the client requested format and the host format are different a temporary buffer may be required to hold the converted data. However, in general PortAudio should aim to convert data in-place. Functions may be needed to establish when temporary buffers are needed, and to allocate them.</P> 741 <P>Due to a mismatch between the API buffer size and the PortAudio callback buffer size some Host APIs require PortAudio to shuffle data among multiple buffers in order to fulfil client requests - this has not yet been considered within the current proposal.</P> 742 <P>Memory allocation should probably be handled with platform specific functions such as Win32 GlobalAlloc() rather than using malloc()</P> 743 <H4>Impact Analysis</H4> 744 <P>This proposal only effects PortAudio implementors. Increasing the utility of shared code will improve the quality of all PortAudio implementations in terms of speed, size, and robustness. It should also reduce the effort involved in porting PortAudio to a new host API.</P> 745 <P>____________</P></TT></BODY> 34 </BODY> 746 35 </HTML> 747 36
Note: See TracChangeset
for help on using the changeset viewer.
