daliansky / XiaoMi-Pro-Hackintosh

XiaoMi NoteBook Pro Hackintosh
BSD Zero Clause License
2.61k stars 471 forks source link

Overall Audio State #96

Open qeeqez opened 5 years ago

qeeqez commented 5 years ago

Hi, I noticed that my headset's microphone doesn't work. I tested all layout-ids to find something. UPD: after many reboots and some ALCPlugFix reinstalls, I seem it's working but quieter than layout-id 30 or 29.

Experienced issues with audio on different layout-ids

ALCPlugFix was deleted for proper testing

layout-id

99 - Current


28

stevezhengshiqi commented 5 years ago

Hi, thank you for your efforts. I am not quite sure the change of layout-id would cause side effects or not. I knows a little about how @daliansky did on the layout-id 99, but it seems reliable so I may have to consider carefully before change the id. Here is a reference of how daliansky make a compatible AppleALC: https://blog.daliansky.net/Use-AppleALC-sound-card-to-drive-the-correct-posture-of-AppleHDA.html.

qeeqez commented 5 years ago

I've read that guide. @daliansky made a proper layout for our laptop. Thanks him for the detailed guide. But "Headphone mic problem" depends on DSP settings. We could amplify it, however, we hear headphone sound in it. Checked how Windows works - you can hear sound in microphone, but it stays quiet when you are speaking, so you haven't got side effects seen on mac. Leave that issue open, maybe somebody will take an effort.

stevezhengshiqi commented 5 years ago

@qeeqez Hi, do you have a chance to extract HdaCodec dump from latest Clover+FN+F8 or in Linux? I am trying to rework on layout-id 99, and I can't find Headphone Mic codec in my codec dump which generated from Clover. HdaCodec#0 (Realtek ALC298).txt

qeeqez commented 5 years ago

@stevezhengshiqi I'll try tomorrow if you are still waiting for it :)

stevezhengshiqi commented 5 years ago

@qeeqez Don’t worry, feel free to do it.^^

qeeqez commented 5 years ago

@stevezhengshiqi Hi, I tried to extract codec with clover - no mic here, also tried with Linux live usb - no mic too, it even doesn't work at all. Windows is Ok. I'll try to install Linux and check later.

stevezhengshiqi commented 5 years ago

@qeeqez Thank you so much for helping. It's weird that headphone mic is not included in codec dump. I am also trying to extract dump from Windows.

stevezhengshiqi commented 5 years ago

I extract pinconfig from windows, and it looks the same as codec dump generated by Clover.

stevezhengshiqi commented 5 years ago

I just reworked the whole thing, and this is the note if anyone is interested. AppleALC Notes.zip

Menchen commented 5 years ago

Hi, I'm interested in what you changed 4fa8a259a03bab88f8297035e95b3c891e237f63 in ALCPlugFix binary because It has improved so much in headphone fix, but still need to replug something after sleep in a rare case.

Here's mine after add wake detection, fix on boot and fix every hour.(definitely overkill)

//
//  main.m
//  ALCPlugFix
//
//  Created by Oleksandr Stoyevskyy on 11/3/16.
//  Copyright © 2016 Oleksandr Stoyevskyy. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreAudio/CoreAudio.h>
#import <CoreFoundation/CoreFoundation.h>
#import <AppKit/AppKit.h>

@protocol DaemonProtocol
- (void)performWork;
@end

@interface NSString (ShellExecution)
- (NSString*)runAsCommand;
@end

@implementation NSString (ShellExecution)

- (NSString*)runAsCommand {
    NSPipe* pipe = [NSPipe pipe];

    NSTask* task = [[NSTask alloc] init];
    [task setLaunchPath: @"/bin/sh"];
    [task setArguments:@[@"-c", [NSString stringWithFormat:@"%@", self]]];
    [task setStandardOutput:pipe];

    NSFileHandle* file = [pipe fileHandleForReading];
    [task launch];

    return [[NSString alloc] initWithData:[file readDataToEndOfFile] encoding:NSUTF8StringEncoding];
}

@end

# pragma mark ALCPlugFix Object Conforms to Protocol

@interface ALCPlugFix : NSObject <DaemonProtocol>
@end;
@implementation ALCPlugFix
- (id)init
{
    self = [super init];
    if (self) {
        // Do here what you needs to be done to start things

        [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
                                                               selector: @selector(receiveWakeNote:)
                                                                   name: NSWorkspaceDidWakeNotification object: NULL];

    }
    return self;
}

- (void)dealloc
{
    // Do here what needs to be done to shut things down
    //[super dealloc];
}

- (void)performWork
{
    // This method is called periodically to perform some routine work
    NSLog(@"Performing periodical fixing ...");
    NSString *output1 = [@"hda-verb 0x18 SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
    NSString *output2 = [@"hda-verb 0x1a SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];

}
- (void) receiveWakeNote: (NSNotification*) note
{
    NSLog(@"receiveSleepNote: %@", [note name]);
    NSLog(@"Wake detected, fixing ...");
    NSString *output1 = [@"hda-verb 0x18 SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
    NSString *output2 = [@"hda-verb 0x1a SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
}

@end

# pragma mark Setup the daemon

// Seconds runloop runs before performing work
#define kRunLoopWaitTime 3600.0

BOOL keepRunning = TRUE;

void sigHandler(int signo)
{
    NSLog(@"sigHandler: Received signal %d", signo);

    switch (signo) {
        case SIGTERM: keepRunning = FALSE; break; // SIGTERM means we must quit
        default: break;
    }
}

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"Headphones daemon running!");

        signal(SIGHUP, sigHandler);
        signal(SIGTERM, sigHandler);

        ALCPlugFix *task = [[ALCPlugFix alloc] init];

        AudioDeviceID defaultDevice = 0;
        UInt32 defaultSize = sizeof(AudioDeviceID);

        const AudioObjectPropertyAddress defaultAddr = {
            kAudioHardwarePropertyDefaultOutputDevice,
            kAudioObjectPropertyScopeGlobal,
            kAudioObjectPropertyElementMaster
        };

        AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultAddr, 0, NULL, &defaultSize, &defaultDevice);

        AudioObjectPropertyAddress sourceAddr;
        sourceAddr.mSelector = kAudioDevicePropertyDataSource;
        sourceAddr.mScope = kAudioDevicePropertyScopeOutput;
        sourceAddr.mElement = kAudioObjectPropertyElementMaster;

        NSLog(@"Init fixing");
        NSString *output1 = [@"hda-verb 0x18 SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
        NSString *output2 = [@"hda-verb 0x1a SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];

        AudioObjectAddPropertyListenerBlock(defaultDevice, &sourceAddr, dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(UInt32 inNumberAddresses, const AudioObjectPropertyAddress * inAddresses) {

//            UInt32 bDataSourceId = 0;
//            UInt32 bDataSourceIdSize = sizeof(UInt32);
//            AudioObjectGetPropertyData(defaultDevice, inAddresses, 0, NULL, &bDataSourceIdSize, &bDataSourceId);
//            if (bDataSourceId == 'ispk') {
                // Recognized as internal speakers
//                NSLog(@"Headphones removed! Fixing!");
//                NSString *output1 = [@"hda-verb 0x18 SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
//                NSString *output2 = [@"hda-verb 0x1a SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
//            } else if (bDataSourceId == 'hdpn') {
                // Recognized as headphones
//                NSLog(@"Headphones inserted! Fixing!");
//                NSString *output1 = [@"hda-verb 0x18 SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
//                NSString *output2 = [@"hda-verb 0x1a SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
//            }
            NSLog(@"Audio device changed! Fixing!");
            NSString *output1 = [@"hda-verb 0x18 SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];
            NSString *output2 = [@"hda-verb 0x1a SET_PIN_WIDGET_CONTROL 0x20" runAsCommand];

        });

        while (keepRunning) {
            [task performWork];
            CFRunLoopRunInMode(kCFRunLoopDefaultMode, kRunLoopWaitTime, false);
        }
//        [task release];

        NSLog(@"Daemon exiting");
    }
    return 0;
}

I'm thinking to add screensDidWakeNotification which call every screen wake and maybe remove "auto fix". But maybe it's overkill and in any case mine solution still need more testing.

As always, thanks for your hard work.

stevezhengshiqi commented 5 years ago

@Menchen Nice job! Could you send your m.c? I think I need to change hda-verb command to get better experience. For example 0x21 command is needed.

Menchen commented 5 years ago

@stevezhengshiqi https://github.com/Menchen/ALCPlugFix Added wake detection(unlock and wake from sleep), auto fix every hour and some code refactoring. You should clone the entire repo as some library (AppKit) is added to xcodeproj.

use xcodebuild -target ALCPlugFix to build, I'm using your hda-verb.

fixAudio function is called to fix (no matter what input source).

Quick install

sudo cp build/Release/ALCPlugFix /usr/bin
sudo chmod 755 /usr/bin/ALCPlugFix
sudo chown root:wheel /usr/bin/ALCPlugFix
stevezhengshiqi commented 5 years ago

@Menchen Great job! Just an ask: Is it possible to move had-verb and ALCPlugFix to /usr/local/bin/ and let ALCPlugFix point to that new location?

It may be cleaner if files are in this new location, and it seems like macOS Update Assistant would wipe out all the user-defined files in /user/bin/ when updating system.

Menchen commented 5 years ago

So you want to move out from /usr/local/bin/ or?

ALCPlugFix binary will find the first had-verb in $PATH which /usr/local/bin/ is in by default(If you want to change the location to current folder should be trivial by adding ./ before had-verb command). About ALCPlugFix binary itself don't matter where it's in, you just need to modify the launch agent plist to find it by hardcode its location (or add to $PATH, need to modify user environment so not recommended.) to be able to auto launch at boot.

stevezhengshiqi commented 5 years ago

Currently ALCPlugFix is installed in /usr/bin/, I tried to move them to /usr/local/bin/.

I moved ALCPlugFix and hda-verb to /usr/local/bin/ and edited the Agent to the new location(/usr/local/bin/ALCPlugFix) but it doesn't work. It seems that ALCPlugFix can't find /usr/bin/local/had-verb(I will debug that latter.)

ALCPlugFix binary will find the first had-verb in $PATH which /usr/local/bin/ is in by default

Could you explain it more specifically? Sorry that I can't find that PATH in main.m except in L31.

Menchen commented 5 years ago

You can do which had-verb to see what's binary it's going to use, I'm going to debug a little because maybe root doesn't have /usr/local/bin in it's PATH, also you can see what's in you PATH by echo $PATH


Update: Also $PATH is a shell terminology, ALCPlugFix run command by /bin/sh -c "YOUR COMMAND"

I have tested moving had-verb to /usr/local/bin/ and running ALCPlugFix directly and it works, Also after your PR, I have noticed double fix message per plug. My fault forgot to kill before running..

Another solution would be installing LaunchAgent as user Agent as it doesn't need root, so it doesn't mess with the system, but I think all user agent runs after login?.. not sure about that.

stevezhengshiqi commented 5 years ago

Thanks for your advice!

Update: Not sure either. Does the root LaunchAgent with /usr/local/bin/ALCPlugFix works on your device? It it does, the problem may due to my own setup.

Menchen commented 5 years ago

@stevezhengshiqi got it working in /usr/local/bin. Just check my repo, I have added support to detect and find hda-verb in work directory.


Update: It seem that LaunchDaemon is better because it run before user log in.

stevezhengshiqi commented 5 years ago

@Menchen Nice Job! I think in L11, the address should also change to /usr/local/bin/ALCPlugFix.

Also, in L19, the location should be /usr/local/bin/.

It works for me, will update your scripts to this repository, thank you!

Menchen commented 5 years ago

@stevezhengshiqi Fixed! Sorry for the late response and thanks for catching the bug, that happened to me for editing it manually instead of copying my own setup. Also, I tested it with LaunchDaemons and it works better as Daemons can launch before login(No need of GUI).

stevezhengshiqi commented 5 years ago

@Menchen Could you ensure that works? I just tested and the LaunchDaemons doesn't work for me.

BTW, in L9, the location should change.

Menchen commented 5 years ago

@stevezhengshiqi thanks again for pointing the bug, About LaunchDaemons I have tested more than twice with full reboot and more time with warm-reboot.

Update: Confirmed working after 'a clean' using install script. You maybe have some leftover that conflict the plist.

stevezhengshiqi commented 5 years ago

@Menchen I am pretty sure I have a clean install, and I will recheck it later.

My situation is that when the plist is in LaunchDaemon, I have great headphone output and input, but after I replug the headphone, the sound disappears. Closing and opening the lid enable headphone working again, but no sound after replugging.

When the plist is in LaunchAgent, I don't have replug issue. I know these two folders are basically the same except loading time, so I am confused. May due to my set up.

Menchen commented 5 years ago

Replug is working for me, ps aux | grep -i ALCPlugFix Use this to check if ALCPlugFix is running, and add the following to plist to debug.

<key>StandardOutPath</key>
<string>/tmp/alcplugfix.log</string>
<key>StandardErrorPath</key>
<string>/tmp/alcplugfix.log</string>
stevezhengshiqi commented 5 years ago

@Menchen Here are two troubleshooting files. For each situation, I frst use internal speaker, then plug headphone, then replug, then sleep and wake, then replug.

LaunchDaemon.zip LaunchAgent.zip I guess maybe AppKit class is loaded after login(?), so the LaunchDaemon one fail to load its dependency? Not sure about that. I will debug it more on the next day.

Menchen commented 5 years ago

ALCPlugFix is running in LaunchDaemon, and both your log and screenshot confirm that, would have a crash message or some segment fault if something is wrong. Interesting that when using LaunchDaemon Audio device change is not watched, thus replug is not working, and yeah you should rest, it's 3 AM in your timezone(LOL).

Update: I found it after adding debug code. It seems you can't hook audio listener before login. It gives an error with no documentation

Menchen commented 5 years ago

@stevezhengshiqi You were right about not working with LaunchDaemons, I had forgotten to test with sleep.

I have fixed that bug about hooking to AudioListener at boot (Maybe daemon run before audio service and initiate?) by adding delay and retry until success.

It seems the only benefit using LaunchDaemon is when you left the headphone plugged and don't want to hear noise when you type your password wrong, otherwise, ALCPlugFix won't work until you log in.

stevezhengshiqi commented 5 years ago

@Menchen It works, thanks a lot for your efforts! The benefits may seem small, but theorticallly LaunchDaemons is a better place for the ALCPlugFix service. Merged that into this repository.

stevezhengshiqi commented 5 years ago

@Menchen Hi, I got some feedback that ALCPlugFix is not working on Catalina. I guess the issue relates to the new privacy protections in 10.15. According to macOS 10.15 Release Note,

resources for a launchd service must be stored in locations that aren’t privacy sensitive.

I will ask them to provide the debug log. Just let you know that maybe there's a compatibility issue in 10.15. I can't verify the issue because my device is broken.

Menchen commented 5 years ago

Thanks for the feedback, I’m going to update to Catalina this week.

Menchen commented 5 years ago

@stevezhengshiqi I have updated to Catalina and both ALCPlugFix(system launch daemon) and VMBTFirmUpdater(that use user launch agent) work fine(I have checked from the log file and using htop to check if it's still running).

Some weir thing I have noticed is that VMBTFirmUpdater asks for InputMonitoring(not a malware, and you can always build from its GitHub)... maybe it's needed for wake detection, but ALCPlugFIx doesn't need any special permission(besides the root for launch daemon, maybe that's why it don't need more permission ).

Screenshot 2019-10-10 at 20 43 21

I'm using the following plist if that matter

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>good.win.ALCPlugFix</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/ALCPlugFix</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>ServiceIPC</key>
    <false/>
    <!--Shuold be directory that hda-verb at-->
    <key>WorkingDirectory</key>
    <string>/usr/local/bin/</string>
    <key>StandardOutPath</key>
    <string>/tmp/alcplugfix.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/alcplugfix.log</string>
</dict>
</plist>

with permission as following:

-rw-r--r-- 1 root wheel 707 Apr 30 22:19 /Library/LaunchDaemons/good.win.ALCPlugFix.plist -rwxr-xr-x 1 mc staff 36576 Sep 7 23:09 /usr/local/bin/ALCPlugFix -rwxr-xr-x 1 mc admin 14844 Apr 30 19:10 /usr/local/bin/hda-verb

Another thing that they should check is in privacy settings to find wheter there's some entry about ALCPlugFix, below one is compiled with Catalina base API, it may help. ALCPlugFix.zip .

Menchen commented 5 years ago

Also check gate master to allow any app may help too

Menchen commented 5 years ago

I found out that you may need to re load again using launchctl, a reinstall would fix it.

stevezhengshiqi commented 4 years ago

@Menchen Hi, would you mind have a minor fix in https://github.com/Menchen/ALCPlugFix/blob/master/alc_fix/install.sh: change all $USER to "$USER"? It's due to that I use submodule now, which directs to your repository, but the install.sh makes CI shellcheck unhappy.

Menchen commented 4 years ago

It should be ok now.

stevezhengshiqi commented 4 years ago

@Menchen Hi, it seems that https://github.com/acidanthera/AppleALC/pull/614 is trying to get rid of CodecCommander. His ALCPlugFix version made few changes like https://github.com/black-dragon74/ALCPlugFix/commit/41cec7fa92dcd639e8526505a702b51453fa087f. Mind looking at that? No rush, we are good if keep using CodecCommander.

black-dragon74 commented 4 years ago

@stevezhengshiqi Please wait for some time. I am re-writing the ALCPlugFix to be used with my patch. It'll be up soon. I'll let you know of the status.

You are indeed correct in assuming we are trying to get rid of CodecCommander as AppleALC is capable of sending the verbs. My patch enables us to send verbs from the user-space to the kernel.

So, you will need one less kext and AppleALC will be the only thing you need. To get rid of compiling the ALCPlugFix binary manually, users will now have an option to provide custom PLIST containing all the hda-verb commands for ALCPlugFix.

Regards

stevezhengshiqi commented 4 years ago

@black-dragon74 Thank you for the explanation. Yeah, I can see you moved hda-verb source files into AppleALC and allow AppleALC to send verb commands. That would be really great to merge legacy CodecCommander into AppleALC and merge Codec commands into the plist for AppleALC. Looking forward to your ALCPlugFix new versions.

Also, @Menchen did great jobs on improving the daemon for ALCPlugFix. Maybe his work can help: https://github.com/Menchen/ALCPlugFix.

Have a great day

Menchen commented 4 years ago

By just looking the code using my phone it seem just a change of binary path... ALCPlugFix should work same providing the correct path by changing the workspace in launch daemon plist...

I will update once the PR is merged.. Edit: I think I might just make a small generic framework to let user hook to system event without compiling by loading a text file (json/plist) and run a custom command... This can replace ALCPlugFix, VMBTFirmUploader, and the voltageshifter daemon that doesn't run right after wake... But It might take me a while due to school and my lack of objective-c/swift knowledge...

black-dragon74 commented 4 years ago

@stevezhengshiqi the project is up at: https://github.com/black-dragon74/ALCPlugFix-Swift. Documentation is still pending (will do tomorrow). No more compiling the source ever again. In order for alc-verb to use you will need a compatible AppleALC kext (changes will be merged to master before next month's release maybe).

The config file can be configured to send commands on following events selectively:

Also, it is a very bad idea to send the same command on every event like the modified ALCPlugFix above does. Though it might work, it is not at all recommended. Like in alc_295.plist of ALCPlugFix-Swift, you can see I am sending the verbs exclusively on headset plug in.

Regards

stevezhengshiqi commented 4 years ago

@black-dragon74 Thanks for further explanation. I agree it's a clearer and cleaner way than the old ALCPlugFIx.

Sorry for the lack of knowledge on hda commands, I am not sure when should we send SET_PIN_WIDGET_CONTROL and SET_UNSOLICITED_ENABLE commands, since I never thought about it when I use ALCPlugFix.

In my understanding, for EAPD speakers, I need [Speaker Node] SET_PIN_WIDGET_CONTROL [param] whenOn Wake,

and I need [Jack Node] SET_PIN_WIDGET_CONTROL [param] and [Jack Node] SET_UNSOLICITED_ENABLE [param] for jack and mic when On Connect, if I need them on old ALCPlugFix.

Please correct me if I am wrong.

stevezhengshiqi commented 3 years ago

Seems done. Here's the latest compiled version of AppleALC with black-dragon74's PR. AppleALC-1.5.4-RELEASE.zip CC @Menchen

black-dragon74 commented 3 years ago

Also, The latest ALCPlugFix-Swift loses the alc-verb or hda-verb binary dependency. So all it needs to work is latest AppleALC (one attached above). Just download and run install.sh.

To get an idea of basic config file for it, take a look at: https://github.com/black-dragon74/ALCPlugFix-Swift/blob/master/ALCPlugFix-Swift/Misc/alc_295.plist

stevezhengshiqi commented 3 years ago

@black-dragon74 Hi, thank you for the effort. My headphone is working when startup, but not working after a sleep-and-wake cycle. My macOS version is 10.14.6. I can find the logs file in /var/log, but they are empty.

Here's my configuration file. alc_298.plist.zip