Code Monkey home page Code Monkey logo

Comments (28)

allquixotic avatar allquixotic commented on August 30, 2024 1

This is the first time I've heard of a bug like this. Thus it might either be something very new, or something specific to your machine.

I have a few other Macs floating around that I'll test on when I get a chance, but it may not be soon.

Could this be in some way related to a new macOS security measure? (It wouldn't be the first time). For example, are you using a third-party terminal application, or are you calling the code from an untrusted application? Some applications need to be whitelisted in accessibility settings before they are allowed to work correctly.

Maybe, but I tried it both with iTerm2 and the native Mac Terminal app, and neither one pops up a security prompt asking me to permit microphone access or anything like that. They don't appear as options in Privacy to even enable microphone access, because they don't seem to need it.

It also wouldn't be the first time for macOS to change some behavior of the C API "silently". Do you know whether this might have happened in response to some update you installed?

The only possible update it could have been is between Ventura 13.0.0 and Ventura 13.0.1. I'm not 100% sure I had tested this both before and after the 13.0.1 upgrade, as I wasn't paying attention to specifically when I installed the update vs. when I was messing with python-soundcard.

And, if you would indulge me, could you try testing the number of channels in your Rust wrapper? I wonder if this is somehow specific to soundcard, or in fact applies to every CoreAudio application.

I wasn't able to get this working in Rust, but that's mainly due to my own incompetence with figuring out how to do raw memory allocation in Rust. The furthest I got was some program crashes. I can't put any more time into it unfortunately.

If you don't have time to help me here, that's perfectly understandable as well. But I'd be grateful for your help, as I personally don't have a recent macOS machine to test these things on!

from soundcard.

bastibe avatar bastibe commented on August 30, 2024

Thank you for the bug report.

Could you try to run something like

    """A list of all connected speakers."""
    device_ids = _CoreAudio.get_property(
        _cac.kAudioObjectSystemObject,
        _cac.kAudioHardwarePropertyDevices,
        "AudioObjectID")
    return [_Speaker(id=d) for d in device_ids]

This should confirm whether the channel detection is somehow broken, or the problem is elsewhere.

Also, could you grab the .channels property of your default_speaker()?

from soundcard.

allquixotic avatar allquixotic commented on August 30, 2024
>>> import soundcard
>>> device_ids = soundcard.coreaudio._CoreAudio.get_property(soundcard.coreaudio._cac.kAudioObjectSystemObject, soundc
... ard.coreaudio._cac.kAudioHardwarePropertyDevices, "AudioObjectID")
>>> [soundcard.coreaudio._Speaker(id=d) for d in device_ids]
[<Speaker P27h-20 (0 channels)>, <Speaker C49RG9x (0 channels)>, <Speaker C49RG9x (0 channels)>, <Speaker HyperX Cloud Alpha Wireless (0 channels)>, <Speaker Shure MV88+ (0 channels)>, <Speaker MacBook Pro Microphone (0 channels)>, <Speaker MacBook Pro Speakers (0 channels)>, <Speaker Microsoft Teams Audio (0 channels)>, <Speaker Loopback Audio (0 channels)>]

soundcard.default_speaker().channels is also 0.

In short: yes, everything is showing as 0 channels.

from soundcard.

allquixotic avatar allquixotic commented on August 30, 2024

I ended up bypassing the need for the Python soundcard lib by rewriting my code in Rust and using a CoreAudio binding to do what I needed (after I learned how the heck to use CoreAudio in the first place);

https://github.com/allquixotic/macpitch/blob/main/src/main.rs

I don't actually read or use the channels in any of this, but I'm more than willing to try out code in either Python or Rust that calls CoreAudio on my system and attempts to identify the number of channels for my devices.

Just as a reminder, this is on MacOS Ventura (latest stable version) on a M1 Max MacBook Pro (latest MBP model) that this seems to go awry. I also have several external displays and USB soundcards attached.

I'm not sure what exactly caused all the channels to start displaying as 0. I also have the Rogue Amoeba Audio Capture Engine (ACE) installed, which is a kernel-mode driver that provides "loopback" functionality for CoreAudio devices. I'm not sure how this could/would affect the number of channels in the CoreAudio API, though.

from soundcard.

bastibe avatar bastibe commented on August 30, 2024

This is the first time I've heard of a bug like this. Thus it might either be something very new, or something specific to your machine.

Could this be in some way related to a new macOS security measure? (It wouldn't be the first time). For example, are you using a third-party terminal application, or are you calling the code from an untrusted application? Some applications need to be whitelisted in accessibility settings before they are allowed to work correctly.

It also wouldn't be the first time for macOS to change some behavior of the C API "silently". Do you know whether this might have happened in response to some update you installed?

And, if you would indulge me, could you try testing the number of channels in your Rust wrapper? I wonder if this is somehow specific to soundcard, or in fact applies to every CoreAudio application.

If you don't have time to help me here, that's perfectly understandable as well. But I'd be grateful for your help, as I personally don't have a recent macOS machine to test these things on!

from soundcard.

debasish-mihup avatar debasish-mihup commented on August 30, 2024

@bastibe Slightly off topic as I don't wish to create a fresh ticket. I have an older intel based macbook air and the system is able to take audio feed from microphone and lists all microphone connected but it does not detect any system audio i.e. loopback=True. Any idea why this could be?

from soundcard.

bastibe avatar bastibe commented on August 30, 2024

You should have seen a warning saying that the loopback functionality is not available on macOS. If you know how to implement it on macOS, I'd be grateful for a hint, or pull request.

from soundcard.

debasish-mihup avatar debasish-mihup commented on August 30, 2024

Blackhole project is another project which achieves this, although it is a different product suite in itself.

from soundcard.

allquixotic avatar allquixotic commented on August 30, 2024

I'd never heard of Blackhole, but seemingly it's very similar to Rogue Amoeba's Audio Capture Engine, except that it's open source (GPL3). Embedding Blackhole within Python SoundCard is impractical, because there are installation steps to installing the Blackhole package at the system level, which we can't coordinate when just installing a Python package.

Also, licensing: because this project is licensed under the BSD license, which prevents combining this code with GPL3, it would probably violate the GPL to automatically install Blackhole with SoundCard.

I'm not sure there's a better way to do it than to instruct Mac users who need loopback to install Blackhole or Audio Capture Engine (or equivalent; there might be other competitors).

We can't support the SoundCard loopback property on any particular sound device, though, because the name of any given audio capture device created by Blackhole, ACE, etc. could be user-defined, so we have no way of identifying which device might be a loopback.

from soundcard.

bastibe avatar bastibe commented on August 30, 2024

Presumably, there's some way of implementing loopback devices on macOS within soundcard. I just haven't found the relevant API in Core Audio, yet.

Loopback devices were a later addition to soundcard, partly contributed by pull requests. They were not included in the original release, and therefore were not part of my original research. Which is to say, there might be a trivial way to do this.

from soundcard.

debasish-mihup avatar debasish-mihup commented on August 30, 2024

@bastibe @allquixotic There is another similar package https://github.com/kyleneideck/BackgroundMusic#recording-system-audio that enables system audio recording. Maybe worth checking it out if not done already.

from soundcard.

conorsleithsonos avatar conorsleithsonos commented on August 30, 2024

@bastibe I can repro this issue on my M1 MacBook Pro running Ventura 13.1 on System python (3.9.6) but not on Homebrew installed python (3.10.4). Let me know if I can help troubleshoot

from soundcard.

bastibe avatar bastibe commented on August 30, 2024

I bet that's a sandboxing issue. In the past, some people needed to activate something in the accessibility settings to get around issues like this. As far as I know, there is nothing I can do about that in the software itself.

If you do find a reason or workaround, please let me know.

from soundcard.

alfonsocv12 avatar alfonsocv12 commented on August 30, 2024

I have two Macs where I have tested the code

  • Intel Mac with macOS Monterrey soundcard is working
    • Soundcard 0.4.2
  • Intel Mac with macOS Ventura 13.4 soundcard is working
    • Soundcard 0.4.2
  • M2 Pro with Ventura 13.3.1 same issue channels not appearing
    • Soundcard 0..4.2
  • M2 Pro with Ventura 13.4 same issue channels not appearing
    • Soundcard 0.4.2

I’m updating the Intel Mac to see if it’s related to Apple Silicon or Ventura.

I use an app to request permission for the terminal so that’s not the reason

Edited: I'm using a Focusrite 3th gen

Edited2:

I have finished updating the Intel Mac with Ventura 13.4 and SoundCard still works.

@allquixotic One question the setup work at some point on the Apple silicon Mac?

from soundcard.

alfonsocv12 avatar alfonsocv12 commented on August 30, 2024

I think I found the problem @bastibe

The channel number is not automatically assigned on Apple Silicon

I'm using this Function from Coreaudio

Apple Silicon

AudioChannelDescription[] 1
0.0

Intel

AudioChannelDescription[] 1
1.401298464324817e-45

I found that it's possible to use this

AudioChannelDescription *channelDescription = [[AudioChannelDescription alloc] init];
[channelDescription setChannelLabel:@"Left" forChannelNumber:0];

I'm not too experienced with CoreAudio so I'll prefer suggestions on this

Please let me know if this makes sense

from soundcard.

alfonsocv12 avatar alfonsocv12 commented on August 30, 2024

More interesting findings with this issue. I wanted to verify that the Permission theory was correct.

So I wrote this CPP code

#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h>

void requestMicrophonePermission(AudioDeviceID deviceID) {
    OSStatus status;
    AudioObjectPropertyAddress selectorAddress;
    selectorAddress.mSelector = kAudioDevicePropertyDataSource;
    selectorAddress.mScope = kAudioDevicePropertyScopeInput;
    selectorAddress.mElement = kAudioObjectPropertyElementMain;

    // Request microphone permission
    status = AudioObjectSetPropertyData(deviceID, &selectorAddress, 0, nullptr, sizeof(CFStringRef), "Microphone");

    if(status != noErr) {
        printf("Error: %d\n", status);
    }
    printf("Request microphone permission: %d\n", status);
}

int main()
{
    AudioDeviceID deviceID;
    UInt32 size = sizeof(deviceID);
    AudioObjectPropertyAddress propertyAddress = {
        kAudioHardwarePropertyDefaultInputDevice,
        kAudioObjectPropertyScopeGlobal,
        kAudioObjectPropertyElementMain
    };
    AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, &size, &deviceID);

    requestMicrophonePermission(deviceID);

    printf("Device ID: %u\n", deviceID);

    AudioObjectPropertyAddress propertyAddress2 = {
        kAudioDevicePropertyStreamConfiguration,
        kAudioObjectPropertyScopeInput,
        kAudioObjectPropertyElementMain
    };

    OSStatus status;
    UInt32* size2;
    AudioBufferList bufferList[] = {3};
    status = AudioObjectGetPropertyData(
        deviceID, &propertyAddress2, 0, NULL, size2, bufferList);

    printf("Audio buffer: %u\n", bufferList[0].mNumberBuffers);
    printf("Audio data: %u\n", bufferList[0].mBuffers[0].mNumberChannels);
    printf("Audio data: %u\n", bufferList->mBuffers[0].mNumberChannels);
    // getAudioBufferListFromDeviceID(deviceID);
    return 0;
}

The Apple Silicon Mac returns different errors depending on the input source.

  • Scarlett 8i6 USB Error: 2003332927
  • Macbook pro microphone Error: 1852797029
  • HD Pro Webcam C920 Error: 2003332927

Running the same code on the Intel mac returns 0 so no error on the status

I'm talking about this part of the code

 // Request microphone permission
  status = AudioObjectSetPropertyData(deviceID, &selectorAddress, 0, nullptr, sizeof(CFStringRef), "Microphone");

  if(status != noErr) {
      printf("Error: %d\n", status);
  }
  printf("Request microphone permission: %d\n", status);

from soundcard.

bastibe avatar bastibe commented on August 30, 2024

So we need to request permission for using the sound card from a CLI program? How very interesting, and annoying. Thank you for the analysis.

Is this why we can't get the channel number?

from soundcard.

kafan1986 avatar kafan1986 commented on August 30, 2024

@bastibe Any plans to support MacOS? I believe @alfonsocv12 has given some possible way out for the problems.

from soundcard.

bastibe avatar bastibe commented on August 30, 2024

I don't currently have the time to do it myself. But I'll happily review a pull request.

from soundcard.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.