/* * myLib - https://github.com/taktod/myLib * Copyright (c) 2014 ttProject. All rights reserved. * * Licensed under The MIT license. */ package com.ttProject.frame.speex; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import com.ttProject.frame.AudioSelector; import com.ttProject.frame.IAudioFrame; import com.ttProject.frame.extra.AudioMultiFrame; import com.ttProject.frame.speex.sub.NarrowUnit; import com.ttProject.frame.speex.sub.SubUnit; import com.ttProject.frame.speex.sub.WideUnit; import com.ttProject.frame.speex.type.CommentFrame; import com.ttProject.frame.speex.type.Frame; import com.ttProject.frame.speex.type.HeaderFrame; import com.ttProject.nio.channels.ByteReadChannel; import com.ttProject.nio.channels.IReadChannel; import com.ttProject.unit.IUnit; import com.ttProject.unit.extra.BitConnector; import com.ttProject.unit.extra.BitLoader; import com.ttProject.unit.extra.bit.Bit1; import com.ttProject.unit.extra.bit.Bit2; import com.ttProject.unit.extra.bit.Bit3; import com.ttProject.unit.extra.bit.Bit4; import com.ttProject.unit.extra.bit.Bit5; import com.ttProject.unit.extra.bit.Bit6; import com.ttProject.unit.extra.bit.Bit7; /** * selector for speex frame. * expect to get in order. * headerFrame -> commentFrame -> dataFrame. * @author taktod */ public class SpeexFrameSelector extends AudioSelector { @SuppressWarnings("unused") private Logger logger = Logger.getLogger(SpeexFrameSelector.class); /** headerFrame */ private HeaderFrame headerFrame = null; /** commentFrame */ private CommentFrame commentFrame = null; /** * set the header frame. * (set from out side) * ex: flv has only one kind of header. * flv doesn't have specific byte informaton on it. * @param frame */ public void setHeaderFrame(HeaderFrame frame) { this.headerFrame = frame; } /** * set the comment frame. * same as header frame. * @param frame */ public void setCommentFrame(CommentFrame frame) { this.commentFrame = frame; } /** * {@inheritDoc} */ @Override public IUnit select(IReadChannel channel) throws Exception { if(channel.position() == channel.size()) { return null; } SpeexFrame frame = null; if(headerFrame == null) { // try to get header frame. frame = new HeaderFrame(); headerFrame = (HeaderFrame)frame; } else if(commentFrame == null) { // next try to get comment frame. frame = new CommentFrame(); commentFrame = (CommentFrame)frame; } else { /* * speex frame側で処理すると、bitが中途になったときに、次のframeをうまく処理できなくなることがあるみたいです。 */ return getFrameData(channel); // frame = new Frame(); // frame.setHeaderFrame(headerFrame); } frame.minimumLoad(channel); return frame; } /** * get the speexFrame(can be audioMultiFrame) * @param channel * @return * @throws Exception */ private IAudioFrame getFrameData(IReadChannel channel) throws Exception { List<SubUnit> unitList = new ArrayList<SubUnit>(); BitLoader loader = new BitLoader(channel); AudioMultiFrame multiFrame = new AudioMultiFrame(); try { while(true) { Bit1 firstBit = new Bit1(); loader.load(firstBit); SubUnit unit = null; switch(firstBit.get()) { case 0: // data for frame is ready. multiFrame.addFrame(makeFrame(unitList)); unit = new NarrowUnit(); break; case 1: default: unit = new WideUnit(); break; } unit.load(loader); unitList.add(unit); } } catch(Exception e) { multiFrame.addFrame(makeFrame(unitList)); } if(multiFrame.getFrameList().size() == 1) { return multiFrame.getFrameList().get(0); } return multiFrame; } /** * make minimumUnit of speexFrame. * @param unitList * @return * @throws Exception */ private Frame makeFrame(List<SubUnit> unitList) throws Exception { if(unitList.size() == 0) { return null; } int size = 0; BitConnector connector = new BitConnector(); for(SubUnit su : unitList) { size += su.getBitCount(); connector.feed(su.getBitList()); } switch(size % 8) { case 1:connector.feed(new Bit7(0x3F));break; case 2:connector.feed(new Bit6(0x1F));break; case 3:connector.feed(new Bit5(0x0F));break; case 4:connector.feed(new Bit4(0x07));break; case 5:connector.feed(new Bit3(0x03));break; case 6:connector.feed(new Bit2(0x01));break; case 7:connector.feed(new Bit1(0x00));break; case 0: default: break; } Frame frame = new Frame(); setup(frame); frame.setHeaderFrame(headerFrame); frame.minimumLoad(new ByteReadChannel(connector.connect())); unitList.clear(); return frame; } }