Skip to content

Commit 952754e

Browse files
committed
wip
1 parent 8dae156 commit 952754e

File tree

2 files changed

+31
-14
lines changed

2 files changed

+31
-14
lines changed

app/src/main/cpp/NativeTrack.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,8 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_set(
581581
jint channelMask, jint frameCount, jint trackFlags, jint sessionId, jfloat maxRequiredSpeed,
582582
jint selectedDeviceId, jint bitRate, jlong durationUs, jboolean hasVideo, jboolean smallBuf,
583583
jboolean isStreaming, jint bitWidth, jint offloadBufferSize, jint usage, jint contentType,
584-
jint attrFlags, jint notificationFrames,
585-
jboolean doNotReconnect, jint transferMode) {
584+
jint attrFlags, jint notificationFrames, jboolean doNotReconnect, jint transferMode,
585+
jint contentId, jint syncId, jint encapsulationMode) {
586586
if (android_get_device_api_level() < 23 && maxRequiredSpeed != 1.0f) {
587587
ALOGE("Android 5.x does not support speed adjustment, maxRequiredSpeed != 1f is wrong");
588588
return INT32_MIN;
@@ -591,6 +591,10 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_set(
591591
ALOGE("Android 5.x does not support selected devices, selectedDeviceId != 0 is wrong");
592592
return INT32_MIN;
593593
}
594+
if (android_get_device_api_level() < 30 && (contentId != 0 || syncId != 0)) {
595+
ALOGE("Tuner supported since Android 11.x, (contentId != 0 || syncId != 0) is wrong");
596+
return INT32_MIN;
597+
}
594598
auto holder = (track_holder*) ptr;
595599
jint ret = 0;
596600
fake_sp sharedMemory = {.thePtr = nullptr}; // TODO impl shared memory
@@ -621,9 +625,9 @@ Java_org_akanework_gramophone_logic_utils_NativeTrack_set(
621625
.bit_width = (uint32_t)bitWidth,
622626
.offload_buffer_size = (uint32_t)offloadBufferSize,
623627
.usage = usage,
624-
.encapsulation_mode = 0, // tuner
625-
.content_id = 0, // tuner
626-
.sync_id = 0, // tuner
628+
.encapsulation_mode = encapsulationMode, // tuner
629+
.content_id = contentType, // tuner
630+
.sync_id = syncId, // tuner
627631
};
628632
audioAttributes.newAttrs = {
629633
.content_type = contentType,

app/src/main/kotlin/org/akanework/gramophone/logic/utils/NativeTrack.kt

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import android.media.AudioManager
88
import android.media.AudioMetadataReadMap
99
import android.media.AudioRouting
1010
import android.media.AudioTrack
11+
import android.media.VolumeShaper
1112
import android.os.Build
1213
import android.os.Parcel
1314
import android.util.Log
@@ -19,15 +20,15 @@ import java.nio.ByteBuffer
1920

2021
/*
2122
* Exposes entire API surface of AudioTrack.cpp, with some minor exceptions:
22-
* - Tuner API related features TODO let's bring that back
2323
* - setCallerName/getCallerName because I want to avoid offset hardcoding, and it's only used for metrics
2424
* None of those will impose any limitations for music playback.
2525
*/
2626
class NativeTrack(context: Context, attributes: AudioAttributes, streamType: Int, sampleRate: Int,
2727
format: AudioFormatDetector.Encoding, channelMask: Int, frameCount: Int?, trackFlags: Int,
2828
sessionId: Int, maxRequiredSpeed: Float, selectedDeviceId: Int?, bitRate: Int, durationUs: Long,
2929
hasVideo: Boolean, smallBuf: Boolean, isStreaming: Boolean, offloadBufferSize: Int,
30-
notificationFrames: Int, doNotReconnect: Boolean, transferMode: Int) {
30+
notificationFrames: Int, doNotReconnect: Boolean, transferMode: Int, contentId: Int, syncId: Int,
31+
encapsulationMode: Int) {
3132
companion object {
3233
private const val TAG = "NativeTrack.kt"
3334

@@ -213,22 +214,27 @@ class NativeTrack(context: Context, attributes: AudioAttributes, streamType: Int
213214
offloadBufferSize = 0,
214215
notificationFrames = 0,
215216
doNotReconnect = false,
216-
transferMode = 3
217+
transferMode = 3,
218+
contentId = 0,
219+
syncId = 0,
220+
encapsulationMode = 0
217221
)
218222
}
219223
}
220224
private var sessionId: Int
221225
val ptr: Long
222226
var myState: State
223-
// proxy limitations: a lot of fields not initialized (mSampleRate, mAudioFormat, mChannelMask, ...) which can
224-
// cause some internal checks in various methods to fail; stream event callback is no-op. however, it does:
227+
// proxy limitations: a lot of fields not initialized (mSampleRate, mAudioFormat, mOffloaded, ...) which can
228+
// cause some internal checks in various methods to fail; stream event and playback position callbacks both
229+
// are no-op; we MUST call play(), pause(), stop() and don't use the native methods ourselves for this to work;
230+
// we must also not cache playing/paused/stopped/volume ourselves because it may change under our feet.
231+
// however, it does:
225232
// - register (and overwrite) any codec format listeners on native side ; good for us because we can't register
226233
// one in a normal way due to dependence on volatile offsets. i.e. with proxy we get codec format listeners!
227234
// - register player base (which we really should have on N+ to be a nice citizen and have stuff like ducking)
228235
// - register (and overwrite) routing callback, which is meh but we can just use the java one, it don't hurt
229-
// - volume shapers! these would be near-impossible using the native API because it's all inline.
236+
// - allow for volume shapers! these would be near-impossible using the native API because it's all inline.
230237
// it's a bit fiddly, but we get all possibilities of a native AudioTrack and a Java one - combined.
231-
// however: we MUST call play(), pause(), stop() and don't use the native methods ourselves for this to work.
232238
// reminder: do not call write() or any other standard APIs as we break a lot of assumptions. + proxy is not
233239
// always available (i.e. L/M), hence native methods are preferable where we can.
234240
private val proxy: AudioTrack?
@@ -304,7 +310,8 @@ class NativeTrack(context: Context, attributes: AudioAttributes, streamType: Int
304310
hasVideo = hasVideo, smallBuf = smallBuf, isStreaming = isStreaming, bitWidth = bitWidth,
305311
offloadBufferSize = offloadBufferSize, usage = usage, contentType = contentType,
306312
attrFlags = attrFlags, notificationFrames = notificationFrames, doNotReconnect = doNotReconnect,
307-
transferMode = transferMode)
313+
transferMode = transferMode, contentId = contentId, syncId = syncId,
314+
encapsulationMode = encapsulationMode)
308315
} catch (t: Throwable) {
309316
try {
310317
dtor(ptr)
@@ -377,7 +384,8 @@ class NativeTrack(context: Context, attributes: AudioAttributes, streamType: Int
377384
selectedDeviceId: Int, bitRate: Int, durationUs: Long, hasVideo: Boolean,
378385
smallBuf: Boolean, isStreaming: Boolean, bitWidth: Int, offloadBufferSize: Int,
379386
usage: Int, contentType: Int, attrFlags: Int, notificationFrames: Int,
380-
doNotReconnect: Boolean, transferMode: Int): Int
387+
doNotReconnect: Boolean, transferMode: Int, contentId: Int, syncId: Int,
388+
encapsulationMode: Int): Int
381389
private external fun getRealPtr(@Suppress("unused") ptr: Long): Long
382390
private external fun flagsFromOffset(@Suppress("unused") ptr: Long): Int
383391
private external fun notificationFramesActFromOffset(@Suppress("unused") ptr: Long): Int
@@ -479,6 +487,11 @@ class NativeTrack(context: Context, attributes: AudioAttributes, streamType: Int
479487
return channelCount() * bps
480488
}
481489

490+
@RequiresApi(Build.VERSION_CODES.O)
491+
fun createVolumeShaper(config: VolumeShaper.Configuration): VolumeShaper {
492+
return proxy!!.createVolumeShaper(config)
493+
}
494+
482495
class NativeTrackException : Exception {
483496
constructor(message: String) : super(message)
484497
constructor(message: String, cause: Throwable) : super(message, cause)

0 commit comments

Comments
 (0)