diff --git a/app/build.gradle b/app/build.gradle index a906753f5..8cb811346 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -102,10 +102,14 @@ dependencies { implementation project(':media-lib-session') implementation project(':media-lib-ui') implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.20') + mobileImplementation(ext: 'aar', name: 'dlna-dmc', group: 'fongmi', version: 'release') + //implementation(ext: 'aar', name: 'dlna-dmr', group: 'fongmi', version: 'release') + //implementation(ext: 'aar', name: 'dlna-dms', group: 'fongmi', version: 'release') + implementation(ext: 'aar', name: 'dlna-core', group: 'fongmi', version: 'release') implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.biometric:biometric:1.1.0' implementation 'androidx.lifecycle:lifecycle-viewmodel:2.6.2' - implementation 'androidx.room:room-runtime:2.5.2' + implementation 'androidx.room:room-runtime:2.6.0' implementation 'androidx.media:media:1.6.0' implementation 'cat.ereza:customactivityoncrash:2.4.0' implementation 'com.github.bassaer:materialdesigncolors:1.0.0' @@ -117,6 +121,11 @@ dependencies { implementation 'com.google.android.material:material:1.10.0' implementation 'com.google.zxing:core:3.3.0' implementation 'com.guolindev.permissionx:permissionx:1.7.1' + implementation 'org.eclipse.jetty:jetty-server:8.1.21.v20160908' + implementation 'org.eclipse.jetty:jetty-servlet:8.1.21.v20160908' + implementation 'org.eclipse.jetty:jetty-client:8.1.21.v20160908' + implementation 'org.fourthline.cling:cling-core:2.1.1' + implementation 'org.fourthline.cling:cling-support:2.1.1' implementation 'org.greenrobot:eventbus:3.3.1' implementation 'org.nanohttpd:nanohttpd:2.3.1' implementation('org.simpleframework:simple-xml:2.7.1') { exclude group: 'stax', module: 'stax-api' exclude group: 'xpp3', module: 'xpp3' } @@ -124,9 +133,8 @@ dependencies { leanbackImplementation 'me.jessyan:autosize:1.2.1' mobileImplementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' mobileImplementation 'com.github.chrisbanes:PhotoView:2.3.0' - mobileImplementation 'com.github.devin1014.DLNA-Cast:dlna-dmc:V1.0.0' mobileImplementation 'com.google.android.flexbox:flexbox:3.0.0' mobileImplementation('com.journeyapps:zxing-android-embedded:4.3.0') { transitive = false } - annotationProcessor 'androidx.room:room-compiler:2.5.2' + annotationProcessor 'androidx.room:room-compiler:2.6.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.15.1' } \ No newline at end of file diff --git a/app/libs/dlna-core.aar b/app/libs/dlna-core.aar new file mode 100644 index 000000000..af4c9fcc3 Binary files /dev/null and b/app/libs/dlna-core.aar differ diff --git a/app/libs/dlna-dmc.aar b/app/libs/dlna-dmc.aar new file mode 100644 index 000000000..97634d04c Binary files /dev/null and b/app/libs/dlna-dmc.aar differ diff --git a/app/libs/dlna-dmr.aar b/app/libs/dlna-dmr.aar new file mode 100644 index 000000000..259cf4dcb Binary files /dev/null and b/app/libs/dlna-dmr.aar differ diff --git a/app/libs/dlna-dms.aar b/app/libs/dlna-dms.aar new file mode 100644 index 000000000..ab454cb83 Binary files /dev/null and b/app/libs/dlna-dms.aar differ diff --git a/quickjs/libs/quickjs.aar b/app/libs/quickjs.aar similarity index 100% rename from quickjs/libs/quickjs.aar rename to app/libs/quickjs.aar diff --git a/app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java b/app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java index a9825a2ec..85c3b6922 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java +++ b/app/src/mobile/java/com/fongmi/android/tv/cast/CastDevice.java @@ -1,13 +1,14 @@ package com.fongmi.android.tv.cast; -import org.fourthline.cling.model.meta.Device; +import com.android.cast.dlna.dmc.DLNACastManager; +import com.fongmi.android.tv.bean.Device; import java.util.ArrayList; import java.util.List; public class CastDevice { - private final List> devices; + private final List> devices; private static class Loader { static volatile CastDevice INSTANCE = new CastDevice(); @@ -25,8 +26,8 @@ public class CastDevice { return devices.isEmpty(); } - private com.fongmi.android.tv.bean.Device create(Device item) { - com.fongmi.android.tv.bean.Device device = new com.fongmi.android.tv.bean.Device(); + private Device create(org.fourthline.cling.model.meta.Device item) { + Device device = new Device(); device.setUuid(item.getIdentity().getUdn().getIdentifierString()); device.setName(item.getDetails().getFriendlyName()); device.setType(2); @@ -35,23 +36,28 @@ public class CastDevice { public List getAll() { List items = new ArrayList<>(); - for (Device item : devices) items.add(create(item)); + for (org.fourthline.cling.model.meta.Device item : devices) items.add(create(item)); return items; } - public List add(Device item) { + public List add(org.fourthline.cling.model.meta.Device item) { devices.remove(item); devices.add(item); return getAll(); } - public com.fongmi.android.tv.bean.Device remove(Device device) { + public Device remove(org.fourthline.cling.model.meta.Device device) { devices.remove(device); return create(device); } - public Device find(com.fongmi.android.tv.bean.Device item) { - for (Device device : devices) if (device.getIdentity().getUdn().getIdentifierString().equals(item.getUuid())) return device; + public void clear() { + for (org.fourthline.cling.model.meta.Device device : devices) DLNACastManager.INSTANCE.disconnectDevice(device); + devices.clear(); + } + + public org.fourthline.cling.model.meta.Device find(com.fongmi.android.tv.bean.Device item) { + for (org.fourthline.cling.model.meta.Device device : devices) if (device.getIdentity().getUdn().getIdentifierString().equals(item.getUuid())) return device; return null; } } diff --git a/app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java b/app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java index 9456b6480..327c10187 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java +++ b/app/src/mobile/java/com/fongmi/android/tv/cast/CastVideo.java @@ -1,14 +1,9 @@ package com.fongmi.android.tv.cast; -import androidx.annotation.NonNull; - -import com.android.cast.dlna.core.ICast; import com.fongmi.android.tv.server.Server; import com.github.catvod.utils.Path; -import java.util.UUID; - -public class CastVideo implements ICast { +public class CastVideo { private final String name; private final String url; @@ -24,21 +19,11 @@ public class CastVideo implements ICast { this.url = url; } - @NonNull - @Override - public String getId() { - return UUID.randomUUID().toString(); + public String getName() { + return name; } - @NonNull - @Override - public String getUri() { + public String getUrl() { return url; } - - @NonNull - @Override - public String getName() { - return name; - } } \ No newline at end of file diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java index ae62e58fb..3ecf863a6 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/LiveActivity.java @@ -83,7 +83,7 @@ import okhttp3.Call; import okhttp3.Response; import tv.danmaku.ijk.media.player.ui.IjkVideoView; -public class LiveActivity extends BaseActivity implements CustomKeyDownLive.Listener, CastDialog.Listener, TrackDialog.Listener, Biometric.Callback, PassCallback, LiveCallback, GroupAdapter.OnClickListener, ChannelAdapter.OnClickListener, SubtitleCallback { +public class LiveActivity extends BaseActivity implements CustomKeyDownLive.Listener, TrackDialog.Listener, Biometric.Callback, PassCallback, LiveCallback, GroupAdapter.OnClickListener, ChannelAdapter.OnClickListener, SubtitleCallback { private ActivityLiveBinding mBinding; private Observer mObserveChannel; @@ -901,10 +901,6 @@ public class LiveActivity extends BaseActivity implements CustomKeyDownLive.List PlaybackService.stop(); } - @Override - public void onCastTo() { - } - @Override public void onBright(int progress) { mBinding.widget.bright.setVisibility(View.VISIBLE); diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java index 5e0dec378..ad621d27c 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/activity/VideoActivity.java @@ -116,7 +116,7 @@ import master.flame.danmaku.danmaku.model.IDisplay; import master.flame.danmaku.danmaku.model.android.DanmakuContext; import tv.danmaku.ijk.media.player.ui.IjkVideoView; -public class VideoActivity extends BaseActivity implements Clock.Callback, CustomKeyDownVod.Listener, CastDialog.Listener, TrackDialog.Listener, ControlDialog.Listener, FlagAdapter.OnClickListener, EpisodeAdapter.OnClickListener, QualityAdapter.OnClickListener, QuickAdapter.OnClickListener, ParseAdapter.OnClickListener, SubtitleCallback { +public class VideoActivity extends BaseActivity implements Clock.Callback, CustomKeyDownVod.Listener, TrackDialog.Listener, ControlDialog.Listener, FlagAdapter.OnClickListener, EpisodeAdapter.OnClickListener, QualityAdapter.OnClickListener, QuickAdapter.OnClickListener, ParseAdapter.OnClickListener, SubtitleCallback { private ActivityVideoBinding mBinding; private ViewGroup.LayoutParams mFrameParams; @@ -1501,11 +1501,6 @@ public class VideoActivity extends BaseActivity implements Clock.Callback, Custo PlaybackService.stop(); } - @Override - public void onCastTo() { - onPaused(); - } - @Override public void onScale(int tag) { mHistory.setScale(tag); diff --git a/app/src/mobile/java/com/fongmi/android/tv/ui/custom/dialog/CastDialog.java b/app/src/mobile/java/com/fongmi/android/tv/ui/custom/dialog/CastDialog.java index c62a67c28..e15462626 100644 --- a/app/src/mobile/java/com/fongmi/android/tv/ui/custom/dialog/CastDialog.java +++ b/app/src/mobile/java/com/fongmi/android/tv/ui/custom/dialog/CastDialog.java @@ -12,7 +12,9 @@ import androidx.viewbinding.ViewBinding; import com.android.cast.dlna.dmc.DLNACastManager; import com.android.cast.dlna.dmc.OnDeviceRegistryListener; -import com.android.cast.dlna.dmc.control.ICastInterface; +import com.android.cast.dlna.dmc.control.DeviceControl; +import com.android.cast.dlna.dmc.control.OnDeviceControlListener; +import com.android.cast.dlna.dmc.control.ServiceActionCallback; import com.fongmi.android.tv.App; import com.fongmi.android.tv.Constant; import com.fongmi.android.tv.R; @@ -24,7 +26,6 @@ import com.fongmi.android.tv.cast.CastVideo; import com.fongmi.android.tv.cast.ScanEvent; import com.fongmi.android.tv.cast.ScanTask; import com.fongmi.android.tv.databinding.DialogDeviceBinding; -import com.fongmi.android.tv.impl.Callback; import com.fongmi.android.tv.server.Server; import com.fongmi.android.tv.ui.activity.ScanActivity; import com.fongmi.android.tv.ui.adapter.DeviceAdapter; @@ -33,6 +34,8 @@ import com.github.catvod.net.OkHttp; import com.github.catvod.utils.Path; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import org.fourthline.cling.support.lastchange.EventedValue; +import org.fourthline.cling.support.model.TransportState; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.ThreadMode; @@ -40,19 +43,22 @@ import org.greenrobot.eventbus.ThreadMode; import java.io.IOException; import java.util.List; +import kotlin.Unit; import okhttp3.Call; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Response; -public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListener, ScanTask.Listener, OnDeviceRegistryListener, ICastInterface.CastEventListener { +public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListener, ScanTask.Listener, OnDeviceRegistryListener, OnDeviceControlListener, ServiceActionCallback, okhttp3.Callback { private final FormBody.Builder body; private final OkHttpClient client; + private DialogDeviceBinding binding; private DeviceAdapter adapter; - private Listener listener; + private DeviceControl control; private CastVideo video; + private long position; private boolean fm; public static CastDialog create() { @@ -73,6 +79,7 @@ public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListe if (fd.startsWith("file")) fd = Server.get().getAddress() + "/" + fd.replace(Path.rootPath(), ""); if (fd.contains("127.0.0.1")) fd = fd.replace("127.0.0.1", Server.get().getIP()); body.add("history", history.toString().replace(id, fd)); + position = history.getPosition(); return this; } @@ -89,7 +96,6 @@ public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListe public void show(FragmentActivity activity) { for (Fragment f : activity.getSupportFragmentManager().getFragments()) if (f instanceof BottomSheetDialogFragment) return; show(activity.getSupportFragmentManager(), null); - this.listener = (Listener) activity; } @Override @@ -119,14 +125,12 @@ public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListe private void getDevice() { if (fm) adapter.addAll(Device.getAll()); - adapter.addAll(CastDevice.get().getAll()); - if (CastDevice.get().isEmpty()) App.post(() -> onRefresh(false), 1000); + onRefresh(false); } private void initDLNA() { - DLNACastManager.getInstance().bindCastService(App.get()); - DLNACastManager.getInstance().registerDeviceListener(this); - DLNACastManager.getInstance().registerActionCallbacks(this); + DLNACastManager.INSTANCE.bindCastService(App.get()); + DLNACastManager.INSTANCE.registerDeviceListener(this); } private void onRefresh() { @@ -135,7 +139,7 @@ public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListe private void onRefresh(boolean clear) { if (fm) ScanTask.create(this).start(adapter.getIps()); - DLNACastManager.getInstance().search(null, 3); + DLNACastManager.INSTANCE.search(null); if (clear) adapter.clear(); } @@ -143,27 +147,14 @@ public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListe ScanActivity.start(getActivity()); } - private void onSuccess(Device item) { - if (!item.isMobile()) listener.onCastTo(); + private void onSuccess() { dismiss(); } - private void onError() { + private void onFailure() { Notify.show(R.string.device_offline); } - @Override - public void onSuccess(String result) { - DLNACastManager.getInstance().play(); - listener.onCastTo(); - dismiss(); - } - - @Override - public void onFailed(String errMsg) { - Notify.show(errMsg); - } - @Subscribe(threadMode = ThreadMode.MAIN) public void onScanEvent(ScanEvent event) { ScanTask.create(this).start(event.getAddress()); @@ -175,53 +166,81 @@ public class CastDialog extends BaseDialog implements DeviceAdapter.OnClickListe } @Override - public void onDeviceAdded(org.fourthline.cling.model.meta.Device device) { + public void onDeviceAdded(@NonNull org.fourthline.cling.model.meta.Device device) { adapter.addAll(CastDevice.get().add(device)); } @Override - public void onDeviceRemoved(org.fourthline.cling.model.meta.Device device) { + public void onDeviceRemoved(@NonNull org.fourthline.cling.model.meta.Device device) { adapter.remove(CastDevice.get().remove(device)); } @Override - public void onDeviceUpdated(org.fourthline.cling.model.meta.Device device) { + public void onConnected(@NonNull org.fourthline.cling.model.meta.Device device) { + control.setAVTransportURI(video.getUrl(), video.getName(), this); } @Override - public void onItemClick(Device item) { - if (item.isDLNA()) DLNACastManager.getInstance().cast(CastDevice.get().find(item), video); - else OkHttp.newCall(client, item.getIp().concat("/action?do=cast"), body.build()).enqueue(new Callback() { - @Override - public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { - boolean ok = response.body().string().equals("OK"); - if (ok) App.post(() -> onSuccess(item)); - else App.post(() -> onError()); - } + public void onDisconnected(@NonNull org.fourthline.cling.model.meta.Device device) { + onFailure(); + } - @Override - public void onFailure(@NonNull Call call, @NonNull IOException e) { - App.post(() -> onError()); - } - }); + @Override + public void onSuccess(Unit unit) { + control.play("1", null); + onSuccess(); } @Override - public boolean onLongClick(Device item) { - return false; + public void onFailure(@NonNull String s) { + onFailure(); + } + + @Override + public void onFailure(@NonNull Call call, @NonNull IOException e) { + App.post(this::onFailure); + } + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException { + boolean ok = response.body().string().equals("OK"); + if (ok) App.post(this::onSuccess); + else App.post(this::onFailure); + } + + @Override + public void onItemClick(Device item) { + if (item.isDLNA()) control = DLNACastManager.INSTANCE.connectDevice(CastDevice.get().find(item), this); + else OkHttp.newCall(client, item.getIp().concat("/action?do=cast"), body.build()).enqueue(this); } @Override public void onDestroyView() { super.onDestroyView(); + CastDevice.get().clear(); EventBus.getDefault().unregister(this); - DLNACastManager.getInstance().unregisterListener(this); - DLNACastManager.getInstance().unregisterActionCallbacks(); - DLNACastManager.getInstance().unbindCastService(App.get()); + DLNACastManager.INSTANCE.unregisterListener(this); + DLNACastManager.INSTANCE.unbindCastService(App.get()); + } + + @Override + public void onAvTransportStateChanged(@NonNull TransportState transportState) { + } + + @Override + public void onEventChanged(@NonNull EventedValue eventedValue) { } - public interface Listener { + @Override + public void onRendererVolumeChanged(int i) { + } - void onCastTo(); + @Override + public void onRendererVolumeMuteChanged(boolean b) { + } + + @Override + public boolean onLongClick(Device item) { + return false; } } diff --git a/quickjs/build.gradle b/quickjs/build.gradle index 44c0a5324..13201e904 100644 --- a/quickjs/build.gradle +++ b/quickjs/build.gradle @@ -15,5 +15,5 @@ dependencies { implementation project(':catvod') implementation 'wang.harlon.quickjs:wrapper-java:1.0.0' implementation 'net.sourceforge.streamsupport:android-retrofuture:1.7.4' - implementation(ext: 'aar', name: 'quickjs', group: 'quickjs', version: '1.0.0') + implementation(ext: 'aar', name: 'quickjs', group: 'fongmi', version: 'release') } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 4cb7205a8..3d87e8ff5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -13,13 +13,13 @@ dependencyResolutionManagement { jcenter() google() flatDir { - dirs "$rootDir/quickjs/libs" + dirs "$rootDir/app/libs" } maven { - url 'https://jitpack.io' + url "https://jitpack.io" } maven { - url 'http://4thline.org/m2' + url "http://4thline.org/m2" allowInsecureProtocol = true } }