Skip to content

Commit

Permalink
List devices (#60)
Browse files Browse the repository at this point in the history
* Return devices (#58)

* Return devices

* Fix typo

* add default

* PR comments

* whoops, missed id

* format pa_devices.c

* improvements & fixes for pa_devices

* update deps

* bump version to 0.19.3

* make credo happy, update deps

---------

Co-authored-by: John Davenport <[email protected]>
  • Loading branch information
mat-hek and johns10 authored Jul 11, 2024
1 parent 579d65a commit d82ed2b
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 45 deletions.
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ workflows:
- elixir/lint:
filters:
<<: *filters
cache-version: 2
- elixir/hex_publish:
requires:
- elixir/build_test
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ The plugin that captures and plays sound using the multiplatform PortAudio libra
Add the following line to your `deps` in `mix.exs`. Run `mix deps.get`.

```elixir
{:membrane_portaudio_plugin, "~> 0.19.2"}
{:membrane_portaudio_plugin, "~> 0.19.3"}
```

This package depends on the [PortAudio](http://portaudio.com/) library. The precompiled build will be pulled and linked automatically. However, should there be any problems, consider installing it manually.
Expand Down
49 changes: 28 additions & 21 deletions c_src/membrane_portaudio_plugin/pa_devices.c
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
#include "pa_devices.h"

UNIFEX_TERM list(UnifexEnv *env) {
UNIFEX_TERM result;
Pa_Initialize();
int numDevices = Pa_GetDeviceCount();
if (numDevices < 0) {
printf("\nERROR: Pa_CountDevices returned 0x%x\n", numDevices);
return list_result(env);
} else if (numDevices == 0) {
printf("\nNo audio devices found\n");
} else {
printf("\nAvailable audio devices:\n\n");
int default_input_id = Pa_GetDefaultInputDevice();
int default_output_id = Pa_GetDefaultOutputDevice();
for (int i = 0; i < numDevices; i++) {
const PaDeviceInfo *device_info = Pa_GetDeviceInfo(i);
const char *default_str =
i == default_input_id
? " (default input)"
: i == default_output_id ? " (default output)" : "";
int num_devices = Pa_GetDeviceCount();
if (num_devices < 0) {
char error[2048];
sprintf(error, "Pa_CountDevices returned error, code: %d", num_devices);
result = unifex_raise(env, error);
goto list_error;
}
device *devices = unifex_alloc(sizeof(device) * num_devices);
int default_input_id = Pa_GetDefaultInputDevice();
int default_output_id = Pa_GetDefaultOutputDevice();
for (int i = 0; i < num_devices; i++) {
const PaDeviceInfo *device_info = Pa_GetDeviceInfo(i);

printf("%s%s\r\n\tid: %d\r\n\tmax_input_channels: "
"%d\r\n\tmax_output_channels: %d\r\n\n",
device_info->name, default_str, i, device_info->maxInputChannels,
device_info->maxOutputChannels);
if (i == default_input_id) {
devices[i].default_device = DEFAULT_DEVICE_INPUT;
} else if (i == default_output_id) {
devices[i].default_device = DEFAULT_DEVICE_OUTPUT;
} else {
devices[i].default_device = DEFAULT_DEVICE_FALSE;
}

devices[i].name = (char *)device_info->name;
devices[i].id = i;
devices[i].max_output_channels = device_info->maxOutputChannels;
devices[i].max_input_channels = device_info->maxInputChannels;
devices[i].default_sample_rate = device_info->defaultSampleRate;
}

result = list_result(env, devices, num_devices);
list_error:
Pa_Terminate();
return list_result(env);
return result;
}
14 changes: 13 additions & 1 deletion c_src/membrane_portaudio_plugin/pa_devices.spec.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
module Membrane.PortAudio.Devices

spec list() :: :ok
type(
device :: %Membrane.PortAudio.Device{
id: int,
name: string,
max_input_channels: int,
max_output_channels: int,
default_sample_rate: float,
default_device: default_device
}
)

type(default_device :: false | :input | :output)
spec list() :: devices :: [device]
10 changes: 10 additions & 0 deletions lib/membrane_portaudio.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ defmodule Membrane.PortAudio do
"""
@spec print_devices() :: :ok
def print_devices() do
list_devices()
|> inspect(pretty: true, limit: :infinity, syntax_colors: IO.ANSI.syntax_colors())
|> IO.puts()
end

@doc """
Returns a list of available audio devices.
"""
@spec list_devices() :: [Membrane.PortAudio.Device.t()]
def list_devices() do
Application.ensure_all_started(:membrane_portaudio_plugin)
__MODULE__.SyncExecutor.apply(__MODULE__.Devices, :list, [])
end
Expand Down
27 changes: 27 additions & 0 deletions lib/membrane_portaudio_plugin/device.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule Membrane.PortAudio.Device do
@moduledoc """
Struct carrying information about an audio device.
See `Membrane.PortAudio.list_devices/0` and `Membrane.PortAudio.print_devices/0`.
"""

@type t :: %__MODULE__{
id: non_neg_integer(),
name: String.t(),
max_input_channels: non_neg_integer(),
max_output_channels: non_neg_integer(),
default_device: false | :input | :output,
default_sample_rate: float()
}

@enforce_keys [
:id,
:name,
:max_input_channels,
:max_output_channels,
:default_device,
:default_sample_rate
]

defstruct @enforce_keys
end
2 changes: 1 addition & 1 deletion lib/membrane_portaudio_plugin/sink.ex
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ defmodule Membrane.PortAudio.Sink do

@impl true
def handle_buffer(:input, %Buffer{payload: payload}, _ctx, %{native: native} = state) do
mockable(Native).write_data(payload, native)
apply(mockable(Native), :write_data, [payload, native])
{[], state}
end
end
4 changes: 2 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Membrane.PortAudio.Mixfile do
use Mix.Project

@github_url "https://github.com/membraneframework/membrane_portaudio_plugin"
@version "0.19.2"
@version "0.19.3"

def project do
[
Expand Down Expand Up @@ -40,7 +40,7 @@ defmodule Membrane.PortAudio.Mixfile do
{:membrane_common_c, "~> 0.16.0"},
{:bunch, "~> 1.5"},
{:membrane_raw_audio_format, "~> 0.12.0"},
{:bundlex, "~> 1.5"},
{:unifex, "~> 1.2"},
{:membrane_precompiled_dependency_provider, "~> 0.1.0"},
# Testing
{:mockery, "~> 2.1", runtime: false},
Expand Down
Loading

0 comments on commit d82ed2b

Please sign in to comment.