-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Return devices #58
Return devices #58
Conversation
I was about to start a PR on exactly this, since I have the exact same need (I'm capturing sound cards audio, which can get plugged in / out, not on the same port etc). Thanks for your work! For history context: |
@@ -1,3 +1,12 @@ | |||
module Membrane.PortAudio.Devices | |||
|
|||
spec list() :: :ok | |||
type( | |||
device :: %Device{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
device :: %Device{ | |
device :: %Membrane.PortAudio.Device{ |
Also, let's create a corresponding struct in a Membrane.PortAudio.Device
module.
max_output_channels: int | ||
} | ||
) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
max_output_channels: int | |
} | |
) | |
max_output_channels: int, | |
default_device: default_device | |
} | |
) | |
type(default_device :: false | :input | :output) | |
Then you can use that like device.device_default = DEVICE_DEFAULT_INPUT;
in C
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had added is_default, will move to this instead.
} | ||
) | ||
|
||
spec list() :: {:ok :: label, devices :: [device]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spec list() :: {:ok :: label, devices :: [device]} | |
spec list() :: (devices :: [device]) |
I'll hit these changes shortly. |
Thanks for considering my changes, and your valuable feedback. I implemented everything you've recommended. I do question the way we are handling returns. Since I removed the :ok from the spec, I can no longer use return_list_ok. Given my limited experience with Unifex, it's not obvious how to do this, so I just accepted your proposal. Additionally, I was seeing intermittent segmentation faults in dev, so I changed the way I was assigning names to dynamically allocate memory on the device, and then copy the value from deviceInfo. I hope that resolves the segmentation fault, but for the safety of your users I should probably kick this around on my local a bit before you merge this PR. Maybe give it a closer eye and make sure I haven't done anything grotesque with memory management? I'm a bit green with C. |
Hi @johns10, basically, the Regarding this particular error, you're right, we need to do something about it. If we're about to return an error, it should be somehow structured, for example |
Pa_Initialize(); | ||
int numDevices = Pa_GetDeviceCount(); | ||
if (numDevices < 0) { | ||
device devices[numDevices]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if numDevices
is negative? :P Also, I'd allocate this on the heap just in case numDevices
is big for some reason
devices[i].name = malloc(strlen(device_info->name) + 1); | ||
if (device_info->name != NULL) | ||
{ | ||
strcpy(devices[i].name, device_info->name); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you allocate anything on the heap, you should free it. In this case, after the call to list_result
. However, unifex does malloc and memcpy when converting to an erlang term, so it seems redundant.
@@ -0,0 +1,10 @@ | |||
defmodule Membrane.PortAudio.Device do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a piece of doc would be great
def print_devices() do | ||
Application.ensure_all_started(:membrane_portaudio_plugin) | ||
|
||
__MODULE__.SyncExecutor.apply(__MODULE__.Devices, :list, []) | ||
|> IO.inspect() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add list_devices/0
here too, the existing one is in a private module and not guarded with the sync executor
* Return devices * Fix typo * add default * PR comments * whoops, missed id
* 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]>
I want to ship this in a desktop app. So, I'd like to call
Membrane.PortAudio.Devices.list()
and get back a list of devices so the user can select one.I implemented it by adding a
device
spec and iterating over the DeviceInfo structs to createdevices
. I then return those in a list.This is my first crack at NIF's so be gentle.