Search in sources :

Example 6 with Playable

use of de.danoeh.antennapod.model.playback.Playable in project AntennaPod by AntennaPod.

the class PlaybackService method onStartCommand.

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onStartCommand(intent, flags, startId);
    Log.d(TAG, "OnStartCommand called");
    stateManager.startForeground(R.id.notification_playing, notificationBuilder.build());
    NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
    notificationManager.cancel(R.id.notification_streaming_confirmation);
    final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1);
    final boolean hardwareButton = intent.getBooleanExtra(MediaButtonReceiver.EXTRA_HARDWAREBUTTON, false);
    Playable playable = intent.getParcelableExtra(EXTRA_PLAYABLE);
    if (keycode == -1 && playable == null) {
        Log.e(TAG, "PlaybackService was started with no arguments");
        stateManager.stopService();
        return Service.START_NOT_STICKY;
    }
    if ((flags & Service.START_FLAG_REDELIVERY) != 0) {
        Log.d(TAG, "onStartCommand is a redelivered intent, calling stopForeground now.");
        stateManager.stopForeground(true);
    } else {
        if (keycode != -1) {
            boolean notificationButton;
            if (hardwareButton) {
                Log.d(TAG, "Received hardware button event");
                notificationButton = false;
            } else {
                Log.d(TAG, "Received media button event");
                notificationButton = true;
            }
            boolean handled = handleKeycode(keycode, notificationButton);
            if (!handled && !stateManager.hasReceivedValidStartCommand()) {
                stateManager.stopService();
                return Service.START_NOT_STICKY;
            }
        } else {
            stateManager.validStartCommandWasReceived();
            boolean stream = intent.getBooleanExtra(EXTRA_SHOULD_STREAM, true);
            boolean allowStreamThisTime = intent.getBooleanExtra(EXTRA_ALLOW_STREAM_THIS_TIME, false);
            boolean allowStreamAlways = intent.getBooleanExtra(EXTRA_ALLOW_STREAM_ALWAYS, false);
            boolean startWhenPrepared = intent.getBooleanExtra(EXTRA_START_WHEN_PREPARED, false);
            boolean prepareImmediately = intent.getBooleanExtra(EXTRA_PREPARE_IMMEDIATELY, false);
            sendNotificationBroadcast(NOTIFICATION_TYPE_RELOAD, 0);
            if (allowStreamAlways) {
                UserPreferences.setAllowMobileStreaming(true);
            }
            boolean localFeed = URLUtil.isContentUrl(playable.getStreamUrl());
            if (stream && !NetworkUtils.isStreamingAllowed() && !allowStreamThisTime && !localFeed) {
                displayStreamingNotAllowedNotification(intent);
                PlaybackPreferences.writeNoMediaPlaying();
                stateManager.stopService();
                return Service.START_NOT_STICKY;
            }
            Observable.fromCallable(() -> {
                if (playable instanceof FeedMedia) {
                    return DBReader.getFeedMedia(((FeedMedia) playable).getId());
                } else {
                    return playable;
                }
            }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(playableLoaded -> {
                if (!playable.getIdentifier().equals(PlaybackPreferences.getCurrentlyPlayingFeedMediaId())) {
                    PlaybackPreferences.clearCurrentlyPlayingTemporaryPlaybackSpeed();
                }
                mediaPlayer.playMediaObject(playableLoaded, stream, startWhenPrepared, prepareImmediately);
                addPlayableToQueue(playableLoaded);
            }, error -> {
                Log.d(TAG, "Playable was not found. Stopping service.");
                error.printStackTrace();
                stateManager.stopService();
            });
            return Service.START_NOT_STICKY;
        }
    }
    return Service.START_NOT_STICKY;
}
Also used : Playable(de.danoeh.antennapod.model.playback.Playable) FeedMedia(de.danoeh.antennapod.model.feed.FeedMedia) NotificationManagerCompat(androidx.core.app.NotificationManagerCompat)

Example 7 with Playable

use of de.danoeh.antennapod.model.playback.Playable in project AntennaPod by AntennaPod.

the class PlaybackService method skipEndingIfNecessary.

private void skipEndingIfNecessary() {
    Playable playable = mediaPlayer.getPlayable();
    if (!(playable instanceof FeedMedia)) {
        return;
    }
    int duration = getDuration();
    int remainingTime = duration - getCurrentPosition();
    FeedMedia feedMedia = (FeedMedia) playable;
    FeedPreferences preferences = feedMedia.getItem().getFeed().getPreferences();
    int skipEnd = preferences.getFeedSkipEnding();
    if (skipEnd > 0 && skipEnd * 1000 < getDuration() && (remainingTime - (skipEnd * 1000) > 0) && ((remainingTime - skipEnd * 1000) < (getCurrentPlaybackSpeed() * 1000))) {
        Log.d(TAG, "skipEndingIfNecessary: Skipping the remaining " + remainingTime + " " + skipEnd * 1000 + " speed " + getCurrentPlaybackSpeed());
        Context context = getApplicationContext();
        String skipMesg = context.getString(R.string.pref_feed_skip_ending_toast, skipEnd);
        Toast toast = Toast.makeText(context, skipMesg, Toast.LENGTH_LONG);
        toast.show();
        this.autoSkippedFeedMediaId = feedMedia.getItem().getIdentifyingValue();
        mediaPlayer.skip();
    }
}
Also used : FeedPreferences(de.danoeh.antennapod.model.feed.FeedPreferences) Context(android.content.Context) Toast(android.widget.Toast) Playable(de.danoeh.antennapod.model.playback.Playable) FeedMedia(de.danoeh.antennapod.model.feed.FeedMedia)

Example 8 with Playable

use of de.danoeh.antennapod.model.playback.Playable in project AntennaPod by AntennaPod.

the class DBWriter method addQueueItem.

/**
 * Appends FeedItem objects to the end of the queue. The 'read'-attribute of all items will be set to true.
 * If a FeedItem is already in the queue, the FeedItem will not change its position in the queue.
 *
 * @param context             A context that is used for opening a database connection.
 * @param performAutoDownload true if an auto-download process should be started after the operation.
 * @param markAsUnplayed      true if the items should be marked as unplayed when enqueueing
 * @param itemIds             IDs of the FeedItem objects that should be added to the queue.
 */
public static Future<?> addQueueItem(final Context context, final boolean performAutoDownload, final boolean markAsUnplayed, final long... itemIds) {
    return dbExec.submit(() -> {
        if (itemIds.length < 1) {
            return;
        }
        final PodDBAdapter adapter = PodDBAdapter.getInstance();
        adapter.open();
        final List<FeedItem> queue = DBReader.getQueue(adapter);
        boolean queueModified = false;
        LongList markAsUnplayedIds = new LongList();
        List<QueueEvent> events = new ArrayList<>();
        List<FeedItem> updatedItems = new ArrayList<>();
        ItemEnqueuePositionCalculator positionCalculator = new ItemEnqueuePositionCalculator(UserPreferences.getEnqueueLocation());
        Playable currentlyPlaying = PlayableUtils.createInstanceFromPreferences(context);
        int insertPosition = positionCalculator.calcPosition(queue, currentlyPlaying);
        for (long itemId : itemIds) {
            if (!itemListContains(queue, itemId)) {
                final FeedItem item = DBReader.getFeedItem(itemId);
                if (item != null) {
                    queue.add(insertPosition, item);
                    events.add(QueueEvent.added(item, insertPosition));
                    item.addTag(FeedItem.TAG_QUEUE);
                    updatedItems.add(item);
                    queueModified = true;
                    if (item.isNew()) {
                        markAsUnplayedIds.add(item.getId());
                    }
                    insertPosition++;
                }
            }
        }
        if (queueModified) {
            applySortOrder(queue, events);
            adapter.setQueue(queue);
            for (QueueEvent event : events) {
                EventBus.getDefault().post(event);
            }
            EventBus.getDefault().post(FeedItemEvent.updated(updatedItems));
            if (markAsUnplayed && markAsUnplayedIds.size() > 0) {
                DBWriter.markItemPlayed(FeedItem.UNPLAYED, markAsUnplayedIds.toArray());
            }
        }
        adapter.close();
        if (performAutoDownload) {
            DBTasks.autodownloadUndownloadedItems(context);
        }
    });
}
Also used : FeedItem(de.danoeh.antennapod.model.feed.FeedItem) Playable(de.danoeh.antennapod.model.playback.Playable) ArrayList(java.util.ArrayList) QueueEvent(de.danoeh.antennapod.event.QueueEvent) LongList(de.danoeh.antennapod.core.util.LongList)

Example 9 with Playable

use of de.danoeh.antennapod.model.playback.Playable in project AntennaPod by AntennaPod.

the class PlaybackService method bufferUpdate.

@Subscribe(threadMode = ThreadMode.MAIN)
@SuppressWarnings("unused")
public void bufferUpdate(BufferUpdateEvent event) {
    if (event.hasEnded()) {
        Playable playable = getPlayable();
        if (getPlayable() instanceof FeedMedia && playable.getDuration() <= 0 && mediaPlayer.getDuration() > 0) {
            // Playable is being streamed and does not have a duration specified in the feed
            playable.setDuration(mediaPlayer.getDuration());
            DBWriter.setFeedMedia((FeedMedia) playable);
            updateNotificationAndMediaSession(playable);
        }
    }
}
Also used : Playable(de.danoeh.antennapod.model.playback.Playable) FeedMedia(de.danoeh.antennapod.model.feed.FeedMedia) Subscribe(org.greenrobot.eventbus.Subscribe)

Example 10 with Playable

use of de.danoeh.antennapod.model.playback.Playable in project AntennaPod by AntennaPod.

the class FeedMedia method getMediaItem.

/**
 * Returns a MediaItem representing the FeedMedia object.
 * This is used by the MediaBrowserService
 */
public MediaBrowserCompat.MediaItem getMediaItem() {
    Playable p = this;
    MediaDescriptionCompat.Builder builder = new MediaDescriptionCompat.Builder().setMediaId(String.valueOf(id)).setTitle(p.getEpisodeTitle()).setDescription(p.getFeedTitle()).setSubtitle(p.getFeedTitle());
    if (item != null) {
        // getImageLocation() also loads embedded images, which we can not send to external devices
        if (item.getImageUrl() != null) {
            builder.setIconUri(Uri.parse(item.getImageUrl()));
        } else if (item.getFeed() != null && item.getFeed().getImageUrl() != null) {
            builder.setIconUri(Uri.parse(item.getFeed().getImageUrl()));
        }
    }
    return new MediaBrowserCompat.MediaItem(builder.build(), MediaBrowserCompat.MediaItem.FLAG_PLAYABLE);
}
Also used : Playable(de.danoeh.antennapod.model.playback.Playable) MediaDescriptionCompat(android.support.v4.media.MediaDescriptionCompat)

Aggregations

Playable (de.danoeh.antennapod.model.playback.Playable)35 Context (android.content.Context)14 CountDownLatch (java.util.concurrent.CountDownLatch)13 LocalPSMP (de.danoeh.antennapod.core.service.playback.LocalPSMP)11 PlaybackServiceMediaPlayer (de.danoeh.antennapod.playback.base.PlaybackServiceMediaPlayer)11 Test (org.junit.Test)11 UiThreadTest (androidx.test.annotation.UiThreadTest)10 AssertionFailedError (junit.framework.AssertionFailedError)9 MediumTest (androidx.test.filters.MediumTest)8 FeedMedia (de.danoeh.antennapod.model.feed.FeedMedia)8 LayoutInflater (android.view.LayoutInflater)3 Nullable (androidx.annotation.Nullable)3 PlayerErrorEvent (de.danoeh.antennapod.event.PlayerErrorEvent)3 FeedItem (de.danoeh.antennapod.model.feed.FeedItem)3 FeedPreferences (de.danoeh.antennapod.model.feed.FeedPreferences)3 Intent (android.content.Intent)2 Bundle (android.os.Bundle)2 Log (android.util.Log)2 View (android.view.View)2 ViewGroup (android.view.ViewGroup)2