Skip to content

Commit 327befe

Browse files
authored
Merge pull request #1249 from cph-cachet/noise/1242
`audio_stream` 4.3.0 and `noise_meter` 5.2.0
2 parents 5f2f3aa + 3a6287c commit 327befe

File tree

23 files changed

+175
-115
lines changed

23 files changed

+175
-115
lines changed

packages/audio_streamer/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## 4.3.0
2+
3+
* Fix issue where stream function made a new thread each time a recording starts - Fixes [#1242](https://github.com/cph-cachet/flutter-plugins/issues/1242)
4+
* Updated Gradle and Kotlin
5+
* Updated `permission_handler: ^12.0.0`
6+
* Updated `sdk >=3.8.1`
7+
18
## 4.2.2
29

310
* Reverts [#1226](https://github.com/cph-cachet/flutter-plugins/pull/1226)

packages/audio_streamer/android/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ group 'plugins.cachet.audio_streamer'
22
version '1.0-SNAPSHOT'
33

44
buildscript {
5-
ext.kotlin_version = '1.9.22'
5+
ext.kotlin_version = '2.2.10'
66
repositories {
77
google()
88
mavenCentral()
99
}
1010

1111
dependencies {
12-
classpath 'com.android.tools.build:gradle:8.2.1'
12+
classpath 'com.android.tools.build:gradle:8.12.1'
1313
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1414
}
1515
}
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
org.gradle.jvmargs=-Xmx1536M
2-
android.enableR8=true
32
android.useAndroidX=true
43
android.enableJetifier=true

packages/audio_streamer/android/settings.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ pluginManagement {
2020

2121
plugins {
2222
id "dev.flutter.flutter-plugin-loader" version "1.0.2"
23-
id "com.android.application" version "8.1.0" apply false
24-
id "org.jetbrains.kotlin.android" version "1.9.20" apply false
23+
id "com.android.application" version "8.12.1" apply false
24+
id "org.jetbrains.kotlin.android" version "2.2.10" apply false
2525
}
2626

2727
include ":app"

packages/audio_streamer/android/src/main/kotlin/plugins/cachet/audio_streamer/AudioStreamerPlugin.kt

Lines changed: 80 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ class AudioStreamerPlugin : FlutterPlugin, RequestPermissionsResultListener, Eve
3434

3535
// / Variables (i.e. will change value)
3636
private var eventSink: EventSink? = null
37-
private var recording = false
37+
@Volatile private var recording = false
38+
private var recordingThread: Thread? = null
39+
3840

3941
private var currentActivity: Activity? = null
4042

@@ -48,16 +50,19 @@ class AudioStreamerPlugin : FlutterPlugin, RequestPermissionsResultListener, Eve
4850
methodChannel.setMethodCallHandler {
4951
call, result ->
5052
if (call.method == "getSampleRate") {
51-
// Sample rate never changes, so return the given sample rate.
52-
result.success(audioRecord?.getSampleRate())
53+
if (::audioRecord.isInitialized) {
54+
result.success(audioRecord.sampleRate)
55+
} else {
56+
result.error("UNAVAILABLE", "AudioRecord not initialized.", null)
57+
}
5358
} else {
5459
result.notImplemented()
5560
}
5661
}
5762
}
5863

5964
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
60-
recording = false
65+
stopRecording()
6166
}
6267

6368
override fun onDetachedFromActivity() {
@@ -83,20 +88,19 @@ class AudioStreamerPlugin : FlutterPlugin, RequestPermissionsResultListener, Eve
8388
*/
8489
override fun onListen(arguments: Any?, events: EventSink?) {
8590
this.eventSink = events
86-
recording = true
8791
sampleRate = (arguments as Map<*, *>)["sampleRate"] as Int
8892
if (sampleRate < 4000 || sampleRate > 48000) {
8993
events!!.error("SampleRateError", "A sample rate of " + sampleRate + "Hz is not supported by Android.", null)
9094
return
9195
}
92-
streamMicData()
96+
startRecording()
9397
}
9498

9599
/**
96100
* Called from Flutter, which cancels the stream.
97101
*/
98102
override fun onCancel(arguments: Any?) {
99-
recording = false
103+
stopRecording()
100104
}
101105

102106
/**
@@ -105,11 +109,36 @@ class AudioStreamerPlugin : FlutterPlugin, RequestPermissionsResultListener, Eve
105109
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray): Boolean {
106110
val requestAudioPermissionCode = 200
107111
when (requestCode) {
108-
requestAudioPermissionCode -> if (grantResults[0] == PackageManager.PERMISSION_GRANTED) return true
112+
requestAudioPermissionCode -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) return true
109113
}
110114
return false
111115
}
112116

117+
private fun startRecording() {
118+
if (recording) {
119+
Log.w(logTag, "Recording is already in progress")
120+
return
121+
}
122+
recording = true
123+
recordingThread = Thread { streamMicData() }
124+
recordingThread?.start()
125+
}
126+
127+
private fun stopRecording() {
128+
if (!recording) {
129+
Log.w(logTag, "Recording is not in progress")
130+
return
131+
}
132+
recording = false
133+
try {
134+
recordingThread?.join()
135+
} catch (e: InterruptedException) {
136+
e.printStackTrace()
137+
}
138+
recordingThread = null
139+
}
140+
141+
113142
/**
114143
* Starts recording and streaming audio data from the mic.
115144
* Uses a buffer array of size 512. Whenever buffer is full, the content is sent to Flutter.
@@ -119,39 +148,51 @@ class AudioStreamerPlugin : FlutterPlugin, RequestPermissionsResultListener, Eve
119148
* https://www.newventuresoftware.com/blog/record-play-and-visualize-raw-audio-data-in-android
120149
*/
121150
private fun streamMicData() {
122-
Thread(
123-
Runnable {
124-
Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO)
125-
val audioBuffer = ShortArray(bufferSize / 2)
126-
audioRecord = AudioRecord(
127-
MediaRecorder.AudioSource.DEFAULT,
128-
sampleRate,
129-
AudioFormat.CHANNEL_IN_MONO,
130-
AudioFormat.ENCODING_PCM_16BIT,
131-
bufferSize,
132-
)
133-
if (audioRecord.state != AudioRecord.STATE_INITIALIZED) {
134-
Log.e(logTag, "Audio Record can't initialize!")
135-
return@Runnable
136-
}
137-
/** Start recording loop */
138-
audioRecord.startRecording()
139-
while (recording) {
140-
/** Read data into buffer */
141-
audioRecord.read(audioBuffer, 0, audioBuffer.size)
151+
Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO)
152+
153+
val audioBuffer = ShortArray(bufferSize / 2)
154+
try {
155+
audioRecord = AudioRecord(
156+
MediaRecorder.AudioSource.DEFAULT,
157+
sampleRate,
158+
AudioFormat.CHANNEL_IN_MONO,
159+
AudioFormat.ENCODING_PCM_16BIT,
160+
bufferSize,
161+
)
162+
163+
if (audioRecord.state != AudioRecord.STATE_INITIALIZED) {
164+
Log.e(logTag, "Audio Record can't initialize!")
165+
eventSink?.error("MIC_ERROR", "Audio Record can't initialize!", null)
166+
recording = false
167+
return
168+
}
169+
170+
audioRecord.startRecording()
171+
172+
while (recording) {
173+
val readSize = audioRecord.read(audioBuffer, 0, audioBuffer.size)
174+
if(readSize > 0) {
175+
val audioBufferList = ArrayList<Double>()
176+
for (i in 0 until readSize) {
177+
val normalizedImpulse = audioBuffer[i].toDouble() / maxAmplitude.toDouble()
178+
audioBufferList.add(normalizedImpulse)
179+
}
142180
Handler(Looper.getMainLooper()).post {
143-
// / Convert to list in order to send via EventChannel.
144-
val audioBufferList = ArrayList<Double>()
145-
for (impulse in audioBuffer) {
146-
val normalizedImpulse = impulse.toDouble() / maxAmplitude.toDouble()
147-
audioBufferList.add(normalizedImpulse)
148-
}
149-
eventSink!!.success(audioBufferList)
181+
eventSink?.success(audioBufferList)
150182
}
151183
}
152-
audioRecord.stop()
184+
}
185+
} catch (e: Exception) {
186+
Log.e(logTag, "Error while recording audio", e)
187+
eventSink?.error("MIC_ERROR", "Error while recording audio", e.message)
188+
} finally {
189+
if (::audioRecord.isInitialized) {
190+
if (audioRecord.recordingState == AudioRecord.RECORDSTATE_RECORDING) {
191+
audioRecord.stop()
192+
}
153193
audioRecord.release()
154-
},
155-
).start()
194+
}
195+
recording = false
196+
}
156197
}
157-
}
198+
}
Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
org.gradle.jvmargs=-Xmx1536M
2-
android.enableR8=true
32
android.useAndroidX=true
43
android.enableJetifier=true
5-
android.defaults.buildfeatures.buildconfig=true
64
android.nonTransitiveRClass=false
75
android.nonFinalResIds=false
86

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#Sun Mar 12 17:19:03 CST 2023
22
distributionBase=GRADLE_USER_HOME
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
44
distributionPath=wrapper/dists
55
zipStorePath=wrapper/dists
66
zipStoreBase=GRADLE_USER_HOME

packages/audio_streamer/example/android/settings.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pluginManagement {
1818

1919
plugins {
2020
id "dev.flutter.flutter-plugin-loader" version "1.0.2"
21-
id "com.android.application" version "8.1.0" apply false
22-
id "org.jetbrains.kotlin.android" version "1.9.20" apply false
21+
id "com.android.application" version '8.12.1' apply false
22+
id "org.jetbrains.kotlin.android" version "2.2.10" apply false
2323
}
2424

2525
include ":app"

packages/audio_streamer/example/ios/Flutter/AppFrameworkInfo.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
<key>CFBundleVersion</key>
2222
<string>1.0</string>
2323
<key>MinimumOSVersion</key>
24-
<string>12.0</string>
24+
<string>13.0</string>
2525
</dict>
2626
</plist>

packages/audio_streamer/example/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Uncomment this line to define a global platform for your project
2-
# platform :ios, '12.0'
2+
# platform :ios, '13.0'
33

44
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
55
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

0 commit comments

Comments
 (0)