/*
* festivoice
*
* Copyright 2009 FURUHASHI Sadayuki, KASHIHARA Shuzo, SHIBATA Yasuharu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.festivoice;
import java.lang.*;
import java.net.*;
import org.xiph.speex.SpeexEncoder;
import javax.sound.sampled.*;
public class Client extends Thread
{
private static final int LIMIT_TIME = 5;
private StreamSender sender;
private StreamReceiver receiver;
private AudioFormat format;
private InetSocketAddress serverAddress;
private TargetDataLine inputDataLine;
private ClientUserInfoManager clientUserInfoManager;
private boolean endFlag = false;
private static final int COUNT_FRAMES = 4;
private Runnable initCallback;
private boolean isMicAvailable = true;
public Client(String channelName, String userName, InetSocketAddress serverAddress,
int mode, int quality, boolean vbr) throws Exception
{
format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 16000.0F, 16, 1, 2, 16000.0F, false);
clientUserInfoManager = new ClientUserInfoManager();
DatagramSocket socket = new DatagramSocket();
// Initialize StreamSender
try {
DataLine.Info inputDataLineInfo = new DataLine.Info(TargetDataLine.class, format);
inputDataLine = (TargetDataLine)AudioSystem.getLine(inputDataLineInfo);
inputDataLine.open();
} catch (Exception e) {
isMicAvailable = false;
}
ThreadedPacketSender.SessionInfo sessionInfo =
new ThreadedPacketSender.SessionInfo(serverAddress, socket, channelName, userName);
StreamSender.CodecInfo inputCodecInfo =
new StreamSender.CodecInfo(format, mode, quality, vbr, COUNT_FRAMES);
sender = new StreamSender(sessionInfo, inputDataLine, inputCodecInfo);
// Initialize StreamReceiver
ThreadedLineOut.CodecInfo outputCodecInfo =
new ThreadedLineOut.CodecInfo(format, mode, sender.getDecodeBufferSize(), COUNT_FRAMES);
DataLine.Info outputLineInfo = new DataLine.Info(SourceDataLine.class, format);
receiver = new StreamReceiver(socket, outputLineInfo, outputCodecInfo, clientUserInfoManager);
}
public void setListenOnly(boolean flag)
{
if(!isMicAvailable) { flag = true; }
sender.setListenOnly(flag);
}
public boolean isMicAvailable()
{
return this.isMicAvailable;
}
public void run()
{
try {
if(isMicAvailable) {
// Start input line
inputDataLine.start();
//while (!inputDataLine.isRunning()) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
//}
}
} catch (Exception e) {
isMicAvailable = false;
}
// Start StreamSender
if(!isMicAvailable) {
sender.setListenOnly(true);
}
sender.start();
// Start StreamReceiver
receiver.start();
if(initCallback != null) {
initCallback.run();
}
while(!endFlag) {
try {
clientUserInfoManager.stepTimeout(LIMIT_TIME);
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
}
// Stop data source
try {
inputDataLine.stop();
} catch (Exception e) {
// ignore error
}
}
public void end()
{
endFlag = true;
}
public Iterable<? extends IClientUserInfo> getClientUserInfoIterator()
{
return clientUserInfoManager.getClientUserInfoIterator();
}
public void setInitCallback(Runnable initCallback)
{
// 初期化が完了したときに呼ぶ
this.initCallback = initCallback;
}
public void setUserUpdateCallback(Runnable userUpdateCallback)
{
// ユーザー一覧が更新されたときに呼ぶ
clientUserInfoManager.setUserUpdateCallback(userUpdateCallback);
}
}