@@ -73,14 +73,8 @@ static ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audi
73
73
typedef int32_t (*ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audio_output_flags_tPFviPvS4_ES4_jRKNS_2spINS_7IMemoryEEEbiNS0_13transfer_typeEPK20audio_offload_info_tiiPK18audio_attributes_tb_t)
74
74
(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 */ );
75
75
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 ;
78
76
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);
79
77
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 ;
84
78
typedef int32_t (*ZN7android11AudioSystem10getLatencyEiPj_t)(int32_t output, uint32_t * latency);
85
79
static ZN7android11AudioSystem10getLatencyEiPj_t ZN7android11AudioSystem10getLatencyEiPj = nullptr ;
86
80
typedef int32_t (*ZN7android11AudioSystem13getFrameCountEiPm_t)(int32_t output, size_t * frameCount);
@@ -89,10 +83,10 @@ typedef int32_t(*ZN7android11AudioSystem15getSamplingRateEiPj_t)(int32_t output,
89
83
static ZN7android11AudioSystem15getSamplingRateEiPj_t ZN7android11AudioSystem15getSamplingRateEiPj = nullptr ;
90
84
typedef void (*ZN7android11AudioSystem13releaseOutputEi19audio_stream_type_t15audio_session_t_t)(uint32_t output, int32_t stream, int32_t session);
91
85
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 ;
94
86
typedef bool (*ZNK7android10AudioTrack19isOffloadedOrDirectEv_t)(void * thisptr);
95
87
static ZNK7android10AudioTrack19isOffloadedOrDirectEv_t ZNK7android10AudioTrack19isOffloadedOrDirectEv = nullptr ;
88
+ typedef bool (*ZN7android10AudioTrack15setOutputDeviceEi_t)(void * thisptr, int32_t selectedDeviceId);
89
+ static ZN7android10AudioTrack15setOutputDeviceEi_t ZN7android10AudioTrack15setOutputDeviceEi = nullptr ;
96
90
typedef bool (*ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t_t)(audio_offload_info_t_v26 & offloadInfo);
97
91
static ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t_t ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t = nullptr ;
98
92
@@ -109,6 +103,7 @@ struct track_holder {
109
103
MyCallback* callback = nullptr ;
110
104
void * ats = nullptr ;
111
105
bool deathEmulation = false ;
106
+ int ignoredDeaths = 0 ;
112
107
bool died = false ;
113
108
JavaVM* vm = nullptr ;
114
109
};
@@ -171,6 +166,10 @@ class MyCallback : public virtual android::AudioTrack::IAudioTrackCallback {
171
166
}
172
167
void onNewIAudioTrack () override {
173
168
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
+ }
174
173
if (mHolder ->deathEmulation ) {
175
174
// block any further callbacks, and access to track object other than dtor
176
175
mHolder ->died = true ;
@@ -350,29 +349,18 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_00024Companion_initDlsym(J
350
349
if (android_get_device_api_level () <= 30 ) {
351
350
DLSYM_OR_RETURN (libaudioclient, ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t, false )
352
351
}
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
+ }
354
356
DLSYM_OR_RETURN (libaudioclient, ZNK7android10AudioTrack19isOffloadedOrDirectEv, false )
355
357
}
356
358
if (android_get_device_api_level () == 23 ) {
357
359
DLSYM_OR_RETURN (libaudioclient, ZN7android11AudioSystem10getLatencyEiPj, false )
358
360
DLSYM_OR_RETURN (libaudioclient, ZN7android11AudioSystem13getFrameCountEiPm, false )
359
361
DLSYM_OR_RETURN (libaudioclient, ZN7android11AudioSystem15getSamplingRateEiPj, false )
360
- }
361
- if (android_get_device_api_level () >= 22 && android_get_device_api_level () < 29 ) {
362
362
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 )
376
364
}
377
365
if (android_get_device_api_level () >= 31 ) {
378
366
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(
438
426
ALOGE (" Android 5.x does not support speed adjustment, maxRequiredSpeed != 1f is wrong" );
439
427
return INT32_MIN;
440
428
}
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" );
443
431
return INT32_MIN;
444
432
}
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" );
448
435
return INT32_MIN;
449
436
}
450
437
auto holder = (track_holder*) ptr;
@@ -489,7 +476,7 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_doSet(
489
476
} else {
490
477
offloadInfo.oldInfo = {
491
478
.version = AUDIO_MAKE_OFFLOAD_INFO_VERSION (0 , 1 ),
492
- .size = sizeof (audio_offload_info_t_legacy ),
479
+ .size = sizeof (audio_offload_info_t_v26 ),
493
480
.sample_rate = (uint32_t )sampleRate,
494
481
.channel_mask = (uint32_t )channelMask,
495
482
.format = (uint32_t )format,
@@ -566,6 +553,8 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_doSet(
566
553
/* selectedDeviceId = */ selectedDeviceId
567
554
);
568
555
} 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);
569
558
ret = ZN7android10AudioTrack3setE19audio_stream_type_tj14audio_format_tjm20audio_output_flags_tPFviPvS4_ES4_iRKNS_2spINS_7IMemoryEEEb15audio_session_tNS0_13transfer_typeEPK20audio_offload_info_tjiPK18audio_attributes_tbf (
570
559
holder->track ,
571
560
/* streamType = */ streamType,
@@ -717,6 +706,24 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_doSet(
717
706
holder->deathEmulation = !ZNK7android10AudioTrack19isOffloadedOrDirectEv (holder->track );
718
707
}
719
708
}
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
+ }
720
727
return ret;
721
728
}
722
729
@@ -797,94 +804,6 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_00024Companion_isOffloadSu
797
804
return ZN7android11AudioSystem18isOffloadSupportedERK20audio_offload_info_t (offloadInfo.oldInfo );
798
805
}
799
806
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
-
888
807
// TODO
889
808
// void setAudioTrackCallback(const sp<media::IAudioTrackCallback>& callback) {
890
809
// mAudioTrackCallback->setAudioTrackCallback(callback);
0 commit comments