Are you bothering by the AMR problem in MMF? The MMF is really annoying for developers.
In SDK 0.9 or 1.2, you may use CAmrToPcmDecoder and CPcmToAmrEncoder to convert between PCM and AMR with ease. But in SDK 2.x, this feature is erased. SDK announces that a new MMF framework can do this instead now!!! But it seems all developers encounter big problem when handle AMR using MMF!!!! Maybe MMF is not designed for more clear interface but more complexity!
In fact, we can handle AMR using AMR codec library in MMF server directly. Like the following code:
// Uid of PCM16toAMR codec is 0x101FAF68
CMMFCodec* codec = CMMFCodec::NewL(TUid::Uid(0x101FAF68));
CMMFDescriptorBuffer* srcbuf = CMMFDescriptorBuffer::NewL(320);
// Copy your PCM frame data into srcbuf, for example: srcbuf->Data().Copy(pcmbuf);
CMMFDescriptorBuffer* dstbuf = CMMFDescriptorBuffer::NewL(32);
TCodecProcessResult result = codec->ProcessL(*srcbuf, *dstbuf):
// now the dstbuf contains an AMR frame data
If you want to convert AMR to PCM16, just change the UID to 0x101FAF67.
Notice: In SDK 2.1 and 2nd Edition, you may use CMMFPtrBuffer to reduce memory copy actions.
Notice: The codec works in synchronous manner, so don't use encode/decode large buffer in CActive::RunL().
BUT, I CAN'T SOLVE THE FOLLOWING PROBLEM!!!!!!!!!!!!!!!!!!!!!!
When convert PCM to AMR, the default mode is MR475 and I don't know how to change it!!!! CMMFCodec provides a function ConfigureL to configure codec-specific attributes, but no document provides the format the attribute string!!!! Can anybody help me to solve this problem?
I use probably the same way as you I stream into PCM16 and than I am converting into AMR in the way you use. Everything works super on emulator, but when doing the same on the device Nokina 6630 the sound quality and speed is not good. I think problem could be with sampling frequency, it should be between 8000Hz and 11025Hz, but in TMdaAudioDataSettings enumeration is not possibility to set it, so i use ESampleRateFixed.
I recored precisely 20 second long PCM16 file on emulator
the raw file was 320kB long which gives me approx. 16000 bytes per second => 8000 Hz sample rate for 16 bit bit rate.
I converted it into AMR file, which is approx. 12 kB in length, it gives me 600 bytes ber second => 4800 bits per second, so I could say that the AMR is type MR475( 4.75 kbps ). When I copy amr file to emulator and it could be nicely played by built-in player without any problem.
I started the same application on Nokia 6630 and I recorded also 20 second long clip. But now
PCM16 file is 198 000 bytes long
AMR file is 8053 bytes long
Why different sizes than on emulator, maybe device has another parameters or codecs used...
PCM is streamed with speed 9900 bytes per second, for 16 bit bitrate it gives me 5000 Hz????
for AMR it is 3.2 kbps - I dont know amr wit such parameters...
WHAT IS WRONG??? AM I DOING SOMETHING WRONG???
I don't try to record to file. Instead, I use a 320bytes buffer to save record data(PCM16). The buffer can contain exactly one frame(20ms)'s data. Each time the buffer is full, I get a notification from MMF and convert the PCM data to AMR at this time. After that, AMR data is saved to a file and PCM data is discarded.
My code works in both emulator and N6630 phone.
BTW. You may check the wav file you get directly, check how much speech data you get. Maybe less than 20secs, I think.
after few days of playing I found the sources of problems I have.
- CMMFCodec could use only 4.75 kbps AMR type
- data cout be streamed only with 16 bit bit rate and 8000Hz
- AMR storage format is specified in RFC3267. it is prepared to be RTP payload
- when CMMFCodec::ProcessL() is called with buffer size, which is not alligned on 320 bytes boundary it doesnt produce amr frame and data are thrown away - you LOST them
- if CMMFCodec::ProcessL() is called 2 times after with buffers of size less than 320 bytes it leaves with USER 23 error, doesnt matter how big prepared buffer is
- when MaiscBufferCopied() is called on emulator the data chunk is as big as the provided buffer up to 4096 bytes, so it could be divided into 12 buffers of 320bytes in size - 3840 bytes in size. The rest 256 bytes will be thrown away by CMMFCodec::ProcessL() method. You could of course prepend them to the next buffer, but from this moment you must prepend all buffers. But if you will dont do it created amr will be about 6% shorter!
- Thanks God the 6630 produces only 320 bytes long chunks of raw data, so there is no problem with loosing data
- BUT input streaming is EXTREMLY sensitive for resources, if for example you want to save pcm into file and convert it to amr the streaming could slow to send only few bytes of streamed data per second!!! So my advice is to run it with maximal priority, not using file server during streaming, streamig only into memory buffer.
- any external interruption MUST stop streaming!! or you will loose voice data, for example browsing file structure using file explorer slows the data stream from 16000 bytes per second to 9600 bytes => the resulting AMR is unusable!
- the only soulution I found is measuring time and data stream size and when it slows down streaming is STOPPED
can you please tell me if there is some documentation about:
I dont see anything about it, So i don't know what parameters to pass to it.
If not can you post some of the parameters that you know the
configureL functio,n for the amr->pcm codec, doess indeed take?
Also if you have any experience about what happens when the destination buffer I pass is too small, it will be very usefull.
First, thanks a lot for the answer it helped me a lot.
So Now I know how to set the bitrate for the amr using the codec.
Now I have one more question
When I pass a destination buffer to the ProcessL function
that is too small to contain the compressed data the processL
function completely freezes!!!
I thought that it would return with a result saying it only processed some of the buffer, but no it is compmletely stuck.
Did you ever try this? did you play with the buffer's size that you pass? or do you always pass a buffer that is bigger/identical to the compression's size?
In fact, I suggest you use AMRDLL to perform encoding in 6600. That's more simple.
For output size, the maximum AMR data size per frame is defined by AMR specification. For example, one frame of AMR in MR475 mode is no more than 13 bytes. For MR122, the maximum size is 32. One frame of PCM16 data is 320 bytes, so you may use (length of source) / 10 + 32 as the output buffer length.
Thanks for you answer, I now understand that I can calculate the size of the output buffer according to the amr bitrate I am using.
Still I want to know if you ever tried giving the codec a smaller buffer, I want to know if the api freezes for you as well, because according to the documentation it is supposed to handle it well.
I also tried this with another codec and it worked fine, seems only amr is problematic.
In my program I am using a big buffer and pass a TPtr of it everytime to the process function. Now I can create the buffer to be exactly the multiply of an amr frame(13) but I want to be able to handle a different bitrate.
As for the TAmrEncParams(), I noticed that there are actually only 4 different bitrates when i change imode to be 0,1,2,4
all of the rest are identical. Do you have experience with the relation between iMode and the bitrate that comes out in the end?
for example i know that iMode = 0 means using MR475
But what does using 1,2...7 gives?