Android, NDK, Audio routing, forcing audio through the headset
Asked Answered
B

0

1

Use-case

  • Record Android Headset audio

Environment

  • Samsung Galaxy 5
  • Android 5.0
  • Windows Desktop OS w/ a USB audio capture device

Implementation

  • Hook the Android device headset output to the Windows OS Line-In input
  • Record whatever is sent out from the Android Device

Problem statement

  • If plugging in the Audio jack while audio is playing on the Android device the device audio output is routed through the headset jack and recording works properly
  • Once audio playback ( for eg. a song ) has stopped on the Android device, the next time it'll start audio playback will use the device speaker rather than the headset jack ( used for recording )

Attempted Problem resolution

  • A native C++ command line tool running under the shell account ( can't use Java for this )
  • dynamically load 'libmedia.so' and call eg. android::AudioSystem::setForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_HEADPHONES)
  • logcat reports:
    • 02-26 10:39:50.418 289 1707 ServiceManager Permission failure: android.permission.MODIFY_AUDIO_SETTINGS from uid=2000 pid=19577
    • 02-26 10:39:50.418 289 1707 Request requires android.permission.MODIFY_AUDIO_SETTINGS

Questions

  • Having in mind that the solution should run on a non-rooted device
    • Is there a way to grant the 'android.permission.MODIFY_AUDIO_SETTINGS' permission to the 'shell' account?
    • Is there any other way to force system wide( and not app specific ) audio through the headset ?

Code snap

            HRESULT forceAudioThroughHeadPhones() {
                typedef int(*SET_FORCE_USE)(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
                struct sigaction sa, osa;
                sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO;
                sa.sa_sigaction = [](int signo, siginfo_t* psi, void *data)->void { ucontext_t *uc = (ucontext_t *)data; };
                sigaction(SIGILL, &sa, &osa);
                void* hMod = dlopen("libmedia.so", RTLD_LAZY);
                sigaction(SIGILL, &osa, 0);
                if (0 == hMod)
                    return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
                SET_FORCE_USE setForceUse = (SET_FORCE_USE)dlsym(hMod, "_ZN7android11AudioSystem11setForceUseE24audio_policy_force_use_t25audio_policy_forced_cfg_t");
                if (0 == setForceUse)
                    return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
                android::status_t err;
                if (ERROR_SUCCESS != (err = setForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_HEADPHONES)))
                    return E_FAIL;
                if (ERROR_SUCCESS != (err = setForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM, AUDIO_POLICY_FORCE_HEADPHONES)))
                    return E_FAIL;
                return S_OK;
            }
  • 'setForceUse' returns -1, errno equals to 'Zero'.

UPDATE:

I get the same permission logcat errors when using adb shell service call ...:

10|shell@klte:/ $ service call media.audio_policy 1 i32 2 
Result: Parcel(ffffffff    '....')
Butene answered 26/2, 2015 at 8:59 Comment(3)
This is a very surprising problem report. How would an ordinary user listen to music on headphones with this device? Or is the problem confined to the audio output of a specific application, which is perhaps designed to intentionally use the speaker rather than headphones?Hemocyte
This is not specific to an application, For example: it happens with the built-in 'Music' application ( used to play the music play-lists ), and thus, while a song is playing it properly is sent to the headset, when one song switch to the next audio revert to the speaker. BIG NOTE: when using the Headset provided w/ the phone, audio DOESN'T fall-back to the speaker, this happen ONLY when connecting the device to the 'Line-in' socket of my Win8 PC, mayB it's due to the connection impedance I don't know, still, have to figure-out a workaroundButene
Okay, that it works with stock headphones changes things, and makes it seem more like the detection mechanism than a bug. Try putting 32 ohm resistors across each speaker channel, to simulate the load of a high impedance headphone. You should probably also couple the audio to the input through a .1uF or 1uF non-polarized capacitor (though the input may already have one, it is better to provide your own).Hemocyte

© 2022 - 2024 — McMap. All rights reserved.