07-02-2009 08:26 AM
This is a continuance of a Thread by bmagown under 'BlackBerry 8300 Series Smartphone - BlackBerry Curve' forum section That can be found on:
Solved! Go to Solution.
12-09-2008 09:59 AM
02-18-2009 03:52 PM - last edited on 02-18-2009 04:14 PM
Same problem here. Here is my attempt at demonstrating this and also logging all "playerUpdate" data.
The program records into a byte-array and then plays it successfully.
When trying to record and play and the same time things do not work. The log clearly shows the interference between the two playes.
Is this something that I should expect to work. Any interfaces I am missing to play and record audio in full-duplex?
Avner Aviad
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.media.PlayerListener;
import javax.microedition.media.control.RecordControl;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.RichTextField;
import net.rim.device.api.ui.container.MainScreen;
public class RecordAndPlay extends UiApplication{
private byte[] _bytesRecorded = null;
private byte[] _bytesToPlay = null;
private MainMenuScreen _screen = null;
public static void main(String argv[])
{
new RecordAndPlay();
}
public RecordAndPlay()
{
try
{
pushScreen(_screen = new MainMenuScreen());
enterEventDispatcher();
} catch (IOException e)
{
_screen.reportException(e);
}
}
class AudioRecorder extends Thread implements PlayerListener
{
public void run()
{
try
{
Player playerR = Manager.createPlayer("capture://audio?encoding=aud
io/amr"); playerR.addPlayerListener(this);
playerR.realize();
RecordControl recordControl = (RecordControl) playerR.getControl("RecordControl");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
recordControl.setRecordStream(outputStream);
Manager.playTone(69, 500, 100);
Thread.sleep(500);
recordControl.startRecord();
playerR.start();
Thread.sleep(5000);
recordControl.commit();
_bytesRecorded = outputStream.toByteArray();
outputStream.close();
playerR.close();
synchronized (_screen)
{
_screen.notify();
}
} catch (Exception e)
{
_screen.reportException(e);
}
}
public void playerUpdate(Player player, final String event, Object eventData)
{
_screen.log("R-" + event + "[" + (eventData == null ? "" : eventData.toString()) + "]");
}
}
class AudioPlayer extends Thread implements PlayerListener
{
public void run()
{
try
{
_bytesToPlay = new byte[_bytesRecorded.length];
System.arraycopy(_bytesRecorded, 0, _bytesToPlay, 0, _bytesRecorded.length);
ByteArrayInputStream inputStream = new ByteArrayInputStream(_bytesToPlay);
Player playerP = Manager.createPlayer(inputStream, "audio/amr");
playerP.addPlayerListener(this);
playerP.realize();
playerP.prefetch();
playerP.start();
Thread.sleep(5000);
playerP.stop();
playerP.close();
synchronized (_screen)
{
_screen.notify();
}
} catch (Exception e)
{
_screen.reportException(e);
}
}
public void playerUpdate(Player player, String event, Object eventData)
{
_screen.log("P-" + event + "[" + (eventData == null ? "" : eventData.toString()) + "]");
}
}
class MainMenuScreen extends MainScreen
{
private ButtonField _buttonField = new ButtonField("Start");
private RichTextField _logField = new RichTextField();
private long _tStart;
public MainMenuScreen() throws IOException
{
super();
_tStart = System.currentTimeMillis();
add(_buttonField);
Font f = _logField.getFont();
_logField.setFont(f.derive(f.getStyle(), f.getHeight() * 3 / 5));
add(_logField);
}
public void log(final String sValue)
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
long t = System.currentTimeMillis() - _tStart;
_logField.insert("[" + ((t / 1000) + "." + t % 1000) + "] " + sValue + "\n");
}
});
}
protected boolean navigationClick(int status, int time)
{
Thread r = new Thread()
{
public void run()
{
try
{
synchronized (_screen)
{
log("Recording");
(new AudioRecorder()).start();
_screen.wait();
log("Playing");
(new AudioPlayer()).start();
_screen.wait();
log("Recording & Playing");
(new AudioRecorder()).start();
(new AudioPlayer()).start();
_screen.wait();
_screen.wait();
// log("Playing again");
// (new AudioPlayer()).start();
// _screen.wait();
}
} catch (Exception e)
{
reportException(e);
}
}
};
r.start();
return true;
}
void reportException(final Exception e)
{
UiApplication.getUiApplication().invokeAndWait(new Runnable()
{
public void run()
{
log("Exception " + e.getMessage());
Dialog.inform(e.toString());
}
});
}
}
}
07-02-2009 03:50 AM
Not a bug.
MMAPI just does not facilitate full duplex.
You cannot record and play at the same time ;(
I have used a similar approach as you have and it works in the simulator but not on the device. (On the device the recorder would capture data only when the player was not playing.)
I guess simulator 'enables' this because it just forwards the recording/playing request to the OS.
I have researched the subject and have found many reports people trying to do this but all have failed.
But I could never get to the bottom of this. I would like to know why, and exactly at what point does this break.
The MMAPI Manager can handle only one player at a time ? Not true since you can play more than one audio at a time.
So why is there a limit that we cannot record and play at the same time - where exactly is the catch?
Anyone has a technical explanation of this ?
07-02-2009 08:15 AM
07-02-2009 08:23 AM - last edited on 07-02-2009 08:27 AM
@drizzt09
You are absolutely right.
I missed the 'secton name' part of the thread
(found it through generic search)
Please continue the discussion on: Full duplex - developers section
07-03-2009 04:09 PM
08-14-2009 06:13 PM
Hi mark ,
could you please give model's name that support playback and recording simultaneously ?
08-17-2009 01:59 PM
10-09-2009 10:03 PM
I was able to get the code sample posted by aaviad to work -- but with a catch, it only seems to work when passing audio/amr as the codec.
If I use the exact same code snippet, but instead pass audio/basic as the codec (to both the player and recorder), the simultaneous record/playback part of the test fails. So it records OK, plays back OK, but then when it tries to playback while simultaneously recording, the playback does not work, and when it finally plays back the second recording nothing is heard either. Eg, the crucial part of the test fails.
I get this same behavior on both the 4.6 emulator and a GSM Blackberry Bold device running OS 4.6.
Has anyone reading this gotten simultaneous playback/record to work with the audio/basic (pcm) codec and willing to share their findings?