hornetseye-alsa 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +1 -1
- data/ext/alsainput.cc +136 -57
- data/ext/alsainput.hh +18 -7
- data/ext/alsaoutput.cc +7 -22
- data/ext/alsaoutput.hh +0 -1
- data/lib/hornetseye-alsa/alsainput.rb +2 -5
- metadata +4 -4
    
        data/Rakefile
    CHANGED
    
    
    
        data/ext/alsainput.cc
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            /* HornetsEye - Computer Vision with Ruby
         | 
| 2 | 
            -
               Copyright (C)  | 
| 2 | 
            +
               Copyright (C) 2012   Jan Wedekind
         | 
| 3 3 |  | 
| 4 4 | 
             
               This program is free software: you can redistribute it and/or modify
         | 
| 5 5 | 
             
               it under the terms of the GNU General Public License as published by
         | 
| @@ -19,16 +19,17 @@ using namespace std; | |
| 19 19 |  | 
| 20 20 | 
             
            VALUE AlsaInput::cRubyClass = Qnil;
         | 
| 21 21 |  | 
| 22 | 
            -
            AlsaInput::AlsaInput( | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
               | 
| 22 | 
            +
            AlsaInput::AlsaInput(const string &pcmName, unsigned int rate,
         | 
| 23 | 
            +
                                 unsigned int channels) throw (Error):
         | 
| 24 | 
            +
              m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate ), m_channels( channels ),
         | 
| 25 | 
            +
              m_periodSize(1024), m_threadInitialised(false), m_start(0), m_count(0),
         | 
| 26 | 
            +
              m_size(rate)
         | 
| 26 27 | 
             
            {
         | 
| 27 28 | 
             
              try {
         | 
| 28 29 | 
             
                snd_pcm_hw_params_t *hwParams;
         | 
| 29 | 
            -
                snd_pcm_hw_params_alloca( | 
| 30 | 
            -
                int err = snd_pcm_open( | 
| 31 | 
            -
             | 
| 30 | 
            +
                snd_pcm_hw_params_alloca(&hwParams);
         | 
| 31 | 
            +
                int err = snd_pcm_open(&m_pcmHandle, m_pcmName.c_str(), SND_PCM_STREAM_CAPTURE,
         | 
| 32 | 
            +
                                       0);
         | 
| 32 33 | 
             
                ERRORMACRO( err >= 0, Error, , "Error opening PCM device \"" << m_pcmName
         | 
| 33 34 | 
             
                            << "\": " << snd_strerror( err ) );
         | 
| 34 35 | 
             
                err = snd_pcm_hw_params_any( m_pcmHandle, hwParams );
         | 
| @@ -48,16 +49,22 @@ AlsaInput::AlsaInput( const string &pcmName, unsigned int rate, | |
| 48 49 | 
             
                err = snd_pcm_hw_params_set_channels( m_pcmHandle, hwParams, channels );
         | 
| 49 50 | 
             
                ERRORMACRO( err >= 0, Error, , "Error setting number of channels of PCM device \""
         | 
| 50 51 | 
             
                            << m_pcmName << "\" to " << channels << ": " << snd_strerror( err ) );
         | 
| 51 | 
            -
                 | 
| 52 | 
            -
                 | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
                 | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 52 | 
            +
                unsigned int bufferTime = 500000;
         | 
| 53 | 
            +
                err = snd_pcm_hw_params_set_buffer_time_near(m_pcmHandle, hwParams, &bufferTime, NULL);
         | 
| 54 | 
            +
                ERRORMACRO(err >= 0, Error, , "Error setting buffer time of PCM device \""
         | 
| 55 | 
            +
                           << m_pcmName << "\" to " << bufferTime << " us: " << snd_strerror(err));
         | 
| 56 | 
            +
                unsigned int periods = 16;
         | 
| 57 | 
            +
                err = snd_pcm_hw_params_set_periods_near(m_pcmHandle, hwParams, &periods, NULL);
         | 
| 58 | 
            +
                ERRORMACRO(err >= 0, Error, , "Error setting periods of PCM device \""
         | 
| 59 | 
            +
                           << m_pcmName << "\" to " << periods << ": " << snd_strerror(err));
         | 
| 58 60 | 
             
                err = snd_pcm_hw_params( m_pcmHandle, hwParams );
         | 
| 59 61 | 
             
                ERRORMACRO( err >= 0, Error, , "Error setting parameters of PCM device \""
         | 
| 60 62 | 
             
                            << m_pcmName << "\": " << snd_strerror( err ) );
         | 
| 63 | 
            +
                err = snd_pcm_hw_params_get_period_size(hwParams, &m_periodSize, NULL);
         | 
| 64 | 
            +
                ERRORMACRO( err >= 0, Error, , "Error getting period size of PCM device \""
         | 
| 65 | 
            +
                            << m_pcmName << "\": " << snd_strerror( err ) );
         | 
| 66 | 
            +
                err = pthread_mutex_init(&m_mutex, NULL);
         | 
| 67 | 
            +
                ERRORMACRO(err == 0, Error, , "Error initialising mutex: " << strerror(err));
         | 
| 61 68 | 
             
              } catch ( Error &e ) {
         | 
| 62 69 | 
             
                close();
         | 
| 63 70 | 
             
                throw e;
         | 
| @@ -72,29 +79,59 @@ AlsaInput::~AlsaInput(void) | |
| 72 79 | 
             
            void AlsaInput::close(void)
         | 
| 73 80 | 
             
            {
         | 
| 74 81 | 
             
              if ( m_pcmHandle != NULL ) {
         | 
| 75 | 
            -
                 | 
| 82 | 
            +
                drop();
         | 
| 83 | 
            +
                pthread_mutex_destroy(&m_mutex);
         | 
| 76 84 | 
             
                snd_pcm_close( m_pcmHandle );
         | 
| 77 85 | 
             
                m_pcmHandle = NULL;
         | 
| 78 86 | 
             
              };
         | 
| 79 87 | 
             
            }
         | 
| 80 88 |  | 
| 81 | 
            -
            SequencePtr AlsaInput::read( | 
| 89 | 
            +
            SequencePtr AlsaInput::read(int samples) throw (Error)
         | 
| 82 90 | 
             
            {
         | 
| 83 | 
            -
              ERRORMACRO( | 
| 84 | 
            -
             | 
| 85 | 
            -
              SequencePtr frame( | 
| 86 | 
            -
               | 
| 87 | 
            -
               | 
| 88 | 
            -
             | 
| 89 | 
            -
                 | 
| 90 | 
            -
                 | 
| 91 | 
            -
             | 
| 91 | 
            +
              ERRORMACRO(m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
         | 
| 92 | 
            +
                         << "\" is not open. Did you call \"close\" before?");
         | 
| 93 | 
            +
              SequencePtr frame(new Sequence((int)(samples * 2 * m_channels)));
         | 
| 94 | 
            +
              lock();
         | 
| 95 | 
            +
              if (!m_data.get()) {
         | 
| 96 | 
            +
                if (m_threadInitialised) pthread_join(m_thread, NULL);
         | 
| 97 | 
            +
                m_data = boost::shared_array<short int>(new short int[m_size * m_channels]);
         | 
| 98 | 
            +
                m_start = 0;
         | 
| 99 | 
            +
                m_count = 0;
         | 
| 100 | 
            +
                pthread_create(&m_thread, NULL, staticThreadFunc, this);
         | 
| 92 101 | 
             
              };
         | 
| 93 | 
            -
               | 
| 94 | 
            -
             | 
| 102 | 
            +
              int n = samples;
         | 
| 103 | 
            +
              if (n > m_count) n = m_count;
         | 
| 104 | 
            +
              if (m_start + n > m_size) {
         | 
| 105 | 
            +
                memcpy(frame->data(), m_data.get() + m_start * m_channels, (m_size - m_start) * 2 * m_channels);
         | 
| 106 | 
            +
                memcpy(frame->data() + (m_size - m_start) * 2 * m_channels, m_data.get(), (n + m_start - m_size) * 2 * m_channels);
         | 
| 107 | 
            +
              } else
         | 
| 108 | 
            +
                memcpy(frame->data(), m_data.get() + m_start * m_channels, n * 2 * m_channels);
         | 
| 109 | 
            +
              m_start += n;
         | 
| 110 | 
            +
              if (m_start >= m_size) m_start -= m_size;
         | 
| 111 | 
            +
              m_count -= n;
         | 
| 112 | 
            +
              if (n < samples) {
         | 
| 113 | 
            +
                try {
         | 
| 114 | 
            +
                  readi((short int *)frame->data() + n * m_channels * 2, samples - n);
         | 
| 115 | 
            +
                } catch (Error &e) {
         | 
| 116 | 
            +
                  unlock();
         | 
| 117 | 
            +
                  throw e;
         | 
| 118 | 
            +
                }
         | 
| 119 | 
            +
              }
         | 
| 120 | 
            +
              unlock();
         | 
| 95 121 | 
             
              return frame;
         | 
| 96 122 | 
             
            }
         | 
| 97 123 |  | 
| 124 | 
            +
            void AlsaInput::drop(void) throw (Error)
         | 
| 125 | 
            +
            {
         | 
| 126 | 
            +
              ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
         | 
| 127 | 
            +
                          << "\" is not open. Did you call \"close\" before?" );
         | 
| 128 | 
            +
              lock();
         | 
| 129 | 
            +
              m_data.reset();
         | 
| 130 | 
            +
              m_count = 0;
         | 
| 131 | 
            +
              snd_pcm_drop(m_pcmHandle);
         | 
| 132 | 
            +
              unlock();
         | 
| 133 | 
            +
            }
         | 
| 134 | 
            +
             | 
| 98 135 | 
             
            unsigned int AlsaInput::rate(void)
         | 
| 99 136 | 
             
            {
         | 
| 100 137 | 
             
              return m_rate;
         | 
| @@ -109,6 +146,7 @@ int AlsaInput::avail(void) throw (Error) | |
| 109 146 | 
             
            {
         | 
| 110 147 | 
             
              ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
         | 
| 111 148 | 
             
                          << "\" is not open. Did you call \"close\" before?" );
         | 
| 149 | 
            +
              lock();
         | 
| 112 150 | 
             
              snd_pcm_sframes_t frames;
         | 
| 113 151 | 
             
              int err = 0;
         | 
| 114 152 | 
             
              while ( ( frames = snd_pcm_avail( m_pcmHandle ) ) < 0 ) {
         | 
| @@ -117,22 +155,34 @@ int AlsaInput::avail(void) throw (Error) | |
| 117 155 | 
             
                          "retrieval from PCM device \"" << m_pcmName << "\": "
         | 
| 118 156 | 
             
                          << snd_strerror( err ) );
         | 
| 119 157 | 
             
              };
         | 
| 158 | 
            +
              frames += m_count;
         | 
| 159 | 
            +
              unlock();
         | 
| 120 160 | 
             
              return frames;
         | 
| 121 161 | 
             
            }
         | 
| 122 162 |  | 
| 123 | 
            -
             | 
| 163 | 
            +
            void AlsaInput::readi(short int *data, int count)
         | 
| 124 164 | 
             
            {
         | 
| 125 | 
            -
              ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
         | 
| 126 | 
            -
                          << "\" is not open. Did you call \"close\" before?" );
         | 
| 127 | 
            -
              snd_pcm_sframes_t frames;
         | 
| 128 165 | 
             
              int err;
         | 
| 129 | 
            -
              while ( | 
| 130 | 
            -
                 | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 133 | 
            -
             | 
| 166 | 
            +
              while ((err = snd_pcm_readi(m_pcmHandle, data, count)) < 0) {
         | 
| 167 | 
            +
                if (err == -EBADFD)
         | 
| 168 | 
            +
                  err = snd_pcm_prepare(m_pcmHandle);
         | 
| 169 | 
            +
                else
         | 
| 170 | 
            +
                  err = snd_pcm_recover(m_pcmHandle, err, 1);
         | 
| 171 | 
            +
                ERRORMACRO(err >= 0, Error, , "Error reading audio frames from PCM device \""
         | 
| 172 | 
            +
                           << m_pcmName << "\": " << snd_strerror(err));
         | 
| 134 173 | 
             
              };
         | 
| 135 | 
            -
               | 
| 174 | 
            +
              ERRORMACRO(count == err, Error, , "Only managed to read " << err << " of "
         | 
| 175 | 
            +
                         << count << " frames from PCM device \"" << m_pcmName << "\"" );
         | 
| 176 | 
            +
            }
         | 
| 177 | 
            +
             | 
| 178 | 
            +
            void AlsaInput::lock(void)
         | 
| 179 | 
            +
            {
         | 
| 180 | 
            +
              pthread_mutex_lock( &m_mutex );
         | 
| 181 | 
            +
            }
         | 
| 182 | 
            +
             | 
| 183 | 
            +
            void AlsaInput::unlock(void)
         | 
| 184 | 
            +
            {
         | 
| 185 | 
            +
              pthread_mutex_unlock( &m_mutex );
         | 
| 136 186 | 
             
            }
         | 
| 137 187 |  | 
| 138 188 | 
             
            void AlsaInput::prepare(void) throw (Error)
         | 
| @@ -144,17 +194,59 @@ void AlsaInput::prepare(void) throw (Error) | |
| 144 194 | 
             
                          << "\": " << snd_strerror( err ) );
         | 
| 145 195 | 
             
            }
         | 
| 146 196 |  | 
| 197 | 
            +
            void AlsaInput::threadFunc(void)
         | 
| 198 | 
            +
            {
         | 
| 199 | 
            +
              bool quit = false;
         | 
| 200 | 
            +
              while (!quit) {
         | 
| 201 | 
            +
                snd_pcm_wait(m_pcmHandle, 1000);
         | 
| 202 | 
            +
                try {
         | 
| 203 | 
            +
                  lock();
         | 
| 204 | 
            +
                  if (m_data.get()) {
         | 
| 205 | 
            +
                    int n = m_periodSize;
         | 
| 206 | 
            +
                    if (m_count + n > m_size) {
         | 
| 207 | 
            +
                      int m_size_new = m_size;
         | 
| 208 | 
            +
                      while(m_size_new < m_count + n) m_size_new = 2 * m_size_new;
         | 
| 209 | 
            +
                      boost::shared_array<short int> data(new short int[m_size_new * m_channels]);
         | 
| 210 | 
            +
                      if (m_start + m_count > m_size) {
         | 
| 211 | 
            +
                        memcpy(data.get(), m_data.get() + m_start * m_channels, (m_size - m_start) * 2 * m_channels);
         | 
| 212 | 
            +
                        memcpy(data.get() + (m_size - m_start) * m_channels, m_data.get(), (m_start + m_count - m_size) * 2 * m_channels);
         | 
| 213 | 
            +
                      } else
         | 
| 214 | 
            +
                        memcpy(data.get(), m_data.get() + m_start * m_channels, m_count * 2 * m_channels);
         | 
| 215 | 
            +
                      m_data = data;
         | 
| 216 | 
            +
                      m_start = 0;
         | 
| 217 | 
            +
                      m_size = m_size_new;
         | 
| 218 | 
            +
                    };
         | 
| 219 | 
            +
                    int offset = m_start + m_count;
         | 
| 220 | 
            +
                    if (offset > m_size) offset -= m_size;
         | 
| 221 | 
            +
                    if (offset + n > m_size) n = m_size - offset;
         | 
| 222 | 
            +
                    readi(m_data.get() + offset * m_channels, n);
         | 
| 223 | 
            +
                    m_count += n;
         | 
| 224 | 
            +
                  } else
         | 
| 225 | 
            +
                    quit = true;
         | 
| 226 | 
            +
                  unlock();
         | 
| 227 | 
            +
                } catch (Error &e) {
         | 
| 228 | 
            +
                  quit = true;
         | 
| 229 | 
            +
                  m_data.reset();
         | 
| 230 | 
            +
                  unlock();
         | 
| 231 | 
            +
                }
         | 
| 232 | 
            +
              };
         | 
| 233 | 
            +
            }
         | 
| 234 | 
            +
             | 
| 235 | 
            +
            void *AlsaInput::staticThreadFunc( void *self )
         | 
| 236 | 
            +
            {
         | 
| 237 | 
            +
              ((AlsaInput *)self)->threadFunc();
         | 
| 238 | 
            +
              return self;
         | 
| 239 | 
            +
            }
         | 
| 147 240 | 
             
            VALUE AlsaInput::registerRubyClass( VALUE rbModule )
         | 
| 148 241 | 
             
            {
         | 
| 149 242 | 
             
              cRubyClass = rb_define_class_under( rbModule, "AlsaInput", rb_cObject );
         | 
| 150 | 
            -
              rb_define_singleton_method( | 
| 151 | 
            -
             | 
| 243 | 
            +
              rb_define_singleton_method(cRubyClass, "new",
         | 
| 244 | 
            +
                                         RUBY_METHOD_FUNC(wrapNew), 3);
         | 
| 152 245 | 
             
              rb_define_method( cRubyClass, "close", RUBY_METHOD_FUNC( wrapClose ), 0 );
         | 
| 153 246 | 
             
              rb_define_method( cRubyClass, "read", RUBY_METHOD_FUNC( wrapRead ), 1 );
         | 
| 154 247 | 
             
              rb_define_method( cRubyClass, "rate", RUBY_METHOD_FUNC( wrapRate ), 0 );
         | 
| 155 248 | 
             
              rb_define_method( cRubyClass, "channels", RUBY_METHOD_FUNC( wrapChannels ), 0 );
         | 
| 156 249 | 
             
              rb_define_method( cRubyClass, "avail", RUBY_METHOD_FUNC( wrapAvail ), 0 );
         | 
| 157 | 
            -
              rb_define_method( cRubyClass, "delay", RUBY_METHOD_FUNC( wrapDelay ), 0 );
         | 
| 158 250 | 
             
              rb_define_method( cRubyClass, "prepare", RUBY_METHOD_FUNC( wrapPrepare ), 0 );
         | 
| 159 251 | 
             
            }
         | 
| 160 252 |  | 
| @@ -164,14 +256,13 @@ void AlsaInput::deleteRubyObject( void *ptr ) | |
| 164 256 | 
             
            }
         | 
| 165 257 |  | 
| 166 258 | 
             
            VALUE AlsaInput::wrapNew( VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
         | 
| 167 | 
            -
                                      VALUE rbChannels | 
| 259 | 
            +
                                      VALUE rbChannels)
         | 
| 168 260 | 
             
            {
         | 
| 169 261 | 
             
              VALUE retVal = Qnil;
         | 
| 170 262 | 
             
              try {
         | 
| 171 263 | 
             
                rb_check_type( rbPCMName, T_STRING );
         | 
| 172 | 
            -
                AlsaInputPtr ptr( | 
| 173 | 
            -
             | 
| 174 | 
            -
                                                 NUM2INT( rbPeriods ), NUM2INT( rbFrames ) ) );
         | 
| 264 | 
            +
                AlsaInputPtr ptr(new AlsaInput(StringValuePtr(rbPCMName),
         | 
| 265 | 
            +
                                               NUM2UINT(rbRate), NUM2UINT(rbChannels)));
         | 
| 175 266 | 
             
                retVal = Data_Wrap_Struct( rbClass, 0, deleteRubyObject,
         | 
| 176 267 | 
             
                                           new AlsaInputPtr( ptr ) );
         | 
| 177 268 | 
             
              } catch ( exception &e ) {
         | 
| @@ -224,18 +315,6 @@ VALUE AlsaInput::wrapAvail( VALUE rbSelf ) | |
| 224 315 | 
             
              return rbRetVal;
         | 
| 225 316 | 
             
            }
         | 
| 226 317 |  | 
| 227 | 
            -
            VALUE AlsaInput::wrapDelay( VALUE rbSelf )
         | 
| 228 | 
            -
            {
         | 
| 229 | 
            -
              VALUE rbRetVal = Qnil;
         | 
| 230 | 
            -
              try {
         | 
| 231 | 
            -
                AlsaInputPtr *self; Data_Get_Struct( rbSelf, AlsaInputPtr, self );
         | 
| 232 | 
            -
                rbRetVal = INT2NUM( (*self)->delay() );
         | 
| 233 | 
            -
              } catch ( exception &e ) {
         | 
| 234 | 
            -
                rb_raise( rb_eRuntimeError, "%s", e.what() );
         | 
| 235 | 
            -
              };
         | 
| 236 | 
            -
              return rbRetVal;
         | 
| 237 | 
            -
            }
         | 
| 238 | 
            -
             | 
| 239 318 | 
             
            VALUE AlsaInput::wrapPrepare( VALUE rbSelf )
         | 
| 240 319 | 
             
            {
         | 
| 241 320 | 
             
              try {
         | 
    
        data/ext/alsainput.hh
    CHANGED
    
    | @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            /* HornetsEye - Computer Vision with Ruby
         | 
| 2 | 
            -
               Copyright (C)  | 
| 2 | 
            +
               Copyright (C) 2012   Jan Wedekind
         | 
| 3 3 |  | 
| 4 4 | 
             
               This program is free software: you can redistribute it and/or modify
         | 
| 5 5 | 
             
               it under the terms of the GNU General Public License as published by
         | 
| @@ -26,33 +26,44 @@ class AlsaInput | |
| 26 26 | 
             
            {
         | 
| 27 27 | 
             
            public:
         | 
| 28 28 | 
             
              AlsaInput( const std::string &pcmName = "default:0",
         | 
| 29 | 
            -
                         unsigned int rate = 48000, unsigned int channels = 2 | 
| 30 | 
            -
                         int periods = 16, snd_pcm_uframes_t frames = 1024 ) throw (Error);
         | 
| 29 | 
            +
                         unsigned int rate = 48000, unsigned int channels = 2) throw (Error);
         | 
| 31 30 | 
             
              virtual ~AlsaInput(void);
         | 
| 32 31 | 
             
              void close(void);
         | 
| 33 32 | 
             
              SequencePtr read( int samples ) throw (Error);
         | 
| 33 | 
            +
              void drop(void) throw (Error);
         | 
| 34 34 | 
             
              unsigned int rate(void);
         | 
| 35 35 | 
             
              unsigned int channels(void);
         | 
| 36 36 | 
             
              int avail(void) throw (Error);
         | 
| 37 | 
            -
               | 
| 37 | 
            +
              void lock(void);
         | 
| 38 | 
            +
              void unlock(void);
         | 
| 38 39 | 
             
              void prepare(void) throw (Error);
         | 
| 39 40 | 
             
              static VALUE cRubyClass;
         | 
| 40 41 | 
             
              static VALUE registerRubyClass( VALUE rbModule );
         | 
| 41 42 | 
             
              static void deleteRubyObject( void *ptr );
         | 
| 42 | 
            -
              static VALUE wrapNew( | 
| 43 | 
            -
             | 
| 43 | 
            +
              static VALUE wrapNew(VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
         | 
| 44 | 
            +
                                   VALUE rbChannels);
         | 
| 44 45 | 
             
              static VALUE wrapClose( VALUE rbSelf );
         | 
| 45 46 | 
             
              static VALUE wrapRead( VALUE rbSelf, VALUE rbSamples );
         | 
| 46 47 | 
             
              static VALUE wrapRate( VALUE rbSelf );
         | 
| 47 48 | 
             
              static VALUE wrapChannels( VALUE rbSelf );
         | 
| 48 49 | 
             
              static VALUE wrapAvail( VALUE rbSelf );
         | 
| 49 | 
            -
              static VALUE wrapDelay( VALUE rbSelf );
         | 
| 50 50 | 
             
              static VALUE wrapPrepare( VALUE rbSelf );
         | 
| 51 51 | 
             
            protected:
         | 
| 52 | 
            +
              void readi(short int *data, int count);
         | 
| 53 | 
            +
              void threadFunc(void);
         | 
| 54 | 
            +
              static void *staticThreadFunc( void *self );
         | 
| 52 55 | 
             
              snd_pcm_t *m_pcmHandle;
         | 
| 53 56 | 
             
              std::string m_pcmName;
         | 
| 54 57 | 
             
              unsigned int m_rate;
         | 
| 55 58 | 
             
              unsigned int m_channels;
         | 
| 59 | 
            +
              snd_pcm_uframes_t m_periodSize;
         | 
| 60 | 
            +
              bool m_threadInitialised;
         | 
| 61 | 
            +
              boost::shared_array<short int> m_data;
         | 
| 62 | 
            +
              int m_start;
         | 
| 63 | 
            +
              int m_count;
         | 
| 64 | 
            +
              int m_size;
         | 
| 65 | 
            +
              pthread_t m_thread;
         | 
| 66 | 
            +
              pthread_mutex_t m_mutex;
         | 
| 56 67 | 
             
            };
         | 
| 57 68 |  | 
| 58 69 | 
             
            typedef boost::shared_ptr< AlsaInput > AlsaInputPtr;
         | 
    
        data/ext/alsaoutput.cc
    CHANGED
    
    | @@ -77,7 +77,7 @@ AlsaOutput::~AlsaOutput(void) | |
| 77 77 |  | 
| 78 78 | 
             
            void AlsaOutput::close(void)
         | 
| 79 79 | 
             
            {
         | 
| 80 | 
            -
              if ( | 
| 80 | 
            +
              if (m_pcmHandle != NULL) {
         | 
| 81 81 | 
             
                drain();
         | 
| 82 82 | 
             
                pthread_mutex_destroy(&m_mutex);
         | 
| 83 83 | 
             
                snd_pcm_close( m_pcmHandle );
         | 
| @@ -113,10 +113,10 @@ void AlsaOutput::write(SequencePtr frame) throw (Error) | |
| 113 113 | 
             
                m_size = m_size_new;
         | 
| 114 114 | 
             
              };
         | 
| 115 115 | 
             
              int offset = m_start + m_count;
         | 
| 116 | 
            -
              if (offset  | 
| 116 | 
            +
              if (offset >= m_size) offset -= m_size;
         | 
| 117 117 | 
             
              if (offset + n > m_size) {
         | 
| 118 118 | 
             
                memcpy(m_data.get() + offset * m_channels, frame->data(), (m_size - offset) * 2 * m_channels);
         | 
| 119 | 
            -
                memcpy(m_data.get(), frame->data() + (m_size - offset) * m_channels, (n +  | 
| 119 | 
            +
                memcpy(m_data.get(), frame->data() + (m_size - offset) * 2 * m_channels, (n + offset - m_size) * 2 * m_channels);
         | 
| 120 120 | 
             
              } else
         | 
| 121 121 | 
             
                memcpy(m_data.get() + offset * m_channels, frame->data(), n * 2 * m_channels);
         | 
| 122 122 | 
             
              m_count += n;
         | 
| @@ -130,8 +130,8 @@ void AlsaOutput::drop(void) throw (Error) | |
| 130 130 | 
             
              lock();
         | 
| 131 131 | 
             
              m_data.reset();
         | 
| 132 132 | 
             
              m_count = 0;
         | 
| 133 | 
            -
              unlock();
         | 
| 134 133 | 
             
              snd_pcm_drop(m_pcmHandle);
         | 
| 134 | 
            +
              unlock();
         | 
| 135 135 | 
             
            }
         | 
| 136 136 |  | 
| 137 137 | 
             
            void AlsaOutput::drain(void) throw (Error)
         | 
| @@ -155,19 +155,6 @@ unsigned int AlsaOutput::channels(void) | |
| 155 155 | 
             
              return m_channels;
         | 
| 156 156 | 
             
            }
         | 
| 157 157 |  | 
| 158 | 
            -
            int AlsaOutput::avail(void) throw (Error)
         | 
| 159 | 
            -
            {
         | 
| 160 | 
            -
              snd_pcm_sframes_t frames;
         | 
| 161 | 
            -
              int err = 0;
         | 
| 162 | 
            -
              while ( ( frames = snd_pcm_avail( m_pcmHandle ) ) < 0 ) {
         | 
| 163 | 
            -
                err = snd_pcm_recover( m_pcmHandle, frames, 1 );
         | 
| 164 | 
            -
                ERRORMACRO( err >= 0, Error, , "Error querying number of available frames for "
         | 
| 165 | 
            -
                          "update of PCM device \"" << m_pcmName << "\": "
         | 
| 166 | 
            -
                          << snd_strerror( err ) );
         | 
| 167 | 
            -
              };
         | 
| 168 | 
            -
              return frames;
         | 
| 169 | 
            -
            }
         | 
| 170 | 
            -
             | 
| 171 158 | 
             
            int AlsaOutput::delay(void) throw (Error)
         | 
| 172 159 | 
             
            {
         | 
| 173 160 | 
             
              ERRORMACRO(m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
         | 
| @@ -226,11 +213,8 @@ void AlsaOutput::threadFunc(void) | |
| 226 213 | 
             
                  if (m_count <= 0) m_data.reset();
         | 
| 227 214 | 
             
                  if (m_start >= m_size) m_start -= m_size;
         | 
| 228 215 | 
             
                  if (m_data.get()) {
         | 
| 229 | 
            -
                    if (m_start + n > m_size)  | 
| 230 | 
            -
             | 
| 231 | 
            -
                      writei(m_data.get(), m_start + n - m_size);
         | 
| 232 | 
            -
                    } else
         | 
| 233 | 
            -
                      writei(m_data.get() + m_start * m_channels, n);
         | 
| 216 | 
            +
                    if (m_start + n > m_size) n = m_size - m_start;
         | 
| 217 | 
            +
                    writei(m_data.get() + m_start * m_channels, n);
         | 
| 234 218 | 
             
                    m_start += n;
         | 
| 235 219 | 
             
                    m_count -= n;
         | 
| 236 220 | 
             
                  } else
         | 
| @@ -238,6 +222,7 @@ void AlsaOutput::threadFunc(void) | |
| 238 222 | 
             
                  unlock();
         | 
| 239 223 | 
             
                } catch (Error &e) {
         | 
| 240 224 | 
             
                  quit = true;
         | 
| 225 | 
            +
                  m_data.reset();
         | 
| 241 226 | 
             
                  unlock();
         | 
| 242 227 | 
             
                }
         | 
| 243 228 | 
             
              };
         | 
    
        data/ext/alsaoutput.hh
    CHANGED
    
    | @@ -50,7 +50,6 @@ public: | |
| 50 50 | 
             
              static VALUE wrapChannels( VALUE rbSelf );
         | 
| 51 51 | 
             
              static VALUE wrapDelay( VALUE rbSelf );
         | 
| 52 52 | 
             
            protected:
         | 
| 53 | 
            -
              int avail(void) throw (Error);
         | 
| 54 53 | 
             
              void writei(short int *data, int count) throw (Error);
         | 
| 55 54 | 
             
              void threadFunc(void);
         | 
| 56 55 | 
             
              static void *staticThreadFunc( void *self );
         | 
| @@ -45,14 +45,11 @@ module Hornetseye | |
| 45 45 | 
             
                  # @param [String] pcm_name Name of the PCM device
         | 
| 46 46 | 
             
                  # @param [Integer] rate Desired sampling rate.
         | 
| 47 47 | 
             
                  # @param [Integer] channels Number of channels (1=mono, 2=stereo).
         | 
| 48 | 
            -
                  # @param [Integer] periods Number of audio frames of the input buffer.
         | 
| 49 | 
            -
                  # @param [Integer] frames Size of the audio frames of the input buffer.
         | 
| 50 48 | 
             
                  # @return [AlsaInput] An object for accessing the microphone.
         | 
| 51 49 | 
             
                  #
         | 
| 52 50 | 
             
                  # @see #rate
         | 
| 53 | 
            -
                  def new( | 
| 54 | 
            -
             | 
| 55 | 
            -
                    orig_new pcm_name, rate, channels, periods, frames
         | 
| 51 | 
            +
                  def new(pcm_name = 'default', rate = 48000, channels = 2)
         | 
| 52 | 
            +
                    orig_new pcm_name, rate, channels
         | 
| 56 53 | 
             
                  end
         | 
| 57 54 |  | 
| 58 55 | 
             
                end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: hornetseye-alsa
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 4 | 
            +
              hash: 31
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 1
         | 
| 8 | 
            -
              - 1
         | 
| 9 8 | 
             
              - 2
         | 
| 10 | 
            -
               | 
| 9 | 
            +
              - 0
         | 
| 10 | 
            +
              version: 1.2.0
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Jan Wedekind
         | 
| @@ -15,7 +15,7 @@ autorequire: | |
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 17 |  | 
| 18 | 
            -
            date: 2012-11- | 
| 18 | 
            +
            date: 2012-11-16 00:00:00 Z
         | 
| 19 19 | 
             
            dependencies: 
         | 
| 20 20 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 21 21 | 
             
              name: malloc
         |