MediaPlayer 流服务中的协议异常(MediaHTTPConnection:readAt 20709376 / 32768 => java.net.ProtocolException)

拉德克·加科夫斯基

我制作了一个 Android 应用程序,其主要功能是从我的服务器播放音频流。但是由于某种原因,音乐在大约 20 分钟后停止播放,并且该应用程序抛出 ProtocolException(来自Android Studio logcat图像上的应用程序的日志)。Android Studio logcat

这个错误更奇怪,因为它只发生在某些设备上。多个小米设备(均使用Android 10)和三星Galaxy S9(也使用Android 10)出现错误,但在三星Galaxy S10(Android 10)和华为平板电脑上不会发生错误,只要用户播放音乐就会播放不要阻止它。

这是我的 PlayerService 类代码,负责将 MediaPlayer 作为服务运行:

public class PlayerService extends Service {

private static final String CHANNEL_ID = "PlayerServiceChannel";
private static final int SERVICE_ID = 1;
private MediaPlayer player;
private Notification notification;
private JsonObjectHandler jsonObjectHandler;
private int streamIndex = 9999;
private Messenger messenger;
private PendingIntent pendingIntent;
private NotificationManager notificationManager;
private PendingIntent closeApp;
private WifiManager.WifiLock wifiLock;

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    try {
        JSONObject jsonObject = new JSONObject(Objects.requireNonNull(intent.getStringExtra("JsonInfo")));
        jsonObjectHandler = new JsonObjectHandler(jsonObject);
    } catch (JSONException e) {
        jsonObjectHandler = null;
    }
    return START_REDELIVER_INTENT;
}

@Override
public void onCreate() {
    super.onCreate();
    wifiLock = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE))
            .createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "playerServiceWiFiLock");
    HandlerThread thread = new HandlerThread("ServiceStartArgument", Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();
    Looper mServiceLooper = thread.getLooper();
    ServiceHandler mServiceHandler = new ServiceHandler(mServiceLooper);
    messenger = new Messenger(mServiceHandler);
    PhoneStateListener mPhoneStateListener = new PhoneStateListener() {

        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            switch (state) {
                case TelephonyManager.CALL_STATE_RINGING:

                case TelephonyManager.CALL_STATE_OFFHOOK:
                    stopForeground(true);
                    stopSelf();
                    break;
                case TelephonyManager.CALL_STATE_IDLE:
                    break;
            }
            super.onCallStateChanged(state, incomingNumber);
        }
    };

    TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
    if (mgr != null) {
        mgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
    }

    createNotificationChannel();

    Intent notificationIntent = new Intent(this, LoginActivity.class);

    pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            stopSelf();
            unregisterReceiver(this);
            System.exit(0);
        }
    };

    IntentFilter intentFilter = new IntentFilter("android.intent.CLOSE_APP");
    registerReceiver(broadcastReceiver, intentFilter);

    Intent intentClose = new Intent("android.intent.CLOSE_APP");

    closeApp = PendingIntent.getBroadcast(this, 0, intentClose, 0);

    updateNotification(streamIndex);

    startForeground(SERVICE_ID, notification);
}

private NotificationCompat.Builder createNotification(int streamIndex) {
    String defaultValue;
    if (jsonObjectHandler == null || streamIndex == 9999) {
        defaultValue = "";
    } else {
        defaultValue =
                jsonObjectHandler.getPlaylistButtons().get(streamIndex).getButtonName();
    }
    return new NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ikonastream48)
            .setContentIntent(pendingIntent)
            .setContentTitle(getString(R.string.app_name))
            .setContentText(defaultValue)
            .setDefaults(0)
            .setSound(null)
            .addAction(R.drawable.ic_close_black, getString(R.string.close), closeApp);
}

private void updateNotification(int streamIndex) {
    notification = createNotification(streamIndex).build();
    notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    assert notificationManager != null;
    notificationManager.notify(SERVICE_ID, notification);
}

private void createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel serviceChannel = new NotificationChannel(
                CHANNEL_ID, "Example Service Channel", NotificationManager.IMPORTANCE_DEFAULT);

        serviceChannel.setSound(null, null);

        notificationManager = getSystemService(NotificationManager.class);
        if (notificationManager != null) {
            notificationManager.createNotificationChannel(serviceChannel);
        }
    }
}

private void stopServicePlayer() {
    if (player != null) {
        player.stop();
        player.reset();
        player.release();
        player = null;
    }
    stopForeground(true);
}

@Override
public void onDestroy() {
    super.onDestroy();
    stopServicePlayer();
    if (wifiLock.isHeld()) wifiLock.release();
}

private void sendMessageBroadcast(Intent intent) {
    LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
    if (streamIndex != 9999) {
        Intent intent1 = new Intent("streamIndex");
        intent1.putExtra("INDEX", streamIndex);
        sendMessageBroadcast(intent1);
    }
    return messenger.getBinder();
}

private final class ServiceHandler extends Handler {

    ServiceHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if (msg.what == 0) {
            player = new MediaPlayer();
            player.setOnErrorListener((mp, what, extra) -> false);
            player.setAudioAttributes(new AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
                    .setUsage(AudioAttributes.USAGE_MEDIA)
                    .build());
            player.setAudioStreamType(AudioManager.STREAM_MUSIC);
            player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
            streamIndex = msg.arg1;
            updateNotification(streamIndex);
            try {
                player.setOnPreparedListener(mediaPlayer -> {
                    mediaPlayer.start();
                    Intent intent = new Intent("streamIndex");
                    intent.putExtra("INDEX", streamIndex);
                    sendMessageBroadcast(intent);
                });
                player.setDataSource(jsonObjectHandler
                        .getPlaylistButtons()
                        .get(streamIndex)
                        .getButtonStreamAddress());
            } catch (IOException e) {
                e.printStackTrace();
            }
            player.prepareAsync();
            if (!wifiLock.isHeld()) wifiLock.acquire();
        } else if (msg.what == 1) {
            Intent intent2 = new Intent("streamIndex");
            intent2.putExtra("INDEX", streamIndex);
            sendMessageBroadcast(intent2);
        }
    }
}
}

提前感谢您的所有回复!

PS 代码是几年前写的(在我编程之旅的开始时),所以我知道它看起来很糟糕,需要以更好的方式重写。

拉德克·加科夫斯基

问题出在服务器端。当流在 Lame 编码器中从 CBR 切换到 VBR 时,问题停止发生。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章