Skip to content

Commit

Permalink
Add duration display.
Browse files Browse the repository at this point in the history
  • Loading branch information
alan-signal committed May 14, 2020
1 parent ff3abfb commit 36cde60
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,16 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

@RequiresApi(api = Build.VERSION_CODES.M)
public final class AudioWaveForm {

private static final String TAG = Log.tag(AudioWaveForm.class);

private static final int BARS = 36;
private static final int SAMPLES_PER_BAR = 4;

private final AudioSlide slide;
private final Context context;

Expand All @@ -37,31 +42,30 @@ public AudioWaveForm(AudioSlide slide, Context context) {
this.context = context;
}

private static final LruCache<Uri, float[]> WAVE_FORM_CACHE = new LruCache<>(200);
private static final Executor AUDIO_DECODER_EXECUTOR = SignalExecutors.BOUNDED;
private static final LruCache<Uri, AudioFileInfo> WAVE_FORM_CACHE = new LruCache<>(200);
private static final Executor AUDIO_DECODER_EXECUTOR = SignalExecutors.BOUNDED;

@AnyThread
@RequiresApi(api = Build.VERSION_CODES.M)
public void generateWaveForm(int bars, @NonNull Consumer<float[]> onSuccess, @NonNull Consumer<IOException> onFailure) {
public void generateWaveForm(@NonNull Consumer<AudioFileInfo> onSuccess, @NonNull Consumer<IOException> onFailure) {
AUDIO_DECODER_EXECUTOR.execute(() -> {
try {
long startTime = System.currentTimeMillis();
Uri uri = slide.getUri();
if (uri == null) {
Util.runOnMain(() -> onSuccess.accept(new float[bars]));
Util.runOnMain(() -> onSuccess.accept(null));
return;
}

float[] floats = WAVE_FORM_CACHE.get(uri);
if (floats != null) {
Util.runOnMain(() -> onSuccess.accept(floats));
AudioFileInfo cached = WAVE_FORM_CACHE.get(uri);
if (cached != null) {
Util.runOnMain(() -> onSuccess.accept(cached));
return;
}

float[] blocks = generateWaveForm(uri, bars);
WAVE_FORM_CACHE.put(uri, blocks);
AudioFileInfo fileInfo = generateWaveForm(uri, BARS);
WAVE_FORM_CACHE.put(uri, fileInfo);
Log.d("ALAN", "Form loadtime " + (System.currentTimeMillis() - startTime));
Util.runOnMain(() -> onSuccess.accept(blocks));
Util.runOnMain(() -> onSuccess.accept(fileInfo));
} catch (IOException e) {
Log.e(TAG, "", e);
onFailure.accept(e);
Expand All @@ -71,13 +75,12 @@ public void generateWaveForm(int bars, @NonNull Consumer<float[]> onSuccess, @No

@WorkerThread
@RequiresApi(api = 23)
private float[] generateWaveForm(@NonNull Uri uri, int bars) throws IOException {
private AudioFileInfo generateWaveForm(@NonNull Uri uri, int bars) throws IOException {
try (MediaInput dataSource = DecryptableUriMediaInput.createForUri(context, uri)) {
long[] wave = new long[bars];
int[] waveSamples = new int[bars];
int samplesPerBar = 4;

int[] inputSamples = new int[bars * samplesPerBar];
int[] inputSamples = new int[bars * SAMPLES_PER_BAR];
MediaCodec codec;
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
Expand Down Expand Up @@ -122,16 +125,16 @@ private float[] generateWaveForm(@NonNull Uri uri, int bars) throws IOException
presentationTimeUs,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS) {
int barIndex = (int) (samplesPerBar * (wave.length * extractor.getSampleTime()) / totalDurationUs);
int barIndex = (int) (SAMPLES_PER_BAR * (wave.length * extractor.getSampleTime()) / totalDurationUs);
inputSamples[barIndex]++;
sawInputEOS = !extractor.advance();
if (inputSamples[barIndex] > 0) {
//advance to next bar
int nextBarIndex = (int) (samplesPerBar * (wave.length * extractor.getSampleTime()) / totalDurationUs);
int nextBarIndex = (int) (SAMPLES_PER_BAR * (wave.length * extractor.getSampleTime()) / totalDurationUs);
while (!sawInputEOS && nextBarIndex == barIndex) {
sawInputEOS = !extractor.advance();
if (!sawInputEOS) {
nextBarIndex = (int) (samplesPerBar * (wave.length * extractor.getSampleTime()) / totalDurationUs);
nextBarIndex = (int) (SAMPLES_PER_BAR * (wave.length * extractor.getSampleTime()) / totalDurationUs);
}
}
}
Expand Down Expand Up @@ -184,7 +187,26 @@ private float[] generateWaveForm(@NonNull Uri uri, int bars) throws IOException
for (int i = 0; i < bars; i++) {
floats[i] /= max;
}
return floats;
return new AudioFileInfo(totalDurationUs, floats);
}
}

public static class AudioFileInfo {

private final long durationUs;
private final float[] waveForm;

private AudioFileInfo(long durationUs, float[] waveForm) {
this.durationUs = durationUs;
this.waveForm = waveForm;
}

public long getDuration(@NonNull TimeUnit timeUnit) {
return timeUnit.convert(durationUs, TimeUnit.MICROSECONDS);
}

public float[] getWaveForm() {
return waveForm;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public final class AudioView extends FrameLayout implements AudioSlidePlayer.Lis
private final boolean autoRewind;

@Nullable private final TextView timestamp;
@Nullable private final TextView duration;

@Nullable private SlideClickListener downloadListener;
@Nullable private AudioSlidePlayer audioSlidePlayer;
Expand Down Expand Up @@ -92,6 +93,7 @@ public AudioView(Context context, AttributeSet attrs, int defStyleAttr) {
this.circleProgress = findViewById(R.id.circle_progress);
this.seekBar = findViewById(R.id.seek);
this.timestamp = findViewById(R.id.timestamp);
this.duration = findViewById(R.id.duration);

lottieDirection = REVERSE;
this.playPauseButton.setOnClickListener(new PlayPauseClickedListener());
Expand Down Expand Up @@ -146,11 +148,21 @@ public void setAudio(final @NonNull AudioSlide audio,
if (seekBar instanceof WaveFormSeekBarView) {
WaveFormSeekBarView waveFormView = (WaveFormSeekBarView) seekBar;
if (android.os.Build.VERSION.SDK_INT >= 23) {
new AudioWaveForm(audio, getContext()).generateWaveForm(36,
waveFormView::setWaveData,
e -> waveFormView.setWaveMode(false));
new AudioWaveForm(audio, getContext()).generateWaveForm(
data -> {
waveFormView.setWaveData(data.getWaveForm());
if (duration != null) {
long durationSecs = data.getDuration(TimeUnit.SECONDS);
duration.setText(getContext().getResources().getString(R.string.AudioView_duration, durationSecs / 60, durationSecs % 60));
duration.setVisibility(VISIBLE);
}
},
e -> waveFormView.setWaveMode(false));
} else {
waveFormView.setWaveMode(false);
if (duration != null) {
duration.setVisibility(GONE);
}
}
}
}
Expand Down
18 changes: 17 additions & 1 deletion app/src/main/res/layout/audio_view.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,29 @@

<org.thoughtcrime.securesms.components.WaveFormSeekBarView
android:id="@+id/seek"
android:layout_width="fill_parent"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingStart="16dp"
android:paddingEnd="8dp"
tools:progress="50" />

<TextView
android:id="@+id/duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:fontFamily="sans-serif-light"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?conversation_item_sent_text_secondary_color"
android:textSize="@dimen/conversation_item_date_text_size"
android:visibility="gone"
tools:text="00:30"
tools:visibility="visible" />

</LinearLayout>

<TextView
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,9 @@
<!-- ViewOnceMessageActivity -->
<string name="ViewOnceMessageActivity_video_duration" translatable="false">%1$02d:%2$02d</string>

<!-- AudioView -->
<string name="AudioView_duration" translatable="false">%1$02d:%2$02d</string>

<!-- MessageDisplayHelper -->
<string name="MessageDisplayHelper_bad_encrypted_message">Bad encrypted message</string>
<string name="MessageDisplayHelper_message_encrypted_for_non_existing_session">Message encrypted for non-existing session</string>
Expand Down

0 comments on commit 36cde60

Please sign in to comment.