1
+ #include <jni.h>
2
+ #include <stdio.h>
3
+ #include <opus.h>
4
+ #include <opusenc.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include "utils.h"
8
+
9
+ OggOpusEnc * enc ;
10
+ OggOpusComments * comments ;
11
+ int error ;
12
+
13
+ static inline void set_bits (uint8_t * bytes , int32_t bitOffset , int32_t value ) {
14
+ bytes += bitOffset / 8 ;
15
+ bitOffset %= 8 ;
16
+ * ((int32_t * ) bytes ) |= (value << bitOffset );
17
+ }
18
+
19
+ JNIEXPORT jint JNICALL Java_one_mixin_oggOpusPlayer_OpusAudioRecorder_startRecord (JNIEnv * env , jclass clazz , jstring path ) {
20
+ const char * pathStr = (* env )-> GetStringUTFChars (env , path , 0 );
21
+ if (!pathStr ) {
22
+ LOGE ("Error path" );
23
+ return 0 ;
24
+ }
25
+ comments = ope_comments_create ();
26
+ enc = ope_encoder_create_file (pathStr , comments , 16000 , 1 , 0 , & error );
27
+ if (error != OPE_OK ) {
28
+ LOGE ("Create OggOpusEnc failed" );
29
+ return error ;
30
+ }
31
+ error = ope_encoder_ctl (enc , OPUS_SET_BITRATE_REQUEST , 16 * 1024 );
32
+ if (error != OPE_OK ) {
33
+ return error ;
34
+ }
35
+
36
+ return OPE_OK ;
37
+ }
38
+
39
+ JNIEXPORT jint JNICALL Java_one_mixin_oggOpusPlayer_OpusAudioRecorder_writeFrame (JNIEnv * env , jclass clazz , jshortArray frame , jint len ) {
40
+ jshort * sampleBuffer = (* env ) -> GetShortArrayElements (env , frame , 0 );
41
+ int result = ope_encoder_write (enc , sampleBuffer , len );
42
+ (* env )-> ReleaseShortArrayElements (env , frame , sampleBuffer , 0 );
43
+ return result ;
44
+ }
45
+
46
+ JNIEXPORT void JNICALL Java_one_mixin_oggOpusPlayer_OpusAudioRecorder_stopRecord (JNIEnv * env , jclass clazz ) {
47
+ ope_encoder_drain (enc );
48
+ ope_encoder_destroy (enc );
49
+ ope_comments_destroy (comments );
50
+ LOGI ("ope encoder destroy" );
51
+ }
52
+
53
+ JNIEXPORT jbyteArray JNICALL Java_one_mixin_oggOpusPlayer_OpusAudioRecorder_getWaveform2 (JNIEnv * env , jclass clazz , jshortArray array , jint length ) {
54
+ jshort * sampleBuffer = (* env )-> GetShortArrayElements (env , array , 0 );
55
+ const int32_t resultSamples = 100 ;
56
+ uint16_t * samples = malloc (100 * 2 );
57
+ uint64_t sampleIndex = 0 ;
58
+ uint16_t peakSample = 0 ;
59
+ int32_t sampleRate = (int32_t ) max (1 , length / resultSamples );
60
+ int32_t index = 0 ;
61
+
62
+ for (int32_t i = 0 ; i < length ; i ++ ) {
63
+ uint16_t sample = (uint16_t ) abs (sampleBuffer [i ]);
64
+ if (sample > peakSample ) {
65
+ peakSample = sample ;
66
+ }
67
+ if (sampleIndex ++ % sampleRate == 0 ) {
68
+ if (index < resultSamples ) {
69
+ samples [index ++ ] = peakSample ;
70
+ }
71
+ peakSample = 0 ;
72
+ }
73
+ }
74
+
75
+ int64_t sumSamples = 0 ;
76
+ for (int32_t i = 0 ; i < resultSamples ; i ++ ) {
77
+ sumSamples += samples [i ];
78
+ }
79
+ uint16_t peak = (uint16_t ) (sumSamples * 1.8f / resultSamples );
80
+ if (peak < 2500 ) {
81
+ peak = 2500 ;
82
+ }
83
+
84
+ for (int32_t i = 0 ; i < resultSamples ; i ++ ) {
85
+ uint16_t sample = (uint16_t ) ((int64_t ) samples [i ]);
86
+ if (sample > peak ) {
87
+ samples [i ] = peak ;
88
+ }
89
+ }
90
+
91
+ (* env )-> ReleaseShortArrayElements (env , array , sampleBuffer , 0 );
92
+
93
+ uint32_t bitStreamLength = resultSamples * 5 / 8 + 1 ;
94
+ jbyteArray result = (* env )-> NewByteArray (env , bitStreamLength );
95
+ if (result ) {
96
+ uint8_t * bytes = malloc (bitStreamLength + 4 );
97
+ memset (bytes , 0 , bitStreamLength + 4 );
98
+ for (int32_t i = 0 ; i < resultSamples ; i ++ ) {
99
+ int32_t value = min (31 , abs ((int32_t ) samples [i ]) * 31 / peak );
100
+ set_bits (bytes , i * 5 , value & 31 );
101
+ }
102
+ (* env )-> SetByteArrayRegion (env , result , 0 , bitStreamLength , (jbyte * ) bytes );
103
+ }
104
+
105
+ free (samples );
106
+
107
+ return result ;
108
+ }
0 commit comments