Skip to content

Commit

Permalink
Merge pull request #1581 from pedroSG94/refactor/sources
Browse files Browse the repository at this point in the history
Refactor/sources
  • Loading branch information
pedroSG94 authored Sep 16, 2024
2 parents fb5b490 + 9cc8a61 commit 9a22578
Show file tree
Hide file tree
Showing 41 changed files with 328 additions and 102 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ allprojects {
}
dependencies {
implementation 'com.github.pedroSG94.RootEncoder:library:2.5.0'
//Optional, allow use BitmapSource, CameraXSource and CameraUvcSource
implementation 'com.github.pedroSG94.RootEncoder:extra-sources:2.5.0'
}
```
Expand All @@ -76,6 +78,7 @@ dependencies {
## Features:

- [x] Android min API 16.
- [x] Extra video sources minAPI 21+ (BitmapSource, CameraXSource and CameraUvcSource)

### Encoder:

Expand Down Expand Up @@ -135,8 +138,6 @@ https://haivision.github.io/srt-rfc/draft-sharabayko-srt.html

https://github.com/pedroSG94/RTSP-Server

[Support UVC camera (use rotation example and change the video source on fly using the menu):](https://github.com/pedroSG94/RootEncoder/tree/feature/usb-camera)

### 3rd party projects:

Projects related with the library developed by other users.
Expand Down
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ android {

dependencies {
implementation(project(":library"))
implementation(project(":extra-sources"))
implementation(libs.androidx.constraintlayout)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.multidex)
implementation(libs.bundles.androidx.camera)
}
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION"/>

<!-- This is only to allow compile extra-sources modules in app with min version 16. Never do it-->
<uses-sdk tools:overrideLibrary="com.pedro.extrasources,com.serenegiant.uvccamera,androidx.core.ktx,androidx.core,androidx.annotation.experimental"/>

<application
android:name=".App"
android:requestLegacyExternalStorage="true"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ import androidx.fragment.app.Fragment
import com.pedro.common.ConnectChecker
import com.pedro.library.base.recording.RecordController
import com.pedro.library.generic.GenericStream
import com.pedro.library.util.sources.video.Camera1Source
import com.pedro.library.util.sources.video.Camera2Source
import com.pedro.encoder.input.sources.video.Camera1Source
import com.pedro.encoder.input.sources.video.Camera2Source
import com.pedro.extrasources.CameraXSource
import com.pedro.streamer.R
import com.pedro.streamer.utils.PathUtils
import com.pedro.streamer.utils.toast
Expand Down
32 changes: 29 additions & 3 deletions app/src/main/java/com/pedro/streamer/rotation/RotationActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ import android.view.View
import android.view.View.OnTouchListener
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import com.pedro.library.util.sources.audio.MicrophoneSource
import com.pedro.library.util.sources.video.Camera1Source
import com.pedro.library.util.sources.video.Camera2Source
import com.pedro.encoder.input.sources.audio.MicrophoneSource
import com.pedro.encoder.input.sources.video.Camera1Source
import com.pedro.encoder.input.sources.video.Camera2Source
import com.pedro.encoder.input.video.CameraHelper
import com.pedro.extrasources.BitmapSource
import com.pedro.extrasources.CameraUvcSource
import com.pedro.extrasources.CameraXSource
import com.pedro.streamer.R
import com.pedro.streamer.utils.FilterMenu
import com.pedro.streamer.utils.toast
Expand Down Expand Up @@ -74,19 +78,28 @@ class RotationActivity : AppCompatActivity(), OnTouchListener {
R.id.video_source_camera1 -> {
currentVideoSource = item.updateMenuColor(this, currentVideoSource)
cameraFragment.genericStream.changeVideoSource(Camera1Source(applicationContext))
updateOrientation(false)
}
R.id.video_source_camera2 -> {
currentVideoSource = item.updateMenuColor(this, currentVideoSource)
cameraFragment.genericStream.changeVideoSource(Camera2Source(applicationContext))
updateOrientation(false)
}
R.id.video_source_camerax -> {
currentVideoSource = item.updateMenuColor(this, currentVideoSource)
cameraFragment.genericStream.changeVideoSource(CameraXSource(applicationContext))
updateOrientation(false)
}
R.id.video_source_camera_uvc -> {
currentVideoSource = item.updateMenuColor(this, currentVideoSource)
cameraFragment.genericStream.changeVideoSource(CameraUvcSource())
updateOrientation(true)
}
R.id.video_source_bitmap -> {
currentVideoSource = item.updateMenuColor(this, currentVideoSource)
val bitmap = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
cameraFragment.genericStream.changeVideoSource(BitmapSource(bitmap))
updateOrientation(false)
}
R.id.audio_source_microphone -> {
currentAudioSource = item.updateMenuColor(this, currentAudioSource)
Expand Down Expand Up @@ -121,4 +134,17 @@ class RotationActivity : AppCompatActivity(), OnTouchListener {
}
return false
}

private fun updateOrientation(isUvc: Boolean) {
//UVC cameras can't adapt orientation depend of the device orientation so we need force use always landscape orientations
if (isUvc) {
cameraFragment.genericStream.getGlInterface().autoHandleOrientation = false
cameraFragment.genericStream.getGlInterface().setCameraOrientation(0)
} else { //Reset orientation to the correct orientation depend of device orientation
cameraFragment.genericStream.getGlInterface().autoHandleOrientation = true
val orientation = CameraHelper.getCameraOrientation(this)
cameraFragment.genericStream.getGlInterface().setCameraOrientation(if (orientation == 0) 270 else orientation - 90)
cameraFragment.genericStream.getGlInterface().setIsPortrait(CameraHelper.isPortrait(this))
}
}
}
6 changes: 3 additions & 3 deletions app/src/main/java/com/pedro/streamer/screen/ScreenActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import com.pedro.common.ConnectChecker
import com.pedro.library.base.recording.RecordController
import com.pedro.library.util.sources.audio.MixAudioSource
import com.pedro.library.util.sources.audio.InternalAudioSource
import com.pedro.library.util.sources.audio.MicrophoneSource
import com.pedro.encoder.input.sources.audio.MixAudioSource
import com.pedro.encoder.input.sources.audio.InternalAudioSource
import com.pedro.encoder.input.sources.audio.MicrophoneSource
import com.pedro.streamer.R
import com.pedro.streamer.utils.toast
import com.pedro.streamer.utils.updateMenuColor
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/java/com/pedro/streamer/screen/ScreenService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ import androidx.core.app.NotificationCompat
import com.pedro.common.ConnectChecker
import com.pedro.library.base.recording.RecordController
import com.pedro.library.generic.GenericStream
import com.pedro.library.util.sources.audio.MixAudioSource
import com.pedro.library.util.sources.audio.AudioSource
import com.pedro.library.util.sources.audio.InternalAudioSource
import com.pedro.library.util.sources.audio.MicrophoneSource
import com.pedro.library.util.sources.video.NoVideoSource
import com.pedro.library.util.sources.video.ScreenSource
import com.pedro.encoder.input.sources.audio.MixAudioSource
import com.pedro.encoder.input.sources.audio.AudioSource
import com.pedro.encoder.input.sources.audio.InternalAudioSource
import com.pedro.encoder.input.sources.audio.MicrophoneSource
import com.pedro.encoder.input.sources.video.NoVideoSource
import com.pedro.encoder.input.sources.video.ScreenSource
import com.pedro.streamer.R
import com.pedro.streamer.utils.PathUtils
import com.pedro.streamer.utils.toast
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/menu/rotation_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
android:title="@string/camerax"
android:id="@+id/video_source_camerax"
/>
<item
android:title="@string/camera_uvc"
android:id="@+id/video_source_camera_uvc"
/>
<item
android:title="@string/bitmap"
android:id="@+id/video_source_bitmap"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<string name="camera1">Camera1</string>
<string name="camera2">Camera2</string>
<string name="camerax">CameraX</string>
<string name="camera_uvc">CameraUVC</string>
<string name="bitmap">Bitmap</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
<div class="sidebar--inner" id="sideMenu"></div>
</div>
<div id="main">
<div class="main-content" data-page-type="member" id="content" pageids="library::com.pedro.library.view/GlStreamInterface/forceOrientation/#com.pedro.library.view.OrientationForced/PointingToDeclaration//794302154">
<div class="main-content" data-page-type="member" id="content" pageids="library::com.pedro.library.view/GlStreamInterface/forceOrientation/#com.pedro.encoder.input.sources.OrientationForced/PointingToDeclaration//794302154">
<div class="breadcrumbs"><a href="../../index.html">library</a><span class="delimiter">/</span><a href="../index.html">com.pedro.library.view</a><span class="delimiter">/</span><a href="index.html">GlStreamInterface</a><span class="delimiter">/</span><span class="current">forceOrientation</span></div>
<div class="cover ">
<h1 class="cover"><span>force</span><wbr><span><span>Orientation</span></span></h1>
Expand Down
1 change: 1 addition & 0 deletions encoder/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ afterEvaluate {
}

dependencies {
implementation(libs.kotlinx.coroutines.android)
testImplementation(libs.junit)
api(libs.androidx.annotation)
api(project(":common"))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.pedro.library.util.sources
package com.pedro.encoder.input.sources

import android.media.projection.MediaProjection

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.view
package com.pedro.encoder.input.sources

/**
* Created by pedro on 16/2/24.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.util.sources.audio
package com.pedro.encoder.input.sources.audio

import android.content.Context
import android.media.AudioFormat
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.util.sources.audio
package com.pedro.encoder.input.sources.audio

import com.pedro.encoder.input.audio.GetMicrophoneData

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.util.sources.audio
package com.pedro.encoder.input.sources.audio

import android.media.AudioAttributes
import android.media.AudioPlaybackCaptureConfiguration
Expand All @@ -28,7 +28,7 @@ import com.pedro.encoder.input.audio.CustomAudioEffect
import com.pedro.encoder.input.audio.GetMicrophoneData
import com.pedro.encoder.input.audio.MicrophoneManager
import com.pedro.encoder.input.audio.VolumeEffect
import com.pedro.library.util.sources.MediaProjectionHandler
import com.pedro.encoder.input.sources.MediaProjectionHandler

/**
* Created by pedro on 12/1/24.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.util.sources.audio
package com.pedro.encoder.input.sources.audio

import android.media.AudioDeviceInfo
import android.media.MediaRecorder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
*
*/

package com.pedro.library.util.sources.audio
package com.pedro.encoder.input.sources.audio

import android.media.AudioDeviceInfo
import android.media.MediaRecorder
import android.media.projection.MediaProjection
import android.os.Build
import androidx.annotation.RequiresApi
Expand Down Expand Up @@ -45,21 +47,31 @@ import java.util.concurrent.TimeUnit
* This is to avoid echo in microphone track.
*
* Recommended increase microphone volume to 2f,
* because the internal audio normally is higher and you can't hear audio track properly
* because the internal audio normally is higher and you can't hear audio track properly.
*
* Tested in 2 devices (Android 12 and Android 14). This could change depend of the model or not, I'm not sure:
* MediaRecorder.AudioSource.DEFAULT, MediaRecorder.AudioSource.MIC -> If other app open the microphone you receive buffers with silence from the microphone until the other app release the microphone (maybe you need close the app).
* MediaRecorder.AudioSource.CAMCORDER -> Block the access to microphone to others apps. Others apps can't instantiate the microphone.
* MediaRecorder.AudioSource.VOICE_COMMUNICATION -> Block the access to microphone to others apps. Others apps can instantiate the microphone but receive buffers with silence from the microphone.
*/
@RequiresApi(Build.VERSION_CODES.Q)
class MixAudioSource(
mediaProjection: MediaProjection
mediaProjection: MediaProjection,
microphoneAudioSource: Int = MediaRecorder.AudioSource.DEFAULT
): AudioSource() {

private val microphoneVolumeEffect = VolumeEffect()
private val internalVolumeEffect = VolumeEffect()
private val microphone = MicrophoneSource().apply { setAudioEffect(microphoneVolumeEffect) }
private val internal = InternalAudioSource(mediaProjection).apply { setAudioEffect(internalVolumeEffect) }
private val microphone = MicrophoneSource(audioSource = microphoneAudioSource).apply {
setAudioEffect(microphoneVolumeEffect)
}
private val internal = InternalAudioSource(mediaProjection).apply {
setAudioEffect(internalVolumeEffect)
}

private val scope = CoroutineScope(Dispatchers.IO)
private val microphoneQueue: BlockingQueue<Frame> = LinkedBlockingQueue(500)
private val internalQueue: BlockingQueue<Frame> = LinkedBlockingQueue(500)
private val microphoneQueue: BlockingQueue<Frame> = LinkedBlockingQueue(2)
private val internalQueue: BlockingQueue<Frame> = LinkedBlockingQueue(2)
private var running = false
//We need read with a higher buffer to get enough time to mix it
private val inputSize = AudioEncoder.inputSize
Expand All @@ -73,26 +85,26 @@ class MixAudioSource(
if (!isRunning()) {
microphoneQueue.clear()
internalQueue.clear()
microphone.start(callback1)
internal.start(callback2)
microphone.start(microphoneCallback)
internal.start(internalCallback)
running = true
scope.launch {
val min = Byte.MIN_VALUE.toInt()
val max = Byte.MAX_VALUE.toInt()

while (running) {
runCatching {
val frame1 = async { runInterruptible { microphoneQueue.poll(1, TimeUnit.SECONDS) } }
val frame2 = async { runInterruptible { internalQueue.poll(1, TimeUnit.SECONDS) } }
val r = awaitAll(frame1, frame2)
val microphoneFrame = async { runInterruptible { microphoneQueue.poll(1, TimeUnit.SECONDS) } }
val internalFrame = async { runInterruptible { internalQueue.poll(1, TimeUnit.SECONDS) } }
val result = awaitAll(microphoneFrame, internalFrame)
async {
val microphoneBuffer = r[0]?.buffer ?: return@async
val internalBuffer = r[1]?.buffer ?: return@async
val microphoneBuffer = result[0]?.buffer ?: return@async
val internalBuffer = result[1]?.buffer ?: return@async
val mixBuffer = ByteArray(inputSize)
for (i in mixBuffer.indices) { //mix buffers with same config
mixBuffer[i] = (microphoneBuffer[i] + internalBuffer[i]).coerceIn(min, max).toByte()
}
getMicrophoneData.inputPCMData(Frame(mixBuffer, 0, mixBuffer.size, r[0].timeStamp))
getMicrophoneData.inputPCMData(Frame(mixBuffer, 0, mixBuffer.size, result[0].timeStamp))
}
}.exceptionOrNull()
}
Expand All @@ -116,13 +128,13 @@ class MixAudioSource(

override fun isRunning(): Boolean = running

private val callback1 = object: GetMicrophoneData {
private val microphoneCallback = object: GetMicrophoneData {
override fun inputPCMData(frame: Frame) {
microphoneQueue.trySend(frame)
}
}

private val callback2 = object: GetMicrophoneData {
private val internalCallback = object: GetMicrophoneData {
override fun inputPCMData(frame: Frame) {
internalQueue.trySend(frame)
}
Expand Down Expand Up @@ -155,4 +167,8 @@ class MixAudioSource(
}

fun isInternalAudioMuted(): Boolean = internal.isMuted()

fun setMicrophonePreferredDevice(deviceInfo: AudioDeviceInfo?) {
microphone.setPreferredDevice(deviceInfo)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.util.sources.audio
package com.pedro.encoder.input.sources.audio

import android.os.Build
import androidx.annotation.RequiresApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

@file:Suppress("DEPRECATION")

package com.pedro.library.util.sources.video
package com.pedro.encoder.input.sources.video

import android.content.Context
import android.graphics.SurfaceTexture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.util.sources.video
package com.pedro.encoder.input.sources.video

import android.content.Context
import android.graphics.SurfaceTexture
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.pedro.library.util.sources.video
package com.pedro.encoder.input.sources.video

import android.graphics.SurfaceTexture
import android.os.Build
Expand Down
Loading

0 comments on commit 9a22578

Please sign in to comment.