@babblevoice/projectrtp 2.5.35 → 2.6.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.
@@ -1,9 +1,17 @@
1
1
 
2
+ /* needed to build on ubuntu */
3
+ #include <utility>
4
+
2
5
  #include <iostream>
6
+ #include <algorithm>
3
7
 
4
8
  #include "projectrtpsoundfile.h"
5
9
  #include "globals.h"
6
10
 
11
+
12
+ constexpr size_t AIOCBSINGLECHANBUFFNUMSAMPLES = L1616PAYLOADSAMPLES;
13
+ constexpr size_t AIOCBBUFFERNUMSAMPLES = ( AIOCBSINGLECHANBUFFNUMSAMPLES * MAXNUMBEROFCHANNELS );
14
+
7
15
  /*
8
16
  soundfile
9
17
  */
@@ -13,13 +21,8 @@ soundfile::soundfile( int fromfile ) :
13
21
  ourwavheader(),
14
22
  currentcbindex( 0 ),
15
23
  cbwavheader(),
16
- buffer( nullptr ) {
17
-
18
- /*
19
- Soundfile blindly reads the format and passes to the codec - so it must be in a format we support - or there will be silence.
20
- Our macro player (to be written) will choose the most appropriate file to play based on the codec of the channel.
21
- */
22
- this->buffer = new uint8_t[ L16WIDEBANDBYTES * MAXNUMBEROFCHANNELS * SOUNDFILENUMBUFFERS * 2 /* 16 bit */ ];
24
+ buffer(),
25
+ filelock( true /* initialised as locked */ ) {
23
26
 
24
27
  /* As it is asynchronous - we read wav header + ahead */
25
28
  memset( &this->cbwavheader, 0, sizeof( aiocb ) );
@@ -30,29 +33,33 @@ soundfile::soundfile( int fromfile ) :
30
33
 
31
34
  off_t fileoffset = sizeof( wavheader );
32
35
  for( auto i = 0; i < SOUNDFILENUMBUFFERS; i++ ) {
33
- memset( &this->cbwavblock[ i ], 0, sizeof( aiocb ) );
36
+ soundbuffer &thisbuffer = this->buffer[ i ];
37
+ aiocb &thisblock = this->cbwavblock[ i ];
38
+
39
+ thisbuffer.reserve( AIOCBBUFFERNUMSAMPLES );
40
+
41
+ memset( &thisblock, 0, sizeof( aiocb ) );
34
42
  this->cbwavblock[ i ].aio_fildes = this->file;
35
43
 
36
44
  /* These 2 values are modified depending on format and num channels */
37
- this->cbwavblock[ i ].aio_nbytes = L16WIDEBANDBYTES;
38
- this->cbwavblock[ i ].aio_offset = fileoffset;
39
- fileoffset += L16WIDEBANDBYTES;
45
+ thisblock.aio_nbytes = AIOCBBUFFERNUMSAMPLES * sizeof( uint16_t );
46
+ thisblock.aio_offset = fileoffset;
47
+ fileoffset += thisblock.aio_nbytes;
40
48
 
41
- /* this value should never be modified */
42
- this->cbwavblock[ i ].aio_buf = this->buffer + ( i * L16WIDEBANDBYTES * MAXNUMBEROFCHANNELS * 2 );
49
+ thisblock.aio_buf = thisbuffer.data();
43
50
  }
44
51
  }
45
52
 
46
53
  soundfile::~soundfile() {
54
+
55
+ SpinLockGuard guard( this->filelock );
56
+
47
57
  if ( -1 != this->file ) {
48
58
  /* Is there a better way? Not waiting for the cancel can can cause the async
49
59
  opperation to write to our buffer which is much worse */
50
60
  while( AIO_NOTCANCELED == aio_cancel( this->file, NULL ) );
51
61
  close( this->file );
52
- }
53
-
54
- if( nullptr != this->buffer ) {
55
- delete[] this->buffer;
62
+ this->file = -1;
56
63
  }
57
64
  }
58
65
 
@@ -98,7 +105,8 @@ perhaps monitor (std::cerr).
98
105
  */
99
106
  soundfilereader::soundfilereader( std::string &url ) :
100
107
  soundfile( open( url.c_str(), O_RDONLY | O_NONBLOCK, 0 ) ),
101
- blocksize( L16NARROWBANDBYTES ),
108
+ bytecount( L16WIDEBANDBYTES ),
109
+ samplecount( L1616PAYLOADSAMPLES ),
102
110
  badheader( false ),
103
111
  headerread( false ),
104
112
  bodyread( false ),
@@ -107,6 +115,7 @@ soundfilereader::soundfilereader( std::string &url ) :
107
115
 
108
116
  if ( -1 == this->file ) {
109
117
  /* Not much more we can do */
118
+ releasespinlock( this->filelock );
110
119
  return;
111
120
  }
112
121
 
@@ -118,26 +127,27 @@ soundfilereader::soundfilereader( std::string &url ) :
118
127
  this->cbwavheader.aio_buf = &this->ourwavheader;
119
128
 
120
129
  for( auto i = 0; i < SOUNDFILENUMBUFFERS; i++ ) {
121
- memset( &this->cbwavblock[ i ], 0, sizeof( aiocb ) );
122
- this->cbwavblock[ i ].aio_nbytes = L16WIDEBANDBYTES;
123
- this->cbwavblock[ i ].aio_fildes = this->file;
124
- this->cbwavblock[ i ].aio_offset = sizeof( wavheader ) + ( i * L16WIDEBANDBYTES );
125
- this->cbwavblock[ i ].aio_buf = this->buffer + ( i * L16WIDEBANDBYTES );
130
+ aiocb &thisblock = this->cbwavblock[ i ];
131
+ soundbuffer &thisbuffer = this->buffer[ i ];
132
+
133
+ thisbuffer.resize( this->samplecount );
134
+ std::fill_n( thisbuffer.begin(), thisbuffer.size(), 0 );
135
+
136
+ thisblock.aio_nbytes = this->bytecount;
137
+ thisblock.aio_fildes = this->file;
138
+ thisblock.aio_offset = sizeof( wavheader ) + ( i * this->bytecount );
139
+ thisblock.aio_buf = thisbuffer.data();
126
140
  }
127
141
 
128
142
  /* read */
129
143
  if ( aio_read( &this->cbwavheader ) == -1 ) {
130
144
  fprintf( stderr, "aio_read read of header failed in soundfile\n" );
131
145
  this->badheader = true;
146
+ releasespinlock( this->filelock );
132
147
  return;
133
148
  }
134
149
 
135
- if ( aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
136
- fprintf( stderr, "aio_read read of block failed in soundfile" );
137
- this->bodyread = true;
138
- return;
139
- }
140
-
150
+ releasespinlock( this->filelock );
141
151
  return;
142
152
  }
143
153
 
@@ -156,6 +166,86 @@ soundfilereader::pointer soundfilereader::create( std::string url ) {
156
166
  return pointer( new soundfilereader( url ) );
157
167
  }
158
168
 
169
+ void soundfilereader::parseheader( void ) {
170
+ if( this->headerread ) return;
171
+
172
+ if( aio_error( &this->cbwavheader ) == EINPROGRESS ) {
173
+ fprintf( stderr, "Read of soundfile wav header has not completed\n" );
174
+ return;
175
+ }
176
+
177
+ this->headerread = true;
178
+
179
+ if( 'W' != this->ourwavheader.wave_header[ 0 ] ) {
180
+ this->badheader = true;
181
+ }
182
+
183
+ switch( this->ourwavheader.sample_rate ) {
184
+ case 8000:
185
+ case 16000:
186
+ break;
187
+ default:
188
+ fprintf( stderr, "Bad sample rate in wav\n" );
189
+ this->badheader = true;
190
+ return;
191
+ }
192
+
193
+ this->ploadtype = L168KPAYLOADTYPE;
194
+ this->bytecount = L16NARROWBANDBYTES;
195
+ this->samplecount = L16PAYLOADSAMPLES;
196
+ switch( this->ourwavheader.audio_format ) {
197
+ case WAVE_FORMAT_PCM: {
198
+ if( 8000 == this->ourwavheader.sample_rate ) {
199
+ this->ploadtype = L168KPAYLOADTYPE;
200
+ this->bytecount = L16NARROWBANDBYTES;
201
+ this->samplecount = L16PAYLOADSAMPLES;
202
+ } else if( 16000 == this->ourwavheader.sample_rate ) {
203
+ this->ploadtype = L1616KPAYLOADTYPE;
204
+ this->bytecount = L16WIDEBANDBYTES;
205
+ this->samplecount = L1616PAYLOADSAMPLES;
206
+ } else {
207
+ this->badheader = true;
208
+ return;
209
+ }
210
+ break;
211
+ }
212
+ case WAVE_FORMAT_ALAW: {
213
+ this->ploadtype = PCMAPAYLOADTYPE;
214
+ this->bytecount = G711PAYLOADBYTES;
215
+ this->samplecount = G711PAYLOADSAMPLES;
216
+ break;
217
+ }
218
+ case WAVE_FORMAT_MULAW: {
219
+ this->ploadtype = PCMUPAYLOADTYPE;
220
+ this->bytecount = G711PAYLOADBYTES;
221
+ this->samplecount = G711PAYLOADSAMPLES;
222
+ break;
223
+ }
224
+ case WAVE_FORMAT_POLYCOM_G722: {
225
+ this->ploadtype = G722PAYLOADTYPE;
226
+ this->bytecount = G722PAYLOADBYTES;
227
+ this->samplecount = G722PAYLOADSAMPLES;
228
+ break;
229
+ }
230
+ case WAVE_FORMAT_GLOBAL_IP_ILBC: {
231
+ this->ploadtype = ILBCPAYLOADTYPE;
232
+ this->bytecount = ILBC20PAYLOADBYTES;
233
+ this->samplecount = ILBC20PAYLOADSAMPLES;
234
+ break;
235
+ }
236
+ default: {
237
+ this->badheader = true;
238
+ fprintf( stderr, "Bad audio format in wav\n" );
239
+ }
240
+ }
241
+
242
+ auto thisindex = this->currentcbindex % SOUNDFILENUMBUFFERS;
243
+ aiocb &thisblock = this->cbwavblock[ thisindex ];
244
+ if ( aio_read( &thisblock ) == -1 ) {
245
+ this->bodyread = true;
246
+ }
247
+ }
248
+
159
249
  /*
160
250
  ## read
161
251
  Asynchronous read.
@@ -167,102 +257,43 @@ We only support 1 channel. Anything else we need to look at.
167
257
  */
168
258
  bool soundfilereader::read( rawsound &out ) {
169
259
 
170
- /* check */
260
+ SpinLockGuard guard( this->filelock );
261
+
262
+ /* check */
171
263
  if ( -1 == this->file ) {
172
264
  fprintf( stderr, "No file for open wav sound\n" );
173
265
  return false;
174
266
  }
175
267
 
176
- if( this->badheader ) {
268
+ this->parseheader();
269
+
270
+ if( this->headerread && this->badheader ) {
177
271
  fprintf( stderr, "Bad wav file\n" );
178
- out.zero();
179
- return true;
272
+ return false;
180
273
  }
181
274
 
182
275
  if( !this->headerread ) {
183
- if( aio_error( &this->cbwavheader ) == EINPROGRESS ) {
184
- fprintf( stderr, "Read of soundfile wav header has not completed\n" );
185
- out.zero();
186
- return true;
187
- }
188
-
189
- if( 'W' != this->ourwavheader.wave_header[ 0 ] ) {
190
- this->badheader = true;
191
- }
192
-
193
- switch( this->ourwavheader.sample_rate ) {
194
- case 8000:
195
- case 16000:
196
- break;
197
- default:
198
- fprintf( stderr, "Bad sample rate in wav\n" );
199
- this->badheader = true;
200
- out.zero();
201
- return true;
202
- }
203
-
204
- this->ploadtype = L168KPAYLOADTYPE;
205
- this->blocksize = L16NARROWBANDBYTES;
206
- switch( this->ourwavheader.audio_format ) {
207
- case WAVE_FORMAT_PCM: {
208
- if( 8000 == this->ourwavheader.sample_rate ) {
209
- this->ploadtype = L168KPAYLOADTYPE;
210
- this->blocksize = L16NARROWBANDBYTES;
211
- } else if( 16000 == this->ourwavheader.sample_rate ) {
212
- this->ploadtype = L1616KPAYLOADTYPE;
213
- this->blocksize = L16WIDEBANDBYTES;
214
- } else {
215
- this->badheader = true;
216
- out.zero();
217
- return true;
218
- }
219
- break;
220
- }
221
- case WAVE_FORMAT_ALAW: {
222
- this->ploadtype = PCMAPAYLOADTYPE;
223
- this->blocksize = G711PAYLOADBYTES;
224
- break;
225
- }
226
- case WAVE_FORMAT_MULAW: {
227
- this->ploadtype = PCMUPAYLOADTYPE;
228
- this->blocksize = G711PAYLOADBYTES;
229
- break;
230
- }
231
- case WAVE_FORMAT_POLYCOM_G722: {
232
- this->ploadtype = G722PAYLOADTYPE;
233
- this->blocksize = G722PAYLOADBYTES;
234
- break;
235
- }
236
- case WAVE_FORMAT_GLOBAL_IP_ILBC: {
237
- this->ploadtype = ILBCPAYLOADTYPE;
238
- this->blocksize = ILBC20PAYLOADBYTES;
239
- break;
240
- }
241
- default: {
242
- this->badheader = true;
243
- out.zero();
244
- fprintf( stderr, "Bad audio format in wav\n" );
245
- return true;
246
- }
247
- }
248
- this->headerread = true;
276
+ out.zero();
277
+ return true;
249
278
  }
250
279
 
251
280
  if( this->initseekmseconds > 0 ) {
252
- this->setposition( this->initseekmseconds );
281
+ this->realsetposition( this->initseekmseconds );
253
282
  out.zero();
254
283
  return true;
255
284
  }
256
285
 
257
- if( aio_error( &this->cbwavblock[ this->currentcbindex ] ) == EINPROGRESS ) {
258
- fprintf( stderr, "Read of soundfile wav block has not completed\n" );
286
+ auto thisindex = this->currentcbindex % SOUNDFILENUMBUFFERS;
287
+ aiocb &thisblock = this->cbwavblock[ thisindex ];
288
+
289
+ if( aio_error( &thisblock ) == EINPROGRESS ) {
259
290
  /* return some silence */
260
291
  out.zero();
261
292
  return true;
262
293
  }
263
294
 
264
295
  /* success? */
265
- int numbytes = aio_return( &this->cbwavblock[ this->currentcbindex ] );
296
+ auto numbytes = aio_return( &thisblock );
266
297
 
267
298
  if( -1 == numbytes ) {
268
299
  fprintf( stderr, "Bad call to aio_return\n" );
@@ -271,32 +302,39 @@ bool soundfilereader::read( rawsound &out ) {
271
302
  return true;
272
303
  }
273
304
 
274
- uint8_t *current = ( uint8_t * ) this->cbwavblock[ this->currentcbindex ].aio_buf;
275
- out = rawsound( current, this->blocksize, this->ploadtype, this->ourwavheader.sample_rate );
305
+ uint8_t *current = ( uint8_t * ) thisblock.aio_buf;
306
+ out = rawsound( current, this->samplecount, this->ploadtype, this->ourwavheader.sample_rate );
276
307
 
277
- if( numbytes < this->blocksize ) {
308
+ if( static_cast<size_t>( numbytes ) < this->bytecount ) {
278
309
  this->bodyread = true;
279
310
  /* TODO if we get a partial read we probably should not zero that part */
280
311
  out.zero();
312
+ return true;
281
313
  }
282
314
 
283
315
  /* Get the next block reading */
284
- auto lastreadoffset = this->cbwavblock[ this->currentcbindex ].aio_offset;
316
+ auto lastreadoffset = thisblock.aio_offset;
285
317
  this->currentcbindex = ( this->currentcbindex + 1 ) % SOUNDFILENUMBUFFERS;
286
318
 
287
- if( this->cbwavblock[ this->currentcbindex ].aio_offset > this->ourwavheader.chunksize ) {
288
- this->cbwavblock[ this->currentcbindex ].aio_offset = sizeof( wavheader );
319
+ aiocb &nextblock = this->cbwavblock[ this->currentcbindex ];
320
+ soundbuffer &thisbuffer = this->buffer[ this->currentcbindex ];
321
+
322
+ /* it shouldn't reallocate - but just in case */
323
+ thisbuffer.resize( this->bytecount );
324
+ nextblock.aio_buf = thisbuffer.data();
325
+
326
+ if( nextblock.aio_offset > this->ourwavheader.chunksize ) {
327
+ nextblock.aio_offset = sizeof( wavheader );
289
328
  } else {
290
- this->cbwavblock[ this->currentcbindex ].aio_offset = lastreadoffset + this->blocksize;
329
+ nextblock.aio_offset = lastreadoffset + this->bytecount;
291
330
  }
292
-
293
- this->cbwavblock[ this->currentcbindex ].aio_nbytes = this->blocksize;
331
+
332
+ nextblock.aio_nbytes = this->bytecount;
294
333
 
295
334
  /* read next block */
296
- if ( !this->bodyread && aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
335
+ if ( aio_read( &nextblock ) == -1 ) {
297
336
  this->bodyread = true;
298
- out.zero();
299
- return true;
337
+ return false;
300
338
  }
301
339
 
302
340
  return true;
@@ -307,63 +345,74 @@ bool soundfilereader::read( rawsound &out ) {
307
345
  Have we completed reading the file.
308
346
  */
309
347
  bool soundfilereader::complete( void ) {
348
+ SpinLockGuard guard( this->filelock );
349
+
310
350
  if( this->badheader ) return true;
311
351
  if( !this->headerread ) return false;
312
352
  if( -1 == this->file ) return true;
313
353
  return this->bodyread;
314
354
  }
315
355
 
316
- /*!md
317
- # setposition and getposition
318
- Gets and sets the position in terms of mS. This can only be called after the header
319
- has been read.
320
- */
321
- void soundfilereader::setposition( long mseconds ) {
356
+ /**
357
+ * Cancel all current block reads recalculate offsets and trigger a new read.
358
+ */
359
+ void soundfilereader::realsetposition( long mseconds ) {
322
360
 
323
- /* check */
324
- if ( -1 == this->file ) {
325
- this->initseekmseconds = mseconds;
326
- return;
327
- }
328
-
329
- if( !this->headerread && aio_error( &this->cbwavheader ) == 0 ) {
330
- this->headerread = true;
331
- }
332
-
333
- if( !this->headerread ) {
334
- this->initseekmseconds = mseconds;
335
- return;
336
- }
361
+ while( AIO_NOTCANCELED == aio_cancel( this->file, NULL ) );
337
362
 
338
363
  this->bodyread = false;
339
- while( AIO_NOTCANCELED == aio_cancel( this->file, NULL ) );
340
364
 
341
- this->currentcbindex = ( this->currentcbindex + 1 ) % SOUNDFILENUMBUFFERS;
365
+ this->currentcbindex = 0;
366
+ aiocb &thisblock = this->cbwavblock[ this->currentcbindex ];
342
367
 
343
368
  off_t our_aio_offset = ( this->ourwavheader.bit_depth /*16*/ / 8 ) * ( this->ourwavheader.sample_rate / 1000 ) * mseconds; /* bytes per sample */
344
- our_aio_offset = ( our_aio_offset / this->blocksize ) * this->blocksize; /* realign to the nearest block */
369
+ our_aio_offset = ( our_aio_offset / this->bytecount ) * this->bytecount; /* realign to the nearest block */
345
370
  our_aio_offset += sizeof( wavheader );
346
371
 
347
372
  for( auto i = 0; i < SOUNDFILENUMBUFFERS; i++ ) {
348
- this->cbwavblock[ ( this->currentcbindex + i ) % SOUNDFILENUMBUFFERS ].aio_offset = our_aio_offset + ( i * L16WIDEBANDBYTES );
373
+
374
+ aiocb &nextblock = this->cbwavblock[ i ];
375
+ soundbuffer &thisbuffer = this->buffer[ i ];
376
+
377
+ nextblock.aio_offset = our_aio_offset + ( i * this->bytecount );
378
+ thisbuffer.resize( this->bytecount );
379
+ nextblock.aio_buf = thisbuffer.data();
349
380
  }
350
381
 
351
- /* read ahead */
352
- if ( aio_read( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
382
+ if ( aio_read( &thisblock ) == -1 ) {
353
383
  this->bodyread = true;
354
384
  }
355
385
 
356
386
  this->initseekmseconds = 0;
387
+ }
388
+
389
+ /*!md
390
+ # setposition and getposition
391
+ Either queue a set positiuon or perform it depending if our header has been read.
392
+ */
393
+ void soundfilereader::setposition( long mseconds ) {
357
394
 
395
+ SpinLockGuard guard( this->filelock );
396
+
397
+ /* check */
398
+ if ( -1 == this->file || !this->headerread ) {
399
+ this->initseekmseconds = mseconds;
400
+ return;
401
+ }
402
+
403
+ this->realsetposition( mseconds );
358
404
  }
359
405
 
360
406
  long soundfilereader::offtomsecs( void ) {
361
- off_t position = this->cbwavblock[ this->currentcbindex ].aio_offset - sizeof( wavheader );
407
+ off_t position = this->cbwavblock[ this->currentcbindex % SOUNDFILENUMBUFFERS ].aio_offset - sizeof( wavheader );
362
408
  return position / ( ( this->ourwavheader.bit_depth / 8 ) * ( this->ourwavheader.sample_rate / 1000 ) );
363
409
  }
364
410
 
365
411
  long soundfilereader::getposition( void ) {
366
- if( this->cbwavblock[ this->currentcbindex ].aio_offset <= ( off_t ) sizeof( wavheader ) ) {
412
+
413
+ SpinLockGuard guard( this->filelock );
414
+
415
+ if( this->cbwavblock[ this->currentcbindex % SOUNDFILENUMBUFFERS ].aio_offset <= ( off_t ) sizeof( wavheader ) ) {
367
416
  return 0;
368
417
  }
369
418
 
@@ -389,6 +438,7 @@ soundfilewriter::soundfilewriter( std::string &url, int16_t numchannels, int32_t
389
438
 
390
439
  if ( -1 == this->file ) {
391
440
  /* Not much more we can do */
441
+ releasespinlock( this->filelock );
392
442
  return;
393
443
  }
394
444
 
@@ -400,8 +450,12 @@ soundfilewriter::soundfilewriter( std::string &url, int16_t numchannels, int32_t
400
450
  blocknumbytes = L16WIDEBANDBYTES;
401
451
  }
402
452
 
453
+ if( numchannels != 2 ) {
454
+ numchannels = 1;
455
+ }
456
+
403
457
  this->ourwavheader.fmt_chunk_size = 16;
404
- this->ourwavheader.num_channels = numchannels; /* or 2 */
458
+ this->ourwavheader.num_channels = numchannels; /* 1 or 2 */
405
459
  this->ourwavheader.sample_rate = samplerate;
406
460
  this->ourwavheader.byte_rate = samplerate * numchannels * this->ourwavheader.bit_depth / 8;
407
461
  this->ourwavheader.chunksize = 0;
@@ -417,9 +471,11 @@ soundfilewriter::soundfilewriter( std::string &url, int16_t numchannels, int32_t
417
471
  std::cerr << "soundfile unable to write wav header to file " << url << std::endl;
418
472
  close( this->file );
419
473
  this->file = -1;
474
+ releasespinlock( this->filelock );
420
475
  return;
421
476
  }
422
477
 
478
+ releasespinlock( this->filelock );
423
479
  return;
424
480
  }
425
481
 
@@ -448,85 +504,107 @@ This should be called on our tick - 20mS should be ample to complete an async wr
448
504
  We maintain SOUNDFILENUMBUFFERS to ensure previous writes have an oppertunity to write.
449
505
  */
450
506
  bool soundfilewriter::write( codecx &in, codecx &out ) {
507
+
508
+ SpinLockGuard guard( this->filelock );
509
+
510
+ if( -1 == this->file ) {
511
+ fprintf( stderr, "soundfile calling write with no open file!\n" );
512
+ return false;
513
+ }
514
+
451
515
  int16_t *inbuf = nullptr;
452
516
  int16_t *outbuf = nullptr;
453
- size_t bufsize = 0;
454
- int bytespersample = 1;
517
+ size_t inbufsize = 0; /* count of int16 vals */
518
+ size_t outbufsize = 0;
519
+ int inbytespersample = 1;
520
+ int outbytespersample = 1;
521
+
522
+ auto format = this->getwavformattopt();
455
523
 
456
524
  if( in.hasdata() ) {
457
- rawsound &inref = in.getref( this->getwavformattopt() );
525
+ rawsound &inref = in.getref( format );
458
526
  if( !inref.isdirty() ) {
459
527
  inbuf = ( int16_t * ) inref.c_str();
460
- bufsize = inref.size();
461
- bytespersample = inref.getbytespersample();
528
+ inbufsize = inref.size();
529
+ inbytespersample = inref.getbytespersample();
462
530
  }
463
531
  }
464
532
 
465
533
  if( out.hasdata() ) {
466
- rawsound &outref = out.getref( this->getwavformattopt() );
534
+ rawsound &outref = out.getref( format );
467
535
  if( !outref.isdirty() ) {
468
536
  outbuf = ( int16_t * ) outref.c_str();
469
- bufsize = outref.size();
470
- bytespersample = outref.getbytespersample();
537
+ outbufsize = outref.size();
538
+ outbytespersample = outref.getbytespersample();
471
539
  }
472
540
  }
473
541
 
474
- if( ( nullptr == inbuf && nullptr == outbuf ) || 0 == bufsize ) {
542
+ /* nothing to do */
543
+ if( nullptr == inbuf && nullptr == outbuf ) {
475
544
  return false;
476
545
  }
477
546
 
478
- size_t buffbytesize = ( bufsize / bytespersample );
479
- if( buffbytesize > this->cbwavblock[ this->currentcbindex ].aio_nbytes ) {
480
- /* this shouldn't happen */
481
- fprintf( stderr, "Trying to save larger block than expected - capping\n" );
482
- bufsize = this->cbwavblock[ this->currentcbindex ].aio_nbytes / bytespersample;
483
- }
547
+ if( inbytespersample != 2 ) inbytespersample = 1;
548
+ if( outbytespersample != 2 ) outbytespersample = 1;
484
549
 
485
- if( aio_error( &this->cbwavblock[ this->currentcbindex ] ) == EINPROGRESS ) {
486
- fprintf( stderr, "soundfile trying to write a packet whilst last is still in progress\n" );
550
+ auto thisindex = this->currentcbindex % SOUNDFILENUMBUFFERS;
551
+ aiocb &thisblock = this->cbwavblock[ thisindex ];
552
+ soundbuffer &thisbuffer = this->buffer[ thisindex ];
553
+
554
+ inbufsize = std::min( inbufsize, AIOCBSINGLECHANBUFFNUMSAMPLES );
555
+ outbufsize = std::min( outbufsize, AIOCBSINGLECHANBUFFNUMSAMPLES );
556
+
557
+ auto largestbufsize = std::max( inbufsize, outbufsize );
558
+ if( 0 == largestbufsize) {
487
559
  return false;
488
560
  }
489
561
 
490
- if( nullptr == this->buffer ) {
491
- fprintf( stderr, "soundfile no write buffer!\n" );
562
+ if( aio_error( &thisblock ) == EINPROGRESS ) {
563
+ fprintf( stderr, "soundfile trying to write a packet whilst last is still in progress\n" );
492
564
  return false;
493
565
  }
494
566
 
495
- this->cbwavblock[ this->currentcbindex ].aio_offset = sizeof( wavheader ) +
496
- ( this->tickcount * this->cbwavblock[ this->currentcbindex ].aio_nbytes );
567
+ auto numchannels = this->ourwavheader.num_channels;
568
+ if( numchannels != 2 ) numchannels = 1;
569
+
570
+ thisbuffer.resize( largestbufsize * numchannels );
571
+ std::fill_n( thisbuffer.begin(), thisbuffer.size(), 0 );
572
+ auto buf = thisbuffer.data();
573
+ thisblock.aio_buf = buf;
497
574
 
498
- int16_t *buf = ( int16_t * ) this->cbwavblock[ this->currentcbindex ].aio_buf;
499
- memset( buf, 0, this->cbwavblock[ this->currentcbindex ].aio_nbytes );
575
+ thisblock.aio_nbytes = largestbufsize * inbytespersample * numchannels;
576
+ thisblock.aio_offset = sizeof( wavheader ) +
577
+ ( this->tickcount * thisblock.aio_nbytes );
500
578
 
501
- if( nullptr != inbuf ) {
502
- for( size_t i = 0; i < bufsize; i++ ) {
579
+ if( inbufsize > 0 && nullptr != inbuf ) {
580
+ for (size_t i = 0; i < inbufsize; i++) {
503
581
  *buf = *inbuf;
504
582
  inbuf++;
505
- buf += this->ourwavheader.num_channels;
583
+ buf += numchannels;
506
584
  }
507
585
  }
508
586
 
509
- buf = ( int16_t * ) this->cbwavblock[ this->currentcbindex ].aio_buf;
510
- /* only works up to 2 channels - which is all we support */
511
- if( this->ourwavheader.num_channels > 1 ) {
512
- buf++;
513
- }
587
+ if( outbufsize > 0 && nullptr != outbuf ) {
588
+ /* start at the beggining again */
589
+ buf = thisbuffer.data();
590
+ /* only works up to 2 channels - which is all we support */
591
+ if( numchannels == 2 ) buf++;
514
592
 
515
- if( nullptr != outbuf ) {
516
- for( size_t i = 0; i < bufsize; i++ ) {
517
- *buf += *outbuf;
518
- outbuf ++;
519
- buf += this->ourwavheader.num_channels;
593
+ for (size_t i = 0; i < outbufsize; i++) {
594
+ auto outval = *outbuf; /////////////////// this is our crash
595
+ *buf += outval;
596
+ outbuf++;
597
+ buf += numchannels;
520
598
  }
521
599
  }
522
600
 
523
- if ( aio_write( &this->cbwavblock[ this->currentcbindex ] ) == -1 ) {
601
+ if ( aio_write( &thisblock ) == -1 ) {
524
602
  fprintf( stderr, "soundfile unable to write wav block to file %s\n", this->url.c_str() );
525
603
  return false;
526
604
  }
527
605
 
528
606
  uint32_t maxbasedonthischunk = 0;
529
- maxbasedonthischunk = this->cbwavblock[ this->currentcbindex ].aio_offset + this->cbwavblock[ this->currentcbindex ].aio_nbytes;
607
+ maxbasedonthischunk = thisblock.aio_offset + thisblock.aio_nbytes;
530
608
  if( maxbasedonthischunk > this->ourwavheader.subchunksize ) {
531
609
  this->ourwavheader.subchunksize = maxbasedonthischunk;
532
610
  this->ourwavheader.chunksize = maxbasedonthischunk + 36;