public void start() { mRunning = true; mSession.setTimestampClock( new TimestampClock() { public int getCurrentTimestamp() { return getCurTs(); } }); try { mPlayer = Manager.createPlayer( new DataSource(null) { SourceStream[] mStream = {mInput}; public void connect() throws IOException { sLogger.info("connect data source"); } public void disconnect() { sLogger.info("disconnect data source"); } public String getContentType() { return "audio/amr"; } public SourceStream[] getStreams() { return mStream; } public void start() throws IOException { sLogger.info("start data source"); } public void stop() throws IOException { sLogger.info("start data source"); } public Control getControl(String controlType) { return null; } public Control[] getControls() { return null; } }); mPlayer.addPlayerListener(this); mPlayer.realize(); AudioPathControl lPathCtr = (AudioPathControl) mPlayer.getControl("net.rim.device.api.media.control.AudioPathControl"); lPathCtr.setAudioPath(AudioPathControl.AUDIO_PATH_HANDSET); mPlayer.prefetch(); // if ( DeviceInfo.isSimulator() == false) { //only start player on real device mPlayer.start(); if (sLogger.isLevelEnabled(Logger.Info)) sLogger.info("Player is started ."); // } } catch (Throwable e) { sLogger.error("player error:", e); } }
/* (non-Javadoc) * @see java.io.InputStream#read(byte[], int, int) */ public int read(byte[] b, int offset, int length) throws IOException { int bytesToReturn = sSilentAmr.length; if (mBuffering) { bytesToReturn = sSilentAmr.length * 8; } try { if (!priority_set && Thread.currentThread().getPriority() != Thread.MAX_PRIORITY) { Thread.currentThread().setPriority(Thread.MAX_PRIORITY); priority_set = true; } // if (sLogger.isLevelEnabled(Logger.Info) && ((mPlayer.getMediaTime()<<3) % 1000 == // 0))sLogger.info("Player media time ["+mPlayer.getMediaTime()+"]"); int lWrittenLenth = 0; while (lWrittenLenth <= bytesToReturn && mRunning) { long ts = getCurTs(); if (mPlayerTs == -1) { mPlayerTs = ts; sLogger.info("Initializing timestamp to [" + mPlayerTs + "]"); } RtpPacket packet = null; try { long diff; while ((diff = (ts - mPlayerTs)) >= 0) { if (diff > 800) { mPlayerTs = ts - 800; sLogger.warn("Too late, skipping " + ((diff - 800) / 8) + " ms..."); } packet = mSession.recvPacket((int) mPlayerTs); if (packet != null) { mReturnedMs += 20; if (mFirstRead) { String lAmrHeader = "#!AMR\n"; lWrittenLenth = lAmrHeader.length(); System.arraycopy( lAmrHeader.getBytes("US-ASCII"), 0, b, offset, lWrittenLenth); length = length - lWrittenLenth; offset += lWrittenLenth; mFirstRead = false; } if ((length < sSilentAmr.length)) { // special case for end of buffer System.arraycopy( packet.getBytes(), packet.getDataOffset() + 1, b, offset, length); lWrittenLenth += length; mTroncatedPacketSize = length; mTroncatedPacket = packet; if (sLogger.isLevelEnabled(Logger.Warn)) sLogger.warn("End of buffer, [" + lWrittenLenth + "] bytes returned"); return lWrittenLenth; } else { if (mTroncatedPacket != null) { // special case for troncated packet int remain = mTroncatedPacket.getRealLength() - mTroncatedPacket.getDataOffset() - 1 - mTroncatedPacketSize; System.arraycopy( mTroncatedPacket.getBytes(), mTroncatedPacket.getDataOffset() + 1 + mTroncatedPacketSize, b, offset, remain); lWrittenLenth += remain; mTroncatedPacketSize = 0; mTroncatedPacket = null; offset += remain; length -= remain; } // +1 because we need to skip the CMR bytes int datalen = packet.getRealLength() - packet.getDataOffset() - 1; System.arraycopy( packet.getBytes(), packet.getDataOffset() + 1, b, offset, datalen); lWrittenLenth += datalen; length -= datalen; offset += datalen; } } mPlayerTs += 160; } } catch (RtpException e) { sLogger.error("Bad RTP packet", e); } if (packet == null) Thread.sleep(20); } if (!mRunning) { // to notify end of stream. return -1; } if (sLogger.isLevelEnabled(Logger.Debug)) sLogger.debug("[" + lWrittenLenth + "] bytes returned"); return lWrittenLenth; } catch (Throwable e) { sLogger.error("Exiting player input stream", e); return -1; } finally { if (bytesToReturn > sSilentAmr.length) { // we were buffering, so now it's ok resetting value mBuffering = false; } } }