feat: adding ringers and more audio boilerplate

This commit is contained in:
jubb 2021-10-27 12:05:09 +11:00
parent cbfabdd0a7
commit 40d9386a81
6 changed files with 141 additions and 20 deletions

View File

@ -92,13 +92,13 @@ class WebRtcTestsActivity: PassphraseRequiredActionBarActivity(), PeerConnection
private val peerConnection by lazy {
// TODO: in a lokinet world, ice servers shouldn't be needed as .loki addresses should suffice to p2p
val turn = PeerConnection.IceServer.builder("turn:freyr.getsession.org:5349").setUsername("webrtc").setPassword("webrtc").createIceServer()
// val stun = PeerConnection.IceServer.builder("stun:freyr.getsession.org").createIceServer()
val iceServers = mutableListOf(turn)
val stun = PeerConnection.IceServer.builder("stun:freyr.getsession.org:5349").setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK).createIceServer()
val turn = PeerConnection.IceServer.builder("turn:freyr.getsession.org:5349").setUsername("webrtc").setPassword("webrtc").setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK).createIceServer()
val iceServers = mutableListOf(turn, stun)
val rtcConfig = PeerConnection.RTCConfiguration(iceServers).apply {
this.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.ENABLED
this.candidateNetworkPolicy = PeerConnection.CandidateNetworkPolicy.ALL
this.iceTransportsType = PeerConnection.IceTransportsType.RELAY
// this.iceTransportsType = PeerConnection.IceTransportsType.RELAY
}
rtcConfig.keyType = PeerConnection.KeyType.ECDSA
connectionFactory.createPeerConnection(rtcConfig, this)!!

View File

@ -8,11 +8,12 @@ import androidx.core.content.ContextCompat
import dagger.hilt.android.AndroidEntryPoint
import org.thoughtcrime.securesms.webrtc.AudioManagerCommand
import org.thoughtcrime.securesms.webrtc.CallManager
import org.thoughtcrime.securesms.webrtc.RTCAudioManager
import java.util.*
import javax.inject.Inject
@AndroidEntryPoint
class WebRtcCallService: Service() {
class WebRtcCallService: Service(), RTCAudioManager.EventListener {
@Inject lateinit var callManager: CallManager
@ -63,9 +64,24 @@ class WebRtcCallService: Service() {
.putExtra(EXTRA_ENABLED, register)
ContextCompat.startForegroundService(context, intent)
}
}
override fun onBind(intent: Intent?): IBinder? = null
override fun onCreate() {
super.onCreate()
// create audio manager
// reset call notification
// register uncaught exception handler
// register network receiver
// telephony listen to call state
}
override fun onDestroy() {
super.onDestroy()
// unregister exception handler
// shutdown audiomanager
// unregister network receiver
// unregister power button
}
}

View File

@ -0,0 +1,5 @@
package org.thoughtcrime.securesms.webrtc
enum class AudioEvent {
}

View File

@ -1,14 +0,0 @@
package org.thoughtcrime.securesms.webrtc
import android.content.Context
import android.media.AudioManager
class RTCAudioManager(context: Context, deviceChangeListener: (currentDevice: AudioDevice?, availableDevices: Collection<AudioDevice>)->Unit) {
enum class AudioDevice {
SPEAKER_PHONE, WIRED_HEADSET, EARPIECE, NONE
}
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
}

View File

@ -0,0 +1,24 @@
package org.thoughtcrime.securesms.webrtc
import android.content.Context
import android.media.AudioManager
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import org.thoughtcrime.securesms.webrtc.audio.IncomingRinger
class RTCAudioManager(context: Context, deviceChangeListener: (currentDevice: AudioDevice?, availableDevices: Collection<AudioDevice>)->Unit) {
enum class AudioDevice {
SPEAKER_PHONE, WIRED_HEADSET, EARPIECE, NONE
}
private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
private val incomingRinger = IncomingRinger(context)
private val stateChannel = Channel<AudioEvent>()
interface EventListener {
fun onAudioDeviceChanged(activeDevice: AudioDevice, devices: Set<AudioDevice>)
}
}

View File

@ -0,0 +1,90 @@
package org.thoughtcrime.securesms.webrtc.audio
import android.content.Context
import android.media.AudioManager
import android.media.MediaPlayer
import android.media.RingtoneManager
import android.os.Vibrator
import org.session.libsignal.utilities.Log
class IncomingRinger(private val context: Context) {
companion object {
const val TAG = "IncomingRinger"
val PATTERN = longArrayOf(0L, 1000L, 1000L)
}
private val vibrator: Vibrator? = context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator?
var mediaPlayer: MediaPlayer? = null
fun start(vibrate: Boolean) {
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
mediaPlayer?.release()
mediaPlayer = createMediaPlayer()
val ringerMode = audioManager.ringerMode
if (shouldVibrate(mediaPlayer, ringerMode, vibrate)) {
Log.i(TAG,"Starting vibration")
vibrator?.vibrate(PATTERN, 1)
} else {
Log.i(TAG,"Skipping vibration")
}
mediaPlayer?.let { player ->
if (ringerMode == AudioManager.RINGER_MODE_NORMAL) {
try {
if (!player.isPlaying) {
player.prepare()
player.start()
Log.i(TAG,"Playing ringtone")
}
} catch (e: Exception) {
Log.e(TAG,"Failed to start mediaPlayer", e)
}
}
} ?: run {
Log.w(TAG,"Not ringing, mediaPlayer: ${mediaPlayer?.let{"available"}}, mode: $ringerMode")
}
}
fun stop() {
mediaPlayer?.release()
mediaPlayer = null
vibrator?.cancel()
}
private fun shouldVibrate(player: MediaPlayer?, ringerMode: Int, vibrate: Boolean): Boolean {
player ?: return true
if (vibrator == null || !vibrator.hasVibrator()) return false
return if (vibrate) ringerMode != AudioManager.RINGER_MODE_SILENT
else ringerMode == AudioManager.RINGER_MODE_VIBRATE
}
fun createMediaPlayer(): MediaPlayer? {
try {
val defaultRingtone = try {
RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE)
} catch (e: Exception) {
Log.e(TAG, "Failed to get default system ringtone", e)
null
} ?: return null
try {
val mediaPlayer = MediaPlayer()
mediaPlayer.setDataSource(context, defaultRingtone)
return mediaPlayer
} catch (e: SecurityException) {
Log.w(TAG, "Failed to create player with ringtone the normal way", e)
}
} catch (e: Exception) {
Log.e(TAG,"Failed to create mediaPlayer")
}
return null
}
}