Allow skipping locks, precompile (#120)

* Allow skipping locks, precompile

* fix tests

* version
This commit is contained in:
bramtayl 2022-07-23 15:42:04 -04:00 committed by GitHub
parent 3939d47a8d
commit fbcd539a76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 76 additions and 35 deletions

View file

@ -17,7 +17,7 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
version: version:
- '1.3' - '1.6'
- '1' - '1'
- 'nightly' - 'nightly'
os: os:

View file

@ -1,7 +1,7 @@
name = "PortAudio" name = "PortAudio"
uuid = "80ea8bcb-4634-5cb3-8ee8-a132660d1d2d" uuid = "80ea8bcb-4634-5cb3-8ee8-a132660d1d2d"
repo = "https://github.com/JuliaAudio/PortAudio.jl.git" repo = "https://github.com/JuliaAudio/PortAudio.jl.git"
version = "1.2.0" version = "1.3.0"
[deps] [deps]
alsa_plugins_jll = "5ac2f6bb-493e-5871-9171-112d4c21a6e7" alsa_plugins_jll = "5ac2f6bb-493e-5871-9171-112d4c21a6e7"
@ -11,7 +11,7 @@ SampledSignals = "bd7594eb-a658-542f-9e75-4c4d8908c167"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb" Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
[compat] [compat]
julia = "1.3" julia = "1.6"
alsa_plugins_jll = "1.2.2" alsa_plugins_jll = "1.2.2"
libportaudio_jll = "19.6.0" libportaudio_jll = "19.6.0"
SampledSignals = "2.1.1" SampledSignals = "2.1.1"

View file

@ -230,19 +230,25 @@ function devices()
end end
# we can handle reading and writing from buffers in a similar way # we can handle reading and writing from buffers in a similar way
function read_or_write(a_function, buffer, use_frames = buffer.frames_per_buffer) function read_or_write(a_function, buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
pointer_to = buffer.pointer_to
data = buffer.data
handle_status( handle_status(
# because we're calling Pa_ReadStream and Pa_WriteStream from separate threads, if acquire_lock
# we put a lock around these calls # because we're calling Pa_ReadStream and Pa_WriteStream from separate threads,
lock( # we put a lock around these calls
let a_function = a_function, lock(
pointer_to = buffer.pointer_to, let a_function = a_function,
data = buffer.data, pointer_to = pointer_to,
use_frames = use_frames data = data,
() -> a_function(pointer_to, data, use_frames) use_frames = use_frames
end, () -> a_function(pointer_to, data, use_frames)
buffer.stream_lock, end,
), buffer.stream_lock,
)
else
a_function(pointer_to, data, use_frames)
end;
warn_xruns = buffer.warn_xruns, warn_xruns = buffer.warn_xruns,
) )
end end
@ -407,21 +413,25 @@ eltype(::Type{Buffer{Sample}}) where {Sample} = Sample
nchannels(buffer::Buffer) = buffer.number_of_channels nchannels(buffer::Buffer) = buffer.number_of_channels
""" """
PortAudio.write_buffer(buffer, use_frames = buffer.frames_per_buffer) PortAudio.write_buffer(buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
Write a number of frames (`use_frames`) from a [`PortAudio.Buffer`](@ref) to PortAudio. Write a number of frames (`use_frames`) from a [`PortAudio.Buffer`](@ref) to PortAudio.
Set `acquire_lock = false` to skip acquiring the lock.
""" """
function write_buffer(buffer::Buffer, use_frames = buffer.frames_per_buffer) function write_buffer(buffer::Buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
read_or_write(Pa_WriteStream, buffer, use_frames) read_or_write(Pa_WriteStream, buffer, use_frames; acquire_lock = acquire_lock)
end end
""" """
PortAudio.read_buffer!(buffer::Buffer, use_frames = buffer.frames_per_buffer) PortAudio.read_buffer!(buffer::Buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
Read a number of frames (`use_frames`) from PortAudio to a [`PortAudio.Buffer`](@ref). Read a number of frames (`use_frames`) from PortAudio to a [`PortAudio.Buffer`](@ref).
Set `acquire_lock = false` to skip acquiring the acquire_lock.
""" """
function read_buffer!(buffer, use_frames = buffer.frames_per_buffer) function read_buffer!(buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
read_or_write(Pa_ReadStream, buffer, use_frames) read_or_write(Pa_ReadStream, buffer, use_frames; acquire_lock = acquire_lock)
end end
""" """
@ -594,10 +604,9 @@ function combine_default_sample_rates(
) )
if input_sample_rate != output_sample_rate if input_sample_rate != output_sample_rate
throw( throw(
ArgumentError( ArgumentError("""
""" Default sample rate $input_sample_rate for input \"$(name(input_device))\" disagrees with
Default sample rate $input_sample_rate for input $(name(input_device)) disagrees with default sample rate $output_sample_rate for output \"$(name(output_device))\".
default sample rate $output_sample_rate for output $(name(output_device)).
Please specify a sample rate. Please specify a sample rate.
""", """,
), ),
@ -907,6 +916,7 @@ end
isopen(stream::PortAudioStream) = isopen(stream.pointer_to) isopen(stream::PortAudioStream) = isopen(stream.pointer_to)
samplerate(stream::PortAudioStream) = stream.sample_rate samplerate(stream::PortAudioStream) = stream.sample_rate
function eltype( function eltype(
::Type{<:PortAudioStream{<:Messenger{Sample}, <:Messenger{Sample}}}, ::Type{<:PortAudioStream{<:Messenger{Sample}, <:Messenger{Sample}}},
) where {Sample} ) where {Sample}
@ -927,7 +937,7 @@ function show(io::IO, stream::PortAudioStream)
print(io, "PortAudioStream{") print(io, "PortAudioStream{")
print(io, eltype(stream)) print(io, eltype(stream))
println(io, "}") println(io, "}")
print(io, " Samplerate: ", samplerate(stream), "Hz") print(io, " Samplerate: ", round(Int, samplerate(stream)), "Hz")
# show source or sink if there's any channels # show source or sink if there's any channels
sink = stream.sink sink = stream.sink
if has_channels(sink) if has_channels(sink)
@ -1043,4 +1053,6 @@ function unsafe_read!(
exchange(source.stream.source_messenger, as_matrix(julia_buffer), already, frame_count) exchange(source.stream.source_messenger, as_matrix(julia_buffer), already, frame_count)
end end
include("precompile.jl")
end # module PortAudio end # module PortAudio

29
src/precompile.jl Normal file
View file

@ -0,0 +1,29 @@
# precompile some important functions
const DEFAULT_SINK_MESSENGER_TYPE = Messenger{Float32, SampledSignalsWriter, Tuple{Matrix{Float32}, Int64, Int64}, Int64}
const DEFAULT_SOURCE_MESSENGER_TYPE = Messenger{Float32, SampledSignalsReader, Tuple{Matrix{Float32}, Int64, Int64}, Int64}
const DEFAULT_STREAM_TYPE = PortAudioStream{DEFAULT_SINK_MESSENGER_TYPE, DEFAULT_SOURCE_MESSENGER_TYPE}
const DEFAULT_SINK_TYPE = PortAudioSink{DEFAULT_SINK_MESSENGER_TYPE, DEFAULT_SOURCE_MESSENGER_TYPE}
const DEFAULT_SOURCE_TYPE = PortAudioSource{DEFAULT_SINK_MESSENGER_TYPE, DEFAULT_SOURCE_MESSENGER_TYPE}
precompile(close, (DEFAULT_STREAM_TYPE,))
precompile(devices, ())
precompile(__init__, ())
precompile(isopen, (DEFAULT_STREAM_TYPE,))
precompile(nchannels, (DEFAULT_SINK_TYPE,))
precompile(nchannels, (DEFAULT_SOURCE_TYPE,))
precompile(PortAudioStream, (Int, Int))
precompile(PortAudioStream, (String, Int, Int))
precompile(PortAudioStream, (String, String, Int, Int))
precompile(samplerate, (DEFAULT_STREAM_TYPE,))
precompile(send, (DEFAULT_SINK_MESSENGER_TYPE,))
precompile(send, (DEFAULT_SOURCE_MESSENGER_TYPE,))
precompile(unsafe_read!, (DEFAULT_SOURCE_TYPE, Vector{Float32}, Int, Int))
precompile(unsafe_read!, (DEFAULT_SOURCE_TYPE, Matrix{Float32}, Int, Int))
precompile(unsafe_write, (DEFAULT_SINK_TYPE, Vector{Float32}, Int, Int))
precompile(unsafe_write, (DEFAULT_SINK_TYPE, Matrix{Float32}, Int, Int))

View file

@ -134,11 +134,11 @@ if !isempty(devices())
source = stream.source source = stream.source
@test sprint(show, stream) == """ @test sprint(show, stream) == """
PortAudioStream{Float32} PortAudioStream{Float32}
Samplerate: 44100.0Hz Samplerate: 44100Hz
2 channel sink: $(repr(input_name)) 2 channel sink: $(repr(output_name))
2 channel source: $(repr(output_name))""" 2 channel source: $(repr(input_name))"""
@test sprint(show, source) == "2 channel source: $(repr(output_name))" @test sprint(show, source) == "2 channel source: $(repr(input_name))"
@test sprint(show, sink) == "2 channel sink: $(repr(input_name))" @test sprint(show, sink) == "2 channel sink: $(repr(output_name))"
write(stream, stream, 5s) write(stream, stream, 5s)
@test PaErrorCode(handle_status(Pa_StopStream(stream.pointer_to))) == paNoError @test PaErrorCode(handle_status(Pa_StopStream(stream.pointer_to))) == paNoError
@test isopen(stream) @test isopen(stream)
@ -209,8 +209,8 @@ if !isempty(devices())
big = typemax(Int) big = typemax(Int)
@test_throws DomainError( @test_throws DomainError(
typemax(Int), typemax(Int),
"$big exceeds maximum input channels for $output_name", "$big exceeds maximum output channels for $output_name",
) PortAudioStream(input_name, output_name, big, 0) ) PortAudioStream(input_name, output_name, 0, big)
@test_throws ArgumentError("Input or output must have at least 1 channel") PortAudioStream( @test_throws ArgumentError("Input or output must have at least 1 channel") PortAudioStream(
input_name, input_name,
output_name, output_name,
@ -219,8 +219,8 @@ if !isempty(devices())
adjust_channels = true, adjust_channels = true,
) )
@test_throws ArgumentError(""" @test_throws ArgumentError("""
Default sample rate 0 for input $output_name disagrees with Default sample rate 0 for input \"$input_name\" disagrees with
default sample rate 1 for output $input_name. default sample rate 1 for output \"$output_name\".
Please specify a sample rate. Please specify a sample rate.
""") combine_default_sample_rates( """) combine_default_sample_rates(
get_device(input_name), get_device(input_name),