Skip to content

Commit 2c1db6e

Browse files
committed
wip
1 parent 864cedb commit 2c1db6e

File tree

4 files changed

+64
-241
lines changed

4 files changed

+64
-241
lines changed

app/src/main/cpp/NativeTrack.cpp

+37-118
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,8 @@ static ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audi
7373
typedef int32_t(*ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audio_output_flags_tPFviPvS4_ES4_jRKNS_2spINS_7IMemoryEEEbiNS0_13transfer_typeEPK20audio_offload_info_tiiPK18audio_attributes_tb_t)
7474
(void* thisptr, int32_t streamType, uint32_t sampleRate, uint32_t format, uint32_t channelMask, size_t frameCount /* = 0 */, uint32_t flags /* = 0 */, legacy_callback_t callback /* = nullptr */, void* user /* = nullptr */, int32_t notificationFrames /* = 0 */, fake_sp& sharedMemory /* = nullptr */, bool threadCanCallJava /* = false */, int32_t audioSessionId /* = 0 */, int32_t transferType /* = TRANSFER_DEFAULT */, void* offloadInfo /* = nullptr */, uid_t uid, pid_t pid, void* attributes /* = nullptr */, bool doNotReconnect /* = false */);
7575
static ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audio_output_flags_tPFviPvS4_ES4_jRKNS_2spINS_7IMemoryEEEbiNS0_13transfer_typeEPK20audio_offload_info_tiiPK18audio_attributes_tb_t ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audio_output_flags_tPFviPvS4_ES4_jRKNS_2spINS_7IMemoryEEEbiNS0_13transfer_typeEPK20audio_offload_info_tiiPK18audio_attributes_tb = nullptr;
76-
typedef int32_t(*ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t_t)(void *attr, uint32_t samplingRate, int32_t format, int32_t channelMask, int32_t flags, void *offloadInfo);
77-
static ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t_t ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t = nullptr;
7876
typedef int32_t(*ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjj14audio_format_tj20audio_output_flags_tiPK20audio_offload_info_t_t)(void *attr, int32_t *output, int32_t session, int32_t *stream, uid_t uid, uint32_t samplingRate, int32_t format, int32_t channelMask, int32_t flags, int32_t selectedDeviceId, void *offloadInfo);
7977
static ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjj14audio_format_tj20audio_output_flags_tiPK20audio_offload_info_t_t ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjj14audio_format_tj20audio_output_flags_tiPK20audio_offload_info_t = nullptr;
80-
typedef int32_t(*ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t_t)(void *attr, int32_t *output, int32_t session, int32_t *stream, uint32_t samplingRate, int32_t format, int32_t channelMask, int32_t flags, void *offloadInfo);
81-
static ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t_t ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t = nullptr;
82-
typedef int32_t(*ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjPK12audio_config20audio_output_flags_tS4_S4__t)(void *attr, int32_t *output, int32_t session, int32_t *stream, uid_t uid, void* config, uint32_t flags, int32_t* selectedDeviceId, int32_t *portId);
83-
static ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjPK12audio_config20audio_output_flags_tS4_S4__t ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjPK12audio_config20audio_output_flags_tS4_S4_ = nullptr;
8478
typedef int32_t(*ZN7android11AudioSystem10getLatencyEiPj_t)(int32_t output, uint32_t* latency);
8579
static ZN7android11AudioSystem10getLatencyEiPj_t ZN7android11AudioSystem10getLatencyEiPj = nullptr;
8680
typedef int32_t(*ZN7android11AudioSystem13getFrameCountEiPm_t)(int32_t output, size_t* frameCount);
@@ -89,10 +83,10 @@ typedef int32_t(*ZN7android11AudioSystem15getSamplingRateEiPj_t)(int32_t output,
8983
static ZN7android11AudioSystem15getSamplingRateEiPj_t ZN7android11AudioSystem15getSamplingRateEiPj = nullptr;
9084
typedef void(*ZN7android11AudioSystem13releaseOutputEi19audio_stream_type_t15audio_session_t_t)(uint32_t output, int32_t stream, int32_t session);
9185
static ZN7android11AudioSystem13releaseOutputEi19audio_stream_type_t15audio_session_t_t ZN7android11AudioSystem13releaseOutputEi19audio_stream_type_t15audio_session_t = nullptr;
92-
typedef void(*ZN7android11AudioSystem13releaseOutputEi_t)(uint32_t output);
93-
static ZN7android11AudioSystem13releaseOutputEi_t ZN7android11AudioSystem13releaseOutputEi = nullptr;
9486
typedef bool(*ZNK7android10AudioTrack19isOffloadedOrDirectEv_t)(void* thisptr);
9587
static ZNK7android10AudioTrack19isOffloadedOrDirectEv_t ZNK7android10AudioTrack19isOffloadedOrDirectEv = nullptr;
88+
typedef bool(*ZN7android10AudioTrack15setOutputDeviceEi_t)(void* thisptr, int32_t selectedDeviceId);
89+
static ZN7android10AudioTrack15setOutputDeviceEi_t ZN7android10AudioTrack15setOutputDeviceEi = nullptr;
9690
typedef bool(*ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t_t)(audio_offload_info_t_v26 & offloadInfo);
9791
static ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t_t ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t = nullptr;
9892

@@ -109,6 +103,7 @@ struct track_holder {
109103
MyCallback* callback = nullptr;
110104
void* ats = nullptr;
111105
bool deathEmulation = false;
106+
int ignoredDeaths = 0;
112107
bool died = false;
113108
JavaVM* vm = nullptr;
114109
};
@@ -171,6 +166,10 @@ class MyCallback : public virtual android::AudioTrack::IAudioTrackCallback {
171166
}
172167
void onNewIAudioTrack() override {
173168
if (!mCallback || mHolder->died) return;
169+
if (mHolder->ignoredDeaths > 0) {
170+
mHolder->ignoredDeaths--;
171+
return; // do not call callback, and do not emulate death.
172+
}
174173
if (mHolder->deathEmulation) {
175174
// block any further callbacks, and access to track object other than dtor
176175
mHolder->died = true;
@@ -350,29 +349,18 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_00024Companion_initDlsym(J
350349
if (android_get_device_api_level() <= 30) {
351350
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t, false)
352351
}
353-
if (android_get_device_api_level() <= 22) {
352+
if (android_get_device_api_level() < 28) {
353+
if (android_get_device_api_level() >= 23) {
354+
DLSYM_OR_RETURN(libaudioclient, ZN7android10AudioTrack15setOutputDeviceEi, false)
355+
}
354356
DLSYM_OR_RETURN(libaudioclient, ZNK7android10AudioTrack19isOffloadedOrDirectEv, false)
355357
}
356358
if (android_get_device_api_level() == 23) {
357359
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem10getLatencyEiPj, false)
358360
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem13getFrameCountEiPm, false)
359361
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem15getSamplingRateEiPj, false)
360-
}
361-
if (android_get_device_api_level() >= 22 && android_get_device_api_level() < 29) {
362362
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem13releaseOutputEi19audio_stream_type_t15audio_session_t, false)
363-
} else {
364-
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem13releaseOutputEi, false)
365-
}
366-
if (android_get_device_api_level() < 28) {
367-
if (android_get_device_api_level() >= 26) {
368-
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjPK12audio_config20audio_output_flags_tS4_S4_, false)
369-
} else if (android_get_device_api_level() >= 23) {
370-
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjj14audio_format_tj20audio_output_flags_tiPK20audio_offload_info_t, false)
371-
} else if (android_get_device_api_level() >= 22) {
372-
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t, false)
373-
} else {
374-
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t, false)
375-
}
363+
DLSYM_OR_RETURN(libaudioclient, ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjj14audio_format_tj20audio_output_flags_tiPK20audio_offload_info_t, false)
376364
}
377365
if (android_get_device_api_level() >= 31) {
378366
DLSYM_OR_RETURN(libaudioclient, ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_t20audio_channel_mask_tm20audio_output_flags_tRKNS_2wpINS0_19IAudioTrackCallbackEEEiRKNS_2spINS_7IMemoryEEEb15audio_session_tNS0_13transfer_typeEPK20audio_offload_info_tRKNS_7content22AttributionSourceStateEPK18audio_attributes_tbfi, false)
@@ -438,13 +426,12 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_doSet(
438426
ALOGE("Android 5.x does not support speed adjustment, maxRequiredSpeed != 1f is wrong");
439427
return INT32_MIN;
440428
}
441-
if (android_get_device_api_level() < 30 && (contentId != 0 || syncId != 0)) {
442-
ALOGE("Tuner is supported since Android 11, (contentId != 0 || syncId != 0) is wrong");
429+
if (android_get_device_api_level() < 23 && selectedDeviceId != 0) {
430+
ALOGE("Android 5.x does not support selected devices, selectedDeviceId != 0 is wrong");
443431
return INT32_MIN;
444432
}
445-
// TODO can we backport selectedDeviceId
446-
if (android_get_device_api_level() < 28 && selectedDeviceId != 0) {
447-
ALOGE("Selected devices are supported since Android 9, selectedDeviceId != 0 is wrong");
433+
if (android_get_device_api_level() < 30 && (contentId != 0 || syncId != 0)) {
434+
ALOGE("Tuner is supported since Android 11, (contentId != 0 || syncId != 0) is wrong");
448435
return INT32_MIN;
449436
}
450437
auto holder = (track_holder*) ptr;
@@ -489,7 +476,7 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_doSet(
489476
} else {
490477
offloadInfo.oldInfo = {
491478
.version = AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1),
492-
.size = sizeof(audio_offload_info_t_legacy),
479+
.size = sizeof(audio_offload_info_t_v26),
493480
.sample_rate = (uint32_t)sampleRate,
494481
.channel_mask = (uint32_t)channelMask,
495482
.format = (uint32_t)format,
@@ -566,6 +553,8 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_doSet(
566553
/* selectedDeviceId = */ selectedDeviceId
567554
);
568555
} else if (android_get_device_api_level() >= 26) { // Android 8.x
556+
// This is safe to call before set() only in O!
557+
ZN7android10AudioTrack15setOutputDeviceEi(holder->track, selectedDeviceId);
569558
ret = ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audio_output_flags_tPFviPvS4_ES4_iRKNS_2spINS_7IMemoryEEEb15audio_session_tNS0_13transfer_typeEPK20audio_offload_info_tjiPK18audio_attributes_tbf(
570559
holder->track,
571560
/* streamType = */ streamType,
@@ -717,6 +706,24 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_doSet(
717706
holder->deathEmulation = !ZNK7android10AudioTrack19isOffloadedOrDirectEv(holder->track);
718707
}
719708
}
709+
if (android_get_device_api_level() >= 23 && android_get_device_api_level() <= 25) {
710+
if (ret == 0 && selectedDeviceId != 0) {
711+
// if selectedDeviceId != 0 before O, we can set it with setOutputDevice() which will
712+
// invalidate the track (in O, we can call setOutputDevice() before set() which means
713+
// there is no track yet). that won't work if it has doNotReconnect set, hence emulate
714+
// that to allow setOutputDevice() to work for now.
715+
// TODO use memory hacks instead and get rid of ignoredDeaths (that'll fix direct too)
716+
if (ZNK7android10AudioTrack19isOffloadedOrDirectEv(holder->track)) {
717+
ALOGE("Ignoring selectedDeviceId emulation because track is offloaded/direct");
718+
} else {
719+
holder->deathEmulation = doNotReconnect;
720+
holder->ignoredDeaths = 1;
721+
// This will instantly invalidate the track.
722+
ZN7android10AudioTrack15setOutputDeviceEi(holder->track, selectedDeviceId);
723+
// TODO the track is now invalid but not yet restored, which is inconsistent
724+
}
725+
}
726+
}
720727
return ret;
721728
}
722729

@@ -797,94 +804,6 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_00024Companion_isOffloadSu
797804
return ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t(offloadInfo.oldInfo);
798805
}
799806

800-
extern "C"
801-
JNIEXPORT void JNICALL
802-
Java_org_akanework_gramophone_logic_utils_NativeTrack_00024Companion_runWithOpenedOutput(
803-
JNIEnv *env, jobject, jint streamType, jint sampleRate, jint format,
804-
jint channelMask, jint frameCount, jint trackFlags, jint sessionId,
805-
jint selectedDeviceId, jint bitRate, jlong durationUs, jboolean hasVideo,
806-
jboolean isStreaming, jint bitWidth, jint offloadBufferSize, jint usage,
807-
jint contentType, jint source,
808-
jint attrFlags, jstring inTags, jobject action) {
809-
if (android_get_device_api_level() >= 28) {
810-
ALOGE("runWithOpenedOutput doesn't work on Pie or later");
811-
return;
812-
}
813-
const char* tags = env->GetStringUTFChars(inTags, nullptr);
814-
audio_attributes_legacy audioAttributes = {
815-
.content_type = contentType,
816-
.usage = usage,
817-
.source = source,
818-
.flags = (uint32_t) attrFlags,
819-
};
820-
audioAttributes.tags[255] = '\0';
821-
strncpy(audioAttributes.tags, tags, 255);
822-
audio_config_v26 config = {};
823-
config.format = format;
824-
config.channel_mask = channelMask;
825-
config.frame_count = frameCount;
826-
config.sample_rate = sampleRate;
827-
config.offload_info = {
828-
.version = AUDIO_MAKE_OFFLOAD_INFO_VERSION(0, 1),
829-
.size = sizeof(audio_offload_info_t_legacy),
830-
.sample_rate = (uint32_t) sampleRate,
831-
.channel_mask = (uint32_t) channelMask,
832-
.format = (uint32_t) format,
833-
.stream_type = streamType,
834-
.bit_rate = (uint32_t) bitRate,
835-
.duration_us = durationUs,
836-
.has_video = (bool) hasVideo,
837-
.is_streaming = (bool) isStreaming,
838-
.bit_width = (uint32_t) bitWidth, // informative, since Android 8.0
839-
.offload_buffer_size = (uint32_t) offloadBufferSize, // informative, since Android 8.0
840-
.usage = usage, // informative, since Android 8.0
841-
};
842-
env->ReleaseStringUTFChars(inTags, tags);
843-
int32_t streamTypeOut = streamType;
844-
int32_t output = 0;
845-
int32_t portId = 0;
846-
int32_t status = 0;
847-
int32_t selectedDeviceIdOut = selectedDeviceId;
848-
std::vector<int32_t> secondaryOutputs;
849-
if (android_get_device_api_level() >= 26) {
850-
status = ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjPK12audio_config20audio_output_flags_tS4_S4_(
851-
&audioAttributes, &output, sessionId, &streamTypeOut, getuid(), &config,
852-
trackFlags, &selectedDeviceIdOut, &portId);
853-
} else if (android_get_device_api_level() >= 23) {
854-
status = ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tjj14audio_format_tj20audio_output_flags_tiPK20audio_offload_info_t(
855-
&audioAttributes, &output, sessionId, &streamTypeOut, getuid(), sampleRate, format, channelMask,
856-
trackFlags, selectedDeviceId, &config.offload_info);
857-
} else if (android_get_device_api_level() >= 22) {
858-
status = ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tPi15audio_session_tP19audio_stream_type_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t(
859-
&audioAttributes, &output, sessionId, &streamTypeOut, sampleRate, format, channelMask,
860-
trackFlags, &config.offload_info);
861-
} else {
862-
output = ZN7android11AudioSystem16getOutputForAttrEPK18audio_attributes_tj14audio_format_tj20audio_output_flags_tPK20audio_offload_info_t(
863-
&audioAttributes, sampleRate, channelMask, format, trackFlags, &config.offload_info);
864-
}
865-
if (status != 0 || output == 0) {
866-
ALOGE("failed runWithOpenedOutput with status %d output %d", status, output);
867-
return;
868-
}
869-
jclass intCls = env->FindClass("java/lang/Integer");
870-
jmethodID intId = env->GetMethodID(intCls, "<init>", "(I)V");
871-
jobject outputInt = env->NewObject(intCls, intId, output);
872-
env->DeleteLocalRef(intCls);
873-
jclass actionCls = env->GetObjectClass(action);
874-
jmethodID id = env->GetMethodID(actionCls, "accept", "(Ljava/lang/Object;)V");
875-
env->DeleteLocalRef(actionCls);
876-
env->CallVoidMethod(action, id, outputInt);
877-
env->DeleteLocalRef(outputInt);
878-
if (android_get_device_api_level() >= 29) {
879-
ZN7android11AudioSystem13releaseOutputEi(portId);
880-
} else if (android_get_device_api_level() >= 22) {
881-
ZN7android11AudioSystem13releaseOutputEi19audio_stream_type_t15audio_session_t(
882-
output, streamType, sessionId);
883-
} else {
884-
ZN7android11AudioSystem13releaseOutputEi(output);
885-
}
886-
}
887-
888807
// TODO
889808
// void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback) {
890809
// mAudioTrackCallback->setAudioTrackCallback(callback);

0 commit comments

Comments
 (0)