diff --git a/.gitignore b/.gitignore index a3ec5c1..d86d68c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ deps/deps.jl *.wav *.flac *.cov +coverage diff --git a/src/PortAudio.jl b/src/PortAudio.jl index d52f6fa..5bd75a8 100644 --- a/src/PortAudio.jl +++ b/src/PortAudio.jl @@ -15,6 +15,11 @@ const POLL_SECONDS=0.005 # initialize PortAudio on module load Pa_Initialize() +function versioninfo(io::IO=STDOUT) + println(io, Pa_GetVersionText()) + println(io, "Version Number: ", Pa_GetVersion()) +end + type PortAudioDevice name::UTF8String hostapi::UTF8String @@ -33,7 +38,7 @@ PortAudioDevice(info::PaDeviceInfo, idx) = PortAudioDevice( function devices() ndevices = Pa_GetDeviceCount() infos = PaDeviceInfo[Pa_GetDeviceInfo(i) for i in 0:(ndevices - 1)] - PortAudioDevice[PortAudioDevice(info, idx) for (idx, info) in enumerate(infos)] + PortAudioDevice[PortAudioDevice(info, idx-1) for (idx, info) in enumerate(infos)] end # not for external use, used in error message printing @@ -126,8 +131,11 @@ function Base.show{T <: PortAudioStream}(io::IO, stream::T) end function Base.close(stream::PortAudioStream) - Pa_StopStream(stream.stream) - Pa_CloseStream(stream.stream) + if stream.stream != C_NULL + Pa_StopStream(stream.stream) + Pa_CloseStream(stream.stream) + stream.stream = C_NULL + end end SampleTypes.nchannels(stream::PortAudioStream) = size(stream.jlbuf, 2) diff --git a/src/libportaudio.jl b/src/libportaudio.jl index fab7d1d..aaec002 100644 --- a/src/libportaudio.jl +++ b/src/libportaudio.jl @@ -134,21 +134,21 @@ type PaStreamInfo sampleRate::Cdouble end -function Pa_OpenDefaultStream(inChannels, outChannels, - sampleFormat::PaSampleFormat, - sampleRate, framesPerBuffer) - streamPtr = Ref{PaStream}(0) - err = ccall((:Pa_OpenDefaultStream, libportaudio), - PaError, (Ref{PaStream}, Cint, Cint, - PaSampleFormat, Cdouble, Culong, - Ref{Void}, Ref{Void}), - streamPtr, inChannels, outChannels, sampleFormat, sampleRate, - framesPerBuffer, C_NULL, C_NULL) - handle_status(err) - - streamPtr[] -end - +# function Pa_OpenDefaultStream(inChannels, outChannels, +# sampleFormat::PaSampleFormat, +# sampleRate, framesPerBuffer) +# streamPtr = Ref{PaStream}(0) +# err = ccall((:Pa_OpenDefaultStream, libportaudio), +# PaError, (Ref{PaStream}, Cint, Cint, +# PaSampleFormat, Cdouble, Culong, +# Ref{Void}, Ref{Void}), +# streamPtr, inChannels, outChannels, sampleFormat, sampleRate, +# framesPerBuffer, C_NULL, C_NULL) +# handle_status(err) +# +# streamPtr[] +# end +# function Pa_OpenStream(inParams, outParams, sampleRate, framesPerBuffer, flags::PaStreamFlags) @@ -219,13 +219,13 @@ function Pa_WriteStream(stream::PaStream, buf::Array, frames::Integer=length(buf nothing end -function Pa_GetStreamInfo(stream::PaStream) - infoptr = ccall((:Pa_GetStreamInfo, libportaudio), Ptr{PaStreamInfo}, - (PaStream, ), stream) - - unsafe_load(infoptr) -end - +# function Pa_GetStreamInfo(stream::PaStream) +# infoptr = ccall((:Pa_GetStreamInfo, libportaudio), Ptr{PaStreamInfo}, +# (PaStream, ), stream) +# +# unsafe_load(infoptr) +# end +# # General utility function to handle the status from the Pa_* functions function handle_status(err::PaError, show_warnings::Bool=true) if err == PA_OUTPUT_UNDERFLOWED || err == PA_INPUT_OVERFLOWED diff --git a/test/runtests.jl b/test/runtests.jl index 4f118b7..311ffec 100755 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -2,10 +2,72 @@ using BaseTestNext using PortAudio +using SampleTypes -println("DEVICES FOUND:") -for d in PortAudio.devices() - println(d) +# these test are currently set up to run on OSX + +@testset "PortAudio Tests" begin + @testset "Reports version" begin + io = IOBuffer() + PortAudio.versioninfo(io) + result = takebuf_string(io) + # make sure this is the same version I tested with + @test result == + """PortAudio V19-devel (built Aug 6 2014 17:54:39) + Version Number: 1899 + """ + end + @testset "Open Default Device" begin + devs = PortAudio.devices() + source = PortAudioSource() + sink = PortAudioSink() + buf = read(source, 0.1s) + @test size(buf) == (round(Int, 0.1s * samplerate(source)), nchannels(source)) + write(sink, buf) + close(source) + close(sink) + end + @testset "Open Device by name" begin + devs = PortAudio.devices() + source = PortAudioSource("Built-in Microph") + sink = PortAudioSink("Built-in Output") + buf = read(source, 0.1s) + @test size(buf) == (round(Int, 0.1s * samplerate(source)), nchannels(source)) + write(sink, buf) + io = IOBuffer() + show(io, source) + @test takebuf_string(io) == + """PortAudio.PortAudioSource{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}("Built-in Microph") + 2 channels sampled at 48000 s⁻¹""" + show(io, sink) + @test takebuf_string(io) == + """PortAudio.PortAudioSink{Float32,SIUnits.SIQuantity{Int64,0,0,-1,0,0,0,0,0,0}}("Built-in Output") + 2 channels sampled at 48000 s⁻¹""" + close(source) + close(sink) + end + @testset "Error on wrong name" begin + @test_throws ErrorException PortAudioSource("foobarbaz") + @test_throws ErrorException PortAudioSink("foobarbaz") + end + # no way to check that the right data is actually getting read or written here, + # but at least it's not crashing. + @testset "Queued Writing" begin + sink = PortAudioSink() + buf = SampleBuf(rand(eltype(sink), 48000, nchannels(sink))*0.1, samplerate(sink)) + t1 = @async write(sink, buf) + t2 = @async write(sink, buf) + @test wait(t1) == 48000 + @test wait(t2) == 48000 + close(sink) + end + @testset "Queued Reading" begin + source = PortAudioSource() + buf = SampleBuf(rand(eltype(source), 48000, nchannels(source)), samplerate(source)) + t1 = @async read!(source, buf) + t2 = @async read!(source, buf) + @test wait(t1) == 48000 + @test wait(t2) == 48000 + close(source) + end end - -exit(0)