PortAudio 2.0
|
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 }