I am trying to implemented the VoIP application using the AudioGroup and AudioStream classes of the android.net.rtp package. But my application not function properly. After "Join" the "AudioGroup" class object with the "AudioStream" object, its send udp packets successfully. I checked that using the packet analyzer. But voice is not hear from the phone. I run my application in 2 phones and try communicate voice between them.
In below I mention my source code.
public class MainActivity extends Activity {
private AudioStream audioStream;
private AudioGroup audioGroup;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
audioGroup = new AudioGroup();
audioGroup.setMode(AudioGroup.MODE_NORMAL);
audioStream = new AudioStream(InetAddress.getByAddress(new byte[] {(byte)192, (byte)168, (byte)1, (byte)4 }));
audioStream.setCodec(AudioCodec.PCMU);
audioStream.setMode(RtpStream.MODE_NORMAL);
audioStream.associate(InetAddress.getByAddress(new byte[] {(byte)192, (byte)168, (byte)1, (byte)2 }), 5004);
audioStream.join(audioGroup);
AudioManager Audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
Audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
}
catch (SocketException e) { e.printStackTrace();}
catch (UnknownHostException e) { e.printStackTrace();}
catch (Exception ex) { ex.printStackTrace();}
}
I set this permissions in the Manifestfile.
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.sip.voip" android:required="true" />
<uses-feature android:name="android.hardware.wifi" android:required="true" />
<uses-feature android:name="android.hardware.microphone" android:required="true" />
I am using the Samsung GALAXY S3 phone with Android 4.0 OS
The trick is to get the port mapping correct. You need to use the port number from audioStream.getLocalPort() and send this port number to the peer in the SDP packet as SIP signalling.
Check out this example application which implements sip functionality
https://github.com/Mobicents/restcomm-android-sdk/tree/master/Examples/JAIN%20SIP
I used the same code you submitted, and got it working with minor changes. Basically i found the problem was getting the port number correct.
When creating the audioStream the port number seems to be random. At Android developer I found: Note that the local port is assigned automatically to conform with RFC 3550.
What I did was I started the application on one phone first and used audioStream.getLocalPort() to find the port number. Then I connected to this port using the other one. This resulted in two-way communication, even if i only had the correct port number on one phone.
Hope this helps.
I think you should set the speaker on!
Maybe you can use the following method:
audioManager.setSpeakerphoneOn(true);
Related
I am currently working on building a System app for android and what the app basically does is running some audio processing on Call Audio. I'm using the Azure Speech SDK for speech transcription. However I'm facing issues while using the AudioRecord API for accessing the audio stream. I'm aware of the security restrictions on android regarding call audio access, and the fact that only System apps are now eligible to do that.
Problems faced -
I want to use the VOICE_CALL audio source but using this source is throwing error Invalid capture preset 4 for AudioAttributes
Digging further I found that the AudioAttributes.java class is preventing the access to this given audio source. Reference - Android Recording Call parameters
Using the MediaRecorder API for the same is also giving error java.lang.RuntimeException: start failed.
The Setup -
Rooted Android device [Motorola G4 plus and Realme Narzo 20A]
App converted to System app by placing the APK inside the system/app directory (Alternatively also tried out placing inside system/priv-app)
Permissions granted -
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
Code -
You can find the code in this repository : https://github.com/ashishpatel16/RealtimeCallTranscription (It was made for reporting problems in the Azure speech SDK but the setup is exactly the same)
CustomAudioStream.java
public class CustomAudioStream extends PullAudioInputStreamCallback {
private final static int SAMPLE_RATE = 16000;
private final AudioStreamFormat format;
private AudioRecord recorder;
private static final String TAG = "CustomAudioStream";
MediaRecorder mRecorder;
private Context context;
public CustomAudioStream(Context context) {
this.format = AudioStreamFormat.getWaveFormatPCM(SAMPLE_RATE, (short)16, (short)1);
this.context = context;
this.initMic();
}
public AudioStreamFormat getFormat() {
return this.format;
}
#Override
public int read(byte[] bytes) {
long ret = this.recorder.read(bytes, 0, bytes.length);
return (int)ret;
}
#Override
public void close() {
this.recorder.release();
this.recorder = null;
}
private void initMic() {
AudioFormat audioFormat = new AudioFormat.Builder()
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.setSampleRate(SAMPLE_RATE)
.setChannelMask(AudioFormat.CHANNEL_IN_MONO)
.build();
this.recorder = new AudioRecord.Builder()
.setAudioFormat(audioFormat)
.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL)
.setBufferSizeInBytes(2048)
.build();
this.recorder.startRecording();
}
}
Questions -
Is there any alternate method to access call audio stream on rooted device?
I could technically build a custom android AOSP from source and modify the AudioAttributes.java class and flash it to the android device but that's a lot of effort. Do I have to do this? Can I achieve this in an easier way?
I am skeptical whether the CAPTURE_AUDIO_OUTPUT permission is granted or not. Are there any more steps involved in gaining these permissions on rooted device?
I am using this code to get MAC ADDRESS and display it in my app. The code works fine for all devices except most latest devices and ANDROID BOX.
it shows null for ANDROID BOX and other latest device.
Here is code:
public static String getWifiMacAddress() {
try {
String interfaceName = "wlan0";
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces) {
if (!intf.getName().equalsIgnoreCase(interfaceName)){
continue;
}
byte[] mac = intf.getHardwareAddress();
if (mac==null){
return "";
}
StringBuilder buf = new StringBuilder();
for (byte aMac : mac) {
buf.append(String.format("%02X:", aMac));
}
if (buf.length()>0) {
buf.deleteCharAt(buf.length() - 1);
}
return buf.toString();
}
} catch (Exception ex) { } // for now eat exceptions
return "";
}
I have written these permissions in manifest file
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
Firstly u will check the permission is granted or not?
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiInfo wInfo = wifiManager.getConnectionInfo();
String macAddress = wInfo.getMacAddress();
Also, add below permission in your manifest file
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
Please refer this link for 6.0 marshmalow
First you will need to add Internet user permission in AndroidManifest.xml.
<uses-permission android:name="android.permission.INTERNET" />
and then Refer this to get mac address: http://robinhenniges.com/en/android6-get-mac-address-programmatically
And if it doesn't works then refer this Android 6.0 changes
from this i have concluded that,
To provide users with greater data protection, starting in this
release, Android removes programmatic access to the device’s local
hardware identifier for apps using the Wi-Fi and Bluetooth APIs. The
WifiInfo.getMacAddress() and the BluetoothAdapter.getAddress() methods
now return a constant value of 02:00:00:00:00:00.
To access the hardware identifiers of nearby external devices via
Bluetooth and Wi-Fi scans, your app must now have the
ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permissions.
Note That : you can't get your own MACs even having those permissions. Read carefully, It is said that you can get other devices MACs having those permissions, but not your own.
As in 6.0 and above adding permission in Manifest alone wont work. You should have runtime permission and grant it if not granted.
Check this link:
https://stackoverflow.com/a/30549756/3910281
I'm trying to show WebRTC chat in WebView.
According to this documentation, WebView v36 supports WebRTC. For my test I'm using a device with Chrome/39.0.0.0 and I have added permissions to the AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<user-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
but when I enter into the chat, I see a Chromium error log (device doesn't show \ translate anything, only 'loading' progress bar):
W/AudioManagerAndroid: Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO
W/AudioManagerAndroid: No audio device will be available for recording
E/chromium: [ERROR:web_contents_delegate.cc(178)] WebContentsDelegate::CheckMediaAccessPermission: Not supported.
E/chromium: [ERROR:web_contents_delegate.cc(178)] WebContentsDelegate::CheckMediaAccessPermission: Not supported.
W/AudioManagerAndroid: Requires MODIFY_AUDIO_SETTINGS and RECORD_AUDIO
W/AudioManagerAndroid: No audio device will be available for recording
D/ChromiumCameraInfo: Camera enumerated: front
Tested on a real device, Android 5.1.1.
additional request for permissions is needed
webView.setWebChromeClient(new WebChromeClient(){
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public void onPermissionRequest(final PermissionRequest request) {
request.grant(request.getResources());
}
});
update but it not working for audio capture
UPDATE found working google-sample code here
You need these permissions to access Camera and Microphone
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="true"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
// don't miss this one
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
Next you need to grant permissions to your webview, check this link for more details:
webView.setWebChromeClient(new WebChromeClient(){
#Override
public void onPermissionRequest(PermissionRequest request) {
runOnUiThread(() -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
String[] PERMISSIONS = {
PermissionRequest.RESOURCE_AUDIO_CAPTURE,
PermissionRequest.RESOURCE_VIDEO_CAPTURE
};
request.grant(PERMISSIONS);
}
});
}
});
If audio playback is not working, use this:
webView.getSettings().setMediaPlaybackRequiresUserGesture(false);
My experience with this in 2022:
CAMERA and RECORD_AUDIO permissions need to be declared in Manifest
setWebChromeClient.onPermissionRequest should check if those permissions have already been granted. If not, use registerForActivityResult(new RequestMultiplePermissions()) to ask the user to grant them.
its mostly error in webview reload becuase when we will request for audio , camera permission on webview , after accept permission , we need to refresh the webpage.
if (permission.equals("android.webkit.resource.AUDIO_CAPTURE")) {
demandForPermission(request.getOrigin().toString(), Manifest.permission.RECORD_AUDIO, MY_PERMISSIONS_REQUEST_RECORD_AUDIO);
} else {
myRequest.grant(request.getResources());
}
I also stuck this problem for many days but after in below link code , 100% working code Android Webview
I'm writing an app to do some basic communication via multicast. I'm running into a problem and can figure why. I'm defining the socket according to the constructor in the API, yet it's not actually setting the variables as specified. Here is a basic code snippet with a bunch of the extra stuff removed:
import java.net.MulticastSocket;
import java.net.InetAddress;
import java.net.NetworkInterface;
...
private InetAddress groupInetAddr = InetAddress.getByName("239.42.42.42");;
private int groupPort = 42000;
private MulticastSocket groupSocket;
netInt = NetInfo.getInterface();
//This is a custom method that chooses a candidate NetworkInterface
//from available options. Returns a NetworkInterface object
try{
groupSocket = new MulticastSocket(groupPort);
groupSocket.setNetworkInterface(netInt);
groupSocket.joinGroup(groupInetAddr);
groupSocket.setTimeToLive(64);
}
catch (Exception e){
Log.i(TAG, "FAILED");
}
I have some test code immediately following this code to confirm that the socket has been created properly, and it isn't...
Log.i(TAG, "groupInetAddr: " + groupInetAddr.toString());
Log.i(TAG, "groupPort: " + groupPort);
Log.i(TAG, "groupSocket.getInetAddress: " + groupSocket.getInetAddress());
Log.i(TAG, "groupSocket.getPort(): " + groupSocket.getPort());
The log results of the test:
GroupSender﹕ groupInetAddr: /239.42.42.42
GroupSender﹕ groupPort: 42000
GroupSender﹕ groupSocket.getInetAddress: null
GroupSender﹕ groupSocket.getPort(): -1
So, as you can see, the InetAddress is being created properly, so that's not the problem, but the socket isn't assigning the InetAddress as the destination. Additionally, when I check Wireshark, there is no IGMP message send out over the LAN to that address.
Additionally, I've added the following permissions to the AndroidManifest.xml to allow access to necessary services.
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.wifi" />
Any ideas? Hopefully I'm just missing something small.
The socket has been constructed correctly. You didn't connect it, so its getInetAddress() returns null and its target port is -1.
That doesn't have anything to do with which multicast groups it has joined. Your expectations are at fault.
The IGMP message is only sent if this host isn't already a member of that group.
It turns out that this code works as intended. The problem is with the Android emulator. It doesn't send out the IGMP message as required.
I was trying to communicate between the emulator and an actual device. I installed the app on 2 devices and they are able to communicate between each other.
I want to access extern usb cameras via v4l on android.
I tried SimpleWebCam. After some slight modifications of the original source codes, i achieved to make it work on a rooted android device. However, on unrooted devices, it keeps complaining about "not have permission to access "/dev/video*". I checked the permission of /dev/video* with "ls -l /dev/video*", and got
crw-rw---- system camera 81, 0 2015-08-18 18:31 video0
I understand that it means /dev/video* are owned by system, and are readable/writable to users in group "camera". So I think if i add
<uses-permission android:name="android.permission.CAMERA" />
in the manifest of my app, the user id of my app will be added to the group "camera", then my app will be allowed to read data from /dev/video*.
But, it still complains about "not have permission to access /dev/video*" now.
i also tried
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
, but still not working.
Do i miss somthing or misunderstand somthing. Any help or discussion will be appreciated.
The codes i used to open device are
int opendevice(int i)
{
struct stat st;
sprintf(dev_name,"/dev/video%d",i);
if (-1 == stat (dev_name, &st)) {
LOGE("Cannot identify '%s': %d, %s", dev_name, errno, strerror (errno));
return ERROR_LOCAL;
}
if (!S_ISCHR (st.st_mode)) {
LOGE("%s is no device", dev_name);
return ERROR_LOCAL;
}
fd = open (dev_name, O_RDWR);// | O_NONBLOCK, 0);
if (-1 == fd) {
LOGE("Cannot open '%s': %d, %s", dev_name, errno, strerror (errno));
return ERROR_LOCAL;
}
return SUCCESS_LOCAL;
}
The return value of open is always -1, with logcat:
Cannot open '/dev/video3': 13, Permission denied
I finally achieve to read images from the external usb camera on unrooted android devices using an opensource project named uvccamera.
Here is the link, https://github.com/saki4510t/UVCCamera
Try to add also
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
in your manifest file:
http://developer.android.com/reference/android/hardware/Camera.html