PortAudio  2.0
TestBasic.java
1 /*
2  * Portable Audio I/O Library
3  * Java Binding for PortAudio
4  *
5  * Based on the Open Source API proposed by Ross Bencina
6  * Copyright (c) 2008 Ross Bencina
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files
10  * (the "Software"), to deal in the Software without restriction,
11  * including without limitation the rights to use, copy, modify, merge,
12  * publish, distribute, sublicense, and/or sell copies of the Software,
13  * and to permit persons to whom the Software is furnished to do so,
14  * subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
24  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  */
27 
28 /*
29  * The text above constitutes the entire PortAudio license; however,
30  * the PortAudio community also makes the following non-binding requests:
31  *
32  * Any person wishing to distribute modifications to the Software is
33  * requested to send the modifications to the original developer so that
34  * they can be incorporated into the canonical version. It is also
35  * requested that these non-binding requests be included along with the
36  * license above.
37  */
38 
39 package com.portaudio;
40 
41 import junit.framework.TestCase;
42 
49 public class TestBasic extends TestCase
50 {
51 
52  public void testDeviceCount()
53  {
55  assertTrue( "version invalid", (PortAudio.getVersion() > 0) );
56  System.out.println( "getVersion = " + PortAudio.getVersion() );
57  System.out.println( "getVersionText = " + PortAudio.getVersionText() );
58  System.out.println( "getDeviceCount = " + PortAudio.getDeviceCount() );
59  assertTrue( "getDeviceCount", (PortAudio.getDeviceCount() > 0) );
61  }
62 
63  public void testListDevices()
64  {
66  int count = PortAudio.getDeviceCount();
67  assertTrue( "getDeviceCount", (count > 0) );
68  for( int i = 0; i < count; i++ )
69  {
70  DeviceInfo info = PortAudio.getDeviceInfo( i );
71  System.out.println( "------------------ #" + i );
72  System.out.println( " name = " + info.name );
73  System.out.println( " hostApi = " + info.hostApi );
74  System.out.println( " maxOutputChannels = "
75  + info.maxOutputChannels );
76  System.out.println( " maxInputChannels = "
77  + info.maxInputChannels );
78  System.out.println( " defaultSampleRate = "
79  + info.defaultSampleRate );
80  System.out.printf( " defaultLowInputLatency = %3d msec\n",
81  ((int) (info.defaultLowInputLatency * 1000)) );
82  System.out.printf( " defaultHighInputLatency = %3d msec\n",
83  ((int) (info.defaultHighInputLatency * 1000)) );
84  System.out.printf( " defaultLowOutputLatency = %3d msec\n",
85  ((int) (info.defaultLowOutputLatency * 1000)) );
86  System.out.printf( " defaultHighOutputLatency = %3d msec\n",
87  ((int) (info.defaultHighOutputLatency * 1000)) );
88 
89  assertTrue( "some channels",
90  (info.maxOutputChannels + info.maxInputChannels) > 0 );
91  assertTrue( "not too many channels", (info.maxInputChannels < 64) );
92  assertTrue( "not too many channels", (info.maxOutputChannels < 64) );
93  }
94 
95  System.out.println( "defaultInput = "
96  + PortAudio.getDefaultInputDevice() );
97  System.out.println( "defaultOutput = "
98  + PortAudio.getDefaultOutputDevice() );
99 
101  }
102 
103  public void testHostApis()
104  {
106  int validApiCount = 0;
107  for( int hostApiType = 0; hostApiType < PortAudio.HOST_API_TYPE_COUNT; hostApiType++ )
108  {
109  int hostApiIndex = PortAudio
110  .hostApiTypeIdToHostApiIndex( hostApiType );
111  if( hostApiIndex >= 0 )
112  {
113  HostApiInfo info = PortAudio.getHostApiInfo( hostApiIndex );
114  System.out.println( "Checking Host API: " + info.name );
115  for( int apiDeviceIndex = 0; apiDeviceIndex < info.deviceCount; apiDeviceIndex++ )
116  {
117  int deviceIndex = PortAudio
118  .hostApiDeviceIndexToDeviceIndex( hostApiIndex,
119  apiDeviceIndex );
120  DeviceInfo deviceInfo = PortAudio
121  .getDeviceInfo( deviceIndex );
122  assertEquals( "host api must match up", hostApiIndex,
123  deviceInfo.hostApi );
124  }
125  validApiCount++;
126  }
127  }
128 
129  assertEquals( "host api counts", PortAudio.getHostApiCount(),
130  validApiCount );
131  }
132 
133  public void testListHostApis()
134  {
136  int count = PortAudio.getHostApiCount();
137  assertTrue( "getHostApiCount", (count > 0) );
138  for( int i = 0; i < count; i++ )
139  {
140  HostApiInfo info = PortAudio.getHostApiInfo( i );
141  System.out.println( "------------------ #" + i );
142  System.out.println( " version = " + info.version );
143  System.out.println( " name = " + info.name );
144  System.out.println( " type = " + info.type );
145  System.out.println( " deviceCount = " + info.deviceCount );
146  System.out.println( " defaultInputDevice = "
147  + info.defaultInputDevice );
148  System.out.println( " defaultOutputDevice = "
149  + info.defaultOutputDevice );
150  assertTrue( "some devices", info.deviceCount > 0 );
151  }
152 
153  System.out.println( "------\ndefaultHostApi = "
154  + PortAudio.getDefaultHostApi() );
156  }
157 
158  public void testCheckFormat()
159  {
161  StreamParameters streamParameters = new StreamParameters();
162  streamParameters.device = PortAudio.getDefaultOutputDevice();
163  int result = PortAudio
164  .isFormatSupported( null, streamParameters, 44100 );
165  System.out.println( "isFormatSupported returns " + result );
166  assertEquals( "default output format", 0, result );
167  // Try crazy channelCount
168  streamParameters.channelCount = 8765;
169  result = PortAudio.isFormatSupported( null, streamParameters, 44100 );
170  System.out.println( "crazy isFormatSupported returns " + result );
171  assertTrue( "default output format", (result < 0) );
173  }
174 
175  static class SineOscillator
176  {
177  double phase = 0.0;
178  double phaseIncrement = 0.01;
179 
180  SineOscillator(double freq, int sampleRate)
181  {
182  phaseIncrement = freq * Math.PI * 2.0 / sampleRate;
183  }
184 
185  double next()
186  {
187  double value = Math.sin( phase );
188  phase += phaseIncrement;
189  if( phase > Math.PI )
190  {
191  phase -= Math.PI * 2.0;
192  }
193  return value;
194  }
195  }
196 
197  public void testStreamError()
198  {
200  StreamParameters streamParameters = new StreamParameters();
201  streamParameters.sampleFormat = PortAudio.FORMAT_FLOAT_32;
202  streamParameters.channelCount = 2;
203  streamParameters.device = PortAudio.getDefaultOutputDevice();
204  int framesPerBuffer = 256;
205  int flags = 0;
206  BlockingStream stream = PortAudio.openStream( null, streamParameters,
207  44100, framesPerBuffer, flags );
208 
209  // Try to write data to a stopped stream.
210  Throwable caught = null;
211  try
212  {
213  float[] buffer = new float[framesPerBuffer
214  * streamParameters.channelCount];
215  stream.write( buffer, framesPerBuffer );
216  } catch( Throwable e )
217  {
218  caught = e;
219  e.printStackTrace();
220  }
221 
222  assertTrue( "caught no expection", (caught != null) );
223  assertTrue( "exception should say stream is stopped", caught
224  .getMessage().contains( "stopped" ) );
225 
226  // Try to write null data.
227  caught = null;
228  try
229  {
230  stream.write( (float[]) null, framesPerBuffer );
231  } catch( Throwable e )
232  {
233  caught = e;
234  e.printStackTrace();
235  }
236  assertTrue( "caught no expection", (caught != null) );
237  assertTrue( "exception should say stream is stopped", caught
238  .getMessage().contains( "null" ) );
239 
240  // Try to write short data to a float stream.
241  stream.start();
242  caught = null;
243  try
244  {
245  short[] buffer = new short[framesPerBuffer
246  * streamParameters.channelCount];
247  stream.write( buffer, framesPerBuffer );
248  } catch( Throwable e )
249  {
250  caught = e;
251  e.printStackTrace();
252  }
253 
254  assertTrue( "caught no expection", (caught != null) );
255  assertTrue( "exception should say tried to", caught.getMessage()
256  .contains( "Tried to write short" ) );
257 
258  stream.close();
259 
261  }
262 
263  public void checkBlockingWriteFloat( int deviceId, double sampleRate )
264  {
265  StreamParameters streamParameters = new StreamParameters();
266  streamParameters.channelCount = 2;
267  streamParameters.device = deviceId;
268  streamParameters.suggestedLatency = PortAudio
269  .getDeviceInfo( streamParameters.device ).defaultLowOutputLatency;
270  System.out.println( "suggestedLatency = "
271  + streamParameters.suggestedLatency );
272 
273  int framesPerBuffer = 256;
274  int flags = 0;
275  BlockingStream stream = PortAudio.openStream( null, streamParameters,
276  (int) sampleRate, framesPerBuffer, flags );
277  assertTrue( "got default stream", stream != null );
278 
279  assertEquals( "stream isStopped", true, stream.isStopped() );
280  assertEquals( "stream isActive", false, stream.isActive() );
281 
282  int numFrames = 80000;
283  double expected = ((double)numFrames) / sampleRate;
284  stream.start();
285  long startTime = System.currentTimeMillis();
286  double startStreamTime = stream.getTime();
287  assertEquals( "stream isStopped", false, stream.isStopped() );
288  assertEquals( "stream isActive", true, stream.isActive() );
289 
290  writeSineData( stream, framesPerBuffer, numFrames, (int) sampleRate );
291 
292  StreamInfo streamInfo = stream.getInfo();
293  System.out.println( "inputLatency of a stream = "+ streamInfo.inputLatency );
294  System.out.println( "outputLatency of a stream = "+streamInfo.outputLatency );
295  System.out.println( "sampleRate of a stream = "+ streamInfo.sampleRate );
296 
297  assertEquals( "inputLatency of a stream ", 0.0, streamInfo.inputLatency, 0.000001 );
298  assertTrue( "outputLatency of a stream ",(streamInfo.outputLatency > 0) );
299  assertEquals( "sampleRate of a stream ", sampleRate, streamInfo.sampleRate, 3 );
300 
301  double endStreamTime = stream.getTime();
302  stream.stop();
303  long stopTime = System.currentTimeMillis();
304 
305  System.out.println( "startStreamTime = " + startStreamTime );
306  System.out.println( "endStreamTime = " + endStreamTime );
307  double elapsedStreamTime = endStreamTime - startStreamTime;
308  System.out.println( "elapsedStreamTime = " + elapsedStreamTime );
309  assertTrue( "elapsedStreamTime: " + elapsedStreamTime,
310  (elapsedStreamTime > 0.0) );
311  assertEquals( "elapsedStreamTime: ", expected, elapsedStreamTime, 0.10 );
312 
313  assertEquals( "stream isStopped", true, stream.isStopped() );
314  assertEquals( "stream isActive", false, stream.isActive() );
315  stream.close();
316 
317  double elapsed = (stopTime - startTime) / 1000.0;
318  assertEquals( "elapsed time to play", expected, elapsed, 0.20 );
319  }
320 
321  public void testBlockingWriteFloat()
322  {
324  checkBlockingWriteFloat( PortAudio.getDefaultOutputDevice(), 44100 );
326  }
327 
328  public void ZtestWriteEachHostAPI()
329  {
331  for( int hostApiIndex = 0; hostApiIndex < PortAudio.getHostApiCount(); hostApiIndex++ )
332  {
333  HostApiInfo hostInfo = PortAudio.getHostApiInfo( hostApiIndex );
334  System.out.println( "-------------\nWriting using Host API: " + hostInfo.name );
335  int deviceId = hostInfo.defaultOutputDevice;
336  System.out.println( " Device ID =" + deviceId );
337  DeviceInfo deviceInfo = PortAudio.getDeviceInfo( deviceId );
338  System.out.println( " sampleRate =" + deviceInfo.defaultSampleRate );
339  checkBlockingWriteFloat( deviceId,
340  (int) deviceInfo.defaultSampleRate );
341  System.out.println( "Finished with " + hostInfo.name );
342  }
344  }
345 
346  private void writeSineData( BlockingStream stream, int framesPerBuffer,
347  int numFrames, int sampleRate )
348  {
349  float[] buffer = new float[framesPerBuffer * 2];
350  SineOscillator osc1 = new SineOscillator( 200.0, sampleRate );
351  SineOscillator osc2 = new SineOscillator( 300.0, sampleRate );
352  int framesLeft = numFrames;
353  while( framesLeft > 0 )
354  {
355  int index = 0;
356  int framesToWrite = (framesLeft > framesPerBuffer) ? framesPerBuffer
357  : framesLeft;
358  for( int j = 0; j < framesToWrite; j++ )
359  {
360  buffer[index++] = (float) osc1.next();
361  buffer[index++] = (float) osc2.next();
362  }
363  stream.write( buffer, framesToWrite );
364  framesLeft -= framesToWrite;
365  }
366  }
367 
368  private void writeSineDataShort( BlockingStream stream,
369  int framesPerBuffer, int numFrames )
370  {
371  short[] buffer = new short[framesPerBuffer * 2];
372  SineOscillator osc1 = new SineOscillator( 200.0, 44100 );
373  SineOscillator osc2 = new SineOscillator( 300.0, 44100 );
374  int framesLeft = numFrames;
375  while( framesLeft > 0 )
376  {
377  int index = 0;
378  int framesToWrite = (framesLeft > framesPerBuffer) ? framesPerBuffer
379  : framesLeft;
380  for( int j = 0; j < framesToWrite; j++ )
381  {
382  buffer[index++] = (short) (osc1.next() * 32767);
383  buffer[index++] = (short) (osc2.next() * 32767);
384  }
385  stream.write( buffer, framesToWrite );
386  framesLeft -= framesToWrite;
387  }
388  }
389 
390  public void testBlockingWriteShort()
391  {
393 
394  StreamParameters streamParameters = new StreamParameters();
395  streamParameters.sampleFormat = PortAudio.FORMAT_INT_16;
396  streamParameters.channelCount = 2;
397  streamParameters.device = PortAudio.getDefaultOutputDevice();
398  streamParameters.suggestedLatency = PortAudio
399  .getDeviceInfo( streamParameters.device ).defaultLowOutputLatency;
400  System.out.println( "suggestedLatency = "
401  + streamParameters.suggestedLatency );
402 
403  int framesPerBuffer = 256;
404  int flags = 0;
405  BlockingStream stream = PortAudio.openStream( null, streamParameters,
406  44100, framesPerBuffer, flags );
407  assertTrue( "got default stream", stream != null );
408 
409  int numFrames = 80000;
410  stream.start();
411  long startTime = System.currentTimeMillis();
412  writeSineDataShort( stream, framesPerBuffer, numFrames );
413  stream.stop();
414  long stopTime = System.currentTimeMillis();
415  stream.close();
416 
417  double elapsed = (stopTime - startTime) / 1000.0;
418  double expected = numFrames / 44100.0;
419  assertEquals( "elapsed time to play", expected, elapsed, 0.20 );
421  }
422 
423  public void testRecordPlayFloat() throws InterruptedException
424  {
425  checkRecordPlay( PortAudio.FORMAT_FLOAT_32 );
426  }
427 
428  public void testRecordPlayShort() throws InterruptedException
429  {
430  checkRecordPlay( PortAudio.FORMAT_INT_16 );
431  }
432 
433  public void checkRecordPlay( int sampleFormat ) throws InterruptedException
434  {
435  int framesPerBuffer = 256;
436  int flags = 0;
437  int sampleRate = 44100;
438  int numFrames = sampleRate * 3;
439  float[] floatBuffer = null;
440  short[] shortBuffer = null;
441 
443  StreamParameters inParameters = new StreamParameters();
444  inParameters.sampleFormat = sampleFormat;
445  inParameters.device = PortAudio.getDefaultInputDevice();
446 
447  DeviceInfo info = PortAudio.getDeviceInfo( inParameters.device );
448  inParameters.channelCount = (info.maxInputChannels > 2) ? 2
449  : info.maxInputChannels;
450  System.out.println( "channelCount = " + inParameters.channelCount );
451  inParameters.suggestedLatency = PortAudio
452  .getDeviceInfo( inParameters.device ).defaultLowInputLatency;
453 
454  if( sampleFormat == PortAudio.FORMAT_FLOAT_32 )
455  {
456  floatBuffer = new float[numFrames * inParameters.channelCount];
457  }
458  else if( sampleFormat == PortAudio.FORMAT_INT_16 )
459  {
460  shortBuffer = new short[numFrames * inParameters.channelCount];
461  }
462  // Record a few seconds of audio.
463  BlockingStream inStream = PortAudio.openStream( inParameters, null,
464  sampleRate, framesPerBuffer, flags );
465 
466  System.out.println( "RECORDING - say something like testing 1,2,3..." );
467  inStream.start();
468 
469  if( sampleFormat == PortAudio.FORMAT_FLOAT_32 )
470  {
471  inStream.read( floatBuffer, numFrames );
472  }
473  else if( sampleFormat == PortAudio.FORMAT_INT_16 )
474  {
475  inStream.read( shortBuffer, numFrames );
476  }
477  Thread.sleep( 100 );
478  int availableToRead = inStream.getReadAvailable();
479  System.out.println( "availableToRead = " + availableToRead );
480  assertTrue( "getReadAvailable ", availableToRead > 0 );
481 
482  inStream.stop();
483  inStream.close();
484  System.out.println( "Finished recording. Begin Playback." );
485 
486  // Play back what we recorded.
487  StreamParameters outParameters = new StreamParameters();
488  outParameters.sampleFormat = sampleFormat;
489  outParameters.channelCount = inParameters.channelCount;
490  outParameters.device = PortAudio.getDefaultOutputDevice();
491  outParameters.suggestedLatency = PortAudio
492  .getDeviceInfo( outParameters.device ).defaultLowOutputLatency;
493 
494  BlockingStream outStream = PortAudio.openStream( null, outParameters,
495  sampleRate, framesPerBuffer, flags );
496  assertTrue( "got default stream", outStream != null );
497 
498  assertEquals( "inStream isActive", false, inStream.isActive() );
499 
500  outStream.start();
501  Thread.sleep( 100 );
502  int availableToWrite = outStream.getWriteAvailable();
503  System.out.println( "availableToWrite = " + availableToWrite );
504  assertTrue( "getWriteAvailable ", availableToWrite > 0 );
505 
506  System.out.println( "inStream = " + inStream );
507  System.out.println( "outStream = " + outStream );
508  assertEquals( "inStream isActive", false, inStream.isActive() );
509  assertEquals( "outStream isActive", true, outStream.isActive() );
510  if( sampleFormat == PortAudio.FORMAT_FLOAT_32 )
511  {
512  outStream.write( floatBuffer, numFrames );
513  }
514  else if( sampleFormat == PortAudio.FORMAT_INT_16 )
515  {
516  outStream.write( shortBuffer, numFrames );
517  }
518  outStream.stop();
519 
520  outStream.close();
522  }
523 }