]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
adding some shit
authorAnthony Minessale <anthony.minessale@gmail.com>
Fri, 9 Dec 2005 19:23:04 +0000 (19:23 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Fri, 9 Dec 2005 19:23:04 +0000 (19:23 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@100 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_module_interfaces.h
src/include/switch_utils.h
src/mod/mod_portaudio/mod_portaudio.c
src/mod/mod_portaudio/pablio.c [new file with mode: 0644]
src/mod/mod_portaudio/pablio.h [new file with mode: 0644]
src/mod/mod_portaudio/ringbuffer.c [new file with mode: 0644]
src/mod/mod_portaudio/ringbuffer.h [new file with mode: 0644]
w32/vsnet/mod_PortAudio.vcproj

index 378ebe337112c5c828a184f44d5c2cc9bcf3abc0..a005c688ab9d826b891ad4865c3a5720ff3dd1f4 100644 (file)
@@ -251,4 +251,11 @@ struct switch_application_interface {
        const struct switch_application_interface *next;
 };
 
+struct switch_api_interface {
+       const char *interface_name;
+       const char *desc;
+       switch_status (*function)(char *in, char *out, size_t outlen);
+       const struct switch_api_interface *next;
+};
+
 #endif
index 05a3cb8c0e7caa37b135c69eda1d6fcc01bd5538..266c022575afc3de2156bb282f7a334d629ade26 100644 (file)
@@ -78,6 +78,7 @@ typedef typeof(tv.tv_usec) switch_suseconds_t;
 #define switch_copy_flags(dest, src, flags) (dest)->flags &= ~(flags); (dest)->flags |= ((src)->flags & (flags))
 #define switch_strlen_zero(s) (s && *s != '\0') ? 0 : 1
 #define switch_yield(ms) apr_sleep(ms * 10); apr_thread_yield();
+#define SWITCH_DECLARE_GLOBAL_STRING_FUNC(fname, vname) static void fname(char *string) { if (vname) {free(vname); vname = NULL;}vname = strdup(string);}
 
 SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen);
 SWITCH_DECLARE(switch_status) switch_socket_create_pollfd(switch_pollfd_t *poll, switch_socket_t *sock, unsigned int flags, switch_memory_pool *pool);
index 36cb1c88cb280d2bd5b4e5e01ed2891a7d044a04..d96c03d0cba88b3258e79922737341433e025525 100644 (file)
@@ -42,6 +42,8 @@ static const char modname[] = "mod_portaudio";
 static switch_memory_pool *module_pool;
 static int running = 1;
 
+#define SAMPLE_TYPE  paInt16\r
+typedef short SAMPLE;\r
 
 typedef enum {
        TFLAG_IO = (1 << 0),
@@ -60,9 +62,12 @@ typedef enum {
 static struct {
        int debug;
        int port;
+       char *cid_name;
+       char *cid_num;
        char *dialplan;
-       char *soundcard;
        unsigned int flags;
+       int indev;
+       int outdev;
 } globals;
 
 struct private_object {
@@ -73,31 +78,18 @@ struct private_object {
        unsigned char databuf[1024];
        switch_core_session *session;
        switch_caller_profile *caller_profile;  
-       unsigned int codec;
-       unsigned int codecs;
-       switch_mutex_t *mutex;
-       switch_thread_cond_t *cond;
+       PaError err;\r
+    PABLIO_Stream *audio_in;\r
+    PABLIO_Stream *audio_out;
+       int indev;
+       int outdev;
 };
 
-static void set_global_dialplan(char *dialplan)
-{
-       if (globals.dialplan) {
-               free(globals.dialplan);
-               globals.dialplan = NULL;
-       }
-       
-       globals.dialplan = strdup(dialplan);
-}
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan)
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_name, globals.cid_name)
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_num, globals.cid_num)
+
 
-static void set_global_soundcard(char *soundcard)
-{
-       if (globals.soundcard) {
-               free(globals.soundcard);
-               globals.soundcard = NULL;
-       }
-       
-       globals.soundcard = strdup(soundcard);
-}
 static const switch_endpoint_interface channel_endpoint_interface;
 
 static switch_status channel_on_init(switch_core_session *session);
@@ -131,10 +123,6 @@ static switch_status channel_on_init(switch_core_session *session)
 
        switch_set_flag(tech_pvt, TFLAG_IO);
        
-       switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
-       switch_thread_cond_create(&tech_pvt->cond, switch_core_session_get_pool(session));      
-       switch_mutex_lock(tech_pvt->mutex);
-
        /* Move Channel's State Machine to RING */
        switch_channel_set_state(channel, CS_RING);
 
@@ -187,11 +175,13 @@ static switch_status channel_on_hangup(switch_core_session *session)
        assert(tech_pvt != NULL);
 
        switch_clear_flag(tech_pvt, TFLAG_IO);
-       switch_thread_cond_signal(tech_pvt->cond);
 
        switch_core_codec_destroy(&tech_pvt->read_codec);
        switch_core_codec_destroy(&tech_pvt->write_codec);
-       
+
+       CloseAudioStream(tech_pvt->audio_in);\r
+       CloseAudioStream(tech_pvt->audio_out);\r
+
        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
 
        return SWITCH_STATUS_SUCCESS;
@@ -324,35 +314,21 @@ static switch_status channel_read_frame(switch_core_session *session, switch_fra
 {
        switch_channel *channel = NULL;
        struct private_object *tech_pvt = NULL;
-
+       int t;
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
 
        tech_pvt = switch_core_session_get_private(session);
        assert(tech_pvt != NULL);
+\r
+       if      ((t = ReadAudioStream(tech_pvt->audio_in, tech_pvt->read_frame.data, tech_pvt->read_codec.implementation->samples_per_frame))) {\r
+               tech_pvt->read_frame.datalen = t * 2;\r
+               tech_pvt->read_frame.samples = t;\r
+               *frame = &tech_pvt->read_frame;\r
+               return SWITCH_STATUS_SUCCESS;\r
+       }\r
+
 
-       for(;;) {
-               if (switch_test_flag(tech_pvt, TFLAG_IO)) {
-                       switch_thread_cond_wait(tech_pvt->cond, tech_pvt->mutex);
-                       if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
-                               return SWITCH_STATUS_FALSE;                     
-                       }
-                       while (switch_test_flag(tech_pvt, TFLAG_IO) && !switch_test_flag(tech_pvt, TFLAG_VOICE)) {
-                               switch_yield(1000);
-                       }
-       
-                       if (switch_test_flag(tech_pvt, TFLAG_IO)) {
-                               switch_clear_flag(tech_pvt, TFLAG_VOICE);
-                               if(!tech_pvt->read_frame.datalen) {
-                                       continue;
-                               }
-                                               
-                               *frame = &tech_pvt->read_frame;
-                               return SWITCH_STATUS_SUCCESS;
-                       }
-               }
-               break;
-       }
        return SWITCH_STATUS_FALSE;
 }
 
@@ -376,7 +352,8 @@ static switch_status channel_write_frame(switch_core_session *session, switch_fr
                switch_swap_linear(frame->data, (int)frame->datalen / 2);
        }
 */
-
+       
+       WriteAudioStream(tech_pvt->audio_out, (short *)frame->data, (int)(frame->datalen / sizeof(SAMPLE)));
        //XXX send voice
 
        return SWITCH_STATUS_SUCCESS;
@@ -436,6 +413,8 @@ static const switch_loadable_module_interface channel_module_interface = {
 
 static int dump_info(void);
 static void make_call(char *dest);
+static switch_status load_config(void);
+static int get_dev_by_name(char *name, int in);
 
 SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
 
@@ -443,8 +422,9 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_modul
                switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
                return SWITCH_STATUS_TERM;
        }
-\r
-       Pa_Initialize();\r
+
+       Pa_Initialize();
+       load_config();
        dump_info();
        /* connect my internal structure to the blank pointer passed to me */
        *interface = &channel_module_interface;
@@ -473,8 +453,22 @@ static switch_status load_config(void)
                                globals.debug = atoi(val);
                        } else if (!strcmp(var, "dialplan")) {
                                set_global_dialplan(val);
-                       } else if (!strcmp(var, "soundcard")) {
-                               set_global_soundcard(val);
+                       } else if (!strcmp(var, "cid_name")) {
+                               set_global_cid_name(val);
+                       } else if (!strcmp(var, "cid_num")) {
+                               set_global_cid_num(val);
+                       } else if (!strcmp(var, "indev")) {
+                               if (*val == '#') {
+                                       globals.indev = atoi(val+1);
+                               } else {
+                                       globals.indev = get_dev_by_name(val, 1);
+                               }
+                       } else if (!strcmp(var, "outdev")) {
+                               if (*val == '#') {
+                                       globals.outdev = atoi(val+1);
+                               } else {
+                                       globals.outdev = get_dev_by_name(val, 1);
+                               }
                        }
                }
        }
@@ -482,96 +476,118 @@ static switch_status load_config(void)
        if (!globals.dialplan) {
                set_global_dialplan("default");
        }
-
+       
        switch_config_close_file(&cfg);
-
+       
        return SWITCH_STATUS_SUCCESS;
 }
 
 
 SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
 {
-       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "sleep\n");
-       
-       switch_yield(500000);
-       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "sleep\n");
-       
-       make_call("1000");
-       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "sleep\n");
-       
+
+       switch_yield(50000);
+       make_call("8888");
        return SWITCH_STATUS_TERM;
 }
 
 
 SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
 {
-   Pa_Terminate();\r
+   Pa_Terminate();
  
        return SWITCH_STATUS_SUCCESS;
 }
 
 
+static int get_dev_by_name(char *name, int in)
+{
+    int      i;
+    int      numDevices;
+    const    PaDeviceInfo *pdi;
+    numDevices = Pa_CountDevices();
+
+       if( numDevices < 0 ) {
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+        return -2;
+    }
+       for( i=0; i<numDevices; i++ ) {
+        pdi = Pa_GetDeviceInfo( i );
+               if(strstr(pdi->name, name)) {
+                       if(in && pdi->maxInputChannels) {
+                               return i;
+                       } else if (!in && pdi->maxOutputChannels) {
+                               return i;
+                       }
+               }
+       }
+       return -1;
+}
+
 
-static int dump_info(void)\r
-{\r
-    int      i,j;\r
-    int      numDevices;\r
-    const    PaDeviceInfo *pdi;\r
-    PaError  err;\r
-    numDevices = Pa_CountDevices();\r
-    if( numDevices < 0 )\r
-    {\r
-        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );\r
-        err = numDevices;\r
-        goto error;\r
-    }\r
-    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Number of devices = %d\n", numDevices );\r
-    for( i=0; i<numDevices; i++ )\r
-    {\r
-        pdi = Pa_GetDeviceInfo( i );\r
-        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "---------------------------------------------- #%d", i );\r
-        if( i == Pa_GetDefaultInputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultInput");\r
-        if( i == Pa_GetDefaultOutputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultOutput");\r
-        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\nName         = %s\n", pdi->name );\r
-        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Max Inputs   = %d", pdi->maxInputChannels  );\r
-        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, ", Max Outputs = %d\n", pdi->maxOutputChannels  );\r
-        if( pdi->numSampleRates == -1 )\r
-        {\r
-            switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] );\r
-        }\r
-        else\r
-        {\r
-            switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rates =");\r
-            for( j=0; j<pdi->numSampleRates; j++ )\r
-            {\r
-                switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " %8.2f,", pdi->sampleRates[j] );\r
-            }\r
-            switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");\r
-        }\r
-        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Native Sample Formats = ");\r
-        if( pdi->nativeSampleFormats & paInt8 )        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt8, ");\r
-        if( pdi->nativeSampleFormats & paUInt8 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paUInt8, ");\r
-        if( pdi->nativeSampleFormats & paInt16 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt16, ");\r
-        if( pdi->nativeSampleFormats & paInt32 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt32, ");\r
-        if( pdi->nativeSampleFormats & paFloat32 )     switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paFloat32, ");\r
-        if( pdi->nativeSampleFormats & paInt24 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt24, ");\r
-        if( pdi->nativeSampleFormats & paPackedInt24 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paPackedInt24, ");\r
-        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");\r
-    }\r
\r
-    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "----------------------------------------------\n");\r
-    return 0;\r
-error:\r
-    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "An error occured while using the portaudio stream\n" );\r
-    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error number: %d\n", err );\r
-    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error message: %s\n", Pa_GetErrorText( err ) );\r
-    return err;\r
-}\r
-\r
-static void make_call(char *dest)\r
-{\r
+static int dump_info(void)
+{
+    int      i,j;
+    int      numDevices;
+    const    PaDeviceInfo *pdi;
+    PaError  err;
+    numDevices = Pa_CountDevices();
+    if( numDevices < 0 )
+    {
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+        err = numDevices;
+        goto error;
+    }
+    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Number of devices = %d\n", numDevices );
+    for( i=0; i<numDevices; i++ )
+    {
+        pdi = Pa_GetDeviceInfo( i );
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "---------------------------------------------- #%d", i );
+        if( i == Pa_GetDefaultInputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultInput");
+        if( i == Pa_GetDefaultOutputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultOutput");
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\nName         = %s\n", pdi->name );
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Max Inputs   = %d", pdi->maxInputChannels  );
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, ", Max Outputs = %d\n", pdi->maxOutputChannels  );
+        if( pdi->numSampleRates == -1 )
+        {
+            switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] );
+        }
+        else
+        {
+            switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rates =");
+            for( j=0; j<pdi->numSampleRates; j++ )
+            {
+                switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " %8.2f,", pdi->sampleRates[j] );
+            }
+            switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");
+        }
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Native Sample Formats = ");
+        if( pdi->nativeSampleFormats & paInt8 )        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt8, ");
+        if( pdi->nativeSampleFormats & paUInt8 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paUInt8, ");
+        if( pdi->nativeSampleFormats & paInt16 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt16, ");
+        if( pdi->nativeSampleFormats & paInt32 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt32, ");
+        if( pdi->nativeSampleFormats & paFloat32 )     switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paFloat32, ");
+        if( pdi->nativeSampleFormats & paInt24 )       switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt24, ");
+        if( pdi->nativeSampleFormats & paPackedInt24 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paPackedInt24, ");
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");
+    }
+    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "----------------------------------------------\n");
+    return 0;
+error:
+    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "An error occured while using the portaudio stream\n" );
+    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error number: %d\n", err );
+    switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error message: %s\n", Pa_GetErrorText( err ) );
+    return err;
+}
+
+static void make_call(char *dest)
+{
        switch_core_session *session;
-                                       
+       int sample_rate = 8000;
+       int codec_ms = 20;
+
        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "New Inbound Channel\n");
        if ((session = switch_core_session_request(&channel_endpoint_interface, NULL))) {
                struct private_object *tech_pvt;
@@ -587,11 +603,10 @@ static void make_call(char *dest)
                        return;
                }
 
-
                if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
                                                                                                                                  globals.dialplan,
-                                                                                                                                 "Test This Shit",
-                                                                                                                                 "1231231234",
+                                                                                                                                 globals.cid_name,
+                                                                                                                                 globals.cid_num,
                                                                                                                                  NULL,
                                                                                                                                  NULL,
                                                                                                                                  dest))) {
@@ -604,8 +619,8 @@ static void make_call(char *dest)
 
                if (switch_core_codec_init(&tech_pvt->read_codec,
                                                                "L16",
-                                                               0,
-                                                               0,
+                                                               sample_rate,
+                                                               codec_ms,
                                                                SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
                                                                NULL) != SWITCH_STATUS_SUCCESS) {
                        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
@@ -613,8 +628,8 @@ static void make_call(char *dest)
                } else {
                        if (switch_core_codec_init(&tech_pvt->write_codec,
                                                                        "L16",
-                                                                       0,
-                                                                       0,
+                                                                       sample_rate,
+                                                                       codec_ms,
                                                                        SWITCH_CODEC_FLAG_ENCODE |SWITCH_CODEC_FLAG_DECODE, NULL) != SWITCH_STATUS_SUCCESS) {
                                switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
                                switch_core_codec_destroy(&tech_pvt->read_codec);       
@@ -622,9 +637,29 @@ static void make_call(char *dest)
                        }
                }
        
+               tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+               switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+               switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
 
-               switch_channel_set_state(channel, CS_INIT);
-               switch_core_session_thread_launch(session);
+               tech_pvt->indev = globals.indev;
+               tech_pvt->outdev = globals.outdev;
+
+               if ((tech_pvt->err = OpenAudioStream( &tech_pvt->audio_in, sample_rate, SAMPLE_TYPE, PABLIO_READ | PABLIO_MONO, tech_pvt->indev, -1)) == paNoError) {
+                       if ((tech_pvt->err = OpenAudioStream(&tech_pvt->audio_out, sample_rate, SAMPLE_TYPE, PABLIO_WRITE | PABLIO_MONO, -1, tech_pvt->outdev)) != paNoError) {
+                               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't open audio out!\n");
+                               CloseAudioStream(tech_pvt->audio_in);
+                       }
+               } else {
+                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't open audio in!\n");                
+               }
+               if (tech_pvt->err == paNoError) {
+                       switch_channel_set_state(channel, CS_INIT);
+                       switch_core_session_thread_launch(session);
+               } else {
+                       switch_core_codec_destroy(&tech_pvt->read_codec);       
+                       switch_core_codec_destroy(&tech_pvt->write_codec);      
+                       switch_core_session_destroy(&session);
+               }
        }               
-\r
+
 }
\ No newline at end of file
diff --git a/src/mod/mod_portaudio/pablio.c b/src/mod/mod_portaudio/pablio.c
new file mode 100644 (file)
index 0000000..b5735da
--- /dev/null
@@ -0,0 +1,327 @@
+/*\r
+ * $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $\r
+ * pablio.c\r
+ * Portable Audio Blocking Input/Output utility.\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+\r
+/* History:\r
+ * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.\r
+ *             add timeOutMSec to CloseAudioStream() to prevent hang.\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "portaudio.h"\r
+#include "ringbuffer.h"\r
+#include "pablio.h"\r
+#include <string.h>\r
+\r
+/************************************************************************/\r
+/******** Constants *****************************************************/\r
+/************************************************************************/\r
+\r
+#define FRAMES_PER_BUFFER    (256)\r
+\r
+/************************************************************************/\r
+/******** Prototypes ****************************************************/\r
+/************************************************************************/\r
+\r
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,\r
+                               unsigned long framesPerBuffer,\r
+                               PaTimestamp outTime, void *userData );\r
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );\r
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );\r
+\r
+/************************************************************************/\r
+/******** Functions *****************************************************/\r
+/************************************************************************/\r
+\r
+/* Called from PortAudio.\r
+ * Read and write data only if there is room in FIFOs.\r
+ */\r
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,\r
+                               unsigned long framesPerBuffer,\r
+                               PaTimestamp outTime, void *userData )\r
+{\r
+    PABLIO_Stream *data = (PABLIO_Stream*)userData;\r
+    long numBytes = data->bytesPerFrame * framesPerBuffer;\r
+    (void) outTime;\r
+\r
+    /* This may get called with NULL inputBuffer during initial setup. */\r
+    if( inputBuffer != NULL )\r
+    {\r
+        RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes );\r
+    }\r
+    if( outputBuffer != NULL )\r
+    {\r
+        int i;\r
+        int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes );\r
+        /* Zero out remainder of buffer if we run out of data. */\r
+        for( i=numRead; i<numBytes; i++ )\r
+        {\r
+            ((char *)outputBuffer)[i] = 0;\r
+        }\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+/* Allocate buffer. */\r
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )\r
+{\r
+    long numBytes = numFrames * bytesPerFrame;\r
+    char *buffer = (char *) malloc( numBytes );\r
+    if( buffer == NULL ) return paInsufficientMemory;\r
+    memset( buffer, 0, numBytes );\r
+    return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );\r
+}\r
+\r
+/* Free buffer. */\r
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )\r
+{\r
+    if( rbuf->buffer ) free( rbuf->buffer );\r
+    rbuf->buffer = NULL;\r
+    return paNoError;\r
+}\r
+\r
+/************************************************************\r
+ * Write data to ring buffer.\r
+ * Will not return until all the data has been written.\r
+ */\r
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )\r
+{\r
+    long bytesWritten;\r
+    char *p = (char *) data;\r
+    long numBytes = aStream->bytesPerFrame * numFrames;\r
+    while( numBytes > 0)\r
+    {\r
+        bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes );\r
+        numBytes -= bytesWritten;\r
+        p += bytesWritten;\r
+        if( numBytes > 0) Pa_Sleep(10);\r
+    }\r
+    return numFrames;\r
+}\r
+\r
+/************************************************************\r
+ * Read data from ring buffer.\r
+ * Will not return until all the data has been read.\r
+ */\r
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )\r
+{\r
+    long bytesRead;\r
+    char *p = (char *) data;\r
+    long numBytes = aStream->bytesPerFrame * numFrames;\r
+    while( numBytes > 0)\r
+    {\r
+        bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes );\r
+        numBytes -= bytesRead;\r
+        p += bytesRead;\r
+        if( numBytes > 0) Pa_Sleep(10);\r
+    }\r
+    return numFrames;\r
+}\r
+\r
+/************************************************************\r
+ * Return the number of frames that could be written to the stream without\r
+ * having to wait.\r
+ */\r
+long GetAudioStreamWriteable( PABLIO_Stream *aStream )\r
+{\r
+    int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+    return bytesEmpty / aStream->bytesPerFrame;\r
+}\r
+\r
+/************************************************************\r
+ * Return the number of frames that are available to be read from the\r
+ * stream without having to wait.\r
+ */\r
+long GetAudioStreamReadable( PABLIO_Stream *aStream )\r
+{\r
+    int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO );\r
+    return bytesFull / aStream->bytesPerFrame;\r
+}\r
+\r
+/************************************************************/\r
+static unsigned long RoundUpToNextPowerOf2( unsigned long n )\r
+{\r
+    long numBits = 0;\r
+    if( ((n-1) & n) == 0) return n; /* Already Power of two. */\r
+    while( n > 0 )\r
+    {\r
+        n= n>>1;\r
+        numBits++;\r
+    }\r
+    return (1<<numBits);\r
+}\r
+\r
+/************************************************************\r
+ * Opens a PortAudio stream with default characteristics.\r
+ * Allocates PABLIO_Stream structure.\r
+ *\r
+ * flags parameter can be an ORed combination of:\r
+ *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,\r
+ *    and either PABLIO_MONO or PABLIO_STEREO\r
+ */\r
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,\r
+                         PaSampleFormat format, long flags, int indev, int outdev )\r
+{\r
+    long   bytesPerSample;\r
+    long   doRead = 0;\r
+    long   doWrite = 0;\r
+    PaError err;\r
+    PABLIO_Stream *aStream;\r
+    long   minNumBuffers;\r
+    long   numFrames;\r
+\r
+    /* Allocate PABLIO_Stream structure for caller. */\r
+    aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );\r
+    if( aStream == NULL ) return paInsufficientMemory;\r
+    memset( aStream, 0, sizeof(PABLIO_Stream) );\r
+\r
+    /* Determine size of a sample. */\r
+    bytesPerSample = Pa_GetSampleSize( format );\r
+    if( bytesPerSample < 0 )\r
+    {\r
+        err = (PaError) bytesPerSample;\r
+        goto error;\r
+    }\r
+    aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;\r
+    aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;\r
+\r
+    /* Initialize PortAudio  */\r
+    err = Pa_Initialize();\r
+    if( err != paNoError ) goto error;\r
+\r
+    /* Warning: numFrames must be larger than amount of data processed per interrupt\r
+     *    inside PA to prevent glitches. Just to be safe, adjust size upwards.\r
+     */\r
+    minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );\r
+    numFrames = minNumBuffers * FRAMES_PER_BUFFER;\r
+    /* The PortAudio callback runs in a high priority thread. But PABLIO\r
+     * runs in a normal foreground thread. So we may have much worse\r
+     * latency in PABLIO. So adjust latency to a safe level.\r
+     */\r
+    {\r
+        const int safeLatencyMSec = 200;\r
+        int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);\r
+        if( minLatencyMSec < safeLatencyMSec )\r
+        {\r
+            numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);\r
+        }\r
+    }\r
+    numFrames = RoundUpToNextPowerOf2( numFrames );\r
+\r
+    /* Initialize Ring Buffers */\r
+    doRead = ((flags & PABLIO_READ) != 0);\r
+    doWrite = ((flags & PABLIO_WRITE) != 0);\r
+    if(doRead)\r
+    {\r
+        err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );\r
+        if( err != paNoError ) goto error;\r
+    }\r
+    if(doWrite)\r
+    {\r
+        long numBytes;\r
+        err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );\r
+        if( err != paNoError ) goto error;\r
+        /* Make Write FIFO appear full initially. */\r
+        numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+        RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );\r
+    }\r
+\r
+    /* Open a PortAudio stream that we will use to communicate with the underlying\r
+     * audio drivers. */\r
+    err = Pa_OpenStream(\r
+              &aStream->stream,\r
+                         (doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice),\r
+              (doRead ? aStream->samplesPerFrame : 0 ),\r
+              format,\r
+              NULL,\r
+                         (doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice),\r
+              (doWrite ? aStream->samplesPerFrame : 0 ),\r
+              format,\r
+              NULL,\r
+              sampleRate,\r
+              FRAMES_PER_BUFFER,\r
+              minNumBuffers,\r
+              paClipOff,       /* we won't output out of range samples so don't bother clipping them */\r
+              blockingIOCallback,\r
+              aStream );\r
+    if( err != paNoError ) goto error;\r
+\r
+    err = Pa_StartStream( aStream->stream );\r
+    if( err != paNoError ) goto error;\r
+\r
+    *rwblPtr = aStream;\r
+    return paNoError;\r
+\r
+error:\r
+    CloseAudioStream( aStream );\r
+    *rwblPtr = NULL;\r
+    return err;\r
+}\r
+\r
+/************************************************************/\r
+PaError CloseAudioStream( PABLIO_Stream *aStream )\r
+{\r
+    PaError err = paNoError;\r
+    int bytesEmpty;\r
+    int byteSize = aStream->outFIFO.bufferSize;\r
+\r
+    if( aStream->stream != NULL ) /* Make sure stream was opened. PLB021214 */\r
+    {\r
+        /* If we are writing data, make sure we play everything written. */\r
+        if( byteSize > 0 )\r
+        {\r
+            int timeOutMSec = 2000;\r
+            bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+            while( (bytesEmpty < byteSize) && (timeOutMSec > 0) )\r
+            {\r
+                Pa_Sleep( 20 );\r
+                timeOutMSec -= 20;\r
+                bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+            }\r
+        }\r
+        err = Pa_StopStream( aStream->stream );\r
+        if( err != paNoError ) goto error;\r
+        err = Pa_CloseStream( aStream->stream );\r
+    }\r
+\r
+error:\r
+    Pa_Terminate();\r
+    PABLIO_TermFIFO( &aStream->inFIFO );\r
+    PABLIO_TermFIFO( &aStream->outFIFO );\r
+    free( aStream );\r
+    return err;\r
+}\r
diff --git a/src/mod/mod_portaudio/pablio.h b/src/mod/mod_portaudio/pablio.h
new file mode 100644 (file)
index 0000000..25bccf8
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _PABLIO_H\r
+#define _PABLIO_H\r
+\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif /* __cplusplus */\r
+\r
+/*\r
+ * $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $\r
+ * PABLIO.h\r
+ * Portable Audio Blocking read/write utility.\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/\r
+ *\r
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.\r
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "portaudio.h"\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+typedef struct\r
+{\r
+    RingBuffer   inFIFO;\r
+    RingBuffer   outFIFO;\r
+    PortAudioStream *stream;\r
+    int          bytesPerFrame;\r
+    int          samplesPerFrame;\r
+}\r
+PABLIO_Stream;\r
+\r
+/* Values for flags for OpenAudioStream(). */\r
+#define PABLIO_READ     (1<<0)\r
+#define PABLIO_WRITE    (1<<1)\r
+#define PABLIO_READ_WRITE    (PABLIO_READ|PABLIO_WRITE)\r
+#define PABLIO_MONO     (1<<2)\r
+#define PABLIO_STEREO   (1<<3)\r
+\r
+/************************************************************\r
+ * Write data to ring buffer.\r
+ * Will not return until all the data has been written.\r
+ */\r
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );\r
+\r
+/************************************************************\r
+ * Read data from ring buffer.\r
+ * Will not return until all the data has been read.\r
+ */\r
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );\r
+\r
+/************************************************************\r
+ * Return the number of frames that could be written to the stream without\r
+ * having to wait.\r
+ */\r
+long GetAudioStreamWriteable( PABLIO_Stream *aStream );\r
+\r
+/************************************************************\r
+ * Return the number of frames that are available to be read from the\r
+ * stream without having to wait.\r
+ */\r
+long GetAudioStreamReadable( PABLIO_Stream *aStream );\r
+\r
+/************************************************************\r
+ * Opens a PortAudio stream with default characteristics.\r
+ * Allocates PABLIO_Stream structure.\r
+ *\r
+ * flags parameter can be an ORed combination of:\r
+ *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,\r
+ *    and either PABLIO_MONO or PABLIO_STEREO\r
+ */\r
+PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,\r
+                         PaSampleFormat format, long flags, int indev, int outdev );\r
+\r
+PaError CloseAudioStream( PABLIO_Stream *aStream );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* _PABLIO_H */\r
diff --git a/src/mod/mod_portaudio/ringbuffer.c b/src/mod/mod_portaudio/ringbuffer.c
new file mode 100644 (file)
index 0000000..867b501
--- /dev/null
@@ -0,0 +1,199 @@
+/*\r
+ * $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $\r
+ * ringbuffer.c\r
+ * Ring Buffer utility..\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+/***************************************************************************\r
+ * Initialize FIFO.\r
+ * numBytes must be power of 2, returns -1 if not.\r
+ */\r
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )\r
+{\r
+    if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */\r
+    rbuf->bufferSize = numBytes;\r
+    rbuf->buffer = (char *)dataPtr;\r
+    RingBuffer_Flush( rbuf );\r
+    rbuf->bigMask = (numBytes*2)-1;\r
+    rbuf->smallMask = (numBytes)-1;\r
+    return 0;\r
+}\r
+/***************************************************************************\r
+** Return number of bytes available for reading. */\r
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )\r
+{\r
+    return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );\r
+}\r
+/***************************************************************************\r
+** Return number of bytes available for writing. */\r
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )\r
+{\r
+    return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));\r
+}\r
+\r
+/***************************************************************************\r
+** Clear buffer. Should only be called when buffer is NOT being read. */\r
+void RingBuffer_Flush( RingBuffer *rbuf )\r
+{\r
+    rbuf->writeIndex = rbuf->readIndex = 0;\r
+}\r
+\r
+/***************************************************************************\r
+** Get address of region(s) to which we can write data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,\r
+                                 void **dataPtr1, long *sizePtr1,\r
+                                 void **dataPtr2, long *sizePtr2 )\r
+{\r
+    long   index;\r
+    long   available = RingBuffer_GetWriteAvailable( rbuf );\r
+    if( numBytes > available ) numBytes = available;\r
+    /* Check to see if write is not contiguous. */\r
+    index = rbuf->writeIndex & rbuf->smallMask;\r
+    if( (index + numBytes) > rbuf->bufferSize )\r
+    {\r
+        /* Write data in two blocks that wrap the buffer. */\r
+        long   firstHalf = rbuf->bufferSize - index;\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = firstHalf;\r
+        *dataPtr2 = &rbuf->buffer[0];\r
+        *sizePtr2 = numBytes - firstHalf;\r
+    }\r
+    else\r
+    {\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = numBytes;\r
+        *dataPtr2 = NULL;\r
+        *sizePtr2 = 0;\r
+    }\r
+    return numBytes;\r
+}\r
+\r
+\r
+/***************************************************************************\r
+*/\r
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )\r
+{\r
+    return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;\r
+}\r
+\r
+/***************************************************************************\r
+** Get address of region(s) from which we can read data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,\r
+                                void **dataPtr1, long *sizePtr1,\r
+                                void **dataPtr2, long *sizePtr2 )\r
+{\r
+    long   index;\r
+    long   available = RingBuffer_GetReadAvailable( rbuf );\r
+    if( numBytes > available ) numBytes = available;\r
+    /* Check to see if read is not contiguous. */\r
+    index = rbuf->readIndex & rbuf->smallMask;\r
+    if( (index + numBytes) > rbuf->bufferSize )\r
+    {\r
+        /* Write data in two blocks that wrap the buffer. */\r
+        long firstHalf = rbuf->bufferSize - index;\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = firstHalf;\r
+        *dataPtr2 = &rbuf->buffer[0];\r
+        *sizePtr2 = numBytes - firstHalf;\r
+    }\r
+    else\r
+    {\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = numBytes;\r
+        *dataPtr2 = NULL;\r
+        *sizePtr2 = 0;\r
+    }\r
+    return numBytes;\r
+}\r
+/***************************************************************************\r
+*/\r
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )\r
+{\r
+    return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;\r
+}\r
+\r
+/***************************************************************************\r
+** Return bytes written. */\r
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes )\r
+{\r
+    long size1, size2, numWritten;\r
+    void *data1, *data2;\r
+    numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );\r
+    if( size2 > 0 )\r
+    {\r
+\r
+        memcpy( data1, data, size1 );\r
+        data = ((char *)data) + size1;\r
+        memcpy( data2, data, size2 );\r
+    }\r
+    else\r
+    {\r
+        memcpy( data1, data, size1 );\r
+    }\r
+    RingBuffer_AdvanceWriteIndex( rbuf, numWritten );\r
+    return numWritten;\r
+}\r
+\r
+/***************************************************************************\r
+** Return bytes read. */\r
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )\r
+{\r
+    long size1, size2, numRead;\r
+    void *data1, *data2;\r
+    numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );\r
+    if( size2 > 0 )\r
+    {\r
+        memcpy( data, data1, size1 );\r
+        data = ((char *)data) + size1;\r
+        memcpy( data, data2, size2 );\r
+    }\r
+    else\r
+    {\r
+        memcpy( data, data1, size1 );\r
+    }\r
+    RingBuffer_AdvanceReadIndex( rbuf, numRead );\r
+    return numRead;\r
+}\r
diff --git a/src/mod/mod_portaudio/ringbuffer.h b/src/mod/mod_portaudio/ringbuffer.h
new file mode 100644 (file)
index 0000000..6f65694
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _RINGBUFFER_H\r
+#define _RINGBUFFER_H\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif /* __cplusplus */\r
+\r
+/*\r
+ * $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $\r
+ * ringbuffer.h\r
+ * Ring Buffer utility..\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program is distributed with the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+typedef struct\r
+{\r
+    long   bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */\r
+/* These are declared volatile because they are written by a different thread than the reader. */\r
+    volatile long   writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */\r
+    volatile long   readIndex;  /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */\r
+    long   bigMask;    /* Used for wrapping indices with extra bit to distinguish full/empty. */\r
+    long   smallMask;  /* Used for fitting indices to buffer. */\r
+    char *buffer;\r
+}\r
+RingBuffer;\r
+/*\r
+ * Initialize Ring Buffer.\r
+ * numBytes must be power of 2, returns -1 if not.\r
+ */\r
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );\r
+\r
+/* Clear buffer. Should only be called when buffer is NOT being read. */\r
+void RingBuffer_Flush( RingBuffer *rbuf );\r
+\r
+/* Return number of bytes available for writing. */\r
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );\r
+/* Return number of bytes available for read. */\r
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf );\r
+/* Return bytes written. */\r
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );\r
+/* Return bytes read. */\r
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );\r
+\r
+/* Get address of region(s) to which we can write data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,\r
+                                 void **dataPtr1, long *sizePtr1,\r
+                                 void **dataPtr2, long *sizePtr2 );\r
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );\r
+\r
+/* Get address of region(s) from which we can read data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be read or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,\r
+                                void **dataPtr1, long *sizePtr1,\r
+                                void **dataPtr2, long *sizePtr2 );\r
+\r
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* _RINGBUFFER_H */\r
index d2da06e1d216aad548e078962a56fcd50906a10a..de624fc4442a642d8941d036b7af7f82bb1e658e 100644 (file)
@@ -42,7 +42,7 @@
                        <Tool\r
                                Name="VCCLCompilerTool"\r
                                Optimization="0"\r
-                               AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\src\include&quot;;&quot;$(ProjectDir)include&quot;;&quot;$(ProjectDir)..\..\libs\apr\include&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_common&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pablio&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_win_wmme&quot;"\r
+                               AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\src\include&quot;;&quot;$(ProjectDir)include&quot;;&quot;$(ProjectDir)..\..\libs\apr\include&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_common&quot;;&quot;$(ProjectDir)\..\..\..\src\mod\mod_portaudio&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_win_wmme&quot;"\r
                                PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
                                MinimalRebuild="true"\r
                                BasicRuntimeChecks="3"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\..\libs\portaudio\pablio\pablio.c"\r
+                               RelativePath="..\..\src\mod\mod_portaudio\pablio.c"\r
                                >\r
                        </File>\r
                        <File\r
-                               RelativePath="..\..\libs\portaudio\pablio\ringbuffer.c"\r
+                               RelativePath="..\..\src\mod\mod_portaudio\ringbuffer.c"\r
                                >\r
                        </File>\r
                </Filter>\r
                        Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
                        UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
                        >\r
+                       <File\r
+                               RelativePath="..\..\src\mod\mod_portaudio\pablio.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\src\mod\mod_portaudio\ringbuffer.h"\r
+                               >\r
+                       </File>\r
                </Filter>\r
                <Filter\r
                        Name="Resource Files"\r