This commit is contained in:
sifacaii 2023-05-19 14:26:20 +08:00
parent 356dd2c1b3
commit 88a1917c40
3 changed files with 208 additions and 139 deletions

View File

@ -18,9 +18,9 @@ public class AVTransportAdapter extends RecyclerView.Adapter{
private Context context;
private ArrayList<AVTransport> avTransports;
public AVTransportAdapter(Context context) {
public AVTransportAdapter(Context context,ArrayList<AVTransport> avTransports) {
this.context = context;
this.avTransports = new ArrayList<>();
this.avTransports = avTransports;
}
@NonNull

View File

@ -0,0 +1,189 @@
package org.sifacai.vlcjellyfin.Dlna;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.lzy.okgo.OkGo;
import org.sifacai.vlcjellyfin.Utils.JfClient;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.parsers.ParserConfigurationException;
public class BroadCastThread extends Thread {
private String TAG = "广播线程";
public static final int TYPE_DEVICE = 1; //发现新设备
public static final int TYPE_NEW_DEVICE_ADDED = 2; //新加了新设备
public static final int TYPE_DEVICE_DEL = 3; //设备离线
public static final int TYPE_MSG = 9; //消息
public static final String GroupAddress = "239.255.255.250";
private byte[] NOTIFY_rootdevice = ("M-SEARCH * HTTP/1.1\n" +
"ST: upnp:rootdevice\n" +
"MX: 10\n" +
"MAN: \"ssdp:discover\"\n" +
"Content-Length: 0\n" +
"HOST: 239.255.255.250:1900").getBytes();
private byte[] NOTIFY_MediaRenderer = ("M-SEARCH * HTTP/1.1\n" +
"ST: urn:schemas-upnp-org:device:MediaRenderer:1\n" +
"MX: 10\n" +
"MAN: \"ssdp:discover\"\n" +
"Content-Length: 0\n" +
"HOST: 239.255.255.250:1900").getBytes();
private Handler handler;
private MulticastSocket mSocket;
private ArrayList<AVTransport> avTransports;
private boolean isStop = false;
public BroadCastThread() {
avTransports = new ArrayList<>();
try {
mSocket = new MulticastSocket(1900);
mSocket.joinGroup(InetAddress.getByName(GroupAddress));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public void run() {
while (mSocket != null && !isStop) {
listenr();
}
}
public void SetHandler(Handler handler) {
this.handler = handler;
}
public ArrayList<AVTransport> GetAVTransportArray() {
return avTransports;
}
/**
* 发送M
*/
public void refresh() {
new Thread(new Runnable() {
@Override
public void run() {
DatagramPacket packet = new DatagramPacket(NOTIFY_rootdevice, NOTIFY_rootdevice.length);
try {
packet.setAddress(InetAddress.getByName(GroupAddress));
packet.setPort(1900);
mSocket.send(packet);
packet.setData(NOTIFY_MediaRenderer);
mSocket.send(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
/**
* 监听广播
*/
private void listenr() {
try {
byte[] buff = new byte[1024];
DatagramPacket packet = new DatagramPacket(buff, buff.length);
mSocket.receive(packet);
String clientIP = packet.getAddress().getHostAddress();
int clientPort = packet.getPort();
String data = new String(packet.getData()).trim();
ProgressNOTIFY(data);
} catch (IOException | XmlPullParserException e) {
throw new RuntimeException(e);
}
}
public void ProgressNOTIFY(String data) throws IOException, XmlPullParserException {
Log.d(TAG, "ProgressNOTIFY: " + data);
if (data.startsWith("M-SEARCH")) return;
HashMap<String, String> dh = DlnaDevice.parseNOTIFY(data);
if (isExitsOrByeBye(dh)) return;
boolean isav = DlnaDevice.isMediaRenderer(dh.get("nt"));
String location = dh.get("location");
if (location == null) location = "";
if (isav && !location.equals("")) {
String xmlstr = JfClient.SendGet(location);
if (xmlstr == null || xmlstr.equals("")) return;
findDevice(location, xmlstr);
}
}
public void findDevice(String location, String xml) {
DlnaDevice device;
try {
device = XmlParser.parseX(xml);
for (int i = 0; i < device.DlnaServices.size(); i++) {
DlnaService ds = device.DlnaServices.get(i);
if (ds.serviceType.indexOf("service:AVTransport") > -1) {
int si = location.indexOf("/", 8);
String url = si > -1 ? location.substring(0, si) : location;
String moduleName = device.friendlyName.equals("") ? device.modelName : device.friendlyName;
AVTransport av = new AVTransport();
av.moduleName = moduleName;
av.serviceId = ds.serviceId;
av.UDN = device.UDN;
av.controlURL = url + (ds.controlURL.startsWith("/") ? ds.controlURL : "/" + ds.controlURL);
av.eventSubURL = url + (ds.eventSubURL.startsWith("/") ? ds.eventSubURL : "/" + ds.eventSubURL);
av.iconurl = device.icon.size() > 0 ? url + "/" + device.icon.get(0) : "";
avTransports.add(av);
if (handler != null) {
Message msg = new Message();
msg.what = TYPE_NEW_DEVICE_ADDED;
handler.sendMessage(msg);
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
}
}
/**
* 是否已存在或byebye
* @param dh
* @return
*/
public boolean isExitsOrByeBye(HashMap<String,String> dh) {
String USN = dh.get("usn");
String[] usns = USN.split("::");
if (usns.length < 2) return true;
for (AVTransport av : avTransports) {
if (usns[0].equals(av.UDN)) {
if(dh.get("nts")!=null && dh.get("nts").toLowerCase().indexOf("byebye") >= 0){
avTransports.remove(av);
Message msg = new Message();
msg.what = TYPE_DEVICE_DEL;
handler.sendMessage(msg);
}
return true;
}
}
return false;
}
public void Stop() {
isStop = true;
}
}

View File

@ -28,42 +28,25 @@ public class DlnaActivity extends BaseActivity {
private JRecyclerView rv;
private AVTransportAdapter avTransportAdapter;
private MulticastSocket mSocket;
private Thread listen_thread;
private byte[] NOTIFY_rootdevice = ("M-SEARCH * HTTP/1.1\n" +
"ST: upnp:rootdevice\n" +
"MX: 10\n" +
"MAN: \"ssdp:discover\"\n" +
"Content-Length: 0\n" +
"HOST: 239.255.255.250:1900").getBytes();
BroadCastThread broadCastTheader = new BroadCastThread();
private byte[] NOTIFY_MediaRenderer = ("M-SEARCH * HTTP/1.1\n" +
"ST: urn:schemas-upnp-org:device:MediaRenderer:1\n" +
"MX: 10\n" +
"MAN: \"ssdp:discover\"\n" +
"Content-Length: 0\n" +
"HOST: 239.255.255.250:1900").getBytes();
private Handler handler = new Handler() {
private Handler handler= new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Bundle b = msg.getData();
AVTransport avt = new AVTransport();
avt.moduleName = b.getString("moduleName");
avt.serviceId = b.getString("serviceId");
avt.UDN = b.getString("UDN");
avt.controlURL = b.getString("controlURL");
avt.eventSubURL = b.getString("eventSubURL");
avt.iconurl = b.getString("iconurl");
avTransportAdapter.addDevice(avt);
case BroadCastThread.TYPE_DEVICE:
break;
case BroadCastThread.TYPE_NEW_DEVICE_ADDED:
avTransportAdapter.notifyDataSetChanged();
break;
case BroadCastThread.TYPE_DEVICE_DEL:
avTransportAdapter.notifyDataSetChanged();
break;
}
}
};
};;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -71,19 +54,12 @@ public class DlnaActivity extends BaseActivity {
setContentView(R.layout.activity_dlna);
getSupportActionBar().hide();
try {
mSocket = new MulticastSocket(1900);
mSocket.joinGroup(InetAddress.getByName("239.255.255.250"));
} catch (IOException e) {
throw new RuntimeException(e);
}
listen_thread = new Thread(listen_Runnable);
broadCastTheader.SetHandler(handler);
findViewById(R.id.refresh).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
refresh();
broadCastTheader.refresh();
}
});
@ -91,7 +67,7 @@ public class DlnaActivity extends BaseActivity {
V7LinearLayoutManager layoutManager = new V7LinearLayoutManager(rv.getContext());
layoutManager.setOrientation(V7LinearLayoutManager.VERTICAL);
rv.setLayoutManager(layoutManager);
avTransportAdapter = new AVTransportAdapter(this);
avTransportAdapter = new AVTransportAdapter(this, broadCastTheader.GetAVTransportArray());
rv.setAdapter(avTransportAdapter);
avTransportAdapter.setOnItemClickListener(new AVTransportAdapter.OnItemClickListener() {
@Override
@ -103,10 +79,10 @@ public class DlnaActivity extends BaseActivity {
Controller.SetAVTransportURI(avTransport.controlURL, vurl, new JfClient.JJCallBack() {
@Override
public void onSuccess(String str) {
Controller.GetMediaInfo(avTransport.controlURL,new JfClient.JJCallBack(){
Controller.GetMediaInfo(avTransport.controlURL, new JfClient.JJCallBack() {
@Override
public void onSuccess(String str) {
Controller.Play(avTransport.controlURL,new JfClient.JJCallBack(){
Controller.Play(avTransport.controlURL, new JfClient.JJCallBack() {
@Override
public void onSuccess(String str) {
ShowToask("已发送!");
@ -140,19 +116,18 @@ public class DlnaActivity extends BaseActivity {
@Override
protected void onStart() {
super.onStart();
if (!listen_thread.isAlive()) listen_thread.start();
refresh();
broadCastTheader.start();
}
@Override
protected void onPause() {
super.onPause();
listen_thread.interrupt();
}
@Override
protected void onStop() {
super.onStop();
broadCastTheader.Stop();
}
@Override
@ -160,99 +135,4 @@ public class DlnaActivity extends BaseActivity {
super.onDestroy();
}
/**
* 刷新设备
*/
private void refresh() {
new Thread(new Runnable() {
@Override
public void run() {
DatagramPacket packet = new DatagramPacket(NOTIFY_rootdevice, NOTIFY_rootdevice.length);
try {
packet.setAddress(InetAddress.getByName("239.255.255.250"));
packet.setPort(1900);
mSocket.send(packet);
packet.setData(NOTIFY_MediaRenderer);
mSocket.send(packet);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}).start();
}
private Runnable listen_Runnable = new Runnable() {
@Override
public void run() {
while (mSocket != null) {
try {
byte[] buff = new byte[1024];
DatagramPacket packet = new DatagramPacket(buff, buff.length);
mSocket.receive(packet);
String clientIP = packet.getAddress().getHostAddress();
int clientPort = packet.getPort();
String data = new String(packet.getData()).trim();
ProgressNOTIFY(data);
} catch (IOException | XmlPullParserException e) {
throw new RuntimeException(e);
}
}
handler.post(listen_thread);
}
};
public void ProgressNOTIFY(String data) throws IOException, XmlPullParserException {
//Log.d(TAG, "ProgressNOTIFY: " + data);
if(data.startsWith("M-SEARCH")) return;
HashMap<String,String> dh = DlnaDevice.parseNOTIFY(data);
boolean isav = DlnaDevice.isMediaRenderer(dh.get("nt"));
String location = dh.get("location");
if(location == null) location = "";
if (isav && !location.equals("")) {
String finalLocation = location;
JfClient.SendGet(location, new JfClient.JJCallBack() {
@Override
public void onSuccess(String str) {
findDevice(finalLocation, str);
}
}, new JfClient.JJCallBack() {
@Override
public void onError(String str) {
ShowToask(str);
}
});
}
}
public void findDevice(String location, String xml) {
DlnaDevice device;
try {
device = XmlParser.parseX(xml);
for (int i = 0; i < device.DlnaServices.size(); i++) {
DlnaService ds = device.DlnaServices.get(i);
if (ds.serviceType.indexOf("service:AVTransport") > -1) {
int si = location.indexOf("/", 8);
String url = si > -1 ? location.substring(0, si) : location;
String moduleName = device.friendlyName.equals("") ? device.modelName : device.friendlyName;
Bundle bundle = new Bundle();
bundle.putString("moduleName", moduleName);
bundle.putString("UDN", device.UDN);
bundle.putString("serviceId", ds.serviceId);
bundle.putString("controlURL", url + (ds.controlURL.startsWith("/") ? ds.controlURL : "/" + ds.controlURL));
bundle.putString("eventSubURL", url + "/" + ds.eventSubURL);
bundle.putString("iconurl", device.icon.size() > 0 ? url + "/" + device.icon.get(0) : "");
Message msg = new Message();
msg.what = 1;
msg.setData(bundle);
handler.sendMessage(msg);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
}
}
}