Skip to content

Loading…

Add propper Live TV support to the Player JSON API #640

Closed
wants to merge 14 commits into from

4 participants

@RobertMe

Does what the title says :)

With this in you can remove PVR.ChannelUp and PVR.ChannelDown as the same can now be done with Player.GoNext (/GoPrevious). GoTo uses the "position" param as channel number (within the current group). I've added a "islive" property to the player. GetItem now returns (some) details about the channel (probably will be expanded later on).

I've also added a PVR.OnCurrentEpgItemChanged notification. This can't be used yet as there is no way to request data back (work in progress). But we've already discussed that epgid + starttime should be the events identifier so that doesn't change.

Another thing I'm unsure off is changing the AnnouncementFlag (IAnnouncer.h) to being two bytes big. But I think you also don't know if there are any consequences to it.

@opdenkamp

you need to send ACTION_CHANNEL_SWITCH to the player instead

Reading these parts of the code (actions and how CHANNEL_SWITCH etc get handled). Wouldn't these stay ACTION_NEXT_ITEM / ACTION_PREV_ITEM (and thus can be handled by default video/audio cases). Didn't test this yet, but I think that should work. And GoTo would then indeed be ACTION_CHANNEL_SWITCH.

I just copy/pasted the code from the old PVR stuff (PVR.ChannelUp/Down). So that's probably also why I didn't think about testing with the default Player methods (as those JSON PVR methods where already "obsolete" a long time then).

yeah next/prev item if you're doing up/down. channel_switch if you want to select a channel number.

Doesn't work :(

Same for the same changes you did in the original PVR code. It just responds with a Playlist error (notification), that there aren't any more items in the playlist.

As I don't know how these actions work etc (can't see they're being called in the players (OMXPlayer/DVDPlayer) OnAction method) I think it would be best if you can debug it yourself? Using your original branch/PR you could use this command to test if it works:
curl -i -X POST -d '{"jsonrpc": "2.0", "method": "PVR.ChannelUp", "params": { }, "id": 1}' http://localhost:8080/jsonrpc -H 'content-type: application/json'

Hmm, seems like it does work (at least ACTION_NEXT_ITEM), but only when the player is fullscreen, not when it's showing the preview (when you open Live TV, select a channel, and don't click the player/select the channel a second time).

I guess that would still be a bug in the handling of the action?

ACTION_NEXT_ITEM should be translated to CDVDMsg::PLAYER_CHANNEL_NEXT by the player. if it's not doing that when not in fullscreen, then that's a bug.

@opdenkamp

should be handled by IsPlayingVideo() if it's not already

That's a bit bugged :( When the channel gets started it takes a while before IsPlayingVideo is true. I guess because of the buffering. So when the JSON API sends OnPlay, and you immediately call GetActivePlayers the Video (or Audio) player isn't active yet.

It may be better to get IsPlayingVideo/Audio return properly (think I also saw another (mainline) PR which did some hackery around IsPlayingVideo because it didn't give the expected result). But for me as an XBMC newbie this was an easier solution.

And thinking about it, doesn't IsPlayingVideo always return true? As AFAIK radio channels also play in the video player? Which I guess results in IsPlayingVideo being true and IsPlayingAudio still being false (didn't read those internals (yet)).

no it checks whether it's a radio channel that's playing

Okay. And what about IsPlaying... not being true immediately? I guess it's because of the buffering, and possibly not getting access to the channel (back-end wise). What do you think is the best way to solve this? As Application automatically sends OnPlay (on the GUI_MSG_PLAYBACK_STARTED: message), so clients expect the player which is started also being returned by GetActivePlayers (or it should also send the OnStop), which it doesn't without this "hack".

@opdenkamp
Owner

this looks a bit meh to me. isn't it a better idea to catch radio/tv under the existing audio/video cases, and just check whether the pvrmanager is playing something in case you need to do something special for pvr? why do you need that extra type from b270594?

@opdenkamp
Owner

same here

@opdenkamp

why the check for the channelid? if the id is < 1, then it's a new channel, which should never end up in here.

Just took it from the other lines (guess those also can't be < 1). Will remove it.

@opdenkamp

this value changes when the use changes the group in the ui, when he changes the order, etc. you can't reliably use this. better use the channel id instead.

need to lock the mutex too btw, since these values can be updated while you're reading it

Okay, will remove number. Channelid is already present (gets added in the JSON code, FileItemHandler::HandleFileItem/FillDetails (don't know from the top of my head)).

Will add the mutex.

@opdenkamp

this is probably better done in player rather than here. and CFileItem takes a value, not a pointer iic.

I guess you mean OMXPlayer::SwitchChannel and DVDPlayer::SwitchChannel? Wouldn't that become a mess when more and more players get added? As the way I've currently written it it's just in a single place, not dependent on the player.

you don't know whether playback actually started here. e.g. if the player can't be started.

Okay, so it's merely about the OnStop? Which could now be send while it wasn't playing. I thought you meant both OnStop and OnStart below. Although that doesn't change much about my opinion of the "this should only be send from a single place", and not duplicating this code between all the players.

@opdenkamp
Owner

hmm. didn't even know we had that code in here. wondering what this is doing here in this class...

right ok, my mistake, misunderstood what this is doing.

@opdenkamp

should be done by sending an action, not like this.

@opdenkamp

you can register an observer to this class and monitor that, rather than spamming the whole application whenever something changes in the epg

Whatever the solution is, the announcement will still be send (and thus still be "spamming", although the amount of notifications has been dropped a lot with my fix for the condition). And I also think this is an integral part of the code on which other parts also may rely. As both JSON-RPC as the Python add-on API use these announcements (and possibly there are other things which use these). So I could create an extra class "somewhere" (not in interfaces/json-rpc, as it isn't solely JSON-RPC what's using it) which watches the Epg of all channels for the ObservableMessageEpgActiveItem notification, and just do the same thing.

Imo the announcement should also always be send, as you can't know whether a JSON client (or add-on) would like to receive the announcement. And there is no way to register an observer for one client (/add-on) but not for the other, so you can't add some PVR.WatchEventChanges JSON-RPC method which will register the observer.

@Montellese what do you think of it?

@opdenkamp
Owner

general: i don't know json-rpc very well, but i don't think you really need that new enum value, when radio is just audio and livetv just video. the only thing it adds is some metadata, that you can probably just add to video/audio descriptors, and leave empty when you're not playing a pvr channel, right?

@montellese could you have a look at this one please. it will be added to the json-rpc pr for mainline when done.

@opdenkamp opdenkamp was assigned
@Montellese

Is the implementation in this PR meant to replace the PR with PVR specific JSON-RPC methods that already exist in the XBMC repo or are these just additional fixes?

I agree on the additional enum values. Isn't it possible to treat radio as audio and do some additional check in a specific implementation to see if it's PVR are not (same for livetv being video)?

@opdenkamp
Owner

@Montellese yeah it's a PR to go on top of xbmc#1412
the PR that i created was just the code that wasn't merged in when PVR was merged. @RobertMe was already working on the pvr bits for json-rpc when we merged. so this will be added to PR 1412 when ready & ok

@RobertMe

Okay, will see if I can remove LiveTV enum. I thought it might be easier to just add the enum value and adding the cases instead of having to write an if for it all the time. But in the end I think the exception to the "rule" is more common then the "rule" itself. (the rule being: audio/video is different than LiveTV)

@opdenkamp
Owner

@RobertMe last merge window before feature freezing for Frodo opening in 4 days. any chance you can get this updated after the comments? otherwise it won't be included in Frodo.

@yallah

:/ Will be very appreciate if we can integrate type Live TV in GetPlayer methods....

@opdenkamp
Owner

closing since it's being picked up by @Montellese now

@opdenkamp opdenkamp closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 14, 2012
  1. @RobertMe
  2. @RobertMe
  3. @RobertMe
  4. @RobertMe
  5. @RobertMe
  6. @RobertMe
  7. @RobertMe
  8. @RobertMe
  9. @RobertMe
  10. @RobertMe

    json-rpc: handle pvr live tv items in announcements

    RobertMe committed
    Set item type and id
    Update player.playerid to show as music and video
  11. @RobertMe

    json-rpc: add Player.SetSubtitle support for live tv

    RobertMe committed
    Returns fails to execute in case of a radio channel instead of tv channel.
  12. @RobertMe

    json-rpc: add Player.SetAudioStream support for live tv

    RobertMe committed
    Returns fails to execute in case of a radio channel instead of tv channel.
  13. @RobertMe
  14. @RobertMe

    epg: add PVR.OnCurrentEpgItemChanged announcement

    RobertMe committed
    This announcement gets send when the current epg item on a channel changes. It
    contains both the channelid and broadcast id to query the details.
View
10 xbmc/epg/Epg.cpp
@@ -31,6 +31,7 @@
#include "pvr/addons/PVRClients.h"
#include "pvr/channels/PVRChannelGroupsContainer.h"
#include "utils/StringUtils.h"
+#include "interfaces/AnnouncementManager.h"
#include "../addons/include/xbmc_pvr_types.h" // TODO extract the epg specific stuff
@@ -258,6 +259,15 @@ bool CEpg::CheckPlayingEvent(void)
if (!bGotPreviousTag || (bGotCurrentTag && previousTag != newTag))
{
NotifyObservers(ObservableMessageEpgActiveItem);
+
+ time_t starttime;
+ newTag.StartAsUTC().GetAsUTCDateTime().GetAsTime(starttime);
+ CVariant data;
+ data["channelid"] = ChannelID();
+ data["epgid"] = EpgID();
+ data["starttime"] = starttime;
+ ANNOUNCEMENT::CAnnouncementManager::Announce(ANNOUNCEMENT::PVR, "xbmc", "OnCurrentEpgItemChanged", data);
+
bReturn = true;
}
View
10 xbmc/interfaces/AnnouncementManager.cpp
@@ -28,6 +28,8 @@
#include "music/tags/MusicInfoTag.h"
#include "music/MusicDatabase.h"
#include "video/VideoDatabase.h"
+#include "pvr/channels/PVRChannel.h"
+#include "PlayListPlayer.h"
#define LOOKUP_PROPERTY "database-lookup"
@@ -183,6 +185,14 @@ void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, c
object["artist"] = item->GetMusicInfoTag()->GetArtist();
}
}
+ else if(item->HasPVRChannelInfoTag())
+ {
+ PVR::CPVRChannel *channel = item->GetPVRChannelInfoTag();
+ id = channel->ChannelID();
+ type = "channel";
+ if(data.isMember("player") && data["player"].isMember("playerid"))
+ object["player"]["playerid"] = channel->IsRadio() ? PLAYLIST_MUSIC : PLAYLIST_VIDEO;
+ }
else
type = "unknown";
View
21 xbmc/interfaces/IAnnouncer.h
@@ -24,17 +24,18 @@ namespace ANNOUNCEMENT
{
enum AnnouncementFlag
{
- Player = 0x01,
- GUI = 0x02,
- System = 0x04,
- VideoLibrary = 0x08,
- AudioLibrary = 0x10,
- Application = 0x20,
- Input = 0x40,
- Other = 0x80
+ Player = 0x0001,
+ GUI = 0x0002,
+ System = 0x0004,
+ VideoLibrary = 0x0008,
+ AudioLibrary = 0x0010,
+ Application = 0x0020,
+ Input = 0x0040,
+ PVR = 0x0080,
+ Other = 0x0100
};
- #define ANNOUNCE_ALL (Player | GUI | System | VideoLibrary | AudioLibrary | Application | Input | Other)
+ #define ANNOUNCE_ALL (Player | GUI | System | VideoLibrary | AudioLibrary | Application | Input | ANNOUNCEMENT::PVR | Other)
/*!
\brief Returns a string representation for the
@@ -60,6 +61,8 @@ namespace ANNOUNCEMENT
return "Application";
case Input:
return "Input";
+ case ANNOUNCEMENT::PVR:
+ return "PVR";
case Other:
return "Other";
default:
View
8 xbmc/interfaces/json-rpc/FileItemHandler.cpp
@@ -36,6 +36,8 @@
#include "TextureCache.h"
#include "ThumbLoader.h"
#include "Util.h"
+#include "epg/EpgInfoTag.h"
+#include "pvr/channels/PVRChannel.h"
using namespace MUSIC_INFO;
using namespace JSONRPC;
@@ -241,6 +243,8 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
object[ID] = (int)item->GetMusicInfoTag()->GetDatabaseId();
else if (item->HasVideoInfoTag() && item->GetVideoInfoTag()->m_iDbId > 0)
object[ID] = item->GetVideoInfoTag()->m_iDbId;
+ else if (item->HasPVRChannelInfoTag() && item->GetPVRChannelInfoTag()->ChannelID() > 0)
+ object[ID] = item->GetPVRChannelInfoTag()->ChannelID();
if (stricmp(ID, "id") == 0)
{
@@ -277,6 +281,8 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
}
else if (item->HasPictureInfoTag())
object["type"] = "picture";
+ else if (item->HasPVRChannelInfoTag())
+ object["type"] = "channel";
if (!object.isMember("type"))
object["type"] = "unknown";
@@ -291,6 +297,8 @@ void CFileItemHandler::HandleFileItem(const char *ID, bool allowFile, const char
FillDetails(item->GetMusicInfoTag(), item, validFields, object);
if (item->HasPictureInfoTag())
FillDetails(item->GetPictureInfoTag(), item, validFields, object);
+ if (item->HasPVRChannelInfoTag())
+ FillDetails(item->GetPVRChannelInfoTag(), item, validFields, object);
object["label"] = item->GetLabel().c_str();
}
View
99 xbmc/interfaces/json-rpc/PlayerOperations.cpp
@@ -34,9 +34,11 @@
#include "video/VideoDatabase.h"
#include "AudioLibrary.h"
#include "GUIInfoManager.h"
+#include "pvr/PVRManager.h"
using namespace JSONRPC;
using namespace PLAYLIST;
+using namespace PVR;
JSONRPC_STATUS CPlayerOperations::GetActivePlayers(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
@@ -98,6 +100,7 @@ JSONRPC_STATUS CPlayerOperations::GetItem(const CStdString &method, ITransportLa
{
case Video:
case Audio:
+ case LiveTV:
{
if (g_application.CurrentFileItem().GetLabel().empty())
{
@@ -110,7 +113,7 @@ JSONRPC_STATUS CPlayerOperations::GetItem(const CStdString &method, ITransportLa
tmpItem.SetPath(g_application.CurrentFileItem().GetPath());
}
}
- else
+ else if (player == Audio)
{
if (!CAudioLibrary::FillFileItem(g_application.CurrentFile(), tmpItem))
{
@@ -217,6 +220,7 @@ JSONRPC_STATUS CPlayerOperations::PlayPause(const CStdString &method, ITransport
result["speed"] = 0;
return OK;
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -229,6 +233,7 @@ JSONRPC_STATUS CPlayerOperations::Stop(const CStdString &method, ITransportLayer
{
case Video:
case Audio:
+ case LiveTV:
CApplicationMessenger::Get().SendAction(CAction(ACTION_STOP));
return ACK;
@@ -277,6 +282,7 @@ JSONRPC_STATUS CPlayerOperations::SetSpeed(const CStdString &method, ITransportL
return OK;
case Picture:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -317,6 +323,7 @@ JSONRPC_STATUS CPlayerOperations::Seek(const CStdString &method, ITransportLayer
return OK;
case Picture:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -333,6 +340,7 @@ JSONRPC_STATUS CPlayerOperations::MoveLeft(const CStdString &method, ITransportL
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -349,6 +357,7 @@ JSONRPC_STATUS CPlayerOperations::MoveRight(const CStdString &method, ITransport
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -365,6 +374,7 @@ JSONRPC_STATUS CPlayerOperations::MoveDown(const CStdString &method, ITransportL
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -381,6 +391,7 @@ JSONRPC_STATUS CPlayerOperations::MoveUp(const CStdString &method, ITransportLay
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -397,6 +408,7 @@ JSONRPC_STATUS CPlayerOperations::ZoomOut(const CStdString &method, ITransportLa
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -413,6 +425,7 @@ JSONRPC_STATUS CPlayerOperations::ZoomIn(const CStdString &method, ITransportLay
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -429,6 +442,7 @@ JSONRPC_STATUS CPlayerOperations::Zoom(const CStdString &method, ITransportLayer
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -448,6 +462,7 @@ JSONRPC_STATUS CPlayerOperations::Rotate(const CStdString &method, ITransportLay
case Video:
case Audio:
+ case LiveTV:
case None:
default:
return FailedToExecute;
@@ -567,6 +582,11 @@ JSONRPC_STATUS CPlayerOperations::GoPrevious(const CStdString &method, ITranspor
SendSlideshowAction(ACTION_PREV_PICTURE);
return ACK;
+ case LiveTV:
+ unsigned int newChannelNumber;
+ g_PVRManager.ChannelDown(&newChannelNumber);
+ return ACK;
+
case None:
default:
return FailedToExecute;
@@ -586,6 +606,11 @@ JSONRPC_STATUS CPlayerOperations::GoNext(const CStdString &method, ITransportLay
SendSlideshowAction(ACTION_NEXT_PICTURE);
return ACK;
+ case LiveTV:
+ unsigned int newChannelNumber;
+ g_PVRManager.ChannelUp(&newChannelNumber);
+ return ACK;
+
case None:
default:
return FailedToExecute;
@@ -602,6 +627,11 @@ JSONRPC_STATUS CPlayerOperations::GoTo(const CStdString &method, ITransportLayer
CApplicationMessenger::Get().PlayListPlayerPlay(position);
break;
+ case LiveTV:
+ if (!g_PVRManager.ChannelSwitch(position))
+ return FailedToExecute;
+ break;
+
case Picture:
case None:
default:
@@ -631,6 +661,7 @@ JSONRPC_STATUS CPlayerOperations::Shuffle(const CStdString &method, ITransportLa
return FailedToExecute;
break;
+ case LiveTV:
default:
return FailedToExecute;
}
@@ -648,6 +679,7 @@ JSONRPC_STATUS CPlayerOperations::UnShuffle(const CStdString &method, ITransport
break;
case Picture:
+ case LiveTV:
default:
return FailedToExecute;
}
@@ -665,6 +697,7 @@ JSONRPC_STATUS CPlayerOperations::Repeat(const CStdString &method, ITransportLay
break;
case Picture:
+ case LiveTV:
default:
return FailedToExecute;
}
@@ -674,10 +707,12 @@ JSONRPC_STATUS CPlayerOperations::Repeat(const CStdString &method, ITransportLay
JSONRPC_STATUS CPlayerOperations::SetAudioStream(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
- switch (GetPlayer(parameterObject["playerid"]))
+ PlayerType player = GetPlayer(parameterObject["playerid"]);
+ switch (player)
{
case Video:
- if (g_application.m_pPlayer)
+ case LiveTV:
+ if (g_application.m_pPlayer && (player != LiveTV || g_PVRManager.IsPlayingTV()))
{
int index = -1;
if (parameterObject["stream"].isString())
@@ -721,10 +756,12 @@ JSONRPC_STATUS CPlayerOperations::SetAudioStream(const CStdString &method, ITran
JSONRPC_STATUS CPlayerOperations::SetSubtitle(const CStdString &method, ITransportLayer *transport, IClient *client, const CVariant &parameterObject, CVariant &result)
{
- switch (GetPlayer(parameterObject["playerid"]))
+ PlayerType player = GetPlayer(parameterObject["playerid"]);
+ switch (player)
{
case Video:
- if (g_application.m_pPlayer)
+ case LiveTV:
+ if (g_application.m_pPlayer && (player != LiveTV || g_PVRManager.IsPlayingTV()))
{
int index = -1;
if (parameterObject["subtitle"].isString())
@@ -784,9 +821,9 @@ int CPlayerOperations::GetActivePlayers()
{
int activePlayers = 0;
- if (g_application.IsPlayingVideo())
+ if (g_application.IsPlayingVideo() || g_PVRManager.IsPlayingTV())
activePlayers |= Video;
- if (g_application.IsPlayingAudio())
+ if (g_application.IsPlayingAudio() || g_PVRManager.IsPlayingRadio())
activePlayers |= Audio;
if (g_windowManager.IsWindowActive(WINDOW_SLIDESHOW))
activePlayers |= Picture;
@@ -822,9 +859,15 @@ PlayerType CPlayerOperations::GetPlayer(const CVariant &player)
// Implicit order
if (choosenPlayer & Video)
- return Video;
+ if (g_PVRManager.IsPlayingTV())
+ return LiveTV;
+ else
+ return Video;
else if (choosenPlayer & Audio)
- return Audio;
+ if (g_PVRManager.IsPlayingRadio())
+ return LiveTV;
+ else
+ return Audio;
else if (choosenPlayer & Picture)
return Picture;
else
@@ -900,6 +943,10 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
result = "picture";
break;
+ case LiveTV:
+ result = g_PVRManager.IsPlayingRadio() ? "audio" : "video";
+ break;
+
default:
return FailedToExecute;
}
@@ -914,6 +961,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
break;
case Picture:
+ case LiveTV:
result = false;
break;
@@ -928,6 +976,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
{
case Video:
case Audio:
+ case LiveTV:
result = g_application.IsPaused() ? 0 : g_application.GetPlaySpeed();
break;
@@ -949,6 +998,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
{
case Video:
case Audio:
+ case LiveTV:
MillisecondsToTimeObject((int)(g_application.GetTime() * 1000.0), result);
break;
@@ -967,6 +1017,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
{
case Video:
case Audio:
+ case LiveTV:
result = g_application.GetPercentage();
break;
@@ -988,6 +1039,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
{
case Video:
case Audio:
+ case LiveTV:
MillisecondsToTimeObject((int)(g_application.GetTotalTime() * 1000.0), result);
break;
@@ -1010,6 +1062,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
{
case Video:
case Audio:
+ case LiveTV:
if (g_playlistPlayer.GetCurrentPlaylist() == playlist)
result = g_playlistPlayer.GetCurrentSong();
else
@@ -1050,6 +1103,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
break;
case Picture:
+ case LiveTV:
default:
result = "off";
break;
@@ -1073,6 +1127,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
result = -1;
break;
+ case LiveTV:
default:
result = -1;
break;
@@ -1091,6 +1146,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
break;
case Picture:
+ case LiveTV:
default:
result = false;
break;
@@ -1106,6 +1162,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
break;
case Picture:
+ case LiveTV:
default:
result = false;
break;
@@ -1121,6 +1178,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
case Video:
case Audio:
+ case LiveTV:
default:
result = false;
break;
@@ -1136,6 +1194,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
case Video:
case Audio:
+ case LiveTV:
default:
result = false;
break;
@@ -1166,6 +1225,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
result = true;
break;
+ case LiveTV:
default:
result = false;
break;
@@ -1181,6 +1241,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
break;
case Picture:
+ case LiveTV:
default:
result = false;
break;
@@ -1192,6 +1253,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
{
case Video:
case Audio:
+ case LiveTV:
if (g_application.m_pPlayer)
{
result = CVariant(CVariant::VariantTypeObject);
@@ -1226,6 +1288,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
switch (player)
{
case Video:
+ case LiveTV:
if (g_application.m_pPlayer)
{
for (int index = 0; index < g_application.m_pPlayer->GetAudioStreamCount(); index++)
@@ -1255,6 +1318,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
switch (player)
{
case Video:
+ case LiveTV:
if (g_application.m_pPlayer)
result = g_application.m_pPlayer->GetSubtitleVisible();
break;
@@ -1271,6 +1335,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
switch (player)
{
case Video:
+ case LiveTV:
if (g_application.m_pPlayer)
{
result = CVariant(CVariant::VariantTypeObject);
@@ -1303,6 +1368,7 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
switch (player)
{
case Video:
+ case LiveTV:
if (g_application.m_pPlayer)
{
for (int index = 0; index < g_application.m_pPlayer->GetSubtitleCount(); index++)
@@ -1327,6 +1393,21 @@ JSONRPC_STATUS CPlayerOperations::GetPropertyValue(PlayerType player, const CStd
break;
}
}
+ else if (property.Equals("islive"))
+ {
+ switch (player)
+ {
+ case LiveTV:
+ result = true;
+ break;
+ case Video:
+ case Audio:
+ case Picture:
+ default:
+ result = false;
+ break;
+ }
+ }
else
return InvalidParams;
View
3 xbmc/interfaces/json-rpc/PlayerOperations.h
@@ -30,7 +30,8 @@ namespace JSONRPC
None = 0,
Video = 0x1,
Audio = 0x2,
- Picture = 0x4
+ Picture = 0x4,
+ LiveTV = 0x08
};
static const int PlayerImplicit = (Video | Audio | Picture);
View
32 xbmc/interfaces/json-rpc/ServiceDescription.h
@@ -200,7 +200,7 @@ namespace JSONRPC
"\"totaltime\", \"playlistid\", \"position\", \"repeat\", \"shuffled\","
"\"canseek\", \"canchangespeed\", \"canmove\", \"canzoom\", \"canrotate\","
"\"canshuffle\", \"canrepeat\", \"currentaudiostream\", \"audiostreams\","
- "\"subtitleenabled\", \"currentsubtitle\", \"subtitles\" ]"
+ "\"subtitleenabled\", \"currentsubtitle\", \"subtitles\", \"islive\" ]"
"}",
"\"Player.Property.Value\": {"
"\"type\": \"object\","
@@ -226,7 +226,8 @@ namespace JSONRPC
"\"audiostreams\": { \"type\": \"array\", \"items\": { \"$ref\": \"Player.Audio.Stream\" } },"
"\"subtitleenabled\": { \"type\": \"boolean\" },"
"\"currentsubtitle\": { \"$ref\": \"Player.Subtitle\" },"
- "\"subtitles\": { \"type\": \"array\", \"items\": { \"$ref\": \"Player.Subtitle\" } }"
+ "\"subtitles\": { \"type\": \"array\", \"items\": { \"$ref\": \"Player.Subtitle\" } },"
+ "\"islive\": { \"type\": \"boolean\" }"
"}"
"}",
"\"Player.Notifications.Item.Type\": {"
@@ -924,14 +925,14 @@ namespace JSONRPC
"\"runtime\", \"set\", \"showlink\", \"streamdetails\", \"top250\", \"votes\","
"\"firstaired\", \"season\", \"episode\", \"showtitle\", \"thumbnail\", \"file\","
"\"resume\", \"artistid\", \"albumid\", \"tvshowid\", \"setid\", \"watchedepisodes\","
- "\"disc\", \"tag\" ]"
+ "\"disc\", \"tag\", \"isradio\", \"number\", \"epgid\", \"currentepgstarttime\" ]"
"}"
"}",
"\"List.Item.All\": {"
"\"extends\": [ \"Video.Details.File\", \"Audio.Details.Media\" ],"
"\"properties\": {"
"\"id\": { \"$ref\": \"Library.Id\" },"
- "\"type\": { \"type\": \"string\", \"enum\": [ \"unknown\", \"movie\", \"episode\", \"musicvideo\", \"song\", \"picture\" ] },"
+ "\"type\": { \"type\": \"string\", \"enum\": [ \"unknown\", \"movie\", \"episode\", \"musicvideo\", \"song\", \"picture\", \"channel\" ] },"
"\"albumartist\": { \"$ref\": \"Array.String\" },"
"\"album\": { \"type\": \"string\" },"
"\"track\": { \"type\": \"integer\" },"
@@ -965,7 +966,11 @@ namespace JSONRPC
"\"tvshowid\": { \"$ref\": \"Library.Id\" },"
"\"watchedepisodes\": { \"type\": \"integer\" },"
"\"disc\": { \"type\": \"integer\" },"
- "\"tag\": { \"$ref\": \"Array.String\" }"
+ "\"tag\": { \"$ref\": \"Array.String\" },"
+ "\"isradio\": { \"type\": \"boolean\" },"
+ "\"number\": { \"type\": \"integer\" },"
+ "\"epgid\": { \"type\": \"integer\" },"
+ "\"currentepgstarttime\": { \"type\": \"integer\" }"
"}"
"}",
"\"List.Fields.Files\": {"
@@ -3091,6 +3096,21 @@ namespace JSONRPC
"{ \"name\": \"data\", \"type\": \"null\", \"required\": true }"
"],"
"\"returns\": null"
- "}"
+ "}",
+ "\"PVR.OnCurrentEpgItemChanged\": {"
+ "\"type\": \"notification\","
+ "\"description\": \"The current epg item on the channel changed\","
+ "\"params\": ["
+ "{ \"name\": \"sender\", \"type\": \"string\", \"required\": true },"
+ "{ \"name\": \"data\", \"type\": \"object\", \"required\": true,"
+ "\"properties\": {"
+ "\"channelid\": { \"type\": \"integer\", \"required\": true },"
+ "\"epgid\": { \"type\": \"integer\", \"required\": true }"
+ "\"starttime\": { \"type\": \"integer\", \"required\": true }"
+ "}"
+ "}"
+ "],"
+ "\"returns\": null"
+ "}"
};
}
View
15 xbmc/interfaces/json-rpc/notifications.json
@@ -211,5 +211,20 @@
{ "name": "data", "type": "null", "required": true }
],
"returns": null
+ },
+ "PVR.OnCurrentEpgItemChanged": {
+ "type": "notification",
+ "description": "The current epg item on the channel changed",
+ "params": [
+ { "name": "sender", "type": "string", "required": true },
+ { "name": "data", "type": "object", "required": true,
+ "properties": {
+ "channelid": { "type": "integer", "required": true },
+ "epgid": { "type": "integer", "required": true },
+ "starttime": { "type": "integer", "required": true }
+ }
+ }
+ ],
+ "returns": null
}
}
View
15 xbmc/interfaces/json-rpc/types.json
@@ -173,7 +173,7 @@
"totaltime", "playlistid", "position", "repeat", "shuffled",
"canseek", "canchangespeed", "canmove", "canzoom", "canrotate",
"canshuffle", "canrepeat", "currentaudiostream", "audiostreams",
- "subtitleenabled", "currentsubtitle", "subtitles" ]
+ "subtitleenabled", "currentsubtitle", "subtitles", "islive" ]
},
"Player.Property.Value": {
"type": "object",
@@ -199,7 +199,8 @@
"audiostreams": { "type": "array", "items": { "$ref": "Player.Audio.Stream" } },
"subtitleenabled": { "type": "boolean" },
"currentsubtitle": { "$ref": "Player.Subtitle" },
- "subtitles": { "type": "array", "items": { "$ref": "Player.Subtitle" } }
+ "subtitles": { "type": "array", "items": { "$ref": "Player.Subtitle" } },
+ "islive": { "type": "boolean" }
}
},
"Player.Notifications.Item.Type": {
@@ -897,14 +898,14 @@
"runtime", "set", "showlink", "streamdetails", "top250", "votes",
"firstaired", "season", "episode", "showtitle", "thumbnail", "file",
"resume", "artistid", "albumid", "tvshowid", "setid", "watchedepisodes",
- "disc", "tag" ]
+ "disc", "tag", "isradio", "number", "epgid", "currentepgstarttime" ]
}
},
"List.Item.All": {
"extends": [ "Video.Details.File", "Audio.Details.Media" ],
"properties": {
"id": { "$ref": "Library.Id" },
- "type": { "type": "string", "enum": [ "unknown", "movie", "episode", "musicvideo", "song", "picture" ] },
+ "type": { "type": "string", "enum": [ "unknown", "movie", "episode", "musicvideo", "song", "picture", "channel" ] },
"albumartist": { "$ref": "Array.String" },
"album": { "type": "string" },
"track": { "type": "integer" },
@@ -938,7 +939,11 @@
"tvshowid": { "$ref": "Library.Id" },
"watchedepisodes": { "type": "integer" },
"disc": { "type": "integer" },
- "tag": { "$ref": "Array.String" }
+ "tag": { "$ref": "Array.String" },
+ "isradio": { "type": "boolean" },
+ "number": { "type": "integer" },
+ "epgid": { "type": "integer" },
+ "currentepgstarttime": { "type": "integer" }
}
},
"List.Fields.Files": {
View
16 xbmc/pvr/PVRManager.cpp
@@ -39,6 +39,7 @@
#include "utils/StringUtils.h"
#include "threads/Atomics.h"
#include "windows/GUIWindowPVRCommon.h"
+#include "interfaces/AnnouncementManager.h"
#include "PVRManager.h"
#include "PVRDatabase.h"
@@ -55,6 +56,7 @@ using namespace std;
using namespace MUSIC_INFO;
using namespace PVR;
using namespace EPG;
+using namespace ANNOUNCEMENT;
CPVRManager::CPVRManager(void) :
CThread("PVR manager"),
@@ -970,6 +972,12 @@ bool CPVRManager::PerformChannelSwitch(const CPVRChannel &channel, bool bPreview
SaveCurrentChannelSettings();
}
+ if (!bPreview && m_currentFile)
+ {
+ CVariant data(CVariant::VariantTypeObject);
+ CAnnouncementManager::Announce(Player, "xbmc", "OnStop", CFileItemPtr(new CFileItem(m_currentFile)), data);
+ }
+
SAFE_DELETE(m_currentFile);
lock.Leave();
@@ -1004,6 +1012,14 @@ bool CPVRManager::PerformChannelSwitch(const CPVRChannel &channel, bool bPreview
g_localizeStrings.Get(19035)); // This channel cannot be played. Check the log for details.
}
+ if (!bPreview && bSwitched)
+ {
+ CVariant param;
+ param["player"]["speed"] = 1;
+ param["player"]["playerid"] = g_playlistPlayer.GetCurrentPlaylist();
+ CAnnouncementManager::Announce(Player, "xbmc", "OnPlay", CFileItemPtr(new CFileItem(channel)), param);
+ }
+
return bSwitched;
}
View
15 xbmc/pvr/channels/PVRChannel.cpp
@@ -146,6 +146,21 @@ CPVRChannel &CPVRChannel::operator=(const CPVRChannel &channel)
return *this;
}
+void CPVRChannel::Serialize(CVariant& value)
+{
+ value["isradio"] = m_bIsRadio;
+ value["name"] = m_strChannelName;
+ value["number"] = m_iCachedChannelNumber;
+ value["epgid"] = m_iEpgId;
+ CEpgInfoTag epgNow;
+ if (GetEPGNow(epgNow))
+ {
+ time_t starttime;
+ epgNow.StartAsUTC().GetAsUTCDateTime().GetAsTime(starttime);
+ value["currentepgstarttime"] = starttime;
+ }
+}
+
/********** XBMC related channel methods **********/
bool CPVRChannel::Delete(void)
View
4 xbmc/pvr/channels/PVRChannel.h
@@ -42,7 +42,7 @@ namespace PVR
typedef boost::shared_ptr<PVR::CPVRChannel> CPVRChannelPtr;
/** PVR Channel class */
- class CPVRChannel : public Observable
+ class CPVRChannel : public Observable, public ISerializable
{
friend class CPVRDatabase;
friend class CPVRChannelGroupInternal;
@@ -52,6 +52,8 @@ namespace PVR
CPVRChannel(bool bRadio = false);
CPVRChannel(const PVR_CHANNEL &channel, unsigned int iClientId);
CPVRChannel(const CPVRChannel &channel);
+
+ virtual void Serialize(CVariant& value);
bool operator ==(const CPVRChannel &right) const;
bool operator !=(const CPVRChannel &right) const;
Something went wrong with that request. Please try again.