Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use NsdManager to lookup MPD servers on local network #863

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MPDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />

<!-- Used to start the service upon boot if the service requires persistence. -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Cover art cache -->
Expand Down
138 changes: 138 additions & 0 deletions MPDroid/src/main/java/com/cafbit/multicasttest/NetThread.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Copyright 2011 David Simmons
* http://cafbit.com/entry/testing_multicast_support_on_android
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cafbit.multicasttest;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.NetworkInterface;
import java.util.Set;

import com.cafbit.netlib.NetUtil;
import com.cafbit.netlib.dns.DNSMessage;

import android.content.Context;
import android.net.wifi.WifiManager.MulticastLock;
import android.util.Log;

/**
* This thread runs in the background while the user has our
* program in the foreground, and handles sending mDNS queries
* and processing incoming mDNS packets.
* @author simmons
*/
public class NetThread extends Thread {

private static final String TAG = "NetThread";

// the standard mDNS multicast address and port number
private static final byte[] MDNS_ADDR =
new byte[] {(byte) 224,(byte) 0,(byte) 0,(byte) 251};
private static final int MDNS_PORT = 5353;

private static final int BUFFER_SIZE = 4096;

private NetworkInterface networkInterface;
private InetAddress groupAddress;
private MulticastSocket multicastSocket = null;
private NetUtil netUtil;
private String servicename;

/**
* Construct the network thread.
* @param activity
* @param servicename Name of service to search for
*/
public NetThread(Context activity, String servicename) {
super("net");
this.servicename = servicename;
netUtil = new NetUtil(activity);
}

/**
* Open a multicast socket on the mDNS address and port.
* @throws IOException
*/
private void openSocket() throws IOException {
multicastSocket = new MulticastSocket(MDNS_PORT);
multicastSocket.setTimeToLive(2);
multicastSocket.setSoTimeout(5000);
multicastSocket.setReuseAddress(true);
multicastSocket.setNetworkInterface(networkInterface);
multicastSocket.joinGroup(groupAddress);
}

/**
*/
@Override
public void run() {
Log.v(TAG, "starting network thread");

Set<InetAddress> localAddresses = NetUtil.getLocalAddresses();
MulticastLock multicastLock = null;

try {
networkInterface = netUtil.getFirstWifiOrEthernetInterface();
if (networkInterface == null) {
throw new IOException("Your WiFi is not enabled.");
}
groupAddress = InetAddress.getByAddress(MDNS_ADDR);

multicastLock = netUtil.getWifiManager().createMulticastLock("unmote");
multicastLock.acquire();
Log.v(TAG, "acquired multicast lock: "+multicastLock);

openSocket();
Log.v(TAG, "opensocket returned");

query(servicename);
Log.v(TAG, "sent query");

// set up the buffer for incoming packets
byte[] responseBuffer = new byte[BUFFER_SIZE];
DatagramPacket response = new DatagramPacket(responseBuffer, BUFFER_SIZE);
multicastSocket.receive(response);
Log.v(TAG, "received response"+response.getSocketAddress());
multicastSocket.close();
} catch (IOException e1) {
Log.v(TAG, "send mdns query failed "+e1.toString());
return;
}

if(multicastSocket != null)
multicastSocket.close();

// release the multicast lock
if(multicastLock != null)
multicastLock.release();

Log.v(TAG, "stopping network thread");
}

/**
* Transmit an mDNS query on the local network.
* @param servicename
* @throws IOException
*/
private void query(String servicename) throws IOException {
byte[] requestData = (new DNSMessage(servicename)).serialize();
DatagramPacket request =
new DatagramPacket(requestData, requestData.length, InetAddress.getByAddress(MDNS_ADDR), MDNS_PORT);
multicastSocket.send(request);
}
}
63 changes: 63 additions & 0 deletions MPDroid/src/main/java/com/cafbit/multicasttest/Util.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2011 David Simmons
* http://cafbit.com/entry/testing_multicast_support_on_android
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.cafbit.multicasttest;

/**
* Various mundate utility methods.
* @author simmons
*/
public class Util {

public static String hexDump(byte[] bytes) {
return hexDump(bytes, 0, bytes.length);
}

public static String hexDump(byte[] bytes, int offset, int length) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<length; i+=16) {
int rowSize = length - i;
if (rowSize > 16) { rowSize = 16; }
byte[] row = new byte[rowSize];
System.arraycopy(bytes, offset+i, row, 0, rowSize);
hexDumpRow(sb, row, i);
}
return sb.toString();
}

private static void hexDumpRow(StringBuilder sb, byte[] bytes, int offset) {
sb.append(String.format("%04X: ",offset));
for (int i=0; i<16; i++) {
if (bytes.length > i) {
sb.append(String.format("%02X ",bytes[i]));
} else {
sb.append(" ");
}
}
for (int i=0; i<16; i++) {
if (bytes.length > i) {
char c = '.';
int v = (int)bytes[i];
if ((v > 0x20) && (v < 0x7F)) {
c = (char)v;
}
sb.append(c);
}
}
sb.append('\n');
}

}
Loading