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 '....')