# Streaming MP3 files



## perrce

I come back looking for help -- this time with streaming MP3 files. I've been playing with the sample music.java file that comes with the HME SDK, and have had mixed success. The problem I've run into is that I can get an MP3 to play using the simulator, but when I run it on the TiVo, I can't get any sound to come out. The funny thing is that even though my code is based on the HME sample mp3 player, the sample player works just fine while mine does not. I've tried using both absolute paths and relative directories, with the same results.

I'm including below a really stripped down test application. Note that to run the program, you'll need to change the value of MP3Test.MP3TestFactory.musicRoot, which is the path to the directory that contains the mp3 files. (You'll also have to supply your own mp3, obviously.)

If anyone can shed some light on why it would work on the simulator, but not on the TiVo, I'd be grateful. Thanks.



Code:


/**
 * 
 */
package org.dazeend.mp3Test;

import com.tivo.hme.bananas.*;
import com.tivo.hme.sdk.*;
import com.tivo.hme.interfaces.*;
import java.io.InputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.net.URLDecoder;
import java.net.URLEncoder;



public class MP3Test extends BApplication {
	
	BScreen nowPlayingScreen; 
	
	/**
	 * Application initialization. Run when application is started from TiVo.
	 */
	public void init(IContext context) throws Exception {
		// Initialization from superclass.
		super.init(context);
		this.nowPlayingScreen = new BScreen(this);
		String track = ((MP3TestFactory)this.getFactory()).musicList.get(0);
		this.play(track);
		
	}
	
	public void play(String path) {
		
		//
        // Construct the URI to send to the receiver. The receiver will
        // connect back to our factory and ask for the file. The URI
        // consists of:
        //
        // (our base URI) + (the track's path name)
        //
		
		String url = this.getContext().getBaseURI().toString();
        try {
            url += URLEncoder.encode(path, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        
		System.out.println("#### Playing MP3: " + url);
		System.out.flush();
        
        // stop any music that might be playing
        this.stop();
        
        // MP3's are played as a resource streamed to the nowPlayingScreen
        this.nowPlayingScreen.setResource(this.nowPlayingScreen.createStream(url, null, true)); 
	}

	public void stop() {
		// MP3's are played as a resource streamed to the nowPlayingScreen
        Resource resource = this.nowPlayingScreen.getResource();
        
        // stop the current stream if one exists
        if (resource != null) {
            resource.remove();
        }
	}
	
	/**
	 * Server side factory.
	 * 
	 */
	public static class MP3TestFactory extends Factory {
		
		public String musicRoot = "/home/ceperry/workspace/MP3Test/test data";
		public List<String> musicList = new ArrayList<String>();
	
		/**
		 *  Create the factory.
		 *  Run when server-side application begins execution.
		 */
		@Override
		protected void init(IArgumentList args) {
			
			// Create the music collection
			this.loadMusic(this.musicRoot, "");
		}
		
		/**
		 * Recursively search for music and load it into the collection.
		 * 
		 * @param musicDir	the root directory to search
		 * @param path		
		 */
		private void loadMusic(String root, String path) {
			
	        File file = new File(root, path);
	        if (file.isDirectory()) {
	            if (path.length() > 0 && !path.endsWith("/")) {
	                path += "/";
	            }
	            String list[] = file.list();             
	            for (int i = 0; i < list.length; i++) {
	                this.loadMusic(root, path + list[i]);
	            }
	        } else if ( path.toLowerCase().endsWith(".mp3") ) {
	        	System.out.println("Found: " + path);
	        	this.musicList.add(path);
	        }
		}
	
	     /* (non-Javadoc)
	     * @see com.tivo.hme.sdk.MP3Factory#getMP3StreamFromURI(java.lang.String)
	     */
		public InputStream getStream(String uri) throws IOException 
	    {
    		System.out.println("### MP3Test.MP3TestFactory.getStream");
    		System.out.println("URI: " + uri);
    		System.out.flush();
	    	
	        File file = new File(this.musicRoot, URLDecoder.decode(uri, "UTF-8"));
	        if (file.exists()) 
	        {
        		System.out.println("File Exists");
        		System.out.flush();
	       
	            InputStream in = new FileInputStream(file);
	            return in;
	        }
	        else
	        {
        		System.out.println("File DNE: treating as uri");
        		System.out.flush();
	        	
	            return super.getStream(uri);
	        }
	    }
	}

}


----------



## perrce

Upon further debugging, it looks like the problem might be related to this line in MP3Test.play(String):


Code:


this.nowPlayingScreen.setResource(this.nowPlayingScreen.createStream(url, null, true));

When run on the TiVo, it doesn't trigger a call to MP3Test.MP3TestFactory.getStream(String). But again, when run through the simulator, getstream(String) is called and music plays just fine.

Any ideas?


----------



## wmcbrine

I can't give you much advice on the Java SDK, but, this is not my idea of "stripped down". I'd prune that sucker a lot more to try and get at the essence of the problem.

This is Python, but it's really stripped down:



Code:


import hme

TITLE = 'MP3 Test'
CLASS_NAME = 'MP3Test'

class MP3Test(hme.Application):
    def startup(self):
        hme.Stream(self, 'http://%s/mp3test/test.mp3' % 
                   self.context.headers['host'])

...and it works.


----------



## perrce

wmcbrine said:


> this is not my idea of "stripped down". I'd prune that sucker a lot more to try and get at the essence of the problem.


Point taken. But for what it's worth, when I posted last time, I thought the problem was something I wrote. (I'm becoming less convinced of that now.) Here's the newly stripped to the bare bones version:



Code:


/**
 *  MP3Test.java
 */
package org.dazeend.mp3Test;

import com.tivo.hme.bananas.BApplication;
import com.tivo.hme.bananas.BScreen;
import com.tivo.hme.interfaces.IContext;

public class MP3Test extends BApplication {
	
	/**
	 * Application initialization. Run when application is started from TiVo.
	 */
	public void init(IContext context) throws Exception {
		super.init(context);

		String track = "test.mp3";
	
		BScreen nowPlayingScreen = new BScreen(this);
		String url = getApp().getContext().getBaseURI().toString() + track;
        
        nowPlayingScreen.setResource(nowPlayingScreen.createStream(url, null, true));
		
	}
}

With this code, I see the same symptoms: Factory.getStream() is called when run through the simulator, but is not called when run through the TiVo.

For completeness, I modified the source of Factory.getStream() to print a message so that I could see in debugging messages when it was being entered. As you can see in the output below (taken from Eclipse), in both cases (Simulator and TiVo) getStream() is successfully called at least once. (I think it's looking for the application icon.) But when run from the TiVo, getStream isn't called a second time (when I try to play the mp3).



Code:


Instance ID = 00000028e56792e9
hme-host-sample version: 1.4.1 threadsafe-experimental
debug: Loaded factory: org.dazeend.mp3Test.MP3Test
debug: Class loader for org.dazeend.mp3Test.MP3Test: sun.misc.Launcher$AppClassLoader
debug: Context class loader: sun.misc.Launcher$AppClassLoader
added factory
MDNS ADD: http://192.168.1.5:7288/mp3Test/
Contacting mDNS localhost daemon at 127.0.0.1:5354
Connection to mDNS localhost daemon failed: java.net.ConnectException: Connection refused
mDNS localhost daemon: service not found.
        > java.net.ConnectException: Connection refused
jmdns library: register [start]: http://192.168.1.5:7288/mp3Test/
jmdns library: register [done]:  http://192.168.1.5:7288/mp3Test/

############### Starting Simulator:
192.168.1.5 icon.png HTTP GET - to factory /mp3Test/
##### com.tivo.hme.sdk.Factory.getStream(): Enter
SDK debug level = 1. Will log: errors,warnings
To control HME SDK debugging, set the property com.tivo.hme.sdk.debug.level
The integer debug level is interpreted as follows:
    0: Only errors logged (default, recommended for installed apps)
    1: Level 0 + errors and warnings logged (recommended for development)
    2: Level 1 + events from receiver logged
    3: Level 2 + commands to receiver logged
Using vStrings!
192.168.1.5 test.mp3 HTTP GET - to factory /mp3Test/
##### com.tivo.hme.sdk.Factory.getStream(): Enter
Connection terminated by receiver
connection to receiver closed


############### Starting App from TiVo:
192.168.1.2 icon.png HTTP GET - to factory /mp3Test/
##### com.tivo.hme.sdk.Factory.getStream(): Enter
SDK debug level = 1. Will log: errors,warnings
To control HME SDK debugging, set the property com.tivo.hme.sdk.debug.level
The integer debug level is interpreted as follows:
    0: Only errors logged (default, recommended for installed apps)
    1: Level 0 + errors and warnings logged (recommended for development)
    2: Level 1 + events from receiver logged
    3: Level 2 + commands to receiver logged
Using vStrings!
Connection terminated by receiver
connection to receiver closed


----------



## perrce

Eureka! I finally got it. I finally found the cause for the problem I was having with streaming mp3 files. The cause seems to be the new SDK I was using (version 1.4.1e). I don't know what is going on under the hood, but using my code, version 1.4.0 plays music and 1.4.1e does not. 

So it's good news / bad news. Good News: I know how to work around the problem: use the older version of the SDK. Bad News: now I can't easily use different resolutions.


----------



## wmcbrine

Oh, yeah, the 1.4.1experimental SDK is broken in several ways. I wouldn't use it.

You could always switch to Python.  Or you could try this.


----------



## PlayTeeVee

perrce said:


> Eureka! I finally got it. I finally found the cause for the problem I was having with streaming mp3 files. The cause seems to be the new SDK I was using (version 1.4.1e). I don't know what is going on under the hood, but using my code, version 1.4.0 plays music and 1.4.1e does not.
> 
> So it's good news / bad news. Good News: I know how to work around the problem: use the older version of the SDK. Bad News: now I can't easily use different resolutions.


Glad you got it to work. Also glad we never 'upgraded' to the new SDK 

-T


----------



## perrce

wmcbrine said:


> Oh, yeah, the 1.4.1experimental SDK is broken in several ways. I wouldn't use it.


<sarcasm>Gee, thanks for the advice.</sarcasm> 



wmcbrine said:


> Or you could try this.


Thanks for the tip. I'll check it out.


----------

