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 CHANGED
@@ -7,7 +7,7 @@ require 'rake/loaders/makefile'
7
7
  require 'rbconfig'
8
8
 
9
9
  PKG_NAME = 'hornetseye-alsa'
10
- PKG_VERSION = '1.1.2'
10
+ PKG_VERSION = '1.2.0'
11
11
  CFG = RbConfig::CONFIG
12
12
  CXX = ENV[ 'CXX' ] || 'g++'
13
13
  RB_FILES = FileList[ 'lib/**/*.rb' ]
data/ext/alsainput.cc CHANGED
@@ -1,5 +1,5 @@
1
1
  /* HornetsEye - Computer Vision with Ruby
2
- Copyright (C) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
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( const string &pcmName, unsigned int rate,
23
- unsigned int channels, int periods,
24
- snd_pcm_uframes_t frames ) throw (Error):
25
- m_pcmHandle(NULL), m_pcmName( pcmName ), m_rate( rate ), m_channels( channels )
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( &hwParams );
30
- int err = snd_pcm_open( &m_pcmHandle, m_pcmName.c_str(), SND_PCM_STREAM_CAPTURE,
31
- 0 );
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
- err = snd_pcm_hw_params_set_periods( m_pcmHandle, hwParams, periods, 0 );
52
- ERRORMACRO( err >= 0, Error, , "Error setting number of periods of PCM device \""
53
- << m_pcmName << "\" to " << periods << ": " << snd_strerror( err ) );
54
- err = snd_pcm_hw_params_set_buffer_size_near( m_pcmHandle, hwParams, &frames );
55
- ERRORMACRO( err >= 0, Error, , "Error setting buffer size of PCM device \""
56
- << m_pcmName << "\" to " << frames << " frames: "
57
- << snd_strerror( err ) );
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
- // drop();
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( int samples ) throw (Error)
89
+ SequencePtr AlsaInput::read(int samples) throw (Error)
82
90
  {
83
- ERRORMACRO( m_pcmHandle != NULL, Error, , "PCM device \"" << m_pcmName
84
- << "\" is not open. Did you call \"close\" before?" );
85
- SequencePtr frame( new Sequence( (int)( samples * 2 * m_channels ) ) );
86
- int err;
87
- while ( ( err = snd_pcm_readi( m_pcmHandle, (short int *)frame->data(),
88
- samples ) ) < 0 ) {
89
- err = snd_pcm_recover( m_pcmHandle, err, 1 );
90
- ERRORMACRO( err >= 0, Error, , "Error reading audio frames from PCM device \""
91
- << m_pcmName << "\": " << snd_strerror( err ) );
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
- ERRORMACRO( samples == err, Error, , "Only managed to read " << err << " of "
94
- << samples << " frames from PCM device \"" << m_pcmName << "\"" );
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
- int AlsaInput::delay(void) throw (Error)
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 ( ( err = snd_pcm_delay( m_pcmHandle, &frames ) ) < 0 ) {
130
- err = snd_pcm_recover( m_pcmHandle, err, 1 );
131
- ERRORMACRO( err >= 0, Error, , "Error querying number of available frames for "
132
- "capture on PCM device \"" << m_pcmName << "\": "
133
- << snd_strerror( err ) );
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
- return frames;
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( cRubyClass, "new",
151
- RUBY_METHOD_FUNC( wrapNew ), 5 );
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, VALUE rbPeriods, VALUE rbFrames )
259
+ VALUE rbChannels)
168
260
  {
169
261
  VALUE retVal = Qnil;
170
262
  try {
171
263
  rb_check_type( rbPCMName, T_STRING );
172
- AlsaInputPtr ptr( new AlsaInput( StringValuePtr( rbPCMName ),
173
- NUM2UINT( rbRate ), NUM2UINT( rbChannels ),
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) 2006, 2007, 2008, 2009, 2010 Jan Wedekind
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
- int delay(void) throw (Error);
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( VALUE rbClass, VALUE rbPCMName, VALUE rbRate,
43
- VALUE rbChannels, VALUE rbPeriods, VALUE rbFrames );
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 ( m_pcmHandle != NULL ) {
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 > m_size) offset -= m_size;
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 + m_size - offset) * 2 * m_channels);
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
- writei(m_data.get() + m_start * m_channels, m_size - m_start);
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( pcm_name = 'default', rate = 48000, channels = 2, periods = 8,
54
- frames = 1024 )
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: 23
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 1
9
8
  - 2
10
- version: 1.1.2
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-14 00:00:00 Z
18
+ date: 2012-11-16 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: malloc