Version 2.0.1
[rtaudio.git] / RtAudio.h
1 /******************************************/\r
2 /*\r
3   RtAudio - realtime sound I/O C++ class\r
4   by Gary P. Scavone, 2001-2002.\r
5 */\r
6 /******************************************/\r
7 \r
8 #if !defined(__RTAUDIO_H)\r
9 #define __RTAUDIO_H\r
10 \r
11 #include <map>\r
12 \r
13 #if defined(__LINUX_ALSA__)\r
14   #include <alsa/asoundlib.h>\r
15   #include <pthread.h>\r
16   #include <unistd.h>\r
17 \r
18   #define THREAD_TYPE\r
19   typedef snd_pcm_t *AUDIO_HANDLE;\r
20   typedef int DEVICE_ID;\r
21   typedef pthread_t THREAD_HANDLE;\r
22   typedef pthread_mutex_t MUTEX;\r
23 \r
24 #elif defined(__LINUX_OSS__)\r
25   #include <pthread.h>\r
26   #include <unistd.h>\r
27 \r
28   #define THREAD_TYPE\r
29   typedef int AUDIO_HANDLE;\r
30   typedef int DEVICE_ID;\r
31   typedef pthread_t THREAD_HANDLE;\r
32   typedef pthread_mutex_t MUTEX;\r
33 \r
34 #elif defined(__WINDOWS_DS__)\r
35   #include <windows.h>\r
36   #include <process.h>\r
37 \r
38   // The following struct is used to hold the extra variables\r
39   // specific to the DirectSound implementation.\r
40   typedef struct {\r
41     void * object;\r
42     void * buffer;\r
43     UINT bufferPointer;\r
44   } AUDIO_HANDLE;\r
45 \r
46   #define THREAD_TYPE __stdcall\r
47   typedef LPGUID DEVICE_ID;\r
48   typedef unsigned long THREAD_HANDLE;\r
49   typedef CRITICAL_SECTION MUTEX;\r
50 \r
51 #elif defined(__IRIX_AL__)\r
52   #include <dmedia/audio.h>\r
53   #include <pthread.h>\r
54   #include <unistd.h>\r
55 \r
56   #define THREAD_TYPE\r
57   typedef ALport AUDIO_HANDLE;\r
58   typedef int DEVICE_ID;\r
59   typedef pthread_t THREAD_HANDLE;\r
60   typedef pthread_mutex_t MUTEX;\r
61 \r
62 #endif\r
63 \r
64 \r
65 // *************************************************** //\r
66 //\r
67 // RtError class declaration.\r
68 //\r
69 // *************************************************** //\r
70 \r
71 class RtError\r
72 {\r
73 public:\r
74   enum TYPE {\r
75     WARNING,\r
76     DEBUG_WARNING,\r
77     UNSPECIFIED,\r
78     NO_DEVICES_FOUND,\r
79     INVALID_DEVICE,\r
80     INVALID_STREAM,\r
81     MEMORY_ERROR,\r
82     INVALID_PARAMETER,\r
83     DRIVER_ERROR,\r
84     SYSTEM_ERROR,\r
85     THREAD_ERROR\r
86   };\r
87 \r
88 protected:\r
89   char error_message[256];\r
90   TYPE type;\r
91 \r
92 public:\r
93   //! The constructor.\r
94   RtError(const char *p, TYPE tipe = RtError::UNSPECIFIED);\r
95 \r
96   //! The destructor.\r
97   virtual ~RtError(void);\r
98 \r
99   //! Prints "thrown" error message to stdout.\r
100   virtual void printMessage(void);\r
101 \r
102   //! Returns the "thrown" error message TYPE.\r
103   virtual const TYPE& getType(void) { return type; }\r
104 \r
105   //! Returns the "thrown" error message string.\r
106   virtual const char *getMessage(void) { return error_message; }\r
107 };\r
108 \r
109 \r
110 // *************************************************** //\r
111 //\r
112 // RtAudio class declaration.\r
113 //\r
114 // *************************************************** //\r
115 \r
116 class RtAudio\r
117 {\r
118 public:\r
119 \r
120   // Support for signed integers and floats.  Audio data fed to/from\r
121   // the tickStream() routine is assumed to ALWAYS be in host\r
122   // byte order.  The internal routines will automatically take care of\r
123   // any necessary byte-swapping between the host format and the\r
124   // soundcard.  Thus, endian-ness is not a concern in the following\r
125   // format definitions.\r
126   typedef unsigned long RTAUDIO_FORMAT;\r
127   static const RTAUDIO_FORMAT RTAUDIO_SINT8;\r
128   static const RTAUDIO_FORMAT RTAUDIO_SINT16;\r
129   static const RTAUDIO_FORMAT RTAUDIO_SINT24; /*!< Upper 3 bytes of 32-bit integer. */\r
130   static const RTAUDIO_FORMAT RTAUDIO_SINT32;\r
131   static const RTAUDIO_FORMAT RTAUDIO_FLOAT32; /*!< Normalized between plus/minus 1.0. */\r
132   static const RTAUDIO_FORMAT RTAUDIO_FLOAT64; /*!< Normalized between plus/minus 1.0. */\r
133 \r
134   //static const int MAX_SAMPLE_RATES = 14;\r
135   enum { MAX_SAMPLE_RATES = 14 };\r
136 \r
137   typedef int (*RTAUDIO_CALLBACK)(char *buffer, int bufferSize, void *userData);\r
138 \r
139   typedef struct {\r
140     char name[128];\r
141     DEVICE_ID id[2];  /*!< No value reported by getDeviceInfo(). */\r
142     bool probed;       /*!< true if the device capabilities were successfully probed. */\r
143     int maxOutputChannels;\r
144     int maxInputChannels;\r
145     int maxDuplexChannels;\r
146     int minOutputChannels;\r
147     int minInputChannels;\r
148     int minDuplexChannels;\r
149     bool hasDuplexSupport; /*!< true if device supports duplex mode. */\r
150     int nSampleRates;      /*!< Number of discrete rates or -1 if range supported. */\r
151     int sampleRates[MAX_SAMPLE_RATES]; /*!< Supported rates or (min, max) if range. */\r
152     RTAUDIO_FORMAT nativeFormats;     /*!< Bit mask of supported data formats. */\r
153   } RTAUDIO_DEVICE;\r
154 \r
155   //! The default constructor.\r
156   /*!\r
157     Probes the system to make sure at least one audio\r
158     input/output device is available and determines\r
159     the api-specific identifier for each device found.\r
160     An RtError error can be thrown if no devices are\r
161     found or if a memory allocation error occurs.\r
162   */\r
163   RtAudio();\r
164 \r
165   //! A constructor which can be used to open a stream during instantiation.\r
166   /*!\r
167     The specified output and/or input device identifiers correspond\r
168     to those enumerated via the getDeviceInfo() method.  If device =\r
169     0, the default or first available devices meeting the given\r
170     parameters is selected.  If an output or input channel value is\r
171     zero, the corresponding device value is ignored.  When a stream is\r
172     successfully opened, its identifier is returned via the "streamId"\r
173     pointer.  An RtError can be thrown if no devices are found\r
174     for the given parameters, if a memory allocation error occurs, or\r
175     if a driver error occurs. \sa openStream()\r
176   */\r
177   RtAudio(int *streamId,\r
178           int outputDevice, int outputChannels,\r
179           int inputDevice, int inputChannels,\r
180           RTAUDIO_FORMAT format, int sampleRate,\r
181           int *bufferSize, int numberOfBuffers);\r
182 \r
183   //! The destructor.\r
184   /*!\r
185     Stops and closes any open streams and devices and deallocates\r
186     buffer and structure memory.\r
187   */\r
188   ~RtAudio();\r
189 \r
190   //! A public method for opening a stream with the specified parameters.\r
191   /*!\r
192     If successful, the opened stream ID is returned.  Otherwise, an\r
193     RtError is thrown.\r
194 \r
195     \param outputDevice: If equal to 0, the default or first device\r
196            found meeting the given parameters is opened.  Otherwise, the\r
197            device number should correspond to one of those enumerated via\r
198            the getDeviceInfo() method.\r
199     \param outputChannels: The desired number of output channels.  If\r
200            equal to zero, the outputDevice identifier is ignored.\r
201     \param inputDevice: If equal to 0, the default or first device\r
202            found meeting the given parameters is opened.  Otherwise, the\r
203            device number should correspond to one of those enumerated via\r
204            the getDeviceInfo() method.\r
205     \param inputChannels: The desired number of input channels.  If\r
206            equal to zero, the inputDevice identifier is ignored.\r
207     \param format: An RTAUDIO_FORMAT specifying the desired sample data format.\r
208     \param sampleRate: The desired sample rate (sample frames per second).\r
209     \param *bufferSize: A pointer value indicating the desired internal buffer\r
210            size in sample frames.  The actual value used by the device is\r
211            returned via the same pointer.  A value of zero can be specified,\r
212            in which case the lowest allowable value is determined.\r
213     \param numberOfBuffers: A value which can be used to help control device\r
214            latency.  More buffers typically result in more robust performance,\r
215            though at a cost of greater latency.  A value of zero can be\r
216            specified, in which case the lowest allowable value is used.\r
217   */\r
218   int openStream(int outputDevice, int outputChannels,\r
219                  int inputDevice, int inputChannels,\r
220                  RTAUDIO_FORMAT format, int sampleRate,\r
221                  int *bufferSize, int numberOfBuffers);\r
222 \r
223   //! A public method which sets a user-defined callback function for a given stream.\r
224   /*!\r
225     This method assigns a callback function to a specific,\r
226     previously opened stream for non-blocking stream functionality.  A\r
227     separate process is initiated, though the user function is called\r
228     only when the stream is "running" (between calls to the\r
229     startStream() and stopStream() methods, respectively).  The\r
230     callback process remains active for the duration of the stream and\r
231     is automatically shutdown when the stream is closed (via the\r
232     closeStream() method or by object destruction).  The callback\r
233     process can also be shutdown and the user function de-referenced\r
234     through an explicit call to the cancelStreamCallback() method.\r
235     Note that a single stream can use only blocking or callback\r
236     functionality at the same time, though it is possible to alternate\r
237     modes on the same stream through the use of the\r
238     setStreamCallback() and cancelStreamCallback() methods (the\r
239     blocking tickStream() method can be used before a callback is set\r
240     and/or after a callback is cancelled).  An RtError will be\r
241     thrown for an invalid device argument.\r
242   */\r
243   void setStreamCallback(int streamId, RTAUDIO_CALLBACK callback, void *userData);\r
244 \r
245   //! A public method which cancels a callback process and function for a given stream.\r
246   /*!\r
247     This method shuts down a callback process and de-references the\r
248     user function for a specific stream.  Callback functionality can\r
249     subsequently be restarted on the stream via the\r
250     setStreamCallback() method.  An RtError will be thrown for an\r
251     invalid device argument.\r
252    */\r
253   void cancelStreamCallback(int streamId);\r
254 \r
255   //! A public method which returns the number of audio devices found.\r
256   int getDeviceCount(void);\r
257 \r
258   //! Fill a user-supplied RTAUDIO_DEVICE structure for a specified device.\r
259   /*!\r
260     Any device between 0 and getDeviceCount()-1 is valid.  If a\r
261     device is busy or otherwise unavailable, the structure member\r
262     "probed" has a value of "false".  The system default input and\r
263     output devices are referenced by device identifier = 0.  On\r
264     systems which allow dynamic default device settings, the default\r
265     devices are not identified by name (specific device enumerations\r
266     are assigned device identifiers > 0).  An RtError will be\r
267     thrown for an invalid device argument.\r
268   */\r
269   void getDeviceInfo(int device, RTAUDIO_DEVICE *info);\r
270 \r
271   //! A public method which returns a pointer to the buffer for an open stream.\r
272   /*!\r
273     The user should fill and/or read the buffer data in interleaved format\r
274     and then call the tickStream() method.  An RtError will be\r
275     thrown for an invalid stream identifier.\r
276   */\r
277   char * const getStreamBuffer(int streamId);\r
278 \r
279   //! Public method used to trigger processing of input/output data for a stream.\r
280   /*!\r
281     This method blocks until all buffer data is read/written.  An\r
282     RtError will be thrown for an invalid stream identifier or if\r
283     a driver error occurs.\r
284   */\r
285   void tickStream(int streamId);\r
286 \r
287   //! Public method which closes a stream and frees any associated buffers.\r
288   /*!\r
289     If an invalid stream identifier is specified, this method\r
290     issues a warning and returns (an RtError is not thrown).\r
291   */\r
292   void closeStream(int streamId);\r
293 \r
294   //! Public method which starts a stream.\r
295   /*!\r
296     An RtError will be thrown for an invalid stream identifier\r
297     or if a driver error occurs.\r
298   */\r
299   void startStream(int streamId);\r
300 \r
301   //! Stop a stream, allowing any samples remaining in the queue to be played out and/or read in.\r
302   /*!\r
303     An RtError will be thrown for an invalid stream identifier\r
304     or if a driver error occurs.\r
305   */\r
306   void stopStream(int streamId);\r
307 \r
308   //! Stop a stream, discarding any samples remaining in the input/output queue.\r
309   /*!\r
310     An RtError will be thrown for an invalid stream identifier\r
311     or if a driver error occurs.\r
312   */\r
313   void abortStream(int streamId);\r
314 \r
315   //! Queries a stream to determine whether a call to the tickStream() method will block.\r
316   /*!\r
317     A return value of 0 indicates that the stream will NOT block.  A positive\r
318     return value indicates the number of sample frames that cannot yet be\r
319     processed without blocking.\r
320   */\r
321   int streamWillBlock(int streamId);\r
322 \r
323 protected:\r
324 \r
325 private:\r
326 \r
327   static const unsigned int SAMPLE_RATES[MAX_SAMPLE_RATES];\r
328 \r
329   enum { FAILURE, SUCCESS };\r
330 \r
331   enum STREAM_MODE {\r
332     PLAYBACK,\r
333     RECORD,\r
334     DUPLEX,\r
335     UNINITIALIZED = -75\r
336   };\r
337 \r
338   enum STREAM_STATE {\r
339     STREAM_STOPPED,\r
340     STREAM_RUNNING\r
341   };\r
342 \r
343   typedef struct {\r
344     int device[2];          // Playback and record, respectively.\r
345     STREAM_MODE mode;       // PLAYBACK, RECORD, or DUPLEX.\r
346     AUDIO_HANDLE handle[2]; // Playback and record handles, respectively.\r
347     STREAM_STATE state;     // STOPPED or RUNNING\r
348     char *userBuffer;\r
349     char *deviceBuffer;\r
350     bool doConvertBuffer[2]; // Playback and record, respectively.\r
351     bool deInterleave[2];    // Playback and record, respectively.\r
352     bool doByteSwap[2];      // Playback and record, respectively.\r
353     int sampleRate;\r
354     int bufferSize;\r
355     int nBuffers;\r
356     int nUserChannels[2];    // Playback and record, respectively.\r
357     int nDeviceChannels[2];  // Playback and record channels, respectively.\r
358     RTAUDIO_FORMAT userFormat;\r
359     RTAUDIO_FORMAT deviceFormat[2]; // Playback and record, respectively.\r
360     bool usingCallback;\r
361     THREAD_HANDLE thread;\r
362     MUTEX mutex;\r
363     RTAUDIO_CALLBACK callback;\r
364     void *userData;\r
365   } RTAUDIO_STREAM;\r
366 \r
367   typedef signed short INT16;\r
368   typedef signed int INT32;\r
369   typedef float FLOAT32;\r
370   typedef double FLOAT64;\r
371 \r
372   char message[256];\r
373   int nDevices;\r
374   RTAUDIO_DEVICE *devices;\r
375 \r
376   std::map<int, void *> streams;\r
377 \r
378   //! Private error method to allow global control over error handling.\r
379   void error(RtError::TYPE type);\r
380 \r
381   /*!\r
382     Private method to count the system audio devices, allocate the\r
383     RTAUDIO_DEVICE structures, and probe the device capabilities.\r
384   */\r
385   void initialize(void);\r
386 \r
387   //! Private method to clear an RTAUDIO_DEVICE structure.\r
388   void clearDeviceInfo(RTAUDIO_DEVICE *info);\r
389 \r
390   /*!\r
391     Private method which attempts to fill an RTAUDIO_DEVICE\r
392     structure for a given device.  If an error is encountered during\r
393     the probe, a "warning" message is reported and the value of\r
394     "probed" remains false (no exception is thrown).  A successful\r
395     probe is indicated by probed = true.\r
396   */\r
397   void probeDeviceInfo(RTAUDIO_DEVICE *info);\r
398 \r
399   /*!\r
400     Private method which attempts to open a device with the given parameters.\r
401     If an error is encountered during the probe, a "warning" message is\r
402     reported and FAILURE is returned (no exception is thrown). A\r
403     successful probe is indicated by a return value of SUCCESS.\r
404   */\r
405   bool probeDeviceOpen(int device, RTAUDIO_STREAM *stream,\r
406                        STREAM_MODE mode, int channels, \r
407                        int sampleRate, RTAUDIO_FORMAT format,\r
408                        int *bufferSize, int numberOfBuffers);\r
409 \r
410   /*!\r
411     Private common method used to check validity of a user-passed\r
412     stream ID.  When the ID is valid, this method returns a pointer to\r
413     an RTAUDIO_STREAM structure (in the form of a void pointer).\r
414     Otherwise, an "invalid identifier" exception is thrown.\r
415   */\r
416   void *verifyStream(int streamId);\r
417 \r
418   /*!\r
419     Private method used to perform format, channel number, and/or interleaving\r
420     conversions between the user and device buffers.\r
421   */\r
422   void convertStreamBuffer(RTAUDIO_STREAM *stream, STREAM_MODE mode);\r
423 \r
424   //! Private method used to perform byte-swapping on buffers.\r
425   void byteSwapBuffer(char *buffer, int samples, RTAUDIO_FORMAT format);\r
426 \r
427   //! Private method which returns the number of bytes for a given format.\r
428   int formatBytes(RTAUDIO_FORMAT format);\r
429 };\r
430 \r
431 // Uncomment the following definition to have extra information spewed to stderr.\r
432 //#define RTAUDIO_DEBUG\r
433 \r
434 #endif\r