Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSDK-2569: Updating to daily-android 0.26.0 #42

Merged
merged 1 commit into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DailyDemo/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ android {
dependencies {
implementation 'androidx.appcompat:appcompat:1.7.0'

implementation 'co.daily:client:0.25.0'
implementation 'co.daily:client:0.26.0'

implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.android.flexbox:flexbox:3.0.0'
Expand Down
Binary file added DailyDemo/app/src/main/assets/vb-library.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 11 additions & 2 deletions DailyDemo/app/src/main/java/co/daily/core/dailydemo/DemoState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import co.daily.model.CallState
import co.daily.model.MediaStreamTrack
import co.daily.model.Participant
import co.daily.model.ParticipantId
import co.daily.settings.VideoProcessor

// As an optimization for larger calls, it would be possible to modify this to
// represent state updates rather than entire state snapshots. The MainActivity
Expand All @@ -23,6 +24,8 @@ data class DemoState(
val availableDevices: AvailableDevices,
val activeAudioDevice: String?,
val screenShareActive: Boolean,
val videoProcessor: VideoProcessor?,
val customAudioTrackFreqHz: Int?
) {
data class StreamsState(
val cameraEnabled: Boolean,
Expand All @@ -41,6 +44,8 @@ data class DemoState(
newAvailableDevices: AvailableDevices = availableDevices,
newActiveAudioDevice: String? = activeAudioDevice,
newScreenShareActive: Boolean = screenShareActive,
newVideoProcessor: VideoProcessor? = videoProcessor,
newCustomAudioTrackFreqHz: Int? = customAudioTrackFreqHz,
) = DemoState(
newStatus,
newInputs,
Expand All @@ -51,7 +56,9 @@ data class DemoState(
newAllParticipants,
newAvailableDevices,
newActiveAudioDevice,
newScreenShareActive
newScreenShareActive,
newVideoProcessor,
newCustomAudioTrackFreqHz
)

companion object {
Expand All @@ -70,7 +77,9 @@ data class DemoState(
audio = emptyList()
),
activeAudioDevice = null,
screenShareActive = false
screenShareActive = false,
videoProcessor = null,
customAudioTrackFreqHz = null
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import co.daily.model.CallState
import co.daily.model.MediaDeviceInfo
import co.daily.model.MeetingToken
import co.daily.model.RequestListener
import co.daily.settings.VideoProcessor
import co.daily.view.VideoView
import com.google.android.material.dialog.MaterialAlertDialogBuilder

Expand Down Expand Up @@ -350,6 +351,10 @@ class MainActivity : AppCompatActivity(), DemoStateListener {

menu.setOnMenuItemClickListener {
when (it.itemId) {
R.id.call_option_change_video_processor -> {
showMenuChangeVideoProcessor()
}

R.id.call_option_change_remote_participant -> {
showMenuChangeRemoteVideo()
}
Expand All @@ -370,6 +375,10 @@ class MainActivity : AppCompatActivity(), DemoStateListener {
startActivity(Intent(this@MainActivity, ChatActivity::class.java))
}

R.id.custom_audio_track -> {
showMenuCustomAudioTrack()
}

else -> {
throw RuntimeException("Unhandled menu item: ${it.itemId}")
}
Expand Down Expand Up @@ -408,6 +417,36 @@ class MainActivity : AppCompatActivity(), DemoStateListener {
initEventListeners()
}

private fun showMenuChangeVideoProcessor() {

data class VideoProcessorMenuChoice(val name: String, val choice: VideoProcessor)

val choices = listOf(
VideoProcessorMenuChoice(name = "Off", choice = VideoProcessor.None),
VideoProcessorMenuChoice(name = "Blur (low)", choice = VideoProcessor.BackgroundBlur(0.6)),
VideoProcessorMenuChoice(name = "Blur (high)", choice = VideoProcessor.BackgroundBlur(1.0)),
VideoProcessorMenuChoice(name = "Image: Library", choice = VideoProcessor.BackgroundImage("vb-library.jpg"))
)

val checkedItem = choices.indexOfFirst { it.choice == demoState?.videoProcessor }
.coerceAtLeast(0)

MaterialAlertDialogBuilder(this)
.setTitle(R.string.call_option_change_video_processor_title)
.setSingleChoiceItems(
choices.map { it.name }.toTypedArray(),
checkedItem
) { _, which ->
val item = choices[which]
Log.i(TAG, "Selected video processor: ${item.name}")
callService?.setVideoProcessor(item.choice)
}
.setNegativeButton("Close") { dialog, _ ->
dialog.dismiss()
}
.show()
}

private fun showMenuChangeRemoteVideo() {

data class RemoteVideoMenuChoice(val name: String, val choice: RemoteVideoChooser)
Expand Down Expand Up @@ -489,6 +528,30 @@ class MainActivity : AppCompatActivity(), DemoStateListener {
.show()
}

private fun showMenuCustomAudioTrack() {

// To demonstrate custom audio tracks, we generate a sine wave.
val choices = listOf(null, 250, 500, 1000, 2000)

val checkedItem = choices.indexOfFirst { it == demoState?.customAudioTrackFreqHz }
.coerceAtLeast(0)

MaterialAlertDialogBuilder(this)
.setTitle(R.string.custom_audio_track)
.setSingleChoiceItems(
choices.map { it?.let { "$it Hz sine" } ?: "None" }.toTypedArray(),
checkedItem
) { _, which ->
val item = choices[which]
Log.i(TAG, "Selected custom audio track: $item")
callService?.setCustomAudioTrack(item)
}
.setNegativeButton("Close") { dialog, _ ->
dialog.dismiss()
}
.show()
}

private fun showMessage(message: String) {
val layout = layoutInflater.inflate(R.layout.custom_toast, findViewById(R.id.custom_toast_id))
val toastMessage: TextView = layout.findViewById(R.id.custom_toast_message)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package co.daily.core.dailydemo.customtracks

import android.os.SystemClock
import android.util.Log
import co.daily.model.customtrack.AudioFrameFormat
import co.daily.model.customtrack.CustomAudioFrameConsumer
import co.daily.model.customtrack.CustomAudioSource
import java.util.concurrent.atomic.AtomicReference
import kotlin.concurrent.thread
import kotlin.math.roundToInt
import kotlin.math.sin

class DemoSineWaveAudioSource(private val sineFreqHz: Int) : CustomAudioSource() {

companion object {
private const val TAG = "DemoSineWaveAudioSource"
}

private val activeConsumer = AtomicReference<CustomAudioFrameConsumer?>(null)

override fun attachFrameConsumer(consumer: CustomAudioFrameConsumer) {

Log.i(TAG, "Frame consumer attached")

activeConsumer.set(consumer)

thread(priority = Thread.MAX_PRIORITY) {
val format = AudioFrameFormat(
bitsPerSample = 16,
sampleRateHz = 48000,
channelCount = 1
)

val periodMs = 50

val data = ShortArray((format.sampleRateHz * periodMs) / 1000)
var samplesRendered = 0

var targetTime = SystemClock.uptimeMillis() + periodMs

while (true) {

while (true) {

val now = SystemClock.uptimeMillis()

if (targetTime <= now) {
break
}

Thread.sleep(targetTime - now)
}

targetTime += periodMs

for (i in data.indices) {
val sampleNum = samplesRendered + i

val timeElapsedSecs = sampleNum.toDouble() / format.sampleRateHz.toDouble()

data[i] = (sin(timeElapsedSecs * 2.0 * Math.PI * sineFreqHz) * Short.MAX_VALUE.toDouble()).roundToInt()
.toShort()
}

samplesRendered += data.size

if (activeConsumer.get() != consumer) {
Log.i(TAG, "Shutting down sample audio renderer")
return@thread
}

consumer.sendFrame(format, data)
}
}
}

override fun detachFrameConsumer() {
Log.i(TAG, "Frame consumer detached")
activeConsumer.set(null)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import co.daily.core.dailydemo.DemoStateListener
import co.daily.core.dailydemo.DeveloperOptionsDialog
import co.daily.core.dailydemo.VideoTrackType
import co.daily.core.dailydemo.chat.ChatProtocol
import co.daily.core.dailydemo.customtracks.DemoSineWaveAudioSource
import co.daily.core.dailydemo.remotevideochooser.RemoteVideoChooser
import co.daily.core.dailydemo.remotevideochooser.RemoteVideoChooserAuto
import co.daily.model.AvailableDevices
Expand All @@ -27,6 +28,8 @@ import co.daily.model.ParticipantId
import co.daily.model.ParticipantLeftReason
import co.daily.model.Recipient
import co.daily.model.RequestListener
import co.daily.model.RequestResult
import co.daily.model.customtrack.CustomTrackName
import co.daily.model.livestream.LiveStreamStatus
import co.daily.model.recording.RecordingStatus
import co.daily.model.streaming.StreamId
Expand All @@ -36,6 +39,7 @@ import co.daily.settings.BitRate
import co.daily.settings.CameraInputSettingsUpdate
import co.daily.settings.CameraPublishingSettingsUpdate
import co.daily.settings.ClientSettingsUpdate
import co.daily.settings.CustomAudioTrackPublishingSettingsUpdate
import co.daily.settings.Enable
import co.daily.settings.FacingModeUpdate
import co.daily.settings.FrameRate
Expand All @@ -48,7 +52,9 @@ import co.daily.settings.VideoEncodingSettingsUpdate
import co.daily.settings.VideoEncodingsSettingsUpdate
import co.daily.settings.VideoMaxQualityUpdate
import co.daily.settings.VideoMediaTrackSettingsUpdate
import co.daily.settings.VideoProcessor
import co.daily.settings.VideoSendSettingsUpdate
import co.daily.settings.subscription.AudioSubscriptionSettingsUpdate
import co.daily.settings.subscription.MediaSubscriptionSettingsUpdate
import co.daily.settings.subscription.Subscribed
import co.daily.settings.subscription.SubscriptionProfile
Expand All @@ -68,6 +74,8 @@ private const val TAG = "CallService"

private const val ACTION_LEAVE = "action_leave"

private val CUSTOM_AUDIO_TRACK = CustomTrackName("demoCustomAudioTrack")

class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {

private val profileActiveCamera = SubscriptionProfile("activeCamera")
Expand Down Expand Up @@ -187,6 +195,18 @@ class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {
updateRemoteVideoChoice()
}

fun setVideoProcessor(videoProcessor: VideoProcessor) {
callClient?.updateInputs(
InputSettingsUpdate(
camera = CameraInputSettingsUpdate(
settings = VideoMediaTrackSettingsUpdate(
processor = videoProcessor
)
)
)
)
}

fun setAudioDevice(device: MediaDeviceInfo) {
if (Build.VERSION.SDK_INT >= 23) {
Log.i(TAG, "Setting audio device to $device")
Expand Down Expand Up @@ -225,6 +245,46 @@ class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {
callClient?.stopScreenShare()
updateServiceState { it.with(newScreenShareActive = false) }
}

fun setCustomAudioTrack(freqHz: Int?) {

val call = callClient ?: return

if (freqHz == null) {
if (state.customAudioTrackFreqHz != null) {
call.removeCustomAudioTrack(CUSTOM_AUDIO_TRACK, ::notifyIfError)
}
} else {

val source = DemoSineWaveAudioSource(sineFreqHz = freqHz)

if (state.customAudioTrackFreqHz != null) {
call.updateCustomAudioTrack(CUSTOM_AUDIO_TRACK, source, ::notifyIfError)
} else {
call.addCustomAudioTrack(CUSTOM_AUDIO_TRACK, source, ::notifyIfError)
}

call.updatePublishing(
publishSettings = PublishingSettingsUpdate(
customAudio = mapOf(
CUSTOM_AUDIO_TRACK to CustomAudioTrackPublishingSettingsUpdate(
isPublishing = Enable()
)
)
)
)
}

updateServiceState { it.with(newCustomAudioTrackFreqHz = freqHz) }
}
}

private fun notifyIfError(result: RequestResult) {
result.error?.msg?.let(::notifyError)
}

private fun notifyError(msg: String) {
listeners.forEach { it.onError(msg) }
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Expand Down Expand Up @@ -302,8 +362,9 @@ class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {
newInputs = DemoState.StreamsState(
cameraEnabled = inputSettings.camera.isEnabled,
micEnabled = inputSettings.microphone.isEnabled,
screenVideoEnabled = inputSettings.screenVideo.isEnabled
)
screenVideoEnabled = inputSettings.screenVideo.isEnabled,
),
newVideoProcessor = inputSettings.camera.settings.processor
)
}
}
Expand Down Expand Up @@ -460,6 +521,8 @@ class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {
private fun setupParticipantSubscriptionProfiles(
callClient: CallClient
) {
val customAudio = mapOf(CUSTOM_AUDIO_TRACK to AudioSubscriptionSettingsUpdate(subscriptionState = Subscribed()))

callClient.updateSubscriptionProfiles(
mapOf(
profileActiveCamera to
Expand All @@ -472,7 +535,8 @@ class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {
),
screenVideo = VideoSubscriptionSettingsUpdate(
subscriptionState = Unsubscribed()
)
),
customAudio = customAudio
),
profileActiveScreenShare to
SubscriptionProfileSettingsUpdate(
Expand All @@ -484,7 +548,8 @@ class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {
receiveSettings = VideoReceiveSettingsUpdate(
maxQuality = VideoMaxQualityUpdate.high
)
)
),
customAudio = customAudio
),
SubscriptionProfile.base to
SubscriptionProfileSettingsUpdate(
Expand All @@ -493,7 +558,8 @@ class DemoCallService : Service(), ChatProtocol.ChatProtocolListener {
),
screenVideo = VideoSubscriptionSettingsUpdate(
subscriptionState = Unsubscribed()
)
),
customAudio = customAudio
)
)
)
Expand Down
Loading
Loading