Запись экрана и звука не работает в фоновом режиме или при переключении с собственного приложения на другие приложения.Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Запись экрана и звука не работает в фоновом режиме или при переключении с собственного приложения на другие приложения.

Сообщение Anonymous »

Код: Выделить всё

public class ScreenRecordService extends Service {
private AudioManager audioManager;
private AudioManager.OnAudioFocusChangeListener afChangeListener;
private static final String TAG = "ScreenRecordService";
private long maxFileSize = NO_SPECIFIED_MAX_SIZE;
private boolean hasMaxFileBeenReached = false;
private int mScreenWidth;
private int mScreenHeight;
private int mScreenDensity;
private int mResultCode;
private Intent mResultData;
private String path;

private MediaProjection mMediaProjection;
private MediaRecorder mMediaRecorder;
private VirtualDisplay mVirtualDisplay;
private String name;
private int audioBitrate;
private int audioSamplingRate;
private static String filePath;
private static String fileName;
private int audioSourceAsInt;
private int videoEncoderAsInt;
private boolean isCustomSettingsEnabled;
private int videoFrameRate;
private int videoBitrate;
private int outputFormatAsInt;
private int orientationHint;

public final static String BUNDLED_LISTENER = "listener";
private Uri returnedUri = null;
private Intent mIntent;
private AudioDeviceCallback audioDeviceCallback;

@Override
public void onCreate() {
super.onCreate();
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
registerAudioDeviceCallback();
}

private void registerAudioDeviceCallback() {
audioDeviceCallback = new AudioDeviceCallback() {
@Override
public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
// Handle audio devices added (e.g., Bluetooth device connected)
Log.e("Issue ", "Issue onAudioDevicesAdded");
handleAudioDeviceChange();
}

@Override
public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
// Handle audio devices removed (e.g., Bluetooth device disconnected)
Log.e("Issue ", "Issue onAudioDevicesRemoved");
handleAudioDeviceChange();
}
};
audioManager.registerAudioDeviceCallback(audioDeviceCallback, null);
}

private void unregisterAudioDeviceCallback() {
audioManager.unregisterAudioDeviceCallback(audioDeviceCallback);
}

private void handleAudioDeviceChange() {
// Check if the MediaRecorder is active
if (mMediaRecorder != null) {
// Pause or resume the screen recording based on audio focus changes
int audioFocusState = audioManager.getMode();
switch (audioFocusState) {
case AudioManager.MODE_NORMAL:
// Resume recording if audio focus is regained
if (mMediaRecorder != null) {
mMediaRecorder.resume();
}
break;
default:
// Pause recording if audio focus is temporarily lost
if (mMediaRecorder != null) {
mMediaRecorder.pause();
}
break;
}
}
}

@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
boolean isAction = false;

//Check if there was an action called
if (intent != null) {
hasMaxFileBeenReached = false;
mIntent = intent;
maxFileSize = intent.getLongExtra(MAX_FILE_SIZE_KEY, NO_SPECIFIED_MAX_SIZE);
byte[] notificationSmallIcon = intent.getByteArrayExtra("notificationSmallBitmap");
int notificationSmallVector = intent.getIntExtra("notificationSmallVector", 0);
String notificationTitle = intent.getStringExtra("notificationTitle");
String notificationDescription = intent.getStringExtra("notificationDescription");
String notificationButtonText = intent.getStringExtra("notificationButtonText");
orientationHint = intent.getIntExtra("orientation", 400);
mResultCode = intent.getIntExtra("code", -1);
mResultData = intent.getParcelableExtra("data");
mScreenWidth = intent.getIntExtra("width",  0);
mScreenHeight = intent.getIntExtra("height", 0);

if (intent.getStringExtra("mUri") != null) {
returnedUri = Uri.parse(intent.getStringExtra("mUri"));
}

if (mScreenHeight == 0 || mScreenWidth == 0) {
HBRecorderCodecInfo hbRecorderCodecInfo = new HBRecorderCodecInfo();
hbRecorderCodecInfo.setContext(this);
mScreenHeight = hbRecorderCodecInfo.getMaxSupportedHeight();
mScreenWidth = hbRecorderCodecInfo.getMaxSupportedWidth();
}

mScreenDensity = intent.getIntExtra("density", 1);
path = intent.getStringExtra("path");
name = intent.getStringExtra("fileName");
String audioSource = intent.getStringExtra("audioSource");
String videoEncoder = intent.getStringExtra("videoEncoder");
videoFrameRate = intent.getIntExtra("videoFrameRate", 30);
videoBitrate = intent.getIntExtra("videoBitrate", 40000000);

if (audioSource != null) {
setAudioSourceAsInt(audioSource);
}
if (videoEncoder != null) {
setvideoEncoderAsInt(videoEncoder);
}

filePath = name;
audioBitrate = intent.getIntExtra("audioBitrate", 128000);
audioSamplingRate = intent.getIntExtra("audioSamplingRate", 44100);
String outputFormat = intent.getStringExtra("outputFormat");
if (outputFormat != null) {
setOutputFormatAsInt(outputFormat);
}

isCustomSettingsEnabled = intent.getBooleanExtra("enableCustomSettings", false);

//Set notification notification button text if developer did not
if (notificationButtonText == null) {
notificationButtonText = "STOP RECORDING";
}
//Set notification bitrate if developer did not
if (audioBitrate == 0) {
audioBitrate = 128000;
}
//Set notification sampling rate if developer did not
if (audioSamplingRate == 0) {
audioSamplingRate = 44100;
}
//Set notification title if developer did not
if (notificationTitle == null || notificationTitle.equals("")) {
notificationTitle = getString(R.string.stop_recording_notification_title);
}
//Set notification description if developer did not
if (notificationDescription == null || notificationDescription.equals("")) {
notificationDescription = getString(R.string.stop_recording_notification_message);
}

//Notification
String channelId = "001";
String channelName = "RecordChannel";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE);
channel.setLightColor(Color.BLUE);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (manager != null) {
manager.createNotificationChannel(channel);
Notification notification;

Intent myIntent = new Intent(this, NotificationReceiver.class);
PendingIntent pendingIntent;

if (Build.VERSION.SDK_INT >= 31) {
pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, PendingIntent.FLAG_IMMUTABLE);
} else {
pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);

}

Notification.Action action = new Notification.Action.Builder(
Icon.createWithResource(this, android.R.drawable.presence_video_online),
notificationButtonText,
pendingIntent).build();

if (notificationSmallIcon != null) {
Bitmap bmp = BitmapFactory.decodeByteArray(notificationSmallIcon, 0, notificationSmallIcon.length);
//Modify notification badge
notification = new Notification.Builder(getApplicationContext(),  channelId).setOngoing(true).setSmallIcon(Icon.createWithBitmap(bmp)).setContentTitle(notificationTitle).setContentText(notificationDescription).addAction(action).build();

} else if (notificationSmallVector != 0) {
notification = new Notification.Builder(getApplicationContext(), channelId).setOngoing(true).setSmallIcon(notificationSmallVector).setContentTitle(notificationTitle).setContentText(notificationDescription).addAction(action).build();
} else {
//Modify notification badge
notification = new Notification.Builder(getApplicationContext(), channelId).setOngoing(true).setSmallIcon(R.drawable.icon).setContentTitle(notificationTitle).setContentText(notificationDescription).addAction(action).build();
}
startForeground(101231, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
}

int audioRoutingMode = audioManager.getMode();

if (audioRoutingMode == AudioManager.MODE_NORMAL) {
// The device is in normal mode, which means microphone audio should not be blocked or redirected
Log.e("Issue ", "Issue Audio routing is normal.");
} else {
// There might be an issue with audio routing settings
Log.e("Issue ", "Issue Potential audio routing issue. Please check device settings.");
// You can display a message to the user informing them to check device audio settings
// For example:
Log.e("Issue ", "Issue Potential audio routing issue. Please check device audio settings.");
}
afChangeListener = focusChange -> {
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
Log.e("Issue 1", "Issue Audio focus loss transient");
// Pause recording if audio focus is temporarily lost
//pauseRecording();
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
Log.e("Issue 2", "Issue Audio focus gain");
// Resume recording if audio focus is regained
//resumeRecording();
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
Log.e("Issue 3", "Issue Audio focus loss");
AudioFocusRequest audioFocusRequest =
new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT)
.build();
audioManager.requestAudioFocus(audioFocusRequest);
// Stop recording if audio focus is permanently lost
// stopRecording();
}
};

// Request audio focus
int result = audioManager.requestAudioFocus(afChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.e("Issue 4", "Issue Audio focus granted");
// Audio focus granted, start recording
startRecording(intent);
} else {
Log.e("Issue 5", "Failed to request audio focus");
// Failed to get audio focus, stop the service
stopSelf();
}

if (returnedUri == null) {
if (path == null) {
path = String.valueOf(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES));
}
}

//Init MediaProjection
//}
} else {
stopSelf(startId);
}

return Service.START_STICKY;
}

private void startRecording(Intent intent) {
initMediaProjection();
try {
initRecorder();
} catch (Exception e) {
throw new RuntimeException(e);
}
initVirtualDisplay();

/*  mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
@Override
public void onError(MediaRecorder mediaRecorder, int what, int extra) {
if (what == 268435556 && hasMaxFileBeenReached) {
// Benign error b/c recording is too short and has no frames.  See SO: https://stackoverflow.com/questions/40616466/mediarecorder-stop-failed-1007
return;
}
ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putInt(ERROR_KEY, SETTINGS_ERROR);
bundle.putString(ERROR_REASON_KEY, String.valueOf(what));
if (receiver != null) {
receiver.send(Activity.RESULT_OK, bundle);
}
}
});*/

/* mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
hasMaxFileBeenReached = true;
Log.i(TAG, String.format(Locale.US, "onInfoListen what :  %d | extra %d", what, extra));
ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putInt(ERROR_KEY, MAX_FILE_SIZE_REACHED_ERROR);
bundle.putString(ERROR_REASON_KEY, getString(R.string.max_file_reached));
if (receiver != null) {
receiver.send(Activity.RESULT_OK, bundle);
}
}
}
});*/

//Start Recording
try {
Log.e("Issue 5", "Issue Record start ended");
mMediaRecorder.start();
ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putInt(ON_START_KEY, ON_START);
if (receiver != null) {
receiver.send(Activity.RESULT_OK, bundle);
}
Log.e("Issue 5", "Issue Record start ended");
} catch (Exception e) {
// From the tests I've done, this can happen if another application is using the mic or if an unsupported video encoder was selected
ResultReceiver receiver = intent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putInt(ERROR_KEY, SETTINGS_ERROR);
bundle.putString(ERROR_REASON_KEY, Log.getStackTraceString(e));
if (receiver != null) {
receiver.send(Activity.RESULT_OK, bundle);
}
}
}

/*    //Pause Recording
private void pauseRecording() {
mMediaRecorder.pause();
ResultReceiver receiver = mIntent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putString(ON_PAUSE_KEY, ON_PAUSE);
if (receiver != null) {
receiver.send(Activity.RESULT_OK, bundle);
}
}*/

/*    //Resume Recording
private void resumeRecording() {
mMediaRecorder.resume();
ResultReceiver receiver = mIntent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putString(ON_RESUME_KEY, ON_RESUME);
if (receiver != null) {
receiver.send(Activity.RESULT_OK,  bundle);
}
}*/

//Set output format as int based on what developer has provided
//It is important to provide one of the following and nothing else.
private void setOutputFormatAsInt(String outputFormat) {
switch (outputFormat) {
case "DEFAULT":
outputFormatAsInt = 0;
break;
case "THREE_GPP":
outputFormatAsInt = 1;
break;
case "AMR_NB":
outputFormatAsInt = 3;
break;
case "AMR_WB":
outputFormatAsInt = 4;
break;
case "AAC_ADTS":
outputFormatAsInt = 6;
break;
case "MPEG_2_TS":
outputFormatAsInt = 8;
break;
case "WEBM":
outputFormatAsInt = 9;
break;
case "OGG":
outputFormatAsInt = 11;
break;
case "MPEG_4":
default:
outputFormatAsInt = 2;
}
}

//Set video encoder as int based on what developer has provided
//It is important to provide one of the following and nothing else.
private void setvideoEncoderAsInt(String encoder) {
switch (encoder) {
case "DEFAULT":
videoEncoderAsInt = 0;
break;
case "H263":
videoEncoderAsInt = 1;
break;
case "H264":
videoEncoderAsInt = 2;
break;
case "MPEG_4_SP":
videoEncoderAsInt = 3;
break;
case "VP8":
videoEncoderAsInt = 4;
break;
case "HEVC":
videoEncoderAsInt = 5;
break;
}
}

//Set audio source as int based on what developer has provided
//It is important to provide one of the following and nothing else.
private void setAudioSourceAsInt(String audioSource) {
switch (audioSource) {
case "DEFAULT":
audioSourceAsInt = 0;
break;
case "MIC":
audioSourceAsInt = 1;
break;
case "VOICE_UPLINK":
audioSourceAsInt = 2;
break;
case "VOICE_DOWNLINK":
audioSourceAsInt = 3;
break;
case "VOICE_CALL":
audioSourceAsInt = 4;
break;
case "CAMCODER":
audioSourceAsInt = 5;
break;
case "VOICE_RECOGNITION":
audioSourceAsInt = 6;
break;
case "VOICE_COMMUNICATION":
audioSourceAsInt = 7;
break;
case "REMOTE_SUBMIX":
audioSourceAsInt = 8;
break;
case "UNPROCESSED":
audioSourceAsInt = 9;
break;
case "VOICE_PERFORMANCE":
audioSourceAsInt = 10;
break;
}
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private void initMediaProjection() {
mMediaProjection = ((MediaProjectionManager) Objects.requireNonNull(getSystemService(Context.MEDIA_PROJECTION_SERVICE))).getMediaProjection(mResultCode, mResultData);
Handler handler = new Handler(Looper.getMainLooper());
mMediaProjection.registerCallback(new MediaProjection.Callback() {
// Nothing
// We don't use it but register it to avoid runtime error from SDK 34+.
}, handler);
}

//Return the output file path as string
public static String getFilePath() {
return filePath;
}

//Return the name of the output file
public static String getFileName() {
return fileName;
}

private void initRecorder() throws Exception {
Log.e("Issue 5",  "Issue Record started");
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
Date curDate = new Date(System.currentTimeMillis());
String curTime = formatter.format(curDate).replace(" ", "");
String videoQuality = "HD";
if (name == null) {
name = videoQuality + curTime;
}

filePath = path + "/" + name + ".mp4";

fileName = name + ".mp4";

mMediaRecorder = new MediaRecorder();

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

if (orientationHint != 400) {
mMediaRecorder.setOrientationHint(orientationHint);
}

//if (isAudioEnabled) {
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.setAudioEncodingBitRate(audioBitrate);
mMediaRecorder.setAudioSamplingRate(audioSamplingRate);
//}

mMediaRecorder.setVideoEncoder(videoEncoderAsInt);

if (returnedUri != null) {
try {
ContentResolver contentResolver = getContentResolver();
FileDescriptor inputPFD = Objects.requireNonNull(contentResolver.openFileDescriptor(returnedUri, "rw")).getFileDescriptor();
mMediaRecorder.setOutputFile(inputPFD);
} catch (Exception e) {
ResultReceiver receiver = mIntent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putString(ERROR_REASON_KEY, Log.getStackTraceString(e));
if (receiver != null) {
receiver.send(Activity.RESULT_OK, bundle);
}
}
} else {
mMediaRecorder.setOutputFile(filePath);
}
mMediaRecorder.setVideoSize(mScreenWidth, mScreenHeight);

if (!isCustomSettingsEnabled) {
mMediaRecorder.setVideoEncodingBitRate(5 * mScreenWidth * mScreenHeight);
mMediaRecorder.setVideoFrameRate(60); //after setVideoSource(), setOutFormat()
} else {
mMediaRecorder.setVideoEncodingBitRate(videoBitrate);
mMediaRecorder.setVideoFrameRate(videoFrameRate);
}

// Catch approaching file limit
if (maxFileSize > NO_SPECIFIED_MAX_SIZE) {
mMediaRecorder.setMaxFileSize(maxFileSize); // in bytes
}

mMediaRecorder.prepare();
Log.e("Issue 5", "Issue Record Prepare");
}

private void initVirtualDisplay() {

Log.e("Issue : ", ""  + mMediaRecorder.getSurface());
mVirtualDisplay = mMediaProjection.createVirtualDisplay(TAG, mScreenWidth, mScreenHeight, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
}

@Override
public void onDestroy() {
super.onDestroy();
resetAll();
callOnComplete();

}

private void callOnComplete() {
if (mIntent != null) {
ResultReceiver receiver = mIntent.getParcelableExtra(ScreenRecordService.BUNDLED_LISTENER);
Bundle bundle = new Bundle();
bundle.putString(ON_COMPLETE_KEY, ON_COMPLETE);
if (receiver != null) {
receiver.send(Activity.RESULT_OK, bundle);
}
}
}

private void resetAll() {
stopForeground(true);
if (mVirtualDisplay != null) {
mVirtualDisplay.release();
mVirtualDisplay = null;
}
if (mMediaRecorder != null) {
mMediaRecorder.setOnErrorListener(null);
mMediaRecorder.reset();
}
if (mMediaProjection != null) {
mMediaProjection.stop();
mMediaProjection = null;
}
}

@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Запись экрана и звука не работает в фоновом режиме или при переключении с собственного приложения на другие приложения.
Я пробовал использовать API захвата воспроизведения звука, но не повезло.
Он работает в Android 11 и более ранних версиях, но выше 11 не может записывать звук.

Аудио источник для смеси аудиопотоков, которые будут представлены удаленно.
Приложение может использовать этот источник звука для захвата смеси аудиопотоков, которая должна быть передана на удаленный приемник, например, на дисплей Wi-Fi. . Пока запись активна, эти аудиопотоки перенаправляются в удаленный субмикс, а не воспроизводятся на динамике устройства или гарнитуре.
Определенные потоки исключаются из удаленного субмикса, включая AudioManager#STREAM_RING, AudioManager#STREAM_ALARM и AudioManager#STREAM_NOTIFICATION. Эти потоки будут по-прежнему отображаться локально, как обычно.
Для захвата удаленного аудио субмикса требуется разрешение Manifest.permission.CAPTURE_AUDIO_OUTPUT. Это разрешение зарезервировано для использования системными компонентами и недоступно сторонним приложениям.
Требуется Manifest.permission.CAPTURE_AUDIO_OUTPUT


Подробнее здесь: https://stackoverflow.com/questions/785 ... itching-fr
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»