PortAudio 2.0

TestBasic.java

00001 /*
00002  * Portable Audio I/O Library
00003  * Java Binding for PortAudio
00004  *
00005  * Based on the Open Source API proposed by Ross Bencina
00006  * Copyright (c) 2008 Ross Bencina
00007  *
00008  * Permission is hereby granted, free of charge, to any person obtaining
00009  * a copy of this software and associated documentation files
00010  * (the "Software"), to deal in the Software without restriction,
00011  * including without limitation the rights to use, copy, modify, merge,
00012  * publish, distribute, sublicense, and/or sell copies of the Software,
00013  * and to permit persons to whom the Software is furnished to do so,
00014  * subject to the following conditions:
00015  *
00016  * The above copyright notice and this permission notice shall be
00017  * included in all copies or substantial portions of the Software.
00018  *
00019  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00020  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00021  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00022  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
00023  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
00024  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00025  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00026  */
00027 
00028 /*
00029  * The text above constitutes the entire PortAudio license; however, 
00030  * the PortAudio community also makes the following non-binding requests:
00031  *
00032  * Any person wishing to distribute modifications to the Software is
00033  * requested to send the modifications to the original developer so that
00034  * they can be incorporated into the canonical version. It is also 
00035  * requested that these non-binding requests be included along with the 
00036  * license above.
00037  */
00038 
00039 package com.portaudio;
00040 
00041 import junit.framework.TestCase;
00042 
00049 public class TestBasic extends TestCase
00050 {
00051 
00052         public void testDeviceCount()
00053         {
00054                 PortAudio.initialize();
00055                 assertTrue( "version invalid", (PortAudio.getVersion() > 0) );
00056                 System.out.println( "getVersion  = " + PortAudio.getVersion() );
00057                 System.out.println( "getVersionText  = " + PortAudio.getVersionText() );
00058                 System.out.println( "getDeviceCount  = " + PortAudio.getDeviceCount() );
00059                 assertTrue( "getDeviceCount", (PortAudio.getDeviceCount() > 0) );
00060                 PortAudio.terminate();
00061         }
00062 
00063         public void testListDevices()
00064         {
00065                 PortAudio.initialize();
00066                 int count = PortAudio.getDeviceCount();
00067                 assertTrue( "getDeviceCount", (count > 0) );
00068                 for( int i = 0; i < count; i++ )
00069                 {
00070                         DeviceInfo info = PortAudio.getDeviceInfo( i );
00071                         System.out.println( "------------------ #" + i );
00072                         System.out.println( "  name              = " + info.name );
00073                         System.out.println( "  hostApi           = " + info.hostApi );
00074                         System.out.println( "  maxOutputChannels = "
00075                                         + info.maxOutputChannels );
00076                         System.out.println( "  maxInputChannels  = "
00077                                         + info.maxInputChannels );
00078                         System.out.println( "  defaultSampleRate = "
00079                                         + info.defaultSampleRate );
00080                         System.out.printf( "  defaultLowInputLatency   = %3d msec\n",
00081                                         ((int) (info.defaultLowInputLatency * 1000)) );
00082                         System.out.printf( "  defaultHighInputLatency  = %3d msec\n",
00083                                         ((int) (info.defaultHighInputLatency * 1000)) );
00084                         System.out.printf( "  defaultLowOutputLatency  = %3d msec\n",
00085                                         ((int) (info.defaultLowOutputLatency * 1000)) );
00086                         System.out.printf( "  defaultHighOutputLatency = %3d msec\n",
00087                                         ((int) (info.defaultHighOutputLatency * 1000)) );
00088 
00089                         assertTrue( "some channels",
00090                                         (info.maxOutputChannels + info.maxInputChannels) > 0 );
00091                         assertTrue( "not too many channels", (info.maxInputChannels < 64) );
00092                         assertTrue( "not too many channels", (info.maxOutputChannels < 64) );
00093                 }
00094 
00095                 System.out.println( "defaultInput  = "
00096                                 + PortAudio.getDefaultInputDevice() );
00097                 System.out.println( "defaultOutput = "
00098                                 + PortAudio.getDefaultOutputDevice() );
00099 
00100                 PortAudio.terminate();
00101         }
00102 
00103         public void testHostApis()
00104         {
00105                 PortAudio.initialize();
00106                 int validApiCount = 0;
00107                 for( int hostApiType = 0; hostApiType < PortAudio.HOST_API_TYPE_COUNT; hostApiType++ )
00108                 {
00109                         int hostApiIndex = PortAudio
00110                                         .hostApiTypeIdToHostApiIndex( hostApiType );
00111                         if( hostApiIndex >= 0 )
00112                         {
00113                                 HostApiInfo info = PortAudio.getHostApiInfo( hostApiIndex );
00114                                 System.out.println( "Checking Host API: " + info.name );
00115                                 for( int apiDeviceIndex = 0; apiDeviceIndex < info.deviceCount; apiDeviceIndex++ )
00116                                 {
00117                                         int deviceIndex = PortAudio
00118                                                         .hostApiDeviceIndexToDeviceIndex( hostApiIndex,
00119                                                                         apiDeviceIndex );
00120                                         DeviceInfo deviceInfo = PortAudio
00121                                                         .getDeviceInfo( deviceIndex );
00122                                         assertEquals( "host api must match up", hostApiIndex,
00123                                                         deviceInfo.hostApi );
00124                                 }
00125                                 validApiCount++;
00126                         }
00127                 }
00128 
00129                 assertEquals( "host api counts", PortAudio.getHostApiCount(),
00130                                 validApiCount );
00131         }
00132 
00133         public void testListHostApis()
00134         {
00135                 PortAudio.initialize();
00136                 int count = PortAudio.getHostApiCount();
00137                 assertTrue( "getHostApiCount", (count > 0) );
00138                 for( int i = 0; i < count; i++ )
00139                 {
00140                         HostApiInfo info = PortAudio.getHostApiInfo( i );
00141                         System.out.println( "------------------ #" + i );
00142                         System.out.println( "  version             = " + info.version );
00143                         System.out.println( "  name                = " + info.name );
00144                         System.out.println( "  type                = " + info.type );
00145                         System.out.println( "  deviceCount         = " + info.deviceCount );
00146                         System.out.println( "  defaultInputDevice  = "
00147                                         + info.defaultInputDevice );
00148                         System.out.println( "  defaultOutputDevice = "
00149                                         + info.defaultOutputDevice );
00150                         assertTrue( "some devices", info.deviceCount > 0 );
00151                 }
00152 
00153                 System.out.println( "------\ndefaultHostApi = "
00154                                 + PortAudio.getDefaultHostApi() );
00155                 PortAudio.terminate();
00156         }
00157 
00158         public void testCheckFormat()
00159         {
00160                 PortAudio.initialize();
00161                 StreamParameters streamParameters = new StreamParameters();
00162                 streamParameters.device = PortAudio.getDefaultOutputDevice();
00163                 int result = PortAudio
00164                                 .isFormatSupported( null, streamParameters, 44100 );
00165                 System.out.println( "isFormatSupported returns " + result );
00166                 assertEquals( "default output format", 0, result );
00167                 // Try crazy channelCount
00168                 streamParameters.channelCount = 8765;
00169                 result = PortAudio.isFormatSupported( null, streamParameters, 44100 );
00170                 System.out.println( "crazy isFormatSupported returns " + result );
00171                 assertTrue( "default output format", (result < 0) );
00172                 PortAudio.terminate();
00173         }
00174 
00175         static class SineOscillator
00176         {
00177                 double phase = 0.0;
00178                 double phaseIncrement = 0.01;
00179 
00180                 SineOscillator(double freq, int sampleRate)
00181                 {
00182                         phaseIncrement = freq * Math.PI * 2.0 / sampleRate;
00183                 }
00184 
00185                 double next()
00186                 {
00187                         double value = Math.sin( phase );
00188                         phase += phaseIncrement;
00189                         if( phase > Math.PI )
00190                         {
00191                                 phase -= Math.PI * 2.0;
00192                         }
00193                         return value;
00194                 }
00195         }
00196 
00197         public void testStreamError()
00198         {
00199                 PortAudio.initialize();
00200                 StreamParameters streamParameters = new StreamParameters();
00201                 streamParameters.sampleFormat = PortAudio.FORMAT_FLOAT_32;
00202                 streamParameters.channelCount = 2;
00203                 streamParameters.device = PortAudio.getDefaultOutputDevice();
00204                 int framesPerBuffer = 256;
00205                 int flags = 0;
00206                 BlockingStream stream = PortAudio.openStream( null, streamParameters,
00207                                 44100, framesPerBuffer, flags );
00208 
00209                 // Try to write data to a stopped stream.
00210                 Throwable caught = null;
00211                 try
00212                 {
00213                         float[] buffer = new float[framesPerBuffer
00214                                         * streamParameters.channelCount];
00215                         stream.write( buffer, framesPerBuffer );
00216                 } catch( Throwable e )
00217                 {
00218                         caught = e;
00219                         e.printStackTrace();
00220                 }
00221 
00222                 assertTrue( "caught no expection", (caught != null) );
00223                 assertTrue( "exception should say stream is stopped", caught
00224                                 .getMessage().contains( "stopped" ) );
00225 
00226                 // Try to write null data.
00227                 caught = null;
00228                 try
00229                 {
00230                         stream.write( (float[]) null, framesPerBuffer );
00231                 } catch( Throwable e )
00232                 {
00233                         caught = e;
00234                         e.printStackTrace();
00235                 }
00236                 assertTrue( "caught no expection", (caught != null) );
00237                 assertTrue( "exception should say stream is stopped", caught
00238                                 .getMessage().contains( "null" ) );
00239 
00240                 // Try to write short data to a float stream.
00241                 stream.start();
00242                 caught = null;
00243                 try
00244                 {
00245                         short[] buffer = new short[framesPerBuffer
00246                                         * streamParameters.channelCount];
00247                         stream.write( buffer, framesPerBuffer );
00248                 } catch( Throwable e )
00249                 {
00250                         caught = e;
00251                         e.printStackTrace();
00252                 }
00253 
00254                 assertTrue( "caught no expection", (caught != null) );
00255                 assertTrue( "exception should say tried to", caught.getMessage()
00256                                 .contains( "Tried to write short" ) );
00257 
00258                 stream.close();
00259 
00260                 PortAudio.terminate();
00261         }
00262 
00263         public void checkBlockingWriteFloat( int deviceId, double sampleRate )
00264         {
00265                 StreamParameters streamParameters = new StreamParameters();
00266                 streamParameters.channelCount = 2;
00267                 streamParameters.device = deviceId;
00268                 streamParameters.suggestedLatency = PortAudio
00269                                 .getDeviceInfo( streamParameters.device ).defaultLowOutputLatency;
00270                 System.out.println( "suggestedLatency = "
00271                                 + streamParameters.suggestedLatency );
00272 
00273                 int framesPerBuffer = 256;
00274                 int flags = 0;
00275                 BlockingStream stream = PortAudio.openStream( null, streamParameters,
00276                                 (int) sampleRate, framesPerBuffer, flags );
00277                 assertTrue( "got default stream", stream != null );
00278 
00279                 assertEquals( "stream isStopped", true, stream.isStopped() );
00280                 assertEquals( "stream isActive", false, stream.isActive() );
00281 
00282                 int numFrames = 80000;
00283                 double expected = ((double)numFrames) / sampleRate;
00284                 stream.start();
00285                 long startTime = System.currentTimeMillis();
00286                 double startStreamTime = stream.getTime();
00287                 assertEquals( "stream isStopped", false, stream.isStopped() );
00288                 assertEquals( "stream isActive", true, stream.isActive() );
00289 
00290                 writeSineData( stream, framesPerBuffer, numFrames, (int) sampleRate );
00291                 
00292                 StreamInfo streamInfo = stream.getInfo();
00293                 System.out.println( "inputLatency of a stream = "+ streamInfo.inputLatency );
00294                 System.out.println( "outputLatency of a stream = "+streamInfo.outputLatency );
00295                 System.out.println( "sampleRate of a stream = "+ streamInfo.sampleRate );
00296                 
00297                 assertEquals( "inputLatency of a stream ", 0.0, streamInfo.inputLatency, 0.000001 );
00298                 assertTrue( "outputLatency of a stream ",(streamInfo.outputLatency > 0) );
00299                 assertEquals( "sampleRate of a stream ", sampleRate, streamInfo.sampleRate, 3 );
00300 
00301                 double endStreamTime = stream.getTime();
00302                 stream.stop();
00303                 long stopTime = System.currentTimeMillis();
00304 
00305                 System.out.println( "startStreamTime = " + startStreamTime );
00306                 System.out.println( "endStreamTime = " + endStreamTime );
00307                 double elapsedStreamTime = endStreamTime - startStreamTime;
00308                 System.out.println( "elapsedStreamTime = " + elapsedStreamTime );
00309                 assertTrue( "elapsedStreamTime: " + elapsedStreamTime,
00310                                 (elapsedStreamTime > 0.0) );
00311                 assertEquals( "elapsedStreamTime: ", expected, elapsedStreamTime, 0.10 );
00312 
00313                 assertEquals( "stream isStopped", true, stream.isStopped() );
00314                 assertEquals( "stream isActive", false, stream.isActive() );
00315                 stream.close();
00316 
00317                 double elapsed = (stopTime - startTime) / 1000.0;
00318                 assertEquals( "elapsed time to play", expected, elapsed, 0.20 );
00319         }
00320 
00321         public void testBlockingWriteFloat()
00322         {
00323                 PortAudio.initialize();
00324                 checkBlockingWriteFloat( PortAudio.getDefaultOutputDevice(), 44100 );
00325                 PortAudio.terminate();
00326         }
00327 
00328         public void ZtestWriteEachHostAPI()
00329         {
00330                 PortAudio.initialize();
00331                 for( int hostApiIndex = 0; hostApiIndex < PortAudio.getHostApiCount(); hostApiIndex++ )
00332                 {
00333                         HostApiInfo hostInfo = PortAudio.getHostApiInfo( hostApiIndex );
00334                         System.out.println( "-------------\nWriting using Host API: " + hostInfo.name );
00335                         int deviceId = hostInfo.defaultOutputDevice;
00336                         System.out.println( "   Device ID  =" + deviceId );
00337                         DeviceInfo deviceInfo = PortAudio.getDeviceInfo( deviceId );
00338                         System.out.println( "   sampleRate =" + deviceInfo.defaultSampleRate );
00339                         checkBlockingWriteFloat( deviceId,
00340                                         (int) deviceInfo.defaultSampleRate );
00341                         System.out.println( "Finished with " + hostInfo.name );
00342                 }
00343                 PortAudio.terminate();
00344         }
00345 
00346         private void writeSineData( BlockingStream stream, int framesPerBuffer,
00347                         int numFrames, int sampleRate )
00348         {
00349                 float[] buffer = new float[framesPerBuffer * 2];
00350                 SineOscillator osc1 = new SineOscillator( 200.0, sampleRate );
00351                 SineOscillator osc2 = new SineOscillator( 300.0, sampleRate );
00352                 int framesLeft = numFrames;
00353                 while( framesLeft > 0 )
00354                 {
00355                         int index = 0;
00356                         int framesToWrite = (framesLeft > framesPerBuffer) ? framesPerBuffer
00357                                         : framesLeft;
00358                         for( int j = 0; j < framesToWrite; j++ )
00359                         {
00360                                 buffer[index++] = (float) osc1.next();
00361                                 buffer[index++] = (float) osc2.next();
00362                         }
00363                         stream.write( buffer, framesToWrite );
00364                         framesLeft -= framesToWrite;
00365                 }
00366         }
00367 
00368         private void writeSineDataShort( BlockingStream stream,
00369                         int framesPerBuffer, int numFrames )
00370         {
00371                 short[] buffer = new short[framesPerBuffer * 2];
00372                 SineOscillator osc1 = new SineOscillator( 200.0, 44100 );
00373                 SineOscillator osc2 = new SineOscillator( 300.0, 44100 );
00374                 int framesLeft = numFrames;
00375                 while( framesLeft > 0 )
00376                 {
00377                         int index = 0;
00378                         int framesToWrite = (framesLeft > framesPerBuffer) ? framesPerBuffer
00379                                         : framesLeft;
00380                         for( int j = 0; j < framesToWrite; j++ )
00381                         {
00382                                 buffer[index++] = (short) (osc1.next() * 32767);
00383                                 buffer[index++] = (short) (osc2.next() * 32767);
00384                         }
00385                         stream.write( buffer, framesToWrite );
00386                         framesLeft -= framesToWrite;
00387                 }
00388         }
00389 
00390         public void testBlockingWriteShort()
00391         {
00392                 PortAudio.initialize();
00393 
00394                 StreamParameters streamParameters = new StreamParameters();
00395                 streamParameters.sampleFormat = PortAudio.FORMAT_INT_16;
00396                 streamParameters.channelCount = 2;
00397                 streamParameters.device = PortAudio.getDefaultOutputDevice();
00398                 streamParameters.suggestedLatency = PortAudio
00399                                 .getDeviceInfo( streamParameters.device ).defaultLowOutputLatency;
00400                 System.out.println( "suggestedLatency = "
00401                                 + streamParameters.suggestedLatency );
00402 
00403                 int framesPerBuffer = 256;
00404                 int flags = 0;
00405                 BlockingStream stream = PortAudio.openStream( null, streamParameters,
00406                                 44100, framesPerBuffer, flags );
00407                 assertTrue( "got default stream", stream != null );
00408 
00409                 int numFrames = 80000;
00410                 stream.start();
00411                 long startTime = System.currentTimeMillis();
00412                 writeSineDataShort( stream, framesPerBuffer, numFrames );
00413                 stream.stop();
00414                 long stopTime = System.currentTimeMillis();
00415                 stream.close();
00416 
00417                 double elapsed = (stopTime - startTime) / 1000.0;
00418                 double expected = numFrames / 44100.0;
00419                 assertEquals( "elapsed time to play", expected, elapsed, 0.20 );
00420                 PortAudio.terminate();
00421         }
00422 
00423         public void testRecordPlayFloat() throws InterruptedException
00424         {
00425                 checkRecordPlay( PortAudio.FORMAT_FLOAT_32 );
00426         }
00427 
00428         public void testRecordPlayShort() throws InterruptedException
00429         {
00430                 checkRecordPlay( PortAudio.FORMAT_INT_16 );
00431         }
00432 
00433         public void checkRecordPlay( int sampleFormat ) throws InterruptedException
00434         {
00435                 int framesPerBuffer = 256;
00436                 int flags = 0;
00437                 int sampleRate = 44100;
00438                 int numFrames = sampleRate * 3;
00439                 float[] floatBuffer = null;
00440                 short[] shortBuffer = null;
00441 
00442                 PortAudio.initialize();
00443                 StreamParameters inParameters = new StreamParameters();
00444                 inParameters.sampleFormat = sampleFormat;
00445                 inParameters.device = PortAudio.getDefaultInputDevice();
00446 
00447                 DeviceInfo info = PortAudio.getDeviceInfo( inParameters.device );
00448                 inParameters.channelCount = (info.maxInputChannels > 2) ? 2
00449                                 : info.maxInputChannels;
00450                 System.out.println( "channelCount = " + inParameters.channelCount );
00451                 inParameters.suggestedLatency = PortAudio
00452                                 .getDeviceInfo( inParameters.device ).defaultLowInputLatency;
00453 
00454                 if( sampleFormat == PortAudio.FORMAT_FLOAT_32 )
00455                 {
00456                         floatBuffer = new float[numFrames * inParameters.channelCount];
00457                 }
00458                 else if( sampleFormat == PortAudio.FORMAT_INT_16 )
00459                 {
00460                         shortBuffer = new short[numFrames * inParameters.channelCount];
00461                 }
00462                 // Record a few seconds of audio.
00463                 BlockingStream inStream = PortAudio.openStream( inParameters, null,
00464                                 sampleRate, framesPerBuffer, flags );
00465 
00466                 System.out.println( "RECORDING - say something like testing 1,2,3..." );
00467                 inStream.start();
00468 
00469                 if( sampleFormat == PortAudio.FORMAT_FLOAT_32 )
00470                 {
00471                         inStream.read( floatBuffer, numFrames );
00472                 }
00473                 else if( sampleFormat == PortAudio.FORMAT_INT_16 )
00474                 {
00475                         inStream.read( shortBuffer, numFrames );
00476                 }
00477                 Thread.sleep( 100 );
00478                 int availableToRead = inStream.getReadAvailable();
00479                 System.out.println( "availableToRead =  " + availableToRead );
00480                 assertTrue( "getReadAvailable ", availableToRead > 0 );
00481 
00482                 inStream.stop();
00483                 inStream.close();
00484                 System.out.println( "Finished recording. Begin Playback." );
00485 
00486                 // Play back what we recorded.
00487                 StreamParameters outParameters = new StreamParameters();
00488                 outParameters.sampleFormat = sampleFormat;
00489                 outParameters.channelCount = inParameters.channelCount;
00490                 outParameters.device = PortAudio.getDefaultOutputDevice();
00491                 outParameters.suggestedLatency = PortAudio
00492                                 .getDeviceInfo( outParameters.device ).defaultLowOutputLatency;
00493 
00494                 BlockingStream outStream = PortAudio.openStream( null, outParameters,
00495                                 sampleRate, framesPerBuffer, flags );
00496                 assertTrue( "got default stream", outStream != null );
00497 
00498                 assertEquals( "inStream isActive", false, inStream.isActive() );
00499 
00500                 outStream.start();
00501                 Thread.sleep( 100 );
00502                 int availableToWrite = outStream.getWriteAvailable();
00503                 System.out.println( "availableToWrite =  " + availableToWrite );
00504                 assertTrue( "getWriteAvailable ", availableToWrite > 0 );
00505 
00506                 System.out.println( "inStream = " + inStream );
00507                 System.out.println( "outStream = " + outStream );
00508                 assertEquals( "inStream isActive", false, inStream.isActive() );
00509                 assertEquals( "outStream isActive", true, outStream.isActive() );
00510                 if( sampleFormat == PortAudio.FORMAT_FLOAT_32 )
00511                 {
00512                         outStream.write( floatBuffer, numFrames );
00513                 }
00514                 else if( sampleFormat == PortAudio.FORMAT_INT_16 )
00515                 {
00516                         outStream.write( shortBuffer, numFrames );
00517                 }
00518                 outStream.stop();
00519 
00520                 outStream.close();
00521                 PortAudio.terminate();
00522         }
00523 }