Skip to content

Commit

Permalink
Fix mute after a period of time
Browse files Browse the repository at this point in the history
  • Loading branch information
HeHang0 committed May 5, 2024
1 parent 3054d07 commit dac02fd
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 84 deletions.
10 changes: 5 additions & 5 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ android {
applicationId "com.picapico.audioshare"
minSdk 21
targetSdk 34
versionCode 178
versionName "1.7.8"
versionCode 179
versionName "1.7.9"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
Expand Down Expand Up @@ -52,9 +52,9 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.media:media:1.7.0'
implementation 'androidx.media3:media3-exoplayer:1.3.0'
implementation 'com.github.HeHang0:exoplayer-extension-flac:1.3.0'
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.media3:media3-exoplayer:1.3.1'
implementation 'com.github.HeHang0:exoplayer-extension-flac:1.3.1'
implementation 'com.google.android.material:material:1.12.0'
implementation 'com.koushikdutta.async:androidasync:3.1.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
Expand Down
39 changes: 27 additions & 12 deletions android/app/src/main/java/com/picapico/audioshare/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.CompoundButton;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.app.ActivityCompat;

import java.net.Inet6Address;
Expand All @@ -34,10 +35,11 @@ public class MainActivity extends AppCompatActivity {
private TcpService tcpService = null;
private boolean isBound = false;
private TextView ipAddress;
private TextView manager;
private SwitchCompat managerSwitch;
private TextView managerText;
private String versionName;
private LinearLayout connectedLayout;
private LinearLayout unConnectedLayout;
private SwitchCompat connectionSwitch;
private TextView connectionText;
private final TcpService.MessageListener messageListener = () -> {
setConnectionStatus();
setListenStatus();
Expand Down Expand Up @@ -69,24 +71,31 @@ protected void onCreate(Bundle savedInstanceState) {
setStatusBarTransparent();
setVersionName();
ipAddress = findViewById(R.id.ipAddress);
manager = findViewById(R.id.manager);
connectedLayout = findViewById(R.id.connected);
unConnectedLayout = findViewById(R.id.unconnected);
managerSwitch = findViewById(R.id.managerSwitch);
managerText = findViewById(R.id.managerText);
connectionSwitch = findViewById(R.id.connectionSwitch);
connectionText = findViewById(R.id.connectionText);
Intent intent = new Intent(this, TcpService.class);
startService(intent);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
manager.setOnClickListener(this::onManagerClick);
managerText.setOnClickListener(this::onManagerClick);
findViewById(R.id.imageView).setOnClickListener(this::onManagerClick);
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.ACCESS_WIFI_STATE
}, 1);
managerSwitch.setOnClickListener(this::onHttpServerRunningChanged);
}

private void onHttpServerRunningChanged(View v) {
if(tcpService == null) return;
tcpService.setHttpRunning(managerSwitch.isChecked());
}

private void onManagerClick(View e){
try {
Uri uri = Uri.parse(manager.getText().toString());
Uri uri = Uri.parse(managerText.getText().toString());
if(uri.isAbsolute()){
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
Expand Down Expand Up @@ -120,8 +129,8 @@ private void setConnectionStatus(){
if(tcpService == null) return;
runOnUiThread(() -> {
boolean playing = tcpService.getPlaying();
connectedLayout.setVisibility(playing ? View.VISIBLE : View.GONE);
unConnectedLayout.setVisibility(playing ? View.GONE : View.VISIBLE);
connectionText.setText(playing ? R.string.connected : R.string.unconnected);
connectionSwitch.setChecked(playing);
});
}

Expand Down Expand Up @@ -154,7 +163,13 @@ private void setListenStatus(){
if(httpPort != 80){
httpAddress += ":" + httpPort;
}
manager.setText(httpAddress);
if(tcpService.getHttpRunning()){
managerText.setText(httpAddress);
managerSwitch.setChecked(true);
}else {
managerText.setText(R.string.musiche_closed);
managerSwitch.setChecked(false);
}
});
}

Expand Down
68 changes: 58 additions & 10 deletions android/app/src/main/java/com/picapico/audioshare/TcpService.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.picapico.audioshare;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.media.AudioAttributes;
import android.media.AudioFormat;
Expand All @@ -19,6 +21,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
Expand Down Expand Up @@ -64,14 +67,18 @@ public class TcpService extends NotificationService {
private final ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
private final Handler mHandler = new Handler(Looper.getMainLooper());
private HttpServer httpServer;
private SharedPreferences mSharedPreferences;
@Override
public void onCreate() {
super.onCreate();
mWakeLockManager = new WakeLockManager(this);
Log.i(TAG, "Service on created");
new Thread(this::startLocalServer).start();
new Thread(this::startServer).start();
this.startHttpServer();
mSharedPreferences = getSharedPreferences("app", Context.MODE_PRIVATE);
if(mSharedPreferences.getBoolean("http-server", true)){
this.startHttpServer();
}
this.startBroadcastTimer();
}
@Override
Expand Down Expand Up @@ -108,7 +115,7 @@ public void onDestroy() {
} catch (IOException e) {
Log.e(TAG, "close tcp server error: " + e);
}
httpServer.stop();
if(httpServer != null) httpServer.stop();
}

private byte readHead(InputStream stream) throws IOException {
Expand Down Expand Up @@ -142,12 +149,13 @@ private int readInt(InputStream stream) throws IOException {
return parseInt(buffer);
}

private int lastPCVolume = 1;
private void processControlStream(byte command, InputStream stream) {
if(command == 2){
try {
int volume = readInt(stream);
volume = maxAudioVolume * volume / 100;
setVolume(volume);
lastPCVolume = maxAudioVolume * volume / 100;
setVolume(lastPCVolume);
} catch (IOException e) {
Log.e(TAG, "read volume error: " + e);
}
Expand Down Expand Up @@ -259,6 +267,7 @@ private void startLocalServer(){
}
}
private void startHttpServer(){
if(httpServer != null) return;
Log.i(TAG, "prepare http start server");
int port = NetworkUtils.getFreePort(Build.MANUFACTURER.equalsIgnoreCase("phicomm") ? 8090 : 8080);
this.setHttpPort(port);
Expand All @@ -277,6 +286,7 @@ public void onMediaMetaChanged(String title, String artist, String album, String
this.setMediaSessionCallback(httpServer.getAudioPlayer().getNotificationCallback());
httpServer.setSharedPreferences(getSharedPreferences("config", Context.MODE_PRIVATE));
httpServer.setAssetManager(getAssets());
httpServer.setVersionName(mVersionName);
}
private void startServer(){
Log.i(TAG, "prepare tcp start server");
Expand Down Expand Up @@ -346,6 +356,7 @@ public synchronized int getListenPort() {
}

private int httpPort = 8088;
private String mVersionName="";

private synchronized void setHttpPort(int httpPort) {
this.httpPort = httpPort;
Expand All @@ -355,18 +366,42 @@ public synchronized int getHttpPort() {
return httpPort;
}

public synchronized boolean getHttpRunning() {
return mSharedPreferences.getBoolean("http-server", true) && httpServer != null;
}

@SuppressLint("ApplySharedPref")
public synchronized void setHttpRunning(boolean running) {
if(running) {
mSharedPreferences.edit().putBoolean("http-server", true).apply();
startHttpServer();
}else {
String message = getResources().getString(R.string.musiche_closed) + ", " + getResources().getString(R.string.effective_after_restart);
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
final Intent intent = getPackageManager().getLaunchIntentForPackage(getPackageName());
if(intent != null){
startActivity(intent);
}
mSharedPreferences.edit().putBoolean("http-server", false).commit();
android.os.Process.killProcess(android.os.Process.myPid());
}
if(mListener != null){
mListener.onMessage();
}
}

public void setMessageListener(MessageListener listener){
mListener = listener;
}

public void setAudioManager(AudioManager audioManager){
mAudioManager = audioManager;
maxAudioVolume = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
httpServer.setAudioManager(audioManager);
if(httpServer != null) httpServer.setAudioManager(audioManager);
}

public void setVersionName(String versionName){
httpServer.setVersionName(versionName);
mVersionName = versionName;
if(httpServer != null) httpServer.setVersionName(versionName);
}

private void playAudio(int sampleRateInHz, int channelConfig, int audioEncoding, int bufferSizeInBytes, Closeable closer, InputStream inputStream, OutputStream outputStream){
Expand All @@ -391,7 +426,7 @@ private void playAudio(int sampleRateInHz, int channelConfig, int audioEncoding,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
audioAttributes.setFlags(AudioAttributes.FLAG_LOW_LATENCY);
}
httpServer.getAudioPlayer().pause();
if(httpServer != null) httpServer.getAudioPlayer().pause();
mAudioTrack = new AudioTrack(
audioAttributes.build(),
audioFormat,
Expand Down Expand Up @@ -428,16 +463,26 @@ private void playAudio(int sampleRateInHz, int channelConfig, int audioEncoding,
Log.w(TAG, "write audio busy");
continue;
}
if(httpServer.getAudioPlayer().isPlaying()) {

if(httpServer != null && httpServer.getAudioPlayer().isPlaying()) {
Log.w(TAG, "write audio playing");
continue;
}
byte[] finalBuffer = buffer;
int finalDataLength = dataLength;
setWriting(true);
mExecutorService.execute(() -> {
mAudioTrack.write(finalBuffer, 0, finalDataLength);
int code = mAudioTrack.write(finalBuffer, 0, finalDataLength);
mAudioTrack.flush();
mHandler.post(() -> setWriting(false));
if(code < 0) {
Log.e(TAG, "write audio data err: " + code);
}
int state = mAudioTrack.getPlayState();
if(state != AudioTrack.PLAYSTATE_PLAYING) {
Log.w(TAG, "write audio state: " + state);
// mAudioTrack.play();
}
});
}
} catch (Exception e) {
Expand Down Expand Up @@ -544,6 +589,9 @@ public void run() {
if(mSocketOutputStream != null) {
mSocketOutputStream.write(new byte[1]);
Log.i(TAG, "send heartbeat");
if(lastPCVolume > 0 && mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC) == 0){
setVolume(lastPCVolume);
}
}
} catch (IOException e) {
Log.e(TAG, "send heartbeat err: " + e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class HttpServer implements AudioPlayer.OnChangedListener {
AsyncHttpServer mServer;
AudioPlayer mAudioPlayer;
List<WebSocket> mWebClients = new ArrayList<>();
final Object mWebClientsLock = new Object();
Map<String, RemoteClient> mRemoteClients = new HashMap<>();
BroadcastReceiver mBroadcastReceiver;
SharedPreferences mPreferences;
Expand All @@ -55,7 +56,6 @@ public HttpServer(Context context, int port) {
mContext = context;
mAudioPlayer = new AudioPlayer(context);
initDeviceName();
initBroadcastReceiver();
}

//region Initialization
Expand Down Expand Up @@ -107,15 +107,21 @@ public boolean onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse
}catch (Exception e){
Log.e(TAG, "start http server error: ", e);
}
initBroadcastReceiver();
return this;
}
public void stop(){
if(mServer == null) return;
try {
mServer.stop();
mAudioPlayer.pause();
}catch (Exception e){
Log.e(TAG, "stop server error");
}
if(mBroadcastReceiver != null) {
mBroadcastReceiver.stop();
mBroadcastReceiver = null;
}
mServer = null;
}
public static String getMarketingName() {
Expand Down Expand Up @@ -583,7 +589,6 @@ public void run() {
localClient.setChannel(client.getChannel());
if(client.getChannel() < 0) {
localClient.send(RemoteMessage.of(RemoteMessage.MessageTypePause));
localClient.setChannel(AudioPlayer.ChannelTypeNone);
}else {
localClient.send(RemoteMessage.of(RemoteMessage.MessageTypeChannel)
.setChannel(client.getChannel()));
Expand Down Expand Up @@ -733,25 +738,31 @@ private void setHeader(AsyncHttpServerResponse response, Map<String, String> hea

//region websocket
private final AsyncHttpServer.WebSocketRequestCallback websocketHandler = (webSocket, request) -> {
mWebClients.add(webSocket);
synchronized (mWebClientsLock){
mWebClients.add(webSocket);
}
webSocket.send(mAudioPlayer.getStatus().toString());
webSocket.setClosedCallback(e -> {
try {
if (e != null) Log.e(TAG, "An error occurred", e);
} finally {
mWebClients.remove(webSocket);
synchronized (mWebClientsLock){
mWebClients.remove(webSocket);
}
}
});
};

private final AsyncHttpServer.WebSocketRequestCallback serverWebsocketHandler = (webSocket, request) -> this.onRemoteServerSocket(webSocket);

public void sendWSMessage(String message){
for (WebSocket socket: mWebClients) {
try {
socket.send(message);
}catch (Exception e){
Log.e(TAG, "send websocket msg error", e);
synchronized (mWebClientsLock){
for (WebSocket socket: mWebClients) {
try {
socket.send(message);
}catch (Exception e){
Log.e(TAG, "send websocket msg error", e);
}
}
}
}
Expand Down
Loading

0 comments on commit dac02fd

Please sign in to comment.