first commit
This commit is contained in:
789
src/aas/AAS_Receiver_Multichannel.java
Normal file
789
src/aas/AAS_Receiver_Multichannel.java
Normal file
@@ -0,0 +1,789 @@
|
||||
package aas;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.sun.jna.Memory;
|
||||
import com.sun.jna.Pointer;
|
||||
import com.un4seen.bass.BASS;
|
||||
import com.un4seen.bass.BASS.BASS_DEVICEINFO;
|
||||
import com.un4seen.bass.BASS.BASS_INFO;
|
||||
import com.un4seen.bass.BASS.IDSPPROC;
|
||||
import com.un4seen.bass.BASS.SYNCPROC;
|
||||
import com.un4seen.bass.BASS.bassconstant;
|
||||
import com.un4seen.bass.BASSmix;
|
||||
|
||||
import anywheresoftware.b4a.BA;
|
||||
import anywheresoftware.b4a.keywords.Bit;
|
||||
import jbass.Bass_DeviceInfo;
|
||||
|
||||
@BA.Events(values = {
|
||||
"log(msg as string)",
|
||||
"openudpstreamchannel(success as boolean, localip as string, localport as int, streamhandle as int, channelnumber as int)",
|
||||
"playbackdevicefailed(deviceid as int)",
|
||||
"streamingstatus(channel as int, vu as int, bufferspace as int)",
|
||||
"playbackstatus(channel as int, value as string)"
|
||||
})
|
||||
|
||||
@BA.ShortName("AAS_Receiver_Multichannel")
|
||||
|
||||
/**
|
||||
* AAS Receiver multichannel with 7.1 soundcard
|
||||
* @author rdkartono
|
||||
*/
|
||||
public class AAS_Receiver_Multichannel {
|
||||
|
||||
private BA ba;
|
||||
private String event;
|
||||
private Object Me = this;
|
||||
private BASS bass;
|
||||
private BASSmix bassmix;
|
||||
private boolean inited = false;
|
||||
private int deviceid = -1;
|
||||
private int mixerhandle = 0 ;
|
||||
private boolean need_log_event = false;
|
||||
private boolean need_openudpstreamchannel_event = false;
|
||||
private boolean need_playbackdevicefailed_event = false;
|
||||
private boolean need_streamingstatus_event = false;
|
||||
private boolean need_playbackstatus_event = false;
|
||||
|
||||
ExecutorService exec = null;
|
||||
|
||||
private class streamstatusclass {
|
||||
public int vu = 0;
|
||||
public int handle = 0;
|
||||
public final Integer chnumber;
|
||||
public DatagramSocket theudp = null;
|
||||
private ByteBuffer buffer;
|
||||
public final IDSPPROC channeldsp;
|
||||
public final SYNCPROC channelstalled;
|
||||
public final SYNCPROC channelend;
|
||||
public final SYNCPROC mixerchannelstalled;
|
||||
public final SYNCPROC mixerchannelend;
|
||||
public int relaystatus = -1;
|
||||
|
||||
public streamstatusclass(int chnumber) {
|
||||
this.chnumber = chnumber;
|
||||
buffer = ByteBuffer.allocate(32*1000);
|
||||
channeldsp = new IDSPPROC() {
|
||||
|
||||
@Override
|
||||
public void DSPPROC(int handle, int channel, Pointer buffer, int length, Pointer user) {
|
||||
if (buffer!=null) {
|
||||
if (length>0) {
|
||||
ByteBuffer bb = buffer.getByteBuffer(0, length);
|
||||
ShortBuffer sb = bb.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
short curvalue=0, maxvalue=0;
|
||||
while(sb.hasRemaining()) {
|
||||
curvalue = sb.get();
|
||||
if (curvalue>maxvalue) maxvalue = curvalue;
|
||||
}
|
||||
vu = (int)( (maxvalue * 100.0)/Short.MAX_VALUE );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
channelstalled = new SYNCPROC() {
|
||||
|
||||
@Override
|
||||
public void SYNCPROC(int handle, int channel, int data, Pointer user) {
|
||||
switch(data) {
|
||||
case 0 :
|
||||
raise_log_event("BASS_ChannelSetSync Channel="+chnumber+" is stalled");
|
||||
break;
|
||||
case 1 :
|
||||
raise_log_event("BASS_ChannelSetSync Channel="+chnumber+" is resumed");
|
||||
break;
|
||||
default :
|
||||
raise_log_event("BASS_ChannelSetSync Channel="+chnumber+" is unknown stall, data="+data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
mixerchannelstalled = new SYNCPROC() {
|
||||
|
||||
@Override
|
||||
public void SYNCPROC(int handle, int channel, int data, Pointer user) {
|
||||
switch(data) {
|
||||
case 0 :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync Channel="+chnumber+" is stalled");
|
||||
break;
|
||||
case 1 :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync Channel="+chnumber+" is resumed");
|
||||
break;
|
||||
default :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync Channel="+chnumber+" is unknown stall, data="+data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
channelend = new SYNCPROC() {
|
||||
|
||||
@Override
|
||||
public void SYNCPROC(int handle, int channel, int data, Pointer user) {
|
||||
switch(data) {
|
||||
case 0 :
|
||||
raise_log_event("BASS_ChannelSetSync channel="+chnumber+" is normal end position");
|
||||
break;
|
||||
case 1 :
|
||||
raise_log_event("BASS_ChannelSetSync channel="+chnumber+" is backward jump in MOD music");
|
||||
break;
|
||||
case 2 :
|
||||
raise_log_event("BASS_ChannelSetSync channel="+chnumber+" is BASS_POS_END position");
|
||||
break;
|
||||
case 3 :
|
||||
raise_log_event("BASS_ChannelSetSync channel="+chnumber+" is end of tail (BASS_ATTRIB_TAIL)");
|
||||
break;
|
||||
default :
|
||||
raise_log_event("BASS_ChannelSetSync channel="+chnumber+" is unknown end, data="+data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
mixerchannelend = new SYNCPROC() {
|
||||
|
||||
@Override
|
||||
public void SYNCPROC(int handle, int channel, int data, Pointer user) {
|
||||
switch(data) {
|
||||
case 0 :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync channel="+chnumber+" is normal end position");
|
||||
break;
|
||||
case 1 :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync channel="+chnumber+" is backward jump in MOD music");
|
||||
break;
|
||||
case 2 :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync channel="+chnumber+" is BASS_POS_END position");
|
||||
break;
|
||||
case 3 :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync channel="+chnumber+" is end of tail (BASS_ATTRIB_TAIL)");
|
||||
break;
|
||||
default :
|
||||
raise_log_event("BASS_Mixer_ChannelSetSync channel="+chnumber+" is unknown end, data="+data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public int BufferRemaining() {
|
||||
return buffer.remaining();
|
||||
}
|
||||
|
||||
public void PushData(byte[] bb, int bblen) {
|
||||
buffer.put(bb,0,bblen);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void PushData(byte[] bb) {
|
||||
buffer.put(bb);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public byte[] PullData(int length) {
|
||||
byte[] readdata = new byte[length];
|
||||
buffer.flip();
|
||||
buffer.get(readdata);
|
||||
buffer.compact();
|
||||
return readdata;
|
||||
}
|
||||
|
||||
public byte[] PullAllData() {
|
||||
if (BufferPosition()>0) {
|
||||
buffer.flip();
|
||||
byte[] readdata = new byte[buffer.remaining()];
|
||||
buffer.get(readdata);
|
||||
buffer.compact();
|
||||
return readdata;
|
||||
} else return null;
|
||||
}
|
||||
|
||||
public int BufferPosition() {
|
||||
return buffer.position();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public boolean Buffer_inWriteMode() {
|
||||
return buffer.limit()==buffer.capacity() ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
private volatile streamstatusclass[] streamingstatus = null;
|
||||
|
||||
public AAS_Receiver_Multichannel() {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||
public void run() {
|
||||
BA.Log("AAS_Receiver_Multichannel ShutdownHook");
|
||||
if (exec!=null) {
|
||||
exec.shutdown();
|
||||
try {
|
||||
exec.awaitTermination(10, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
BA.Log("ExecutorService awaitTermination failed, exception="+e.getMessage());
|
||||
}
|
||||
}
|
||||
CloseDevice();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize AAS Receiver Multichannel
|
||||
* @param event eventname
|
||||
*/
|
||||
public void Initialize(BA ba, String event) {
|
||||
this.ba = ba;
|
||||
this.event = event;
|
||||
check_events();
|
||||
|
||||
bass = new BASS();
|
||||
bassmix = new BASSmix();
|
||||
int bassversion = bass.BASS_GetVersion();
|
||||
int bassmixversion = bassmix.BASS_Mixer_GetVersion();
|
||||
if (bassversion!=0) {
|
||||
if (bassmixversion!=0) {
|
||||
BA.Log("BASS Version="+Bit.ToHexString(bassversion)+", Mixer Version="+Bit.ToHexString(bassmixversion));
|
||||
inited = true;
|
||||
exec = Executors.newFixedThreadPool(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if already initialized and BASS can be loaded
|
||||
* @return
|
||||
*/
|
||||
public boolean IsInitialized() {
|
||||
return inited;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open Playback device
|
||||
* @param devid device id, 0 = no sound, 1 = first real device, 2 = ....
|
||||
* @param samplingrate samplingrate
|
||||
* @return true if can be opened
|
||||
*/
|
||||
public boolean OpenDevice(final int devid, final int samplingrate) {
|
||||
deviceid = -1;
|
||||
if (inited) {
|
||||
BASS_DEVICEINFO dvi = new BASS_DEVICEINFO();
|
||||
if (bass.BASS_GetDeviceInfo(devid, dvi)) {
|
||||
dvi.read();
|
||||
Bass_DeviceInfo dv = new Bass_DeviceInfo(devid, dvi);
|
||||
if (dv.isvalid) {
|
||||
if (dv.IsEnabled()) {
|
||||
if (dv.IsInited()) {
|
||||
// sudah initialized, free dulu
|
||||
bass.BASS_SetDevice(devid);
|
||||
bass.BASS_Free();
|
||||
}
|
||||
|
||||
int flags = bassconstant.BASS_DEVICE_16BITS | bassconstant.BASS_DEVICE_SPEAKERS | bassconstant.BASS_DEVICE_FREQ;
|
||||
if (bass.BASS_Init(devid, samplingrate, flags)) {
|
||||
this.deviceid = devid;
|
||||
|
||||
BASS_INFO bi = new BASS_INFO();
|
||||
if (bass.BASS_GetInfo(bi)) {
|
||||
bi.read();
|
||||
|
||||
|
||||
streamingstatus = new streamstatusclass[bi.speakers];
|
||||
for(int ii=0;ii<streamingstatus.length;ii++) streamingstatus[ii] = new streamstatusclass(ii);
|
||||
|
||||
|
||||
|
||||
} else raise_log_event("BASS_GetInfo failed, error="+bass.GetBassErrorString());
|
||||
|
||||
// bassmix.BASS_MIXER_NONSTOP
|
||||
int mixerflag = 0;
|
||||
int mh = bassmix.BASS_Mixer_StreamCreate(samplingrate, 8, mixerflag);
|
||||
if (mh!=0) {
|
||||
if (bass.BASS_ChannelPlay(mh, true)) {
|
||||
this.mixerhandle = mh;
|
||||
bass.BASS_ChannelSetSync(mh, bassconstant.BASS_SYNC_DEV_FAIL, 0, mixerdevfail, null);
|
||||
bass.BASS_ChannelSetSync(mh, bassconstant.BASS_SYNC_STALL, 0, mixerstalled, null);
|
||||
bass.BASS_ChannelSetSync(mh, bassconstant.BASS_SYNC_END, 0, mixerend, null);
|
||||
|
||||
// pancingan
|
||||
exec.submit(new raisestreamingstatusrunnable());
|
||||
|
||||
return true;
|
||||
} else raise_log_event("BASS_ChannelPlay mixerhandle failed, error="+bass.GetBassErrorString());
|
||||
} else raise_log_event("BASS_Mixer_StreamCreate failed, error="+bass.GetBassErrorString());
|
||||
} else raise_log_event("BASS_Init device="+devid+" failed, error="+bass.GetBassErrorString());
|
||||
} else raise_log_event("OpenDevice device="+devid+" failed, Device is disabled");
|
||||
} else raise_log_event("DeviceInfo for device="+devid+" is invalid");
|
||||
} else raise_log_event("BASS_GetDeviceInfo device="+devid+" failed, error="+bass.GetBassErrorString());
|
||||
} else raise_log_event("Call Initialize first");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private SYNCPROC mixerdevfail = new SYNCPROC() {
|
||||
|
||||
@Override
|
||||
public void SYNCPROC(int handle, int channel, int data, Pointer user) {
|
||||
raise_playbackdevicefailed_event(deviceid);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private SYNCPROC mixerend = new SYNCPROC() {
|
||||
|
||||
@Override
|
||||
public void SYNCPROC(int handle, int channel, int data, Pointer user) {
|
||||
raise_log_event("Mixer reached END");
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private SYNCPROC mixerstalled = new SYNCPROC() {
|
||||
|
||||
@Override
|
||||
public void SYNCPROC(int handle, int channel, int data, Pointer user) {
|
||||
switch(data) {
|
||||
case 0 :
|
||||
raise_playbackstatus_event(100,"stalled");
|
||||
break;
|
||||
case 1 :
|
||||
raise_playbackstatus_event(100,"resumed");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get Opened Playback Device ID
|
||||
* @return -1 if not opened
|
||||
*/
|
||||
public int getDeviceID() {
|
||||
return deviceid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close Playback Device
|
||||
*/
|
||||
public void CloseDevice() {
|
||||
if (deviceid!=-1) {
|
||||
if (inited) {
|
||||
|
||||
if (mixerhandle!=0) {
|
||||
bass.BASS_StreamFree(mixerhandle);
|
||||
}
|
||||
mixerhandle = 0;
|
||||
|
||||
bass.BASS_SetDevice(deviceid);
|
||||
bass.BASS_Free();
|
||||
}
|
||||
}
|
||||
deviceid = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close UDP Streaming for channel
|
||||
* @param channelnumber 0 - 7
|
||||
* @return true if success
|
||||
*/
|
||||
public boolean Close_UDP_StreamChannel(int channelnumber) {
|
||||
if (inited) {
|
||||
if (deviceid!=-1) {
|
||||
streamstatusclass sc = GetStreamingStatusMember(channelnumber);
|
||||
if (sc!=null) {
|
||||
if (sc.theudp!=null) {
|
||||
if (sc.theudp.isClosed()==false) {
|
||||
sc.theudp.close();
|
||||
raise_log_event("Close_UDP_StreamChannel, closing UDP for channel="+sc.chnumber);
|
||||
}
|
||||
sc.theudp = null;
|
||||
}
|
||||
if (sc.handle!=0) {
|
||||
if (!bassmix.BASS_Mixer_ChannelRemove(sc.handle)) {
|
||||
raise_log_event("Close_UDP_StreamChannel BASS_Mixer_ChannelRemove failed for channel="+sc.chnumber+", error="+bass.GetBassErrorString());
|
||||
}
|
||||
if (!bass.BASS_ChannelStop(sc.handle)) {
|
||||
raise_log_event("Close_UDP_StreamChannel BASS_ChannelStop failed for channel="+sc.chnumber+", error="+bass.GetBassErrorString());
|
||||
}
|
||||
if (!bass.BASS_StreamFree(sc.handle)) {
|
||||
raise_log_event("Close_UDP_StreamChannel BASS_StreamFree failed for channel="+sc.chnumber+", error="+bass.GetBassErrorString());
|
||||
}
|
||||
sc.handle = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open UDP Streaming , linked with Soundcard channel
|
||||
* will raise event openudpstreamchannel(success as boolean, localip as string, localport as int, streamhandle as int, channelnumber as int)
|
||||
* @param samplingrate samplingrate
|
||||
* @param localip valid IP address to bind
|
||||
* @param localport valid port
|
||||
* @param channelnumber 0 - (detectedspeakers-1)
|
||||
* @return true if DatagramSocket can be created
|
||||
*/
|
||||
public boolean Open_UDP_StreamChannel(int samplingrate, String localip, int localport, int channelnumber) {
|
||||
if (inited) {
|
||||
if (deviceid!=-1) {
|
||||
streamstatusclass sc = GetStreamingStatusMember(channelnumber);
|
||||
if (sc!=null) {
|
||||
|
||||
DatagramSocket udp = null;
|
||||
// coba open UDP listen
|
||||
try {
|
||||
udp = new DatagramSocket(new InetSocketAddress(localip, localport));
|
||||
|
||||
} catch (SocketException e) {
|
||||
raise_log_event("Unable to create DatagramSocket, exception="+e.getMessage());
|
||||
}
|
||||
if (udp != null) {
|
||||
// berhasil UDP listen
|
||||
// mesti bikin final supaya bisa masuk ba.submitrunnable
|
||||
|
||||
sc.theudp = udp;
|
||||
|
||||
// runnable untuk ambil data dari udp;
|
||||
exec.submit(new udprunnable(channelnumber));
|
||||
|
||||
int flag = bassconstant.BASS_STREAM_DECODE;
|
||||
int handle = bass.BASS_StreamCreate(samplingrate, 1, flag, bassconstant.STREAMPROC_PUSH, null);
|
||||
if (handle!=0) {
|
||||
sc.handle = handle;
|
||||
bass.BASS_ChannelSetAttribute(handle,bassconstant.BASS_ATTRIB_PUSH_LIMIT , 0);
|
||||
bass.BASS_ChannelSetDSP(handle, sc.channeldsp, null, 0);
|
||||
bass.BASS_ChannelSetSync(handle, bassconstant.BASS_SYNC_END, 0, sc.channelend, null);
|
||||
bass.BASS_ChannelSetSync(handle, bassconstant.BASS_SYNC_STALL, 0, sc.channelstalled, null);
|
||||
raise_openudpstreamchannel_event(true, sc.theudp.getLocalAddress().getHostAddress(), sc.theudp.getLocalPort(), sc.handle, sc.chnumber);
|
||||
|
||||
exec.submit(new streamputdatarunnable(channelnumber));
|
||||
|
||||
}else {
|
||||
// gagal buka bass stream
|
||||
raise_log_event("BASS_StreamCreate failed, error="+bass.GetBassErrorString());
|
||||
if (sc.theudp != null) {
|
||||
raise_openudpstreamchannel_event(false, sc.theudp.getLocalAddress().getHostAddress(), sc.theudp.getLocalPort(),0, sc.chnumber);
|
||||
if (sc.theudp.isClosed()==false) {
|
||||
sc.theudp.close();
|
||||
}
|
||||
sc.theudp = null;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
} else raise_log_event("Call OpenDevice first");
|
||||
} else raise_log_event("Call Initialize first");
|
||||
return false;
|
||||
}
|
||||
|
||||
private streamstatusclass GetStreamingStatusMember(int index) {
|
||||
if (streamingstatus != null) {
|
||||
if (index>=0) {
|
||||
if (index<streamingstatus.length) {
|
||||
return streamingstatus[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Runnable untuk raise_streamingstatus_event periodik
|
||||
private class raisestreamingstatusrunnable implements Runnable{
|
||||
boolean keeprunning = true;
|
||||
public raisestreamingstatusrunnable() {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
keeprunning = true;
|
||||
raise_log_event("raisestreamingstatusrunnable started");
|
||||
while(keeprunning) {
|
||||
try {
|
||||
Thread.sleep(150);
|
||||
} catch (InterruptedException e) {
|
||||
keeprunning = false;
|
||||
}
|
||||
|
||||
for(streamstatusclass ssc : streamingstatus) {
|
||||
raise_streamingstatus_event(ssc.chnumber, ssc.vu, ssc.BufferRemaining());
|
||||
}
|
||||
}
|
||||
raise_log_event("raisestreamingstatusrunnable finished");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class streamputdatarunnable implements Runnable{
|
||||
private final int channelnumber;
|
||||
private final streamstatusclass ssc;
|
||||
private int mixchanflag = 0;
|
||||
private boolean keeprunning = false;
|
||||
public streamputdatarunnable(int chnum) {
|
||||
channelnumber = chnum;
|
||||
ssc = GetStreamingStatusMember(channelnumber);
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
if (ssc!=null) {
|
||||
final long delay = bass.BASS_ChannelSeconds2Bytes(ssc.handle, 2);
|
||||
raise_log_event("Runnable StreamPutData started for channel="+ssc.chnumber+", will delay "+delay+" bytes");
|
||||
keeprunning = true;
|
||||
while(keeprunning) {
|
||||
|
||||
synchronized(ssc) {
|
||||
if (ssc.handle==0) {
|
||||
raise_log_event("ssc.handle=0 for channel="+ssc.chnumber+", breaking now");
|
||||
keeprunning = false;
|
||||
}
|
||||
if (ssc.BufferPosition()==0) {
|
||||
try {
|
||||
ssc.wait(3000);
|
||||
} catch (InterruptedException e) {
|
||||
raise_log_event("InterruptException on buffer waiting for channel="+ssc.chnumber);
|
||||
keeprunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
// sampe sini , harusnya ada data, kalau gak ada, selesai aja
|
||||
byte[] dataread = ssc.PullAllData();
|
||||
if (dataread!=null) {
|
||||
int rem = dataread.length;
|
||||
Pointer bb = new Memory(rem);
|
||||
bb.write(0, dataread, 0, rem);
|
||||
|
||||
|
||||
int qq = bass.BASS_StreamPutData(ssc.handle, bb, rem);
|
||||
if (ssc.relaystatus!=1) {
|
||||
ssc.relaystatus = 1;
|
||||
raise_playbackstatus_event(ssc.chnumber, "resumed");
|
||||
}
|
||||
mixchanflag = bassmix.BASS_Mixer_ChannelFlags(ssc.handle, 0, 0);
|
||||
if ((mixchanflag & bassmix.BASS_MIXER_CHAN_PAUSE)>0) {
|
||||
if (qq>delay) {
|
||||
raise_log_event("Resuming mixer for channel="+ssc.chnumber);
|
||||
bassmix.BASS_Mixer_ChannelFlags(ssc.handle, 0, bassmix.BASS_MIXER_CHAN_PAUSE);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
ssc.vu = 0;
|
||||
if (ssc.relaystatus!=0) {
|
||||
ssc.relaystatus = 0;
|
||||
raise_playbackstatus_event(ssc.chnumber,"stalled");
|
||||
//bass.BASS_StreamPutData(ssc.handle, null, bassconstant.BASS_STREAMPROC_END); // bikin gak bisa streaming
|
||||
raise_log_event("Pausing mixer for channel="+ssc.chnumber);
|
||||
bassmix.BASS_Mixer_ChannelFlags(ssc.handle, bassmix.BASS_MIXER_CHAN_PAUSE, bassmix.BASS_MIXER_CHAN_PAUSE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (ssc!=null) {
|
||||
|
||||
raise_log_event("Runnable StreamPutData finished for channel="+ssc.chnumber);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class udprunnable implements Runnable{
|
||||
private final int channelnumber;
|
||||
private final streamstatusclass ssc;
|
||||
private boolean keeprunning = false;
|
||||
public udprunnable(int chnum) {
|
||||
channelnumber = chnum;
|
||||
ssc = GetStreamingStatusMember(channelnumber);
|
||||
}
|
||||
@Override
|
||||
public void run() {
|
||||
if (ssc!=null) {
|
||||
raise_log_event("Runnable UDP Receive started for channel="+ssc.chnumber);
|
||||
keeprunning = true;
|
||||
while(keeprunning) {
|
||||
if (ssc.theudp!=null && ssc.theudp.isClosed()==false) {
|
||||
try {
|
||||
// ngeblok di sini sampe dapat paket
|
||||
DatagramPacket pkg = new DatagramPacket(new byte[1500],1500);
|
||||
ssc.theudp.receive(pkg);
|
||||
|
||||
if (pkg!=null) {
|
||||
|
||||
int length = pkg.getLength();
|
||||
byte[] data = pkg.getData();
|
||||
|
||||
if (ssc!=null) {
|
||||
synchronized(ssc) {
|
||||
ssc.PushData(data, length);
|
||||
ssc.notify();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
raise_log_event("IOException dari theudp, exception="+e.getMessage());
|
||||
ssc.theudp.close();
|
||||
ssc.theudp = null;
|
||||
keeprunning = false;
|
||||
}
|
||||
} else {
|
||||
raise_log_event("theudp Runnable must break, theudp isclosed");
|
||||
keeprunning = false;
|
||||
|
||||
}
|
||||
}
|
||||
raise_log_event("Runnable UDP Receive finished for channel="+ssc.chnumber);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Play handle
|
||||
* Obtain handle from event openudpstreamchannel
|
||||
* @param handle
|
||||
* @param channelnumber 0 - 7
|
||||
* @return true if can be played
|
||||
*/
|
||||
public boolean PlayHandle(int handle, int channelnumber) {
|
||||
if (inited) {
|
||||
if (mixerhandle!=0) {
|
||||
if (handle != 0) {
|
||||
|
||||
int flag = bassmix.BASS_MIXER_CHAN_PAUSE;
|
||||
switch(channelnumber) {
|
||||
case 1 :
|
||||
flag |= bassconstant.BASS_SPEAKER_FRONTRIGHT;
|
||||
break;
|
||||
case 2:
|
||||
flag |= bassconstant.BASS_SPEAKER_REARLEFT;
|
||||
break;
|
||||
case 3:
|
||||
flag |= bassconstant.BASS_SPEAKER_REARRIGHT;
|
||||
break;
|
||||
case 4:
|
||||
flag |= bassconstant.BASS_SPEAKER_REAR2LEFT;
|
||||
break;
|
||||
case 5:
|
||||
flag |= bassconstant.BASS_SPEAKER_REAR2RIGHT;
|
||||
break;
|
||||
case 6:
|
||||
flag |= bassconstant.BASS_SPEAKER_CENTER;
|
||||
break;
|
||||
case 7:
|
||||
flag |= bassconstant.BASS_SPEAKER_LFE;
|
||||
break;
|
||||
default:
|
||||
flag |= bassconstant.BASS_SPEAKER_FRONTLEFT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bassmix.BASS_Mixer_StreamAddChannel(mixerhandle, handle, flag)) {
|
||||
streamstatusclass ssc = GetStreamingStatusMember(channelnumber);
|
||||
if (ssc!=null) {
|
||||
bassmix.BASS_Mixer_ChannelSetSync(handle, bassconstant.BASS_SYNC_STALL, 0, ssc.mixerchannelstalled, null);
|
||||
bassmix.BASS_Mixer_ChannelSetSync(handle, bassconstant.BASS_SYNC_END, 0, ssc.mixerchannelend, null);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else raise_log_event("BASS_Mixer_StreamAddChannel failed , error="+bass.GetBassErrorString());
|
||||
} else raise_log_event("Invalid handle, obtain handle from event openudpstreamchannel");
|
||||
} else raise_log_event("Call OpenDevice first");
|
||||
} else raise_log_event("Call Initialize first");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop playing handle, and remove it
|
||||
* @param handle
|
||||
* @return true if can be done
|
||||
*/
|
||||
public boolean StopHandle(int handle) {
|
||||
if (inited) {
|
||||
if (mixerhandle!=0) {
|
||||
if (handle!=0) {
|
||||
if (bassmix.BASS_Mixer_ChannelRemove(handle)) {
|
||||
if (bass.BASS_StreamFree(handle)) {
|
||||
raise_log_event("StopHandle handle="+handle+" succcess");
|
||||
return true;
|
||||
} else raise_log_event("BASS_StreamFree failed, error="+bass.GetBassErrorString());
|
||||
} else raise_log_event("BASS_Mixer_ChannelRemove failed, error="+bass.GetBassErrorString());
|
||||
} else raise_log_event("Invalid handle, obtain handle from event openudpstreamchannel");
|
||||
} else raise_log_event("Call OpenDevice first");
|
||||
} else raise_log_event("Call Initialize first");
|
||||
return false;
|
||||
}
|
||||
|
||||
private void check_events() {
|
||||
need_log_event = ba.subExists(event+"_log");
|
||||
need_openudpstreamchannel_event = ba.subExists(event+"_openudpstreamchannel");
|
||||
need_playbackdevicefailed_event = ba.subExists(event+"_playbackdevicefailed");
|
||||
need_streamingstatus_event = ba.subExists(event+"_streamingstatus");
|
||||
need_playbackstatus_event = ba.subExists(event+"_playbackstatus");
|
||||
}
|
||||
|
||||
private void raise_log_event(String msg) {
|
||||
if (need_log_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_log", false, new Object[] {msg});
|
||||
}
|
||||
|
||||
private void raise_openudpstreamchannel_event(boolean success, String localip, int localport, int streamhandle, int channelnumber) {
|
||||
if (need_openudpstreamchannel_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_openudpstreamchannel", false, new Object[] {success, localip, localport, streamhandle, channelnumber});
|
||||
}
|
||||
|
||||
private void raise_playbackdevicefailed_event(int deviceid) {
|
||||
if (need_playbackdevicefailed_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_playbackdevicefailed", false, new Object[] {deviceid});
|
||||
}
|
||||
|
||||
private void raise_streamingstatus_event(int channelnumber, int vu, int buffferspace) {
|
||||
if (need_streamingstatus_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_streamingstatus", false, new Object[] {channelnumber, vu, buffferspace});
|
||||
}
|
||||
|
||||
private void raise_playbackstatus_event(int channelnumber, String value) {
|
||||
if (need_playbackstatus_event) ba.raiseEventFromDifferentThread(Me, null, 0, event+"_playbackstatus", false, new Object[] {channelnumber, value});
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user