Bump
This commit is contained in:
@@ -67,6 +67,7 @@ dependencies {
|
||||
implementation(libs.androidx.core.splashscreen)
|
||||
implementation(libs.androidx.compose.navigation)
|
||||
implementation(libs.androidx.media3.common)
|
||||
implementation("co.touchlab:stately-concurrent-collections:2.0.0")
|
||||
implementation(libs.androidx.compose.material3)
|
||||
implementation(libs.androidx.work.runtime.ktx) // androidTestImplementation(platform(libs.androidx.compose.bom))
|
||||
// androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||
|
||||
@@ -34,6 +34,24 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
<service
|
||||
android:name=".MessageListenerService"
|
||||
android:enabled="true"
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
|
||||
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/audio"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.birdsounds.identify
|
||||
|
||||
import android.app.Service
|
||||
|
||||
|
||||
|
||||
import android.content.Intent
|
||||
import android.util.Half.abs
|
||||
import android.util.Log
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.birdsounds.identify.presentation.MessageSender
|
||||
import com.google.android.gms.wearable.MessageEvent
|
||||
import com.google.android.gms.wearable.WearableListenerService
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.ShortBuffer
|
||||
|
||||
class MessageListenerService : WearableListenerService() {
|
||||
private val tag = "MessageListenerService"
|
||||
|
||||
// fun placeSoundClassifier(soundClassifier: SoundClassifier)
|
||||
override fun onMessageReceived(p0: MessageEvent) {
|
||||
super.onMessageReceived(p0)
|
||||
|
||||
|
||||
val t_scored = ByteBuffer.wrap(p0.data).getLong()
|
||||
MessageSender.messageLog.add(t_scored)
|
||||
Log.w("MSG_RECV", t_scored.toString())
|
||||
// Log.i(tag , short_array.map( { abs(it)}).sum().toString())
|
||||
// Log.i(tag, short_array[0].toString())
|
||||
// Log.i(tag, p0.data.toString(Charsets.US_ASCII))
|
||||
// broadcastMessage(p0)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.birdsounds.identify.presentation
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
@@ -12,6 +13,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.core.content.ContextCompat
|
||||
import co.touchlab.stately.collections.ConcurrentMutableCollection
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import com.google.android.gms.wearable.ChannelClient
|
||||
import com.google.android.gms.wearable.ChannelClient.ChannelCallback
|
||||
@@ -65,6 +67,7 @@ class MainState(private val activity: Activity, private val requestPermission: (
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
suspend fun permissionResultReturned() {
|
||||
playbackStateMutatorMutex.mutate {
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
|
||||
@@ -136,6 +139,7 @@ private suspend fun record(activity: (Activity),soundRecorder: SoundRecorder,
|
||||
// // Stop recording
|
||||
// recordingJob.cancel()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
object channelCallback : ChannelClient.ChannelCallback() {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package com.birdsounds.identify.presentation
|
||||
|
||||
import android.content.Context
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.WorkerParameters
|
||||
import com.google.android.gms.wearable.Wearable
|
||||
|
||||
class MessageSendRecv(private val context: Context)
|
||||
{
|
||||
//MainState.
|
||||
}
|
||||
@@ -3,6 +3,9 @@ package com.birdsounds.identify.presentation
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import co.touchlab.stately.collections.ConcurrentMutableCollection
|
||||
import co.touchlab.stately.collections.ConcurrentMutableList
|
||||
import co.touchlab.stately.collections.ConcurrentMutableSet
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import com.google.android.gms.wearable.Wearable
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -15,6 +18,10 @@ object MessageSender {
|
||||
const val tag = "MessageSender"
|
||||
private val job = Job()
|
||||
private val coroutineScope = CoroutineScope(Dispatchers.IO + job)
|
||||
var messageLog = ConcurrentMutableSet<Long>()
|
||||
|
||||
|
||||
|
||||
|
||||
fun sendMessage(path: String, message: ByteArray, context: Context) {
|
||||
coroutineScope.launch {
|
||||
|
||||
@@ -6,9 +6,13 @@ import android.content.Context
|
||||
import android.media.AudioFormat
|
||||
import android.media.AudioRecord
|
||||
import android.media.MediaRecorder
|
||||
import android.os.Message
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresPermission
|
||||
import co.touchlab.stately.collections.ConcurrentMutableCollection
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import java.nio.ByteBuffer
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* A helper class to provide methods to record audio input from the MIC to the internal storage.
|
||||
@@ -27,50 +31,87 @@ class SoundRecorder(
|
||||
}
|
||||
|
||||
|
||||
|
||||
@RequiresPermission(Manifest.permission.RECORD_AUDIO)
|
||||
suspend fun record() {
|
||||
|
||||
|
||||
suspendCancellableCoroutine<Unit> { cont ->
|
||||
var chunk_index: Int = 0
|
||||
val audioSource = MediaRecorder.AudioSource.DEFAULT
|
||||
val sampleRateInHz = 48000
|
||||
val channelConfig = AudioFormat.CHANNEL_IN_MONO
|
||||
val audioFormat = AudioFormat.ENCODING_PCM_8BIT
|
||||
val audioFormat = AudioFormat.ENCODING_PCM_16BIT
|
||||
val buffer_size =
|
||||
4 * AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)
|
||||
// Log.w(TAG, buffer_size.toString())
|
||||
|
||||
val bufferSizeInBytes =
|
||||
sampleRateInHz * 1 * 1; // 3 second sample, 2 bytes for each sample
|
||||
sampleRateInHz * 3 * 2; // 3 second sample, 2 bytes for each sample
|
||||
|
||||
val chunk_size = 2 * sampleRateInHz / 4 // 250ms segments, 2 bytes for each sample
|
||||
val num_chunks: Int = bufferSizeInBytes / chunk_size
|
||||
val chunked_audio_bytes = Array(num_chunks) { ByteArray(chunk_size) }
|
||||
|
||||
val audio_bytes_array = ByteArray(bufferSizeInBytes)
|
||||
val audioRecord = AudioRecord(
|
||||
/* audioSource = */ audioSource,
|
||||
/* sampleRateInHz = */ sampleRateInHz,
|
||||
/* channelConfig = */ channelConfig,
|
||||
/* audioFormat = */ audioFormat,
|
||||
/* bufferSizeInBytes = */ bufferSizeInBytes
|
||||
/* bufferSizeInBytes = */ buffer_size
|
||||
)
|
||||
|
||||
audioRecord.startRecording()
|
||||
|
||||
|
||||
val thread = Thread {
|
||||
|
||||
var last_tstamp: Long = Instant.now().toEpochMilli()
|
||||
while (true) {
|
||||
if (Thread.interrupted()) {
|
||||
// check for the interrupted flag, reset it, and throw exception
|
||||
Log.w(TAG, "Finished thread");
|
||||
break;
|
||||
}
|
||||
chunk_index = chunk_index.mod(num_chunks)
|
||||
val out = audioRecord.read(
|
||||
/* audioData = */ audio_bytes_array,
|
||||
/* audioData = */ chunked_audio_bytes[chunk_index],
|
||||
/* offsetInBytes = */ 0,
|
||||
/* sizeInBytes = */ bufferSizeInBytes,
|
||||
/* readMode = */ AudioRecord.READ_BLOCKING
|
||||
/* sizeInBytes = */ chunk_size,
|
||||
/* readMode = */ android.media.AudioRecord.READ_BLOCKING
|
||||
)
|
||||
|
||||
|
||||
// val audio_u_byte = audio_bytes_array.toUByteArray();
|
||||
// Log.w(TAG, audio_bytes_array.size.toString());
|
||||
val str_beg = audio_bytes_array[0].toString()
|
||||
val str_end = audio_bytes_array[bufferSizeInBytes-1].toString()
|
||||
Log.w(TAG, str_beg + ", " + str_end);
|
||||
// MessageSender.sendMessage("/audio",audio_bytes_array, context)
|
||||
chunk_index += 1;
|
||||
if (last_tstamp in MessageSender.messageLog) {
|
||||
var tstamp: Long = Instant.now().toEpochMilli()
|
||||
val tstamp_buffer = ByteBuffer.allocate(Long.SIZE_BYTES)
|
||||
val tstamp_bytes = tstamp_buffer.putLong(tstamp).array()
|
||||
var byte_send: ByteArray = ByteArray(0)
|
||||
var strr: String = ""
|
||||
for (i in 0..(num_chunks - 1)) {
|
||||
var c_index = i + chunk_index
|
||||
c_index = c_index.mod(num_chunks)
|
||||
strr += c_index.toString();
|
||||
strr += ' '
|
||||
byte_send += chunked_audio_bytes[c_index]
|
||||
}
|
||||
// Log.w(TAG, strr)
|
||||
// Log.w("MSG_SENT",byte_send.sum().toString()+",. "+ tstamp.toString())
|
||||
MessageSender.sendMessage("/audio", tstamp_bytes + byte_send, context)
|
||||
last_tstamp = tstamp;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
thread.start();
|
||||
// thread.join();
|
||||
|
||||
cont.invokeOnCancellation {
|
||||
thread.interrupt();
|
||||
audioRecord.stop();
|
||||
audioRecord.release()
|
||||
state = State.IDLE
|
||||
}
|
||||
state = State.IDLE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user