×

Discussion Board

Page 1 of 4 1234 LastLast
Results 1 to 15 of 53
  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    6

    A easy way to convert PCM to AMR or vice versa in Series 60 SDK 2.x

    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));
    CleanupStack::PushL(codec);
    CMMFDescriptorBuffer* srcbuf = CMMFDescriptorBuffer::NewL(320);
    CleanupStack::PushL(srcbuf);
    // Copy your PCM frame data into srcbuf, for example: srcbuf->Data().Copy(pcmbuf);
    CMMFDescriptorBuffer* dstbuf = CMMFDescriptorBuffer::NewL(32);
    CleanupStack::PushL(dstbuf);
    TCodecProcessResult result = codec->ProcessL(*srcbuf, *dstbuf):
    // now the dstbuf contains an AMR frame data
    CleanupStack::PopAndDestroy(dstbuf);
    CleanupStack::PopAndDestroy(srcbuf);
    CleanupStack::PopAndDestroy(codec);

    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().

    Including:
    mmf\server\mmfcodec.h
    mmf\server\mmfdatabuffer.h
    mmf\plugin\mmfcodecimplementationuids.hrh
    Library:
    MMFServerBaseClasses.lib

    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?

  2. #2
    Super Contributor
    Join Date
    Mar 2004
    Location
    Czech Republic
    Posts
    2,037
    Hi,

    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.

    Have you the same experience with using it?

    Bye
    STeN

    BTW ConfigureL() is not implemented....

    inline void CMMFCodec::ConfigureL(TUid /*aConfigType*/, const TDesC8& /*aConfigData*/)
    {
    User::Leave(KErrNotSupported);
    }
    Last edited by stenlik; 2005-01-27 at 12:18.

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    6
    Hi, stenlik,

    I don't meet your problem because I use exactly 8000HZ PCM16 data as input. This method also works on 6630. The performance is also acceptable. About 4ms per frame.

    And also I don't the ConfigureL method is not implemented. Because CMMFCodec is just a base class and the real implementation in the codec DLL may implements the function.

    The problem is: I got a "access violation" error instead of a "KErrNotSupport" exception when I call ConfigureL. So I am sure the function is implemented.

    Regards,
    Light

  4. #4
    Super Contributor
    Join Date
    Mar 2004
    Location
    Czech Republic
    Posts
    2,037
    Hi,

    Can abybody explain this?

    EMULATOR:
    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.

    DEVICE:
    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???
    PLEASE HELP!!!
    Thanx
    STeN

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    6
    Hi, stenlik,

    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.

    Regards,
    Light

  6. #6
    Super Contributor
    Join Date
    Mar 2004
    Location
    Czech Republic
    Posts
    2,037
    Hi,

    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

    Anybody has the same experiences?????

    Thanx a lot for any answer
    Bye
    STeN

  7. #7
    Super Contributor
    Join Date
    Mar 2004
    Location
    Czech Republic
    Posts
    2,037
    Hi lighthu,

    did you tried CDevSoundAudioInput class??? It is undocumented, but may beit could be used for streaming/recording to amr?? It always crashes with AV problem...

    Bye
    STeN

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    6
    Hi, stenlik,

    In fact there is a little document of CDevSoundAudioInput in SDK document and we also tried it. But unfortunately it doesn't support AMR in 6630 or 2nd Edition SDK.

    I also noticed that the class also provides a function ConfigureL with a codec-specific TDesC8 parameter. I guess this parameter will to passed to CMMFCodec.

    Regards,
    Light

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    6
    Hi, stenlik,

    My problem is solved! Nokia gives us an explaination of the function CMMFCodec::ConfigureL.

    The second parameter of ConfigureL is a (const TDesC8&). But in fact you should pass a (const TAmrEncParams&)!!!!!! You can find this class in SDK 6.1. Now I can use any AMR mode!

    Regards,
    Light

  10. #10
    Registered User
    Join Date
    Dec 2004
    Posts
    18
    Hi lighthu,
    can you please tell me if there is some documentation about:
    const TAmrEncParams
    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.

    Thanks in advance for any help

  11. #11
    Super Contributor
    Join Date
    Mar 2004
    Location
    Czech Republic
    Posts
    2,037
    Hi,

    may be this should solve your problem...:

    /*
    -----------------------------------------------------------------------------

    TAmrEncParams

    AMR encoding parameters.

    -----------------------------------------------------------------------------
    */
    class TAmrEncParams
    {
    public:
    inline TAmrEncParams();
    public:
    TInt iMode; // encoding mode 0-7 (0=MR475,1=MR515,...,7=MR122, default 7)
    TInt iDTX; // DTX flag (TRUE or default FALSE)
    };

    TAmrEncParams::TAmrEncParams() :
    iMode(7), iDTX(0) {}

    Bye
    (feel free to ask more
    STeN

  12. #12
    Registered User
    Join Date
    Dec 2004
    Posts
    18
    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?

    This all happens on the 6600 device for me.

    Thanks for the help

  13. #13
    Registered User
    Join Date
    Feb 2004
    Posts
    23
    Hi lighthu,

    I'm trying to use configureL to modify the output bitrate of AMR stream, but calling the function it gives an "Access Violation". How did you solve this problem?

    I'm calling ConfigureL in such a way:

    TAmrEncParams params;
    TPckg<TAmrEncParams> pkg_params;
    iEncoder->ConfigureL(TUid::Uid(0x101FAF68), pck_params );

    Thanks for any hints.

    Fabrizio

  14. #14
    Registered User
    Join Date
    Jan 2005
    Posts
    6
    Hi, mitay2,

    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.

    Regards,
    Light

  15. #15
    Registered User
    Join Date
    Dec 2004
    Posts
    18
    Hi light,
    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?

    Many thanks for all your help guys

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
×