SageTV Community  

Go Back   SageTV Community > SageTV Development and Customizations > SageTV Studio
Forum Rules FAQs Community Downloads Today's Posts Search

Notices

SageTV Studio Discussion related to the SageTV Studio application produced by SageTV. Questions, issues, problems, suggestions, etc. relating to the Studio software application should be posted here.

Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old 04-04-2007, 08:56 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Unique Media file ID is zero?

I've just taken the cobwebs off my java code in order to update my code for controlling Sage through the CQC home automation software. It's worked great so far, but it needs to do a few more things.

So far, though, everything seems broken! I'm getting all kinds of errors that I never got before, so I think that between java and Sage, more than a few things must have changed.

One of them seems to be that before the GetMediaFileID API call used to return a long, I think, and now returns an int. Not a problem, an easy change. However, so far, no matter which file I select, the API call returns 0 for me.

I should note that all of the files I'm testing with are imported media files, not files recorded by Sage itself. Does Sage not assigned unique file ID's to imported media files?
Reply With Quote
  #2  
Old 04-05-2007, 01:58 AM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
I get valid IDs for both recordings and imported videos. How are you calling GetMediaFileID? Have you tried calling it from Expression Evaluator to make sure the problem's not in your calling code?
__________________
-- Greg
Reply With Quote
  #3  
Old 04-05-2007, 06:49 AM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
I'm calling it from inside my java code, using the sageTV.Api("GetMediaFileId", Object [] {mediaFile}) type of call. (I'm just guessing there, I don't have the code in front of me.

I also have to do some casting to convert it from the return type (object, isn't it?) to Integer, and then to int....but it keeps coming out 0.
Reply With Quote
  #4  
Old 04-05-2007, 12:12 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Post your code when you get a chance, preferably by copying and pasting from your actual source. The function does work, so the bug must be on your end, and we won't be able to make an accurate diagnosis without seeing the exact code you're using to call it.

In the guesswork department, if you spelled the function name "GetMediaFileId" with a small "d" as you did here, that could be a problem. However in that case you would have got an InvocationTargetException, not a zero result. Unless you're catching exceptions and ignoring them. But like I said, it's all guesswork until we see your actual code.
__________________
-- Greg
Reply With Quote
  #5  
Old 04-05-2007, 12:18 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Ok, I'll post it as soon as I get home.

Perhaps this is related.....when I dusted off this code and was trying to run it, I kept getting an exception because of some type casting problem, related to an int. I narrowed it down to the part of my code that returned the file ID. I then checked the API docs for GetMediaFileId(), and it said it returned an int....but my functions expected it to return a long instead.

I assumed that somewhere from version 5 to 6 of the API, that function call was changed to return an int instead of a long. I can't find the version 5 api docs to confirm, but it doesn't really matter.

Anyway, I changed my functions to expect an int instead of a long, and I no longer got the exception, but I did get just 0.

thanks for the help. I really enjoy working with this API and with java, but boy it can really be frustrating to try and debug where something is going wrong.

did you indicate there was a place where I could execute API calls, to see how/if they work? Someplace I could play with API calls without having to compile java code and load the .jar? That would probably help a lot with developing the next capability, if I have a chance to play with the API calls outside of structured code.
Reply With Quote
  #6  
Old 04-05-2007, 12:47 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
I mentioned Studio's Expression Evaluator command (on the Tools menu).

You can also type API calls into Action widgets and evaluate them using Evaluate Widget and Execute Widget Chain (on the right-click menu).
__________________
-- Greg
Reply With Quote
  #7  
Old 04-05-2007, 12:54 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Hmmm...I've never done anything other than compile commands in java code via command line and make it runnable in a .jar....so the actual studio is foreign to me. I guess I'll give it a try hereabouts and see how helpful it is. An expression evaluator sounds good...can it handle multiple statements, such as a call to get a media file, and then the call to get the ID of the passed in media file?
Reply With Quote
  #8  
Old 04-05-2007, 02:14 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Expression Evaluator accepts expressions, not statements. You can have nested calls such as A(B(C)), but not sequential statements like A; B; C.

Using widget code you can build up artitrary sequences of statements and then evaluate them interactively using Execute Widget Chain.

However be warned that widget code is not Java. The expressions you enter into each widget (or into Expression Evaluator) have Java-like syntax, but there are important differences, particularly in the way you use Java objects. The Studio manual has the details; see in particular Chapter 2 and the "Using Java Code" section of Chapter 9.

If you've never used Studio before, this may not be the most efficient way to debug your Java code. But for someone already familiar with Studio and widget code, trying out expressions interactively can be a quick way to test your understanding of the API.

On a side note, if you're doing a lot of API calls from Java, you might want to take a look at the API wrapper functions in my Studio Tools package.
__________________
-- Greg
Reply With Quote
  #9  
Old 04-05-2007, 02:23 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Ya, I'm hoping mainly to use it to increase my understanding of API calls, when the docs don't do a good enough job.

I've created a java class that contains all my api calls, so they are kind of wrapped already...but your collection has the advantage of 1) being complete, and 2) being correct. I think I might just avail myself of those.

From your api wrappers, can I assume that means you'll make all the necessary type cast changes? for instance, the GetMediaFileId() function returns an int, but in java it's really an Object, which has to be cast to an int....do your wrappers return a true java int already?
Reply With Quote
  #10  
Old 04-05-2007, 03:44 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Yes, the declared result type of each wrapper function is as documented in the API docs. So if the docs say int, the result is cast internally to int.

The exceptions to this rule are the wrapped types themselves. If an API returns a Sage.MediaFile, what you actually get back from the wrapped function is a wrapped MedaFile object. Similarly, if an API returns an array of MediaFiles, you get a List of wrapped MediaFiles.

Full details are in the Javadocs that come with the wrappers.
__________________
-- Greg
Reply With Quote
  #11  
Old 04-05-2007, 03:45 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Sweet...that helps. Can't wait to give 'em a try!
Reply With Quote
  #12  
Old 04-05-2007, 07:34 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Here's my code segments that I use to get the file ID. These are members of a MySageApi class.


Code:
    public static int GetCurrentMediaFileId() throws InvocationTargetException
    {
        return ((Integer)sage.SageTV.api("GetMediaFileID", new Object[]{sage.SageTV.api("GetCurrentMediaFile", null)})).intValue ();
    }
    
    public static int GetIdForMediaFile(Object mediaFile) throws InvocationTargetException
    {
        return ((Integer)sage.SageTV.api("GetMediaFileID", new Object[]{mediaFile})).intValue();
    }

By the way, I downloaded your helper/wrapper thing, and I noticed your MediaFileAPI functions were much fewer than are in the actual spec (in fact, there wasn't even a GetMediaFileID() function). Are they just not documented, or are they not included?
Reply With Quote
  #13  
Old 04-05-2007, 08:23 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
One of the goals of my API wrappers was to represent APIs that get or set properties of a MediaFile as methods of the MediaFile object itself, not of the MediaFileAPI. So the ones you're not seeing are most likely the ones that are accessed via mediaFile.Method() rather than mediaFileAPI.Method(mediaFile). The package documentation for gkusnick.sagetv.api goes into some detail about this.

sage.SageTV.api("GetCurrentMediaFile", null) won't work. With Placeshifters and Extenders, you can have multiple instances of the UI running in the same instance of SageTV.exe. Each of those UIs can have a different MediaFile playing. So you have to tell it which UI instance you're talking about in order to use any of the APIs that depend on UI context, such as GetCurrentMediaFile, GetCurrentMenuWidget, GetCurrentSTVFile, etc. The package documentation for sage.api goes into some detail about that.

You'll also need a UI context to initialize my wrappers properly. If you plan to use your code only on PC clients running SageTV.exe or SageTVClient.exe, then you can get away with using the statically defined apiLocalUI. But if you want to support Placeshifter or Extender clients, then you must instantiate the wrappers with the correct UI context for that client. The simplest way to get the right UI context is to call GetUIContextName() from widget code (not Java). You can also get a list of valid context names from GetUIContextNames(), but then you're stuck with the problem of figuring which one goes with which client.

Bottom line is that pure Java plugins, with no Studio code, are best suited to background processes that don't care about the state of the UI. As soon as you start dealing with things like GetCurrentMediaFile, then you need to be in Studio in order to instantiate your code on a per-client basis and connect it up to the proper UI context.
__________________
-- Greg
Reply With Quote
  #14  
Old 04-06-2007, 07:07 AM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Oh, ok....that's a clever way to do it. I read the documentation, and I saw the one example of mediaFile.Method(), but didn't make the connection. Are those object methods documented also somewhere, because I can't find it. In other words, all of the mediaFile methods?

I figured the UI context's would bite me in the butt at some point. But I don't understand, because it DID work...and also, on my PC, I only have one instance of Sage, so I don't understand why this doesn't work. It seems your api helpers make handling the UI context a lot easier, so perhaps it won't be so onerous. However, I'm not against simply telling people if they want to use my code, it can only be on the local UI.

As far as using Studio....I was really hoping to keep my code/interface simple. I've never used Studio, so I don't know how difficult it is for the actual end-user to use.

Let me explain what my code does a little, and then let me know if Studio will do what I need....basically, my code allows for an external program to control Sage via a TCP connection. So, my java code creates a socket server and waits for the external program to connect. Once it connects, the java code polls Sage to determine when settings change, and sends that data to the client program. Also, the client program can send messages (such as Stop, or Mute) and the java receives those messages and calls the appropriate API call to do it.

So, if I run java code in Studio, will I still be able to setup a TCP socket server, and to monitor Sage settings and output that data? If so, then perhaps it is an easier way to go.

Thanks for all the help, by the way. I don't know why suddenly my code stopped working, but if it leads to me doing this in a better way, it'll be worth it.
Reply With Quote
  #15  
Old 04-06-2007, 11:47 AM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
All of the API methods are wrapped and all of the wrapper methods are documented, each under its appropriate class. So if you want to see the methods for MediaFileAPI.MediaFile, you need to bring up that page of the docs by clicking any MediaFileAPI.MediaFile link.

Whether you have just one instance of Sage or many, the API works the same way. You must pass in a valid UI context in order to use context-dependent methods. If you don't, the default is no UI (i.e. the service context), not the local UI. This is a change from Sage V3 and earlier, in which the default (and only) UI context was the local UI.

For what it's worth, I have a similar TCP control class running in my living room system for integration with my whole-house AV controller. The controller receives IR commands from the remote and relays them to Sage via TCP. My TCP listener class receives the commands and passes them to the SageCommand API for execution. I run this class in the client (i.e. I start it from load_at_startup_runnable_classes in SageClient.properties), so I know there's only one UI context in that process, which I access through the static apiLocalUI. So there's no Studio code involved in that control circuit; the listener class starts and stops with the SageTV process. I can get away with this because it's designed for this one specific application -- connecting a PC client to an AV controller via TCP -- and I know it will never be used with Placeshifter or Extenders.

To the extent that this describes your situation as well, you can probably get away with the same shortcut, i.e. using apiLocalUI instead of instantiating a new api instance based on GetUIContextName(). However if you decide you want or need to launch it from Studio code in order to support Placeshifter and Extender clients, the changes you need to make are pretty minimal. Instead of starting your class from load_at_startup_runnable_classes, you'll use Studio to place a call into the STV's ApplicationStarted to instantiate your class, and another call in the ApplicationExiting hook to shut it down again. If it's just for you, you can do those STV edits manually; if you want to distribute it, you'll need to create an STVI to do the editing (which is a whole nother topic). Presumably you'd also need a way to assign different TCP ports to different clients, but I'll let you figure out that part of it.
__________________
-- Greg
Reply With Quote
  #16  
Old 04-06-2007, 12:10 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Well, my use of it seems at least somewhat similar to yours. The TCP application on the other side of the socket from Sage is CQC home automation software. So, my java plugin let's the home automation software control Sage, and also feeds back to it various parameters such as media playing time, or transport control, etc.

So as for if it's just for my use or others....definitely others. There's at least a handful of guys using it now with their CQC installation.

The TCP port thing isn't an issue, as far as addressing multiple clients. For each instance of Sage you want to control, you install another driver on the CQC side, and tell it what port to control Sage through. I have the port number specified in the sage.properties files, so as long as that number matches the number for the CQC driver, they can talk.

I'm still somewhat woefully ignorant of how placeshifters and extenders etc work. I think for now I might just give the stipulation that the CQC driver will only control the main Sage program.

Sounds like for now, I can probably get by with using your API helpers, and specifying the local UI context.... ?
Reply With Quote
  #17  
Old 04-11-2007, 08:40 PM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Well dang. I like the API helpers....but I'm now back to my original problem. The ID returned from the GetMediaFileID call is 0.

Here's the relevant code:

Code:
API SageApi = API.apiLocalUI;
MediaPlayerAPI SageMediaPlayer = new MediaPlayerAPI(SageApi);

MediaFileAPI.MediaFile currentMediaFile = SageMediaPlayer.GetCurrentMediaFile();

int uniqueId = currentMediaFile.GetMediaFileID();
LogMessage("MediaFileID is zero: " + (uniqueId == 0));
This is while trying to play a media file from the imported media library.
Reply With Quote
  #18  
Old 04-11-2007, 09:47 PM
GKusnick's Avatar
GKusnick GKusnick is offline
SageTVaholic
 
Join Date: Dec 2005
Posts: 5,083
Not sure what to tell you. Your code works for me on files that are actually in the Sage media library. It returns zero for files that I play using Browse Media Files.

You might want to check the result of GetCurrentMediaFile to make sure you're getting what you think you're getting.
__________________
-- Greg
Reply With Quote
  #19  
Old 04-12-2007, 05:35 AM
beelzerob beelzerob is offline
Sage Advanced User
 
Join Date: May 2006
Posts: 163
Quote:
Originally Posted by GKusnick View Post
Not sure what to tell you. Your code works for me on files that are actually in the Sage media library. It returns zero for files that I play using Browse Media Files.

You might want to check the result of GetCurrentMediaFile to make sure you're getting what you think you're getting.

You have the answer!

It occured to me while I was driving that I hadn't ACTUALLY imported the media files...I was just playing them through Sage. It's been a while since I worked with this driver and Sage, so I was just taking a shortcut to play the files instead of importing them first.

The part that threw me off, and answer to your other suggestion, is that I was still getting information from the media file, such as title. Turns out the title is really just the filename for the media file.

I guess it makes sense that there would be no show or airing data available for an imported media file. I'll have to put in a check, I guess, for playing a non-native-to-Sage media file, so it doesn't try to get all the meta data.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Delete doesn't delete! SageFL SageTV Software 11 04-24-2007 01:44 PM
SageTV V4.1.11 Beta Is Available - Better Placeshifting! Narflex SageTV Beta Test Software 81 04-04-2006 09:39 PM
SageTV Media Center Software for Windows Now Available for Linux dkardatzke Announcements 0 01-06-2005 09:56 AM


All times are GMT -6. The time now is 06:05 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2023, vBulletin Solutions Inc.
Copyright 2003-2005 SageTV, LLC. All rights reserved.