Is voice call recording back with android 10 (2019)? - android

I'm really interested in call recording in android. But as you already know android officially shuts off voice call recording in android 9. But just after the release of Android 10(sept 3 2019), while going through their new release notes, I came across the following page which looked promising, in terms of call recording.
https://developer.android.com/guide/topics/media/sharing-audio-input.
Here regarding voice call recording following things can be seen.
Voice call + ordinary app
A voice call is active if the audio mode returned by AudioManager.getMode() is MODE_IN_CALL or MODE_IN_COMMUNICATION.
Android shares the input audio according to these rules:
The call always receives audio.
The app can capture audio if it is an accessibility service.
The app can capture the voice call if it is a privileged (pre-installed) app with permission CAPTURE_AUDIO_OUTPUT.
To capture the voice call's uplink (TX), downlink (RX), or both, the app must specify the audio sources MediaRecorder.AudioSource.VOICE_UPLINK or MediaRecorder.AudioSource.VOICE_DOWNLINK, and/or the device AudioDeviceInfo.TYPE_TELEPHONY.
So after reading this I tried to capture audio inside an accessibility service. Here's my code.
Accessibility service
public class MyAccessibilityService extends AccessibilityService {
FrameLayout mLayout;
public MyAccessibilityService() {
}
#Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
}
#Override
public void onInterrupt() {
}
#Override
protected void onServiceConnected() {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.TOP;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
configureStartRecording();
configureStopRecording();
}
private void configureStartRecording() {
Button startRecordingButton = mLayout.findViewById(R.id.btnStartRecording);
startRecordingButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CustomMediaRecorder recorder = CustomMediaRecorder.getInstance();
File audiofile = null;
String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date());
File sampleDir = new File(getExternalFilesDir(null), "/TestRecordingDasa1");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
String file_name = "Record";
try {
audiofile = File.createTempFile(file_name, ".amr", sampleDir);
} catch (IOException e) {
e.printStackTrace();
}
recorder.getRecorder().setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
recorder.getRecorder().setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
recorder.getRecorder().setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.getRecorder().setOutputFile(audiofile.getAbsolutePath());
try {
recorder.getRecorder().prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start(getApplicationContext());
Log.i(MainActivity.LOG_PREFIX, String.format("Recording started. Saving to path: '%s'", audiofile.getAbsolutePath()));
}
});
}
private void configureStopRecording() {
Button button = mLayout.findViewById(R.id.btnStopRecording);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CustomMediaRecorder recorder = CustomMediaRecorder.getInstance();
recorder.stop();
}
});
}
And The accessibility service config has the following configs
android:accessibilityFeedbackType="feedbackGeneric"
android:accessibilityFlags="flagDefault"
android:canPerformGestures="true"
android:canRetrieveWindowContent="true"
So here are my observations.
1. Still we cannot set MediaRecorder.AudioSource.VOICE_DOWNLINK and VOICE_UPLINK audio sources. It fires an exception.
2. When MediaRecorder.AudioSource.VOICE_COMMUNICATION and MediaRecorder.AudioSource.MIC is given mic input prior to starting the call and after disconnecting the call is recorded.
So it looks like we are not getting any stream from the call even from an accessibility service. I tried this on a pixel 3A xl device which is newly updated to android 10.
So after reading this, and after my failed trial I have following questions...
What does this new behavior for android 10 really mean. What is the relevance here for an accessibility service? Which I tried and already failed?
Have I done anything wrong during configuring the accessibility service?
If this approach does not solve call recording issue is android 10 also missing with the call recording feature? Or is there any other way of doing it in android 10. Because I'm only interested in call recording in android 10.
In a nutshell I just want to know whether voice call recording is back with android 10...

First of all thanks for your code. I tried with the same code and I have used MediaRecorder.AudioSource.VOICE_RECOGNITION and I am getting both side call recording in Samsung S10, Oneplus 7 and Real Me.

Related

Answering a Whatsapp video call programmatically

Is there a way to auto answer whatsapp video call using AccessibilityService in Android?
OR is there a way to stimulate a click on headset's/bluetooth's call answering button? How can i get the id of the answering button?? to perform a click with accessibility service
I know that starting from Android 8.0 Oreo we have ANSWER_PHONE_CALLS permission, but for my project i want to use an old device for remote monitoring.
Any help would be appreciated!
----- Update: Thanks to the answer of Mr. hemisphire and Mr. Kahbazi, the app is able to answer the call,but needs to be a system app to work! is there any way to make it work without being a system app? without the headset's button hack?
public class AnswerCall extends AccessibilityService {
#Override
public void onAccessibilityEvent( AccessibilityEvent event )
{
if(event.getEventType() == TYPE_WINDOW_CONTENT_CHANGED)
{
if(event.getPackageName().equals("com.whatsapp"))
{
Thread thread = new Thread() {
#Override
public void run() {
try {
while(true) {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_HEADSETHOOK);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
StringBuilder sb = new StringBuilder();
List<CharSequence> texts = event.getText();
if (!texts.isEmpty())
{
for (CharSequence s : event.getText()) {
sb.append(s);
}
if(sb.toString().equals("Incoming video call"))
Log.d( "onAccessibilityEvent", "whatsapp video call" );
}
}
}
}
#Override
public void onInterrupt() {
}
}
I don't think you can do what you want. Using the AccessibilityService you can know when the video call comes in:
#Override
public void onAccessibilityEvent( AccessibilityEvent event )
{
if(event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)
{
if(event.getPackageName().equals("com.whatsapp"))
{
StringBuilder sb = new StringBuilder();
List<CharSequence> texts = event.getText();
if (!texts.isEmpty())
{
for (CharSequence s : event.getText())
{
sb.append(s);
}
if(sb.toString().equals("Incoming video call"))
{
Log.d( "onAccessibilityEvent", "whatsapp video call" );
}
}
}
}
}
However, I've never been able to answer the call programmatically. The question at How can incoming calls be answered programmatically in Android 5.0 (Lollipop)? does a great job of enumerating all possible options, but most require root and/or being a system app.
You can use sendKeyDownUpSync method from Instrumentation class.
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_HEADSETHOOK);
if this code didn't work, try to use another KeyEvent to find the correct one.
You can see the list of KeyEvent from this link : https://developer.android.com/reference/android/view/KeyEvent.html
You can check more info in from here : Instrumentation
A classic way to achieve this is to observe notifications using the NotificationListenerService and act on the relevant action of the notification.

How to use native Equalizer in the App

I am using the following code to open the Equalizer in the App.
Intent intent = new Intent( );
intent.setAction("android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL");
if (intent.resolveActivity( getActivity().getPackageManager()) != null )
{
startActivityForResult( intent , 100 );
}
else
{
JBUtils.getInstance().showCustomToast( getActivity() , R.string.equalizer_notfound);
}
And added the permission
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
After user changes the Equalizer settings how to apply equalizer settings in the currently playing audio file.We are using the Exoplayer for playing the music file.
Thanks in Advance.
Please look at this issue (closed):
https://github.com/google/ExoPlayer/issues/252
There's an interesting example about using Equalizer in ExoPlayer.
I didn't try it yet but it seems an interesting starting point to integrate standard Equalizer in ExoPlayer.
Let me know if it works!
Here is the example I would start with:
audioRenderer = new MediaCodecAudioTrackRenderer(......){
private Equalizer equalizer;
#Override
public void onAudioSessionId ( int audioSessionId){
releaseEqualizer();
equalizer = new Equalizer(...,audioSessionId);
// Configure equalizer here.
equalizer.setEnabled(true);
}
#Override
public void onDisabled () {
releaseEqualizer();
}
private void releaseEqualizer () {
if (equalizer != null) {
equalizer.release();
equalizer = null;
}
}
};
Moreover there seems to be some issue with the equalizer. You can try to enable the workaround (disabled by default) in AudioTrack, setting the following flag to true:
public static boolean enablePreV21AudioSessionWorkaround = false;
You have to provide the your package name and current Media Player audio session id as extra before starting the activity. Add the below code before calling startActivityForResult.
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, player.getAudioSessionId());
where player is an instance of MediaPlayer.

Google Cast Remote Display Sometimes Loses Video or Audio

My Android app uses the Remote Display API to cast video to the user's Cast-enabled device. Unfortunately, we have to use a proprietary video player, hence why I can't use the normal video API. This is sadly out of my control.
The app waits for the user to select a Display and launch a video. I would say that it works well approximately 50% of the time. Often, audio will cease to play while the video continues. Sometimes (but more rarely) the opposite happens- the Cast screen turns black while audio continues. And there is often audio and video skipping while the video plays, which isn't experienced when just viewing on the device.
I gather playing video over Remote Display isn't ideal, but I'd think audio and video should continue streaming throughout, especially since Remote Display was created for graphic-intensive games in-mind.
Also, the fact that audio stops when the activity is pushed into the background is a bit of a deal-breaker. Are there any plans to change this?
Here are some pieces of code that show how I'm creating the connection and starting video. Maybe I'm doing something dumb that causes it to perform poorly?
This code is called when the user selects a device from the MediaRouteChooserDialog:
#Override
public void onRouteSelected(MediaRouter router, MediaRouter.RouteInfo info) {
selectedDevice = CastDevice.getFromBundle(info.getExtras());
Intent intent = new Intent(mainActivity,
ExampleMainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("cast", true);
PendingIntent notificationPendingIntent = PendingIntent.getActivity(mainActivity, 0, intent, 0);
CastRemoteDisplayLocalService.NotificationSettings settings =
new CastRemoteDisplayLocalService.NotificationSettings.Builder()
.setNotificationPendingIntent(notificationPendingIntent).build();
CastRemoteDisplayLocalService.startService(
mainActivity,
ExamplePresentationService.class,
config.getCastId(castButton.getContext()),
selectedDevice,
settings,
new CastRemoteDisplayLocalService.Callbacks() {
#Override
public void onRemoteDisplaySessionStarted(CastRemoteDisplayLocalService service) {
Log.d(TAG, "onServiceStarted");
}
#Override
public void onRemoteDisplaySessionError(Status errorReason) {
Log.d(TAG, "onServiceError: " + errorReason.getStatusCode());
}
}
);
}
My CastRemoteDisplayLocalService creates the CastPresentation in its createPresentation method:
#TargetApi(17)
private void createPresentation(Display display) {
dismissPresentation();
mPresentation = new PresentationPlayer(this, display, castHelper, adManager);
try {
mPresentation.show();
//mMediaPlayer.start();
} catch (WindowManager.InvalidDisplayException ex) {
Log.e(TAG, "Unable to show presentation, display was removed.", ex);
dismissPresentation();
}
}
And when the user selects a video, the following code is executed in CastPresentation:
public void startVideo(VideoData data) {
FrameLayout videoBase = (FrameLayout)findViewById(R.id.cast_video_frame);
videoBase.setVisibility(View.VISIBLE);
toggleLogoScreen(false);
if (player != null) {
player.stop();
player.close();
player = null;
videoBase.setVisibility(View.VISIBLE);
}
player = CvpPlayer.create(PlayerConstants.PlayerType.NEXSTREAM, castHelper.getExampleMainActivity(), videoBase);
player.setPlayerListener(this);
player.initPlayer();
}
Any ideas are greatly appreciated.

chromecast "failed to start application: no application is running" after called startSession()

I'm testing playing online video using chromecast.
After onRouteSelected(), I create the ApplicationSession and attach a MediaProtocalMessageStream;
Then I called mSession.startSession(); with no APP_ID, so I assume the build-in app inside chromecast play the video for me. This code works perfect and I can play online mp4 videos without writing my own receiver.
But, When I try to leave the video play app, I can't go back anymore, there is always an error message comes from onSessionStartFailed() which says
StartSessionTask failed with error: failed to start application: no
application is running
I don't remember how the first time I got into the video play app, which I don't leave for few day.
But I do know how I leave it, Here is what I did before I can never startSession again:
open Youtube app, get a deviced connected
play some youtube videos
disconnected from a chormecast, then the chromecast return to the starting page
So, doesn't anybody know what's going on here? How to open the build-in video app again?
By the way, My chromecast get a system update just after I return to the starting page, I don't know if google update something cause startSession() fail.
Below is the code I startSession and attach a mediaStream.
mSession = new ApplicationSession(mCastContext, mSelectedDevice);
ApplicationSession.Listener listener = new ApplicationSession.Listener() {
#Override
public void onSessionStarted(ApplicationMetadata appMetadata) {
mChannel = mSession.getChannel();
mStream = new MediaProtocolMessageStream();
mChannel.attachMessageStream(mStream);
if (mStream.getPlayerState() == null) {
ContentMetadata metaData = new ContentMetadata();
metaData.setTitle("Test Video");
String url = "http://www.auby.no/files/video_tests/h264_720p_hp_5.1_6mbps_ac3_planet.mp4";
try {
mCommand = mStream.loadMedia(url, metaData, true);
mCommand.setListener(new MediaProtocolCommand.Listener() {
#Override
public void onCompleted(MediaProtocolCommand arg0) {
onSetVolume(0.5);
}
#Override
public void onCancelled(MediaProtocolCommand arg0) {
}
});
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onSessionStartFailed(SessionError error) {
Log.d("TEST", "Session Started failed");
}
#Override
public void onSessionEnded(SessionError error) {
Log.d("TEST", "Session Started end");
}
};
mSession.setListener(listener);
try {
mSession.startSession();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
You will have to use your own app id and own receiver. Google's default receiver doesn't play video streams anymore (it used to). It only handles Chrome tab mirroring now.

Can android directly play Dynamic HTTP streaming using flash manifest file (.f4m)

I'm trying to make an app that plays live http streaming on android (i already did the same in iphone). The Android official tutorial shows a sample code on how to do http live streaming, which i followed:
public class liveStream extends Activity implements OnClickListener {
Button streamButton;
MediaPlayer mediaPlayer = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_live_stream);
streamButton = (Button) findViewById(R.id.streamButton);
streamButton.setOnClickListener(this);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_live_stream, menu);
return true;
}
public void onClick(View v) {
String url = "http://d2233avv69kunu.cloudfront.net/hds-live/livepkgr/_definst_/liveevent/livestream.f4m";
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(url);
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
mediaPlayer.start();
}
}
thing is I keep on getting an IOException when i try to prepare the player.. I did some research and it appears that I will need to play this off a flash client from my android? If that's so, how can I play live http streaming directly without the third party flash player? Similar to iphone
Android doesn't support flash manifest file (.f4m) live streaming.
Android supported format for streaming
Most android devices from 2.3 on natively support Apple's HLS in some form or another . There are some devices where you'll need to use httplive://.../playlist.m3u8 instead up http://, but as far as I can tell, most devices support an m3u8 URL with just http, especially once you get past Android 3.0

Categories

Resources