It seems multicast reception does not work on some Android devices. I can not receive multicast with 4 out of 13 test devices. On those 4 devices it seems the app does not send the IGMP request to join the multicast group.
The code to receive the multicast looks like so:
WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
WifiManager.WifiLock wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, TAG);
WifiManager.MulticastLock multicastLock = wifiManager.createMulticastLock(TAG);
multicastLock.setReferenceCounted(true);
wifiLock.acquire();
multicastLock.acquire();
try {
MulticastSocket socket = new MulticastSocket(32123);
InetAddress group = InetAddress.getByName("224.1.2.3");
socket.joinGroup(group);
DatagramPacket packet;
byte[] buf = new byte[256];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
socket.leaveGroup(group);
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
multicastLock.release();
wifiLock.release();
The app has the following permissions:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
To demonstrate the problem I created a little test project using the above code on GitHub: MulticastTest.
Is there a problem with my code? Do I miss a permission?
EDIT 1: This problem does not seem to relate to a specific Android version. I can reproduce the behaviour on Android 4.x, 5.x, and 6.x.
EDIT 2: There is a related question.
Bad news: This seems to be related to the affected devices. There is no /proc/net/igmp available exactly on those devices that can not receive the multicast traffic. As already expected this very likely leads to the missing join group request (IP_ADD_MEMBERSHIP).
We tried with the Android Java API, BSD sockets, and Boost.Asio. Same result with all three options.
We verified the problem with an app called Multicast Tester. This app has the same problem on the same devices as our app. No IGMP request is send by the device and of course no multicast traffic is received.
There are some open and closed (with statuses Obsolete and WrongForum) issues in the Android issue tracker. I think the closed issues are marked as Obsolete/WrongForum because it is not a problem in Android but specific to the affected devices (setup).
It seems the kernel on the affected devices was built with
CONFIG_IP_MULTICAST=n
in the kernel configuration file. That's also why /proc/net/igmp is not available on the affected devices. It obviously is only created when CONFIG_IP_MULTICAST is set as can be seen in the Linux kernel code.
Related
I'm having problems to receive constantly the UDP packets from the server with new Nexus 5X (Marshmallow)
I have another real devices that receive all UDP packets, but it seems that something changed in Android API 23.
CODE:
Anyone with the same problem?
if (s == null || s.isClosed()){
Log.v("udp", "----------------------------------------------------new socket---------------------------------");
s = new DatagramSocket(null);
s.setReuseAddress(true);
s.setBroadcast(true);
s.setSoTimeout(5000);
s.bind(new InetSocketAddress(8002));
p = new DatagramPacket(message, message.length);
try{
Thread.sleep(100);
}
catch(Exception e){
}
}
//Log.v("test","---------------------------------------------------- Pas1 ---------------------------------");
message = new byte[100];
//p = new DatagramPacket(message, message.length);
p.setLength(message.length);
s.receive(p);
The problem is:
I receive randomly the broadcast packets, meanwhile in other real devices I receive all.
I'm sure that something was changed in android api 23. It seems that the receive function only "triggers" if it has a packet in the buffer, but if it's called without it "inside", the sockettimeout appears.
Thanks!
Android Marsmallow introduces doze mode, which will suspend network access after some time. Maybe this affects your application as well.
"The following restrictions apply to your apps while in Doze:
- Network access is suspended
- ..."
http://developer.android.com/training/monitoring-device-state/doze-standby.html
The bad news is that you cannot do much about it, except for asking the user to put your application on the list with applications exempted from battery optimization. Be careful with this though, because Google will likely remove your application from the Play store for it (this is why I didn't include source code for it).
"However, it is Google’s opinion of what “the core function of the app” is that matters. Not the user. Not the developer. Google. The user and developer might be in perfect harmony over what adding the app to the whitelist means, but if Google thinks that it is not warranted, Google sets themselves up as being more important than the user and bans the app." (https://commonsware.com/blog/2015/11/11/google-anti-trust-issues.html)
Mostly the only viable option is to use Google Cloud messaging, but that might not be a good solution in your case.
Bad News...
I have disabled the battery optimization, but the Android M have an anormal operation receiving the broadcast UDP packets.
See this picture:
I have another android device (4.1.2) that receive all packets with the same code!
How is it possible?
Sometimes is receiving all packets and sometimes stops(any packets).
Code to disable battery optimization:
if (Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1) {
String pkg=getPackageName();
PowerManager pm=getSystemService(PowerManager.class);
if (!pm.isIgnoringBatteryOptimizations(pkg)) {
Intent i=
new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.setData(Uri.parse("package:" + pkg));
startActivity(i);
}
}
In Android Manifest:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
When I'm running the asynctask to receive the UDP packets, i'm checking these settings:
isDeviceIdleMode() -> FALSE
isIgnoringBatteryOptimizations() -> TRUE
So, this means that doze is not working, right? Then, who is blocking this packets?
I need to be able to receive broadcasts on the Wifi of this phone. It's an HTC Desire, about 2 years old, running Android 2.2.
I've followed the docs and some example code I found, and ended up with this code to enable the multicast:
mWifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock multicastLock = mWifiManager.createMulticastLock("net.inside.broadcast");
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
Log.i("BCXXX", "multicastLock.isHeld() = " + multicastLock.isHeld());
Log.i("BCXXX", "multicastLock.toString() = " + multicastLock.toString());
The log output follows here:
I/BCXXX ( 3302): multicastLock.isHeld() = true
I/BCXXX ( 3302): multicastLock.toString() = MulticastLock{ 45fa2b88; held; refcounted: refcount = 1 }
This seems to confirm that the multicastLock should be held, meaning multicast should work. However, it doesn't. The Android app simply does not receive any broadcast packets except for its own, i.e. the one it sends out to the others. The other machines I should mention can see the Android phone just fine and receive its broadcast messages. I've tried addressing the packets to 255.255.255.255 as well as 192.168.0.255 (with 192.168.0. obviously being the net everyone is connected to in the LAN).
This is a project built with Unity 3.5 and both the Windows and OS X builds work as expected. The Android plugin does get called (as is evident from the log entries).
Any ideas anyone?
I recently compiled ffmpeg and live555 for android, and built my own media client wrapper. The whole system works perfectly in all other systems (windows and linux), but not in android, just no UDP packets could be ever received. The RTSP communication works fine, which uses TCP connection. The session starts successfully, and keeps running in server. After searching for the similar topics, I see it seems that I have to acquire a multicasting permission with wifi at first. So I did:
- put permissions in AndroidManifest.xml
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE""/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"/>
- put following java codes in android Activity::onCreate()
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
if( wm != null ) {
mMCLock = wm.createMulticastLock( TAG );
mMCLock.acquire();
}
But it still doesn't work, the results are all the same in Emulator, in Galaxy S2 Phone and
in Galaxy Tab 10.1. Even I deactivate the live555 module, and just use ffmpeg ( ffmpeg has also its build-in rtsp client, but not as stable as live555, therefor, I ported live555 into android). The results are the same, rtsp ok, rtp not, where rtp uses udp as underlying carrier.
In DDMS is an error registered:
Address Family not supported by protocol
I think, the problem is that the UDP port is still blocked. Maybe getting multicastlock in
java is not enough for native code running in user kernel of android.
Does anyone has idea?
Steven
The UDP Problem in meinem RTSP client has been solved, there is nothing to do with permission and multicast lock. It is the bug inside android stl library implementation, provided in android-ndk-r7 and android-ndk-r8 both. Anyone wants to use gnu-libstdc++.so has to keep in mind: don't use string, especially string::c_str(), it leaves danger pointer in your stack, and damages everything. After I threw out every thing to do with stl, everything works fine, tcp and udp. A little off-topic: Inside the live555, there are at least 20 bugs, and the most fatal errors are: they used unblocked rtp over tcp, therefore, most packets are get lost before they reach the network interface, and at rtsp client, the rtp/tcp socket will never get the packets which are lost in the network interface, and then a rtsp session enters into endless receiving loop, it hangs.
I faced the same problem.
I think, in your bind you are biding to an IP, use htonl(INADDRY_ANY) as s_addr.
not sure whether this helps your cause, but it seems to solve my problem.
Has anyone gotten Multicast to work on Android 2.2, specifically JmDNS for Bonjour service detection. There are many questions & answers from the Android 1.5->2.0 timeframe, including on stackOverflow, that indicate varying levels of success, and a bug in the bug tracker that indicate it was fixed, and closed, for 2.2 (http://code.google.com/p/android/issues/detail?id=2323) . I've tried the "TuneControl" source code, but that worked on ~1.5 and has not been updated, and does not work for me on 2.2.
So, the questions...
1) Has anyone seen multicast work on 2.2, specifically JmDNS, and specifically for Bonjour service detection?
2) What is necessary in code to make this work?
I'm using the appropriate permissions:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
I acquire the multicast lock:
WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
if(wifi != null)
{
MulticastLock mcLock = wifi.createMulticastLock("mylock");
mcLock.acquire();
...
And then try to start jmDNS to look for servers:
mdns = JmDNS.create(addr, HOSTNAME);
jmdns.addServiceListener(TOUCH_ABLE_TYPE, listener);
jmdns.addServiceListener(DACP_TYPE, listener);
...
The listener never sees any services. I've verified using Wireshark that the request packets are sent, and that the server responds, but the response packet are never seen by the socket listener code in the jmDNS library.
So... am I missing something? Is this still a bug? Has ANYONE gotten anything even remotely like this to work???
To (rudely) answer my own question, more information was provided at http://code.google.com/p/android/issues/detail?id=2917#c48 by another person. For posterity, as they say, here is brian.ro...#gmail.com's answer...
"I've spent quite a bit of time
debugging mDNS issues with JmDNS on my
Evo and HTC Hero (CDMA). What I found
is there appears to be a filter in
place in the broadcom wireless driver
on the Evo (and since I'm getting a
similiar reprt from an HTC Desire user
- with the same chipset, presumably that handset as well). The filter, by
default, blocks any non-unicast or
network broadcast traffic, including
multicast. Apparently the theory was
it's a battery saver.
The problem appears to be the
wpa_supplicant on the Evo does not
support removing those filters when
you get a MulticastLock. (Check the
log output right after you get the
lock and you'll see what I mean).
Unfortunately what has happened is the
hardware vendors have fragmented
multicast support.... :("
So... it appears this is a device problem more than a coding problem. D'oh. :( If I get an opportunity to test on another device...
I've been doing a bit of research into this, and I believe it is a problem with Android in general, and fixed in or around Android 2.3.7.
It's a bit too anecdotal, but here's what I tested:
HTC Desire, 2.2, stock: fail
HTC Desire, 2.3.7, CyanogenMod: success
Motorola Milestone, 2.1-update1: fail
HTC Desire S, 2.3.3: fail
Acer Iconia A501, 3.2.1: success
Samsung something, 2.3.3: fail
HTC Legend, 2.2 I think: fail
When I say 'fail', in fact they were all able to send multicast messages to the 'success' devices, but never receive anything back except their own messages - as jldupont describes.
Note that the multicast IM app Kouchat is only available for 2.3.7 onwards, even though it can be made to compile for as far back as 2.1, which gives further credence to this theory.
I think the other reason is your AP does not support.
Other:Computer send/recieve to/from Android
your computer must only use WIFI,Best off all other network
I'm trying to receive data from a multicast address, but the call to MulticastSocket.receive() blocks until a timeout takes place.
I did some network sniffing and found out that my device (and the emulator) never send a MulticastSocket.joinGroup request.
I tried running the same Java code from my PC as a standalone application and it worked well. Could it be that the Android platform blocks IGMP join requests?
Has anyone succeeded with Multicast on Android before?
My manifest file contains the following permission:
I am running my application on 2.1 (Both emulator & device).
Any ideas anyone?
Thanks,
Lukas gives the best explanation and examples that I've seen on his blog: http://codeisland.org/2012/udp-multicast-on-android
In summary:
1. You need the permissions:
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
2. You need a lock:
WifiManager wifi = (WifiManager)getSystemService(Context.WIFI_SERVICE);
if (wifi != null){
WifiManager.MulticastLock lock = wifi.createMulticastLock("mylock");
lock.acquire();
}
3. You have to have a device that supports receiving multicast. Or you can follow his work around for rooted devices.
As it seems, there is no proper multicast support in the emulator.
Here's a bug report and related thread. It is being fixed for froyo.
You need to do something like this
WifiManager wifi = (WifiManager)getSystemService( Context.WIFI_SERVICE );
if(wifi != null)
{
MulticastLock mcLock = wifi.createMulticastLock("mylock");
mcLock.acquire();
}
Reference:
http://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock.html
I read all 2.1 devices not supporting IGMP stack.
IGMP was missing on different HTC, Samsung, and Motorola devices of all android version from 2.1 up to 3.2.
Link in which i read http://www.programmingmobile.com/2012/01/multicast-and-android-big-headache.html