How to send and receive Voice Stream using RTP - android

I am new in SIP call using RTP, now I am trying to send and receive
voice streams using RTP for sip call. I am done with connecting
two emulators and able to send INVITE and INVITE-ACK using jain sip.
After I got an Ack I want to start RTP for media streaming, I use the RtpPacket
function to send and receive
I use RtpFunction to send media with all RTP header like this:
byte Version;
boolean Padding;
boolean Extension;
byte CC;
boolean Marker;
byte PayloadType;
short SequenceNumber;
int TimeStamp;
Please give some ideas and actual links where I can find an answer.

This can be achieved in a simpler manner
AudioManager audio = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
audio.setMode(AudioManager.MODE_IN_COMMUNICATION);
audioGroup = new AudioGroup();
audioGroup.setMode(AudioGroup.MODE_ECHO_SUPPRESSION);
audioStream = new AudioStream(InetAddress.getByAddress(getLocalIPAddress()));
audioStream.setCodec(AudioCodec.PCMU);
audioStream.setMode(RtpStream.MODE_NORMAL);
audioStream.associate(InetAddress.getByName(SipStackAndroid.getRemoteIp()), REMOTE_PORT);
audioStream.join(audioGroup);

We send and receive RTP data using RTPpacket.
import javax.media.rtp.*;
import javax.media.rtp.rtcp.*;
import javax.media.rtp.event.*;
import javax.media.*;
import javax.media.protocol.*;
import java.net.InetAddress;
import javax.media.format.AudioFormat;
import com.sun.media.ui.*;
import java.util.Vector;
public class RTPSourceStream < RTPPlayerWindow > implements ReceiveStreamListener,
ControllerListener {
#SuppressWarnings("rawtypes")
Vector playerlist = new Vector();
#SuppressWarnings("deprecation")
SessionManager mgr = null;
boolean terminatedbyClose = false;
#SuppressWarnings("deprecation")
public SessionManager createManager(String address,
String sport,
String sttl,
boolean listener,
boolean sendlistener) {
return createManager(address,
new Integer(sport).intValue(),
new Integer(sttl).intValue(),
listener,
sendlistener);
}
#SuppressWarnings("deprecation")
public SessionManager createManager(String address,
int port,
int ttl,
boolean listener,
boolean sendlistener) {
mgr = (SessionManager) new com.sun.media.rtp.RTPSessionMgr();
if (mgr == null) return null;
mgr.addFormat(new AudioFormat(AudioFormat.DVI_RTP, 44100, 4, 1), 18);
if (listener) mgr.addReceiveStreamListener(this);
// if (sendlistener) new RTPSendStreamWindow(mgr);
// ask RTPSM to generate the local participants CNAME
String cname = mgr.generateCNAME();
String username = null;
try {
username = System.getProperty("user.name");
} catch (SecurityException e) {
username = "jmf-user";
}
// create our local Session Address
SessionAddress localaddr = new SessionAddress();
try {
InetAddress destaddr = InetAddress.getByName(address);
SessionAddress sessaddr = new SessionAddress(destaddr,
port,
destaddr,
port + 1);
SourceDescription[] userdesclist = new SourceDescription[] {
new SourceDescription(SourceDescription
.SOURCE_DESC_EMAIL,
"jmf-user#sun.com",
1,
false),
new SourceDescription(SourceDescription
.SOURCE_DESC_CNAME,
cname,
1,
false),
new
SourceDescription(SourceDescription.SOURCE_DESC_TOOL, "JMF RTP Player v2.0",
1,
false)
};
mgr.initSession(localaddr,
userdesclist,
0.05,
0.25);
mgr.startSession(sessaddr, ttl, null);
} catch (Exception e) {
System.err.println(e.getMessage());
return null;
}
return mgr;
}
public void update(ReceiveStreamEvent event) {
Player newplayer = null;
RTPPacket playerWindow = null;
// find the sourceRTPSM for this event
SessionManager source = (SessionManager) event.getSource();
// create a new player if a new recvstream is detected
if (event instanceof NewReceiveStreamEvent) {
String cname = "Java Media Player";
ReceiveStream stream = null;
try {
// get a handle over the ReceiveStream
stream = ((NewReceiveStreamEvent) event)
.getReceiveStream();
Participant part = stream.getParticipant();
if (part != null) cname = part.getCNAME();
// get a handle over the ReceiveStream datasource
DataSource dsource = stream.getDataSource();
// create a player by passing datasource to the
// Media Manager
newplayer = Manager.createPlayer(dsource);
System.out.println("created player " + newplayer);
} catch (Exception e) {
System.err.println("NewReceiveStreamEvent exception " +
e.getMessage());
return;
}
if (newplayer == null) return;
playerlist.addElement(newplayer);
newplayer.addControllerListener(this);
// send this player to player GUI
playerWindow = new RTPPacket(newplayer, cname);
}
}
public void controllerUpdate(ControllerEvent evt) {
// get a handle over controller, remove it from the player
// list.
// if player list is empty, close the sesssion manager.
if ((evt instanceof ControllerClosedEvent) ||
(evt instanceof ControllerErrorEvent) ||
(evt instanceof DeallocateEvent)) {
Player p = (Player) evt.getSourceController();
if (!terminatedbyClose) {
if (playerlist.contains(p))
playerlist.removeElement(p);
if ((playerlist.size() == 0) && (mgr != null))
mgr.closeSession("All players are closed");
}
}
}
public void closeManager() {
terminatedbyClose = true;
// first close all the players
for (int i = 0; i < playerlist.size(); i++) {
((Player) playerlist.elementAt(i)).close();
}
if (mgr != null) {
mgr.closeSession("RTP Session Terminated");
mgr = null;
}
}
class RTPPacket extends RTPSourceStream {
public RTPPacket(Player newplayer, String cname) {
// TODO Auto-generated constructor stub
}
}
}

Related

MediaPlayer - Sounds Stop Playing

I am creating a class witch loads up a few sounds. However, isPlaying keeps on throwing an exception after a while and then stops playing that particular sound permanently, while other sounds keep playing OK.
public class MySound {
int m_IdMyId;
int m_ResId;
boolean m_IsLoaded;
MediaPlayer m_Media;
public MySound(int idMyId, int resId){
m_IdMyId = idMyId;
m_ResId = resId;
m_IsLoaded = false;
m_Media = null;
}
}
In this m_IdMyId is just an id for my game. m_ResId is something like R.raw.mysound1. m_IsLoaded I think is automatically set to true as I am loading synconously. m_Media is the MediaPlayer object.
I am calling stop() very regularly, as it is a game and I need to check every second or so to make sure certain sounds are stopped. It is here that it throws an exception when snd.m_Media.isPlaying() is called.
I cannot seem to access e to see what the error is.
Also I would like to know how I can set m_IsLoaded correctly. How do I know when the sound is fully loaded and ready to use?
Here is my management class:
public class MySoundManager {
MainActivity m_Context;
ArrayList<MySound> mySounds;
public MySoundManager(MainActivity context) {
m_Context = context;
mySounds = new ArrayList<MySound>();
mySounds.add(new MySound(8, R.raw.mysound1));
mySounds.add(new MySound(10, R.raw.mysound2));
mySounds.add(new MySound(22, R.raw.mysound3));
mySounds.add(new MySound(100, R.raw.click));
mySounds.add(new MySound(101, R.raw.error));
for(MySound mysound : mySounds) {
mysound.m_Media = MediaPlayer.create(m_Context, mysound.m_ResId); // no need to call prepare(); create() does that for you
mysound.m_IsLoaded = true;
}
}
// I call this when the main thread calls onResume
public void onResume(){
for(MySound mysound : mySounds) {
if(mysound.m_Media == null) {
mysound.m_Media = MediaPlayer.create(m_Context, mysound.m_ResId); // no need to call prepare(); create() does that for you
mysound.m_IsLoaded = true;
}
}
}
// I call this when the main thread calls onPause
public void onPause(){
for(MySound mysound : mySounds) {
if(mysound.m_Media != null) {
mysound.m_Media.stop();
mysound.m_Media.release();
mysound.m_Media = null;
}
}
}
public boolean IsAllLoaded(){
for(MySound mysound : mySounds) {
if(!mysound.m_IsLoaded) return false;
}
return true;
}
public MySound FindMySoundByIdMyId(int idMyId){
try {
for(MySound mysound : mySounds) {
if (mysound.m_IdMyId == idMyId) return mysound;
}
}catch(Exception e) {
MySound snd;
snd = null; // ToDo
}
return null;
}
public void play(int idMyId){
MySound snd;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null)
snd.m_Media.start();
}catch(IllegalStateException e) {
snd = null; // ToDo
}
}
public void pause(int idMyId){
MySound snd;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null &&
snd.m_Media.isPlaying())
snd.m_Media.pause();
}catch(IllegalStateException e) {
snd = null; // ToDo
}
}
public void pauseAll(){
try{
for (MySound mysound : mySounds) {
if(mysound.m_Media.isPlaying())
mysound.m_Media.pause();
}
}catch(IllegalStateException e) {
MySound snd;
snd = null; // ToDo
}
}
public boolean isPlaying(int idMyId, MySound[] fill){
MySound snd;
fill[0] = null;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null){
fill[0] = snd;
return snd.m_Media.isPlaying();
}
}catch(IllegalStateException e) {
snd = null; // ToDo
}
return false;
}
public void stop(int idMyId){
MySound snd;
try{
if((snd = FindMySoundByIdMyId(idMyId)) != null &&
snd.m_Media.isPlaying())
snd.m_Media.stop();
}catch(IllegalStateException e) {
snd = null; // ToDo
}
}
// The str is in the format
// number id, 1 = on 0 = off,dont play if this id playing;
public void PlaySound(String str) {
boolean isplaying;
int i, len, id, idDontPlay, milliNow;
String[] strARR = str.split(";");
String[] strARR2;
Integer[] tmpIntARR;
ArrayList<Integer[]> onARR = new ArrayList<Integer[]>();
ArrayList<Integer> offARR = new ArrayList<Integer>();
MySound snd;
for (i = 0, len = strARR.length; i < len; i++) {
if(strARR[i].length() <= 0) continue;
if((strARR2 = strARR[i].split(",")) != null &&
strARR2.length >= 3 &&
strARR2[0].length() > 0 &&
strARR2[1].length() > 0 &&
strARR2[2].length() > 0){
id = Integer.parseInt(strARR2[0]);
idDontPlay = Integer.parseInt(strARR2[2]);
tmpIntARR = new Integer[2];
tmpIntARR[0] = id;
tmpIntARR[1] = idDontPlay;
if(Integer.parseInt(strARR2[1]) == 1){
onARR.add(tmpIntARR);
} else offARR.add(id);
}
}
// Turn off all sounds that need to be turned off
for (i=0,len=offARR.size();i<len;i++) {
id = offARR.get(i);
stop(id);
}
// Turn all sounds that need to be turned on,
// but only if the sound that blocks a new sound is not playing
for (i=0,len=onARR.size();i<len;i++) {
tmpIntARR = onARR.get(i);
id = tmpIntARR[0];
idDontPlay = tmpIntARR[1];
// We dont play if the idDontPlay sound is already playing
if((snd = FindMySoundByIdMyId(idDontPlay)) != null &&
snd.m_Media.isPlaying())
continue;
if((snd = FindMySoundByIdMyId(id)) != null){
isplaying = snd.m_Media.isPlaying();
milliNow = snd.m_Media.getCurrentPosition();
if(milliNow > (snd.m_Media.getDuration() - 1000) ||
(!isplaying && milliNow > 0)){
snd.m_Media.seekTo(0); // Half a second inside
}
if(!isplaying) snd.m_Media.start();
}
}
}
}
Creating a MediaPlayer instance for every sound is not a good practice to get low latency, especially for short clips. MediaPlayer is for longer clips such as Music files it uses large buffer so, larger buffer means high latency. Also, there is AudioFocus mechanism on Android that may interfere your sound playing session. So, I strongly recommend you to use SoundPool to play short clips like game sounds.

How to programmatically connect with vpn server without using "Secret key"?

I want to connect with VPN server but I don't want to use secret key. Currently the code snippet i found to programmatically create vpn connection is as follows:
MyVpnClient:
package com.example.android.toyvpn;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.os.Bundle;
import android.widget.TextView;
public class ToyVpnClient extends Activity {
public interface Prefs {
String NAME = "connection";
String SERVER_ADDRESS = "server.address";
String SERVER_PORT = "server.port";
String SHARED_SECRET = "shared.secret";
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.form);
final TextView serverAddress = (TextView) findViewById(R.id.address);
final TextView serverPort = (TextView) findViewById(R.id.port);
final TextView sharedSecret = (TextView) findViewById(R.id.secret);
final SharedPreferences prefs = getSharedPreferences(Prefs.NAME, MODE_PRIVATE);
serverAddress.setText(prefs.getString(Prefs.SERVER_ADDRESS, ""));
serverPort.setText(prefs.getString(Prefs.SERVER_PORT, ""));
sharedSecret.setText(prefs.getString(Prefs.SHARED_SECRET, ""));
findViewById(R.id.connect).setOnClickListener(v -> {
prefs.edit()
.putString(Prefs.SERVER_ADDRESS, serverAddress.getText().toString())
.putString(Prefs.SERVER_PORT, serverPort.getText().toString())
.putString(Prefs.SHARED_SECRET, sharedSecret.getText().toString())
.commit();
Intent intent = VpnService.prepare(ToyVpnClient.this);
if (intent != null) {
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
});
findViewById(R.id.disconnect).setOnClickListener(v -> {
startService(getServiceIntent().setAction(ToyVpnService.ACTION_DISCONNECT));
});
}
#Override
protected void onActivityResult(int request, int result, Intent data) {
if (result == RESULT_OK) {
startService(getServiceIntent().setAction(ToyVpnService.ACTION_CONNECT));
}
}
private Intent getServiceIntent() {
return new Intent(this, ToyVpnService.class);
}
}
MyVpnConnection:
package com.example.android.toyvpn;
import static java.nio.charset.StandardCharsets.US_ASCII;
import android.app.PendingIntent;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.concurrent.TimeUnit;
public class ToyVpnConnection implements Runnable {
/**
* Callback interface to let the {#link ToyVpnService} know about new connections
* and update the foreground notification with connection status.
*/
public interface OnEstablishListener {
void onEstablish(ParcelFileDescriptor tunInterface);
}
/** Maximum packet size is constrained by the MTU, which is given as a signed short. */
private static final int MAX_PACKET_SIZE = Short.MAX_VALUE;
/** Time to wait in between losing the connection and retrying. */
private static final long RECONNECT_WAIT_MS = TimeUnit.SECONDS.toMillis(3);
/** Time between keepalives if there is no traffic at the moment.
*
* TODO: don't do this; it's much better to let the connection die and then reconnect when
* necessary instead of keeping the network hardware up for hours on end in between.
**/
private static final long KEEPALIVE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15);
/** Time to wait without receiving any response before assuming the server is gone. */
private static final long RECEIVE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(20);
/**
* Time between polling the VPN interface for new traffic, since it's non-blocking.
*
* TODO: really don't do this; a blocking read on another thread is much cleaner.
*/
private static final long IDLE_INTERVAL_MS = TimeUnit.MILLISECONDS.toMillis(100);
/**
* Number of periods of length {#IDLE_INTERVAL_MS} to wait before declaring the handshake a
* complete and abject failure.
*
* TODO: use a higher-level protocol; hand-rolling is a fun but pointless exercise.
*/
private static final int MAX_HANDSHAKE_ATTEMPTS = 50;
private final VpnService mService;
private final int mConnectionId;
private final String mServerName;
private final int mServerPort;
private final byte[] mSharedSecret;
private PendingIntent mConfigureIntent;
private OnEstablishListener mOnEstablishListener;
public ToyVpnConnection(final VpnService service, final int connectionId,
final String serverName, final int serverPort, final byte[] sharedSecret) {
mService = service;
mConnectionId = connectionId;
mServerName = serverName;
mServerPort= serverPort;
mSharedSecret = sharedSecret;
}
/**
* Optionally, set an intent to configure the VPN. This is {#code null} by default.
*/
public void setConfigureIntent(PendingIntent intent) {
mConfigureIntent = intent;
}
public void setOnEstablishListener(OnEstablishListener listener) {
mOnEstablishListener = listener;
}
#Override
public void run() {
try {
Log.i(getTag(), "Starting");
// If anything needs to be obtained using the network, get it now.
// This greatly reduces the complexity of seamless handover, which
// tries to recreate the tunnel without shutting down everything.
// In this demo, all we need to know is the server address.
final SocketAddress serverAddress = new InetSocketAddress(mServerName, mServerPort);
// We try to create the tunnel several times.
// TODO: The better way is to work with ConnectivityManager, trying only when the
// network is available.
// Here we just use a counter to keep things simple.
for (int attempt = 0; attempt < 10; ++attempt) {
// Reset the counter if we were connected.
if (run(serverAddress)) {
attempt = 0;
}
// Sleep for a while. This also checks if we got interrupted.
Thread.sleep(3000);
}
Log.i(getTag(), "Giving up");
} catch (IOException | InterruptedException | IllegalArgumentException e) {
Log.e(getTag(), "Connection failed, exiting", e);
}
}
private boolean run(SocketAddress server)
throws IOException, InterruptedException, IllegalArgumentException {
ParcelFileDescriptor iface = null;
boolean connected = false;
// Create a DatagramChannel as the VPN tunnel.
try (DatagramChannel tunnel = DatagramChannel.open()) {
// Protect the tunnel before connecting to avoid loopback.
if (!mService.protect(tunnel.socket())) {
throw new IllegalStateException("Cannot protect the tunnel");
}
// Connect to the server.
tunnel.connect(server);
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(false);
// Authenticate and configure the virtual network interface.
iface = handshake(tunnel);
// Now we are connected. Set the flag.
connected = true;
// Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(iface.getFileDescriptor());
// Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(iface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET_SIZE);
// Timeouts:
// - when data has not been sent in a while, send empty keepalive messages.
// - when data has not been received in a while, assume the connection is broken.
long lastSendTime = System.currentTimeMillis();
long lastReceiveTime = System.currentTimeMillis();
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
lastReceiveTime = System.currentTimeMillis();
}
// Read the incoming packet from the tunnel.
length = tunnel.read(packet);
if (length > 0) {
// Ignore control messages, which start with zero.
if (packet.get(0) != 0) {
// Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
}
packet.clear();
// There might be more incoming packets.
idle = false;
lastSendTime = System.currentTimeMillis();
}
// If we are idle or waiting for the network, sleep for a
// fraction of time to avoid busy looping.
if (idle) {
Thread.sleep(IDLE_INTERVAL_MS);
final long timeNow = System.currentTimeMillis();
if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
// We are receiving for a long time but not sending.
// Send empty control messages.
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
lastSendTime = timeNow;
} else if (lastReceiveTime + RECEIVE_TIMEOUT_MS <= timeNow) {
// We are sending for a long time but not receiving.
throw new IllegalStateException("Timed out");
}
}
}
} catch (SocketException e) {
Log.e(getTag(), "Cannot use socket", e);
} finally {
if (iface != null) {
try {
iface.close();
} catch (IOException e) {
Log.e(getTag(), "Unable to close interface", e);
}
}
}
return connected;
}
private ParcelFileDescriptor handshake(DatagramChannel tunnel)
throws IOException, InterruptedException {
// To build a secured tunnel, we should perform mutual authentication
// and exchange session keys for encryption. To keep things simple in
// this demo, we just send the shared secret in plaintext and wait
// for the server to send the parameters.
// Allocate the buffer for handshaking. We have a hardcoded maximum
// handshake size of 1024 bytes, which should be enough for demo
// purposes.
ByteBuffer packet = ByteBuffer.allocate(1024);
// Control messages always start with zero.
packet.put((byte) 0).put(mSharedSecret).flip();
// Send the secret several times in case of packet loss.
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
// Wait for the parameters within a limited time.
for (int i = 0; i < MAX_HANDSHAKE_ATTEMPTS; ++i) {
Thread.sleep(IDLE_INTERVAL_MS);
// Normally we should not receive random packets. Check that the first
// byte is 0 as expected.
int length = tunnel.read(packet);
if (length > 0 && packet.get(0) == 0) {
return configure(new String(packet.array(), 1, length - 1, US_ASCII).trim());
}
}
throw new IOException("Timed out");
}
private ParcelFileDescriptor configure(String parameters) throws IllegalArgumentException {
// Configure a builder while parsing the parameters.
VpnService.Builder builder = mService.new Builder();
for (String parameter : parameters.split(" ")) {
String[] fields = parameter.split(",");
try {
switch (fields[0].charAt(0)) {
case 'm':
builder.setMtu(Short.parseShort(fields[1]));
break;
case 'a':
builder.addAddress(fields[1], Integer.parseInt(fields[2]));
break;
case 'r':
builder.addRoute(fields[1], Integer.parseInt(fields[2]));
break;
case 'd':
builder.addDnsServer(fields[1]);
break;
case 's':
builder.addSearchDomain(fields[1]);
break;
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Bad parameter: " + parameter);
}
}
// Create a new interface using the builder and save the parameters.
final ParcelFileDescriptor vpnInterface;
synchronized (mService) {
vpnInterface = builder
.setSession(mServerName)
.setConfigureIntent(mConfigureIntent)
.establish();
if (mOnEstablishListener != null) {
mOnEstablishListener.onEstablish(vpnInterface);
}
}
Log.i(getTag(), "New interface: " + vpnInterface + " (" + parameters + ")");
return vpnInterface;
}
private final String getTag() {
return ToyVpnConnection.class.getSimpleName() + "[" + mConnectionId + "]";
}
}
MyVpnService:
package com.example.android.toyvpn;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.util.Pair;
import android.widget.Toast;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
public class ToyVpnService extends VpnService implements Handler.Callback {
private static final String TAG = ToyVpnService.class.getSimpleName();
public static final String ACTION_CONNECT = "com.example.android.toyvpn.START";
public static final String ACTION_DISCONNECT = "com.example.android.toyvpn.STOP";
private Handler mHandler;
private static class Connection extends Pair<Thread, ParcelFileDescriptor> {
public Connection(Thread thread, ParcelFileDescriptor pfd) {
super(thread, pfd);
}
}
private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
private final AtomicReference<Connection> mConnection = new AtomicReference<>();
private AtomicInteger mNextConnectionId = new AtomicInteger(1);
private PendingIntent mConfigureIntent;
#Override
public void onCreate() {
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Create the intent to "configure" the connection (just start ToyVpnClient).
mConfigureIntent = PendingIntent.getActivity(this, 0, new Intent(this, ToyVpnClient.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && ACTION_DISCONNECT.equals(intent.getAction())) {
disconnect();
return START_NOT_STICKY;
} else {
connect();
return START_STICKY;
}
}
#Override
public void onDestroy() {
disconnect();
}
#Override
public boolean handleMessage(Message message) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
if (message.what != R.string.disconnected) {
updateForegroundNotification(message.what);
}
return true;
}
private void connect() {
// Become a foreground service. Background services can be VPN services too, but they can
// be killed by background check before getting a chance to receive onRevoke().
updateForegroundNotification(R.string.connecting);
mHandler.sendEmptyMessage(R.string.connecting);
// Extract information from the shared preferences.
final SharedPreferences prefs = getSharedPreferences(ToyVpnClient.Prefs.NAME, MODE_PRIVATE);
final String server = prefs.getString(ToyVpnClient.Prefs.SERVER_ADDRESS, "");
final byte[] secret = prefs.getString(ToyVpnClient.Prefs.SHARED_SECRET, "").getBytes();
final int port;
try {
port = Integer.parseInt(prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, ""));
} catch (NumberFormatException e) {
Log.e(TAG, "Bad port: " + prefs.getString(ToyVpnClient.Prefs.SERVER_PORT, null), e);
return;
}
// Kick off a connection.
startConnection(new ToyVpnConnection(
this, mNextConnectionId.getAndIncrement(), server, port, secret));
}
private void startConnection(final ToyVpnConnection connection) {
// Replace any existing connecting thread with the new one.
final Thread thread = new Thread(connection, "ToyVpnThread");
setConnectingThread(thread);
// Handler to mark as connected once onEstablish is called.
connection.setConfigureIntent(mConfigureIntent);
connection.setOnEstablishListener(new ToyVpnConnection.OnEstablishListener() {
public void onEstablish(ParcelFileDescriptor tunInterface) {
mHandler.sendEmptyMessage(R.string.connected);
mConnectingThread.compareAndSet(thread, null);
setConnection(new Connection(thread, tunInterface));
}
});
thread.start();
}
private void setConnectingThread(final Thread thread) {
final Thread oldThread = mConnectingThread.getAndSet(thread);
if (oldThread != null) {
oldThread.interrupt();
}
}
private void setConnection(final Connection connection) {
final Connection oldConnection = mConnection.getAndSet(connection);
if (oldConnection != null) {
try {
oldConnection.first.interrupt();
oldConnection.second.close();
} catch (IOException e) {
Log.e(TAG, "Closing VPN interface", e);
}
}
}
private void disconnect() {
mHandler.sendEmptyMessage(R.string.disconnected);
setConnectingThread(null);
setConnection(null);
stopForeground(true);
}
private void updateForegroundNotification(final int message) {
startForeground(1, new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_vpn)
.setContentText(getString(message))
.setContentIntent(mConfigureIntent)
.build());
}
}
The above code is from the following url:
https://android.googlesource.com/platform/development/+/master/samples/ToyVpn
I have tried but I am not getting any workaround without secret key. Please help.
Unfortunately, we don't have any further requirements / spec of your VPN server.
You might want to have a look at the OpenVPN or strongSwan VPN (open source) implementations to see if they can fit your requirements. The latter for example provides the following ways of authentication on Android (https://wiki.strongswan.org/projects/strongswan/wiki/androidvpnclient):
Only IKEv2 is supported
Client authentication is limited to:
EAP authentication based on username/password (EAP-MSCHAPv2, EAP-MD5, EAP-GTC)
RSA/ECDSA authentication with private key/certificate
EAP-TLS with private key/certificate (see 1.4.5 for limitations)

Creating a vpn profile and connencting (PPTP) with username and password in android programmatically

I want to build an app that can connect with a single click of button which will create a vpn profile and connect to the vpn profile by parsig the username and password of the vpn server.
The code that is developed and modified is good to create and connect vpn but my vpn requires username and password to be entered so i want to do that programatically.
Here is my project
VpnClient.java
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class VpnClient extends AppCompatActivity{
public interface Prefs {
String NAME = "connection";
String SERVER_ADDRESS = "server.address";
String SERVER_PORT = "server.port";
String SHARED_SECRET = "shared.secret";
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button disconnect = (Button) findViewById(R.id.disconnect);
Button connect = (Button) findViewById(R.id.connect);
// final TextView serverAddress = (TextView) findViewById(R.id.address);
//final TextView serverPort = (TextView) findViewById(R.id.port);
// final TextView sharedSecret = (TextView) findViewById(R.id.secret);
final SharedPreferences prefs = getSharedPreferences(Prefs.NAME, MODE_PRIVATE);
final String serverAddress = ""; !!I insert my vpnserver address in here which is my.vpnserver.com
final String serverPort = ""; !!As server port i am using 1723 for PPTP connection
connect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
prefs.edit()
.putString(Prefs.SERVER_ADDRESS,"")
.putString(Prefs.SERVER_PORT, "")
.putString(Prefs.SHARED_SECRET, "")
.commit();
Intent intent = VpnService.prepare(VpnClient.this);
if (intent != null) {
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
}
});
disconnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startService(getServiceIntent().setAction(MyVpnService.ACTION_DISCONNECT));
}
});
}
#Override
protected void onActivityResult(int request, int result, Intent data) {
if (result == RESULT_OK) {
startService(getServiceIntent().setAction(MyVpnService.ACTION_CONNECT));
}
}
private Intent getServiceIntent() {
return new Intent(this, MyVpnService.class);
}
}
MyVpnService.java
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.support.annotation.RequiresApi;
import android.support.v4.util.Pair;
import android.util.Log;
import android.widget.Toast;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.LogRecord;
public class MyVpnService extends andenter code hereroid.net.VpnService implements android.os.Handler.Callback {
private static final String TAG = MyVpnService.class.getSimpleName();
public static final String ACTION_CONNECT = "com.yaksh.vpn.START";
public static final String ACTION_DISCONNECT = "com.yaksh.vpn.STOP";
private Handler mHandler;
private static class Connection extends Pair<Thread, ParcelFileDescriptor> {
public Connection(Thread thread, ParcelFileDescriptor pfd) {
super(thread, pfd);
}
}
private final AtomicReference<Thread> mConnectingThread = new AtomicReference<>();
private final AtomicReference<Connection> mConnection = new AtomicReference<>();
private AtomicInteger mNextConnectionId = new AtomicInteger(1);
private PendingIntent mConfigureIntent;
#Override
public void onCreate() {
// The handler is only used to show messages.
if (mHandler == null) {
mHandler = new Handler(this);
}
// Create the intent to "configure" the connection (just start ToyVpnClient).
mConfigureIntent = PendingIntent.getActivity(this, 0, new Intent(this, VpnClient.class),
PendingIntent.FLAG_UPDATE_CURRENT);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && ACTION_DISCONNECT.equals(intent.getAction())) {
disconnect();
return START_NOT_STICKY;
} else {
connect();
return START_STICKY;
}
}
#Override
public void onDestroy() {
disconnect();
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public boolean handleMessage(Message message) {
Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
if (message.what != R.string.disconnected) {
updateForegroundNotification(message.what);
}
return true;
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void connect() {
// Become a foreground service. Background services can be VPN services too, but they can
// be killed by background check before getting a chance to receive onRevoke().
updateForegroundNotification(R.string.connecting);
mHandler.sendEmptyMessage(R.string.connecting);
// Extract information from the shared preferences.
final SharedPreferences prefs = getSharedPreferences(VpnClient.Prefs.NAME, MODE_PRIVATE);
final String server = prefs.getString(VpnClient.Prefs.SERVER_ADDRESS, "");
final byte[] secret = prefs.getString(VpnClient.Prefs.SHARED_SECRET, "").getBytes();
final int port;
try {
port = Integer.parseInt(prefs.getString(VpnClient.Prefs.SERVER_PORT, ""));
} catch (NumberFormatException e) {
Log.e(TAG, "Bad port: " + prefs.getString(VpnClient.Prefs.SERVER_PORT, null), e);
return;
}
// Kick off a connection.
startConnection(new VpnConnection(
this, mNextConnectionId.getAndIncrement(), server, port, secret));
}
private void startConnection(final VpnConnection connection) {
// Replace any existing connecting thread with the new one.
final Thread thread = new Thread(connection, "ToyVpnThread");
setConnectingThread(thread);
// Handler to mark as connected once onEstablish is called.
connection.setConfigureIntent(mConfigureIntent);
connection.setOnEstablishListener(new VpnConnection.OnEstablishListener() {
public void onEstablish(ParcelFileDescriptor tunInterface) {
mHandler.sendEmptyMessage(R.string.connected);
mConnectingThread.compareAndSet(thread, null);
setConnection(new Connection(thread, tunInterface));
}
});
thread.start();
}
private void setConnectingThread(final Thread thread) {
final Thread oldThread = mConnectingThread.getAndSet(thread);
if (oldThread != null) {
oldThread.interrupt();
}
}
private void setConnection(final Connection connection) {
final Connection oldConnection = mConnection.getAndSet(connection);
if (oldConnection != null) {
try {
oldConnection.first.interrupt();
oldConnection.second.close();
} catch (IOException e) {
Log.e(TAG, "Closing VPN interface", e);
}
}
}
private void disconnect() {
mHandler.sendEmptyMessage(R.string.disconnected);
setConnectingThread(null);
setConnection(null);
stopForeground(true);
}
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
private void updateForegroundNotification(final int message) {
startForeground(1, new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_vpn)
.setContentText(getString(message))
.setContentIntent(mConfigureIntent)
.build());
}
}
VpnConnection.java
import android.app.PendingIntent;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.support.annotation.RequiresApi;
import android.util.Log;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.concurrent.TimeUnit;
/**
* Created by Yaksh on 11/3/2017.
*/
public class VpnConnection implements Runnable{
/**
* Callback interface to let the {#link MyVpnService} know about new connections
* and update the foreground notification with connection status.
*/
public interface OnEstablishListener {
void onEstablish(ParcelFileDescriptor tunInterface);
}
/** Maximum packet size is constrained by the MTU, which is given as a signed short. */
private static final int MAX_PACKET_SIZE = Short.MAX_VALUE;
/** Time to wait in between losing the connection and retrying. */
private static final long RECONNECT_WAIT_MS = TimeUnit.SECONDS.toMillis(3);
/** Time between keepalives if there is no traffic at the moment.
*
* TODO: don't do this; it's much better to let the connection die and then reconnect when
* necessary instead of keeping the network hardware up for hours on end in between.
**/
private static final long KEEPALIVE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(15);
/** Time to wait without receiving any response before assuming the server is gone. */
private static final long RECEIVE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(20);
/**
* Time between polling the VPN interface for new traffic, since it's non-blocking.
*
* TODO: really don't do this; a blocking read on another thread is much cleaner.
*/
private static final long IDLE_INTERVAL_MS = TimeUnit.MILLISECONDS.toMillis(100);
/**
* Number of periods of length {#IDLE_INTERVAL_MS} to wait before declaring the handshake a
* complete and abject failure.
*
* TODO: use a higher-level protocol; hand-rolling is a fun but pointless exercise.
*/
private static final int MAX_HANDSHAKE_ATTEMPTS = 50;
private final MyVpnService mService;
private final int mConnectionId;
private final String mServerName;
private final int mServerPort;
private final byte[] mSharedSecret;
private PendingIntent mConfigureIntent;
private OnEstablishListener mOnEstablishListener;
public VpnConnection(final MyVpnService service, final int connectionId,
final String serverName, final int serverPort, final byte[] sharedSecret) {
mService = service;
mConnectionId = connectionId;
mServerName = serverName;
mServerPort= serverPort;
mSharedSecret = sharedSecret;
}
/**
* Optionally, set an intent to configure the VPN. This is {#code null} by default.
*/
public void setConfigureIntent(PendingIntent intent) {
mConfigureIntent = intent;
}
public void setOnEstablishListener(OnEstablishListener listener) {
mOnEstablishListener = listener;
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
#Override
public void run() {
try {
Log.i(getTag(), "Starting");
// If anything needs to be obtained using the network, get it now.
// This greatly reduces the complexity of seamless handover, which
// tries to recreate the tunnel without shutting down everything.
// In this demo, all we need to know is the server address.
final SocketAddress serverAddress = new InetSocketAddress(mServerName, mServerPort);
// We try to create the tunnel several times.
// network is available.
// Here we just use a counter to keep things simple.
for (int attempt = 0; attempt < 10; ++attempt) {
// Reset the counter if we were connected.
if (run(serverAddress)) {
attempt = 0;
}
// Sleep for a while. This also checks if we got interrupted.
Thread.sleep(3000);
}
Log.i(getTag(), "Giving up");
} catch (IOException | InterruptedException | IllegalArgumentException e) {
Log.e(getTag(), "Connection failed, exiting", e);
}
}
#RequiresApi(api = Build.VERSION_CODES.KITKAT)
private boolean run(SocketAddress server)
throws IOException, InterruptedException, IllegalArgumentException {
ParcelFileDescriptor iface = null;
boolean connected = false;
// Create a DatagramChannel as the VPN tunnel.
try (DatagramChannel tunnel = DatagramChannel.open()) {
// Protect the tunnel before connecting to avoid loopback.
if (!mService.protect(tunnel.socket())) {
throw new IllegalStateException("Cannot protect the tunnel");
}
// Connect to the server.
tunnel.connect(server);
// For simplicity, we use the same thread for both reading and
// writing. Here we put the tunnel into non-blocking mode.
tunnel.configureBlocking(false);
// Authenticate and configure the virtual network interface.
iface = handshake(tunnel);
// Now we are connected. Set the flag.
connected = true;
// Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(iface.getFileDescriptor());
// Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(iface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(MAX_PACKET_SIZE);
// Timeouts:
// - when data has not been sent in a while, send empty keepalive messages.
// - when data has not been received in a while, assume the connection is broken.
long lastSendTime = System.currentTimeMillis();
long lastReceiveTime = System.currentTimeMillis();
// We keep forwarding packets till something goes wrong.
while (true) {
// Assume that we did not make any progress in this iteration.
boolean idle = true;
// Read the outgoing packet from the input stream.
int length = in.read(packet.array());
if (length > 0) {
// Write the outgoing packet to the tunnel.
packet.limit(length);
tunnel.write(packet);
packet.clear();
// There might be more outgoing packets.
idle = false;
lastReceiveTime = System.currentTimeMillis();
}
// Read the incoming packet from the tunnel.
length = tunnel.read(packet);
if (length > 0) {
// Ignore control messages, which start with zero.
if (packet.get(0) != 0) {
// Write the incoming packet to the output stream.
out.write(packet.array(), 0, length);
}
packet.clear();
// There might be more incoming packets.
idle = false;
lastSendTime = System.currentTimeMillis();
}
// If we are idle or waiting for the network, sleep for a
// fraction of time to avoid busy looping.
if (idle) {
Thread.sleep(IDLE_INTERVAL_MS);
final long timeNow = System.currentTimeMillis();
if (lastSendTime + KEEPALIVE_INTERVAL_MS <= timeNow) {
// We are receiving for a long time but not sending.
// Send empty control messages.
packet.put((byte) 0).limit(1);
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
lastSendTime = timeNow;
} else if (lastReceiveTime + RECEIVE_TIMEOUT_MS <= timeNow) {
// We are sending for a long time but not receiving.
throw new IllegalStateException("Timed out");
}
}
}
} catch (SocketException e) {
Log.e(getTag(), "Cannot use socket", e);
} finally {
if (iface != null) {
try {
iface.close();
} catch (IOException e) {
Log.e(getTag(), "Unable to close interface", e);
}
}
}
return connected;
}
private ParcelFileDescriptor handshake(DatagramChannel tunnel)
throws IOException, InterruptedException {
// To build a secured tunnel, we should perform mutual authentication
// and exchange session keys for encryption. To keep things simple in
// this demo, we just send the shared secret in plaintext and wait
// for the server to send the parameters.
// Allocate the buffer for handshaking. We have a hardcoded maximum
// handshake size of 1024 bytes, which should be enough for demo
// purposes.
ByteBuffer packet = ByteBuffer.allocate(1024);
// Control messages always start with zero.
packet.put((byte) 0).put(mSharedSecret).flip();
// Send the secret several times in case of packet loss.
for (int i = 0; i < 3; ++i) {
packet.position(0);
tunnel.write(packet);
}
packet.clear();
// Wait for the parameters within a limited time.
for (int i = 0; i < MAX_HANDSHAKE_ATTEMPTS; ++i) {
Thread.sleep(IDLE_INTERVAL_MS);
// Normally we should not receive random packets. Check that the first
// byte is 0 as expected.
int length = tunnel.read(packet);
if (length > 0 && packet.get(0) == 0) {
return configure(new String(packet.array(), 1, length - 1).trim());
}
}
throw new IOException("Timed out");
}
private ParcelFileDescriptor configure(String parameters) throws IllegalArgumentException {
// Configure a builder while parsing the parameters.
MyVpnService.Builder builder = mService.new Builder();
for (String parameter : parameters.split(" ")) {
String[] fields = parameter.split(",");
try {
switch (fields[0].charAt(0)) {
case 'm':
builder.setMtu(Short.parseShort(fields[1]));
break;
case 'a':
builder.addAddress(fields[1], Integer.parseInt(fields[2]));
break;
case 'r':
builder.addRoute(fields[1], Integer.parseInt(fields[2]));
break;
case 'd':
builder.addDnsServer(fields[1]);
break;
case 's':
builder.addSearchDomain(fields[1]);
break;
}
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Bad parameter: " + parameter);
}
}
// Create a new interface using the builder and save the parameters.
final ParcelFileDescriptor vpnInterface;
synchronized (mService) {
vpnInterface = builder
.setSession(mServerName)
.setConfigureIntent(mConfigureIntent)
.establish();
if (mOnEstablishListener != null) {
mOnEstablishListener.onEstablish(vpnInterface);
}
}
Log.i(getTag(), "New interface: " + vpnInterface + " (" + parameters + ")");
return vpnInterface;
}
private final String getTag() {
return VpnConnection.class.getSimpleName() + "[" + mConnectionId + "]";
}
}

Chromcast Remoteplayer seek to resume at seek 0 position when using nanohttpd

Chromcast Remote player seek to resume at seek position 0 when using nanohttpd server. Main issue getting when I seek into video player in device its working fine but on TV seek-bar set at 0 position and music stat at beginning.
When to call mRemoteMediaPlayer.seek() in onSeekChanged() getting result success but on TV seek-bar set at 0 position and music stat at beginning.
public class webserver extends NanoHTTPD {
FileInputStream fileInputStream;
public webserver(){
super(8080);
}
#Override
public Response serve(String uri, Method method, Map<String, String> header,Map<String, String> parameters, Map<String, String> files) {
String mediasend=" ";
long size=0;
FileInputStream fis = null;
try {
fis = new FileInputStream(path);
//byte[] buffer = new byte[(int) fis.getChannel().size()];
size=fis.getChannel().size();
} catch (Exception e) {
e.printStackTrace();
}
switch(mediatype){
case "photo":
mediasend="image/jpeg";
break;
case "audio":
mediasend="audio/mp3";
break;
case "video":
mediasend="video/mp4";
break;
}
return new NanoHTTPD.Response(com.castoffline.castActivity.NanoHTTPD.Response.Status.OK,mediasend,fis,size);
}
}
Cast connection code
Cast.CastApi.launchApplication(mApiClient,getString(R.string.app_id),false).setResultCallback(new ResultCallback<Cast.ApplicationConnectionResult>() {
#Override
public void onResult(ApplicationConnectionResult result) {
Status status = result.getStatus();
if (status.isSuccess()) {
ApplicationMetadata applicationMetadata = result.getApplicationMetadata();
mSessionId = result.getSessionId();
String applicationStatus = result.getApplicationStatus();
boolean wasLaunched = result.getWasLaunched();
Log.d(TAG,"application name: "+ applicationMetadata.getName()+ ", status: "+ applicationStatus+ ", sessionId: "+ mSessionId+ ", wasLaunched: "+ wasLaunched);
mApplicationStarted = true;
mRemoteMediaPlayer = new RemoteMediaPlayer();
/*
* Identify the mediatype and send the metadata details to media info
*/
switch(mediatype)
{
case "audio" : mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MUSIC_TRACK);
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "MY MUSIC TRACK"+": "+audioTitle);
mediaMetadata.putString(MediaMetadata.KEY_ARTIST,audioArtist);
mediaMetadata.addImage(new WebImage(Uri.parse("https://www.googledrive.com/host/0B61ekPEN_94sZ21mcnQtbVU2RHM/media.png")));
mediaInfo = new MediaInfo.Builder(ipdevice).setContentType(mimetype).setStreamType(MediaInfo.STREAM_TYPE_BUFFERED).setMetadata(mediaMetadata).build();
break;
case "video" : mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
mediaMetadata.addImage(new WebImage(Uri.parse("https://www.googledrive.com/host/0B61ekPEN_94sZ21mcnQtbVU2RHM/film_reel.png")));
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "My MOVIE"+": "+videoTitle);
mediaInfo = new MediaInfo.Builder(ipdevice).setContentType(mimetype).setStreamType(MediaInfo.STREAM_TYPE_BUFFERED).setMetadata(mediaMetadata).build();
break;
case "photo" : mediaMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO);
mediaMetadata.putString(MediaMetadata.KEY_TITLE, "My PHOTO"+": ");
mediaInfo = new MediaInfo.Builder(ipdevice).setContentType(mimetype).setStreamType(MediaInfo.STREAM_TYPE_BUFFERED).setMetadata(mediaMetadata).build();
break;
default:
}
try {
Cast.CastApi.setMessageReceivedCallbacks(mApiClient,mRemoteMediaPlayer.getNamespace(), mRemoteMediaPlayer);
} catch (IOException e) {
Log.d(TAG, "Exception while creating media channel", e);
}
try {
mRemoteMediaPlayer.load(mApiClient, mediaInfo, false,0).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
Log.d(TAG, "Media loaded successfully");
}
}});
/*
* checks if the video is playing or if it is paused and according it will be played/paused in the receiver
*/
videoview.setPlayPauseListener(new CustomVideoView.PlayPauseListener() {
AudioManager amanager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
#Override
public void onPlay() {
playbackPaused=false; //videoView is playing
if(mSelectedDevice!=null && mApiClient != null && mRemoteMediaPlayer != null){
//volume is set to mute if media is casting in Chromecast
amanager.setStreamMute(AudioManager.STREAM_MUSIC, true);
sendMediaControl(playbackPaused,false);
}else{
amanager.setStreamVolume(AudioManager.STREAM_MUSIC, 3,1);
}
}
#Override
public void onPause(){
playbackPaused=true; //videoView is paused
if (mSelectedDevice != null && mApiClient != null && mRemoteMediaPlayer != null){
amanager.setStreamMute(AudioManager.STREAM_MUSIC, false);
sendMediaControl(playbackPaused,false);
}else{
amanager.setStreamVolume(AudioManager.STREAM_MUSIC, 3,1); }
}
/* Currently Seek function is not working for the media playback while casting
* (non-Javadoc)
* #see com.castoffline.castActivity.CustomVideoView.PlayPauseListener#onSeekChanged(int)
*/
#Override
public void onSeekChanged(int pos){
Log.d(String.valueOf(videoview.getCurrentPosition()),"seekinsie");
// seek(videoview.getCurrentPosition());
Log.d("mimetype ",mimetype);
Log.d("seek1",""+pos);
if (mSelectedDevice != null && mApiClient != null && mRemoteMediaPlayer != null){
videoview.pause();
final long position=videoview.getCurrentPosition();
Log.d("seek",""+position);
mRemoteMediaPlayer.seek(mApiClient,position,RemoteMediaPlayer.RESUME_STATE_UNCHANGED).setResultCallback(new ResultCallback<RemoteMediaPlayer.MediaChannelResult>(){
#Override
public void onResult(MediaChannelResult result) {
if (result.getStatus().isSuccess()) {
Log.d(String.valueOf("State Code "+result.getStatus().getStatusCode()),""+mRemoteMediaPlayer.getApproximateStreamPosition());
}
}
});
mRemoteMediaPlayer.setOnStatusUpdatedListener(new RemoteMediaPlayer.OnStatusUpdatedListener(){
#Override
public void onStatusUpdated() {
#SuppressWarnings("unused")
MediaStatus mediaStatus = mRemoteMediaPlayer.getMediaStatus();
Log.d("seek state update",""+mediaStatus);
}
});
}
}
});
} catch (IllegalStateException e) {
Log.d(TAG, "Problem occurred with media during loading", e);
} catch (Exception e) {
Log.d(TAG, "Problem opening media during loading", e);}
} else {
Log.e(TAG,"application could not launch");
teardown();
}
}
});
}
Remote player control code.
private void sendMediaControl(final boolean playbackPaused,final boolean change)
{
if (mApiClient != null && mRemoteMediaPlayer != null){
mRemoteMediaPlayer.requestStatus(mApiClient).setResultCallback( new ResultCallback<RemoteMediaPlayer.MediaChannelResult>() {
#Override
public void onResult(RemoteMediaPlayer.MediaChannelResult mediaChannelResult) {
if(playbackPaused ==true){
mRemoteMediaPlayer.pause(mApiClient);
}else{
mRemoteMediaPlayer.play(mApiClient);
}
}
});
}
}
There can be two things here:
I don't know if it is a limitation of nanohttpd or a configuration issue but what you are seeing is because the nanaohttpd (at least the way you have configured it) doesn't support seek. When you do a seek, your receiver will call into your http server (nanohttpd in this case) and passes a position and asks the web server to seek to that position and start streaming from there. If the web server doesn't support that, you will not be able to seek successfully. As a test, set up an apache server on your laptop, just for testing, and point to that instead of your embedded web server and see if that works or not.
There might be a mismatch between units of position; so if, say, your local player is using seconds and is reporting, say, 60 when it is a minute into the content and if you send that to the cast receiver, it will be interpreted as 60 milliseconds which is practically same as 0 seconds, so check on that too.

Speech recognizer by WCF service with Xamarin Android app client

I would like to write WCF Serwis where I use Microsotf.Speech.Recognition library to make speech to text service. Here is my Service code:
public class Rozpoznawacz : IRozpoznawacz
{
public void AudioToText(Stream audioStr)
{
SpeechRecognitionEngine _sre = new SpeechRecognitionEngine(new System.Globalization.CultureInfo("pl-PL"));
// Create a simple grammar that recognizes the words
Choices words = new Choices();
// Add the words to be recognised
words.Add("red");
words.Add("green");
words.Add("blue");
words.Add("yellow");
words.Add("orange");
words.Add("Dzień dobry");
words.Add("Chrząszcz");
words.Add("Brzmi");
words.Add("w");
words.Add("trzcinie");
words.Add("Wystaw fakturę");
words.Add("Stefan Burczymucha");
GrammarBuilder gb = new GrammarBuilder();
gb.Culture = new System.Globalization.CultureInfo("pl-PL");
gb.Append(words);
// Create the actual Grammar instance, and then load it into the speech recognizer.
Grammar g = new Grammar(gb);
_sre.LoadGrammar(g);
// Register a handler for the SpeechRecognized event.
_sre.SpeechRecognized +=
new EventHandler<SpeechRecognizedEventArgs>(sre_SpeechRecognized);
//_sre.SetInputToDefaultAudioDevice();
_sre.SetInputToWaveStream(audioStr);
_sre.RecognizeAsync(RecognizeMode.Multiple);
}
void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
string rozpoznanie = "";
rozpoznanie += e.Result.Text;
using (StreamWriter outfile = new StreamWriter(#"C:\Test.txt"))
{
outfile.Write(rozpoznanie);
}
}
public string Test(string query)
{
return string.Format("Przyjęto: {0}", query);
}
}
Next, I tried to write Android App with service references, I tried to record voice and send to webService host, but I don't know how I should send audio file. Here is my not working code in android app:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using Android.Media;
using System.IO;
namespace RozpoznawanieMowyZdalne.Adroid
{
[Activity(Label = "RozpoznawanieMowyZdalne.Adroid", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
MediaRecorder recorder;
MediaPlayer player;
Button btnStart;
Button btnStop;
string path = "/sdcard/test.3gpp";
private RozpoznawaczService.Rozpoznawacz client;
private TextView aLabel;
byte[] audioByte;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
btnStart = FindViewById<Button>(Resource.Id.btnStart);
btnStop = FindViewById<Button>(Resource.Id.btnStop);
btnStart.Click += delegate
{
client.TestAsync("Android");
btnStop.Enabled = !btnStop.Enabled;
btnStart.Enabled = !btnStart.Enabled;
recorder.SetAudioSource(AudioSource.VoiceRecognition);
recorder.SetOutputFormat(OutputFormat.ThreeGpp);
recorder.SetAudioEncoder(AudioEncoder.AmrNb);
recorder.SetOutputFile(path);
recorder.Prepare();
recorder.Start();
Toast.MakeText(this, "Rozpoczęto nagrywanie", ToastLength.Long).Show();
};
btnStop.Click += delegate
{
btnStop.Enabled = !btnStop.Enabled;
recorder.Stop();
Toast.MakeText(this, "Zakończono nagrywanie", ToastLength.Long).Show();
recorder.Reset();
player.SetDataSource(path);
player.Prepare();
player.Start();
File.WriteAllBytes(path, audioByte);
client.AudioToTextAsync(audioByte);
};
InitializeServiceClient();
}
protected override void OnResume()
{
base.OnResume();
recorder = new MediaRecorder();
player = new MediaPlayer();
player.Completion += (sender, e) =>
{
player.Reset();
btnStart.Enabled = !btnStart.Enabled;
};
}
protected override void OnPause()
{
base.OnPause();
player.Release();
recorder.Release();
player.Dispose();
recorder.Dispose();
player = null;
recorder = null;
}
private void InitializeServiceClient()
{
client = new RozpoznawaczService.Rozpoznawacz();
client.TestCompleted += client_TestCompleted;
client.AudioToTextCompleted += client_AudioToTextCompleted;
aLabel = FindViewById<TextView>(Resource.Id.textViewTest);
}
void client_AudioToTextCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
string msg = null;
if (e.Error != null)
{
msg = e.Error.Message;
}
else if (e.Cancelled)
{
msg = "Request was cancelled.";
}
else
{
//msg = e.Result;
}
RunOnUiThread(() => aLabel.Text = "Wyslane");
}
void client_TestCompleted(object sender, RozpoznawaczService.TestCompletedEventArgs e)
{
string msg = null;
if (e.Error != null)
{
msg = e.Error.Message;
}
else if (e.Cancelled)
{
msg = "Request was cancelled.";
}
else
{
msg = e.Result;
}
RunOnUiThread(() => aLabel.Text = msg);
}
}
}
How can I send my audio file to my webService?
PS. File.WriteAllBytes(path, audioByte); - it doesn't work in Android app...

Categories

Resources