mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-23 20:48:43 +00:00
Gain temporary audio focus during voice memo recording.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.audio;
|
package org.thoughtcrime.securesms.audio;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.media.AudioManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
@@ -25,13 +26,15 @@ public class AudioRecorder {
|
|||||||
|
|
||||||
private static final ExecutorService executor = SignalExecutors.newCachedSingleThreadExecutor("signal-AudioRecorder");
|
private static final ExecutorService executor = SignalExecutors.newCachedSingleThreadExecutor("signal-AudioRecorder");
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
|
private final AudioRecorderFocusManager audioFocusManager;
|
||||||
|
|
||||||
private Recorder recorder;
|
private Recorder recorder;
|
||||||
private Uri captureUri;
|
private Uri captureUri;
|
||||||
|
|
||||||
public AudioRecorder(@NonNull Context context) {
|
public AudioRecorder(@NonNull Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
audioFocusManager = AudioRecorderFocusManager.create(context, focusChange -> stopRecording());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startRecording() {
|
public void startRecording() {
|
||||||
@@ -52,6 +55,10 @@ public class AudioRecorder {
|
|||||||
.createForDraftAttachmentAsync(context, () -> Log.i(TAG, "Write successful."), e -> Log.w(TAG, "Error during recording", e));
|
.createForDraftAttachmentAsync(context, () -> Log.i(TAG, "Write successful."), e -> Log.w(TAG, "Error during recording", e));
|
||||||
|
|
||||||
recorder = Build.VERSION.SDK_INT >= 26 ? new MediaRecorderWrapper() : new AudioCodec();
|
recorder = Build.VERSION.SDK_INT >= 26 ? new MediaRecorderWrapper() : new AudioCodec();
|
||||||
|
int focusResult = audioFocusManager.requestAudioFocus();
|
||||||
|
if (focusResult != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
|
||||||
|
Log.w(TAG, "Could not gain audio focus. Received result code " + focusResult);
|
||||||
|
}
|
||||||
recorder.start(fds[1]);
|
recorder.start(fds[1]);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
@@ -70,6 +77,7 @@ public class AudioRecorder {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audioFocusManager.abandonAudioFocus();
|
||||||
recorder.stop();
|
recorder.stop();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package org.thoughtcrime.securesms.audio
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.media.AudioAttributes
|
||||||
|
import android.media.AudioFocusRequest
|
||||||
|
import android.media.AudioManager
|
||||||
|
import android.media.AudioManager.OnAudioFocusChangeListener
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import org.thoughtcrime.securesms.util.ServiceUtil
|
||||||
|
|
||||||
|
abstract class AudioRecorderFocusManager(val context: Context) {
|
||||||
|
protected val audioManager: AudioManager = ServiceUtil.getAudioManager(context)
|
||||||
|
|
||||||
|
abstract fun requestAudioFocus(): Int
|
||||||
|
abstract fun abandonAudioFocus(): Int
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun create(context: Context, changeListener: OnAudioFocusChangeListener): AudioRecorderFocusManager {
|
||||||
|
return if (Build.VERSION.SDK_INT >= 26) {
|
||||||
|
AudioRecorderFocusManager26(context, changeListener)
|
||||||
|
} else {
|
||||||
|
AudioRecorderFocusManagerLegacy(context, changeListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(26)
|
||||||
|
private class AudioRecorderFocusManager26(context: Context, changeListener: OnAudioFocusChangeListener) : AudioRecorderFocusManager(context) {
|
||||||
|
val audioFocusRequest: AudioFocusRequest
|
||||||
|
|
||||||
|
init {
|
||||||
|
val audioAttributes = AudioAttributes.Builder()
|
||||||
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
|
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
|
||||||
|
.build()
|
||||||
|
audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
|
||||||
|
.setAudioAttributes(audioAttributes)
|
||||||
|
.setOnAudioFocusChangeListener(changeListener)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun requestAudioFocus(): Int {
|
||||||
|
return audioManager.requestAudioFocus(audioFocusRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun abandonAudioFocus(): Int {
|
||||||
|
return audioManager.abandonAudioFocusRequest(audioFocusRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AudioRecorderFocusManagerLegacy(context: Context, val changeListener: OnAudioFocusChangeListener) : AudioRecorderFocusManager(context) {
|
||||||
|
override fun requestAudioFocus(): Int {
|
||||||
|
return audioManager.requestAudioFocus(changeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun abandonAudioFocus(): Int {
|
||||||
|
return audioManager.abandonAudioFocus(changeListener)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user