Audio input streaming problem on Series 60 v2.6 based phones (6630/6680)

Login to reply to this topic.
Mon, 2005-07-25 09:25
Joined: 2005-01-24
Forum posts: 76
Hi

I have an application that uses CMdaAudioInputStream in order to record raw PCM data from the microphone.

The CMdaAudioInputStream class has a member function ReadL() that is used to retrieve data from the microphone's hardware buffers. You pass this function a descriptor buffer, and the ReadL() function is supposed to asynchronously callback (using MMdaAudioInputStreamCallback::MaiscBufferCopied()) when the descriptor you passed in has been FILLED with audio data.

This works fine on Series 60 v2.0/2.1 based phones. My application reads 700ms worth of PCM data at a time.

I have a problem on Series 60 v2.6 based phones (6630/6680) however. A call to CMdaAudioInputStream::ReadL() always results in only 320 bytes of PCM being read into the passed descriptor when MMdaAudioInputStreamCallback::MaiscBufferCopied() is called. This means my application has to handle 50 asynchronous callbacks per second in order to record audio in real-time!

Currently it can't keep up, recording audio at around 90% speed due to other asynchronous callbacks and timers in the system.

Does anybody know of a workaround for this problem?

My only other options are:
- to put my audio component on a separate real-time priority thread.
- to use CMMFDevSound instead of CMda* classes

Does anyone has any experience of CMMFDevSound and can confirm that audio streaming using it works better than the CMda* classes that are supposed to wrap around it?

Thanks for any responses.

Tue, 2005-07-26 11:47
Joined: 2005-07-19
Forum posts: 16
Re: Audio input streaming problem on Series 60 v2.6 based phones
Looks like the configuration is programmed for a call back for every 20 ms that is required for AMR encoding and is not essentailly reflecting what size you are specifying.

I am not sure what difference DevSound is going to make in the situation.

regards,
Tony
Wed, 2005-08-17 21:40
Joined: 2005-01-24
Forum posts: 76
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi

I posed the question I asked to Forum Nokia Pro.  They admitted that there is no way to get around only recording 20ms frames of audio with each call to CMdaAudioInputStream::ReadL().  This affects only the Nokia 6630 and 6680 so far.  The 320 bytes PCM is locked.  They have promised to look into making the audio API more flexible again, like it used to be.  50 callbacks per second does put quite a performance strain on an application.

I came to a satisfactory solution to my problems in the end.  First an explanation of what the problem was, then a quick tour of the solutions and failures:

My application is recording voice data, encoding to AMR on the fly and streaming using RTP over GPRS.  It's for a Push-To-Talk application.  In addition to the audio callbacks, the application itself is quite busy behind the scenes with timers, network and UI callbacks all over the place.  The application is still only single-threaded.

When I found out that the 6630/6680 was only recording 320 bytes at a time, my first stop-gap measure was to quickly buffer the recorded 320 bytes recorded, appending it onto another buffer then return from the callback straight away.  Once 700ms were buffered, I encoded the buffer from start to finish in one go.

This seemed to work, however bug-reports started to come in reporting audio glitches after several seconds.  It seems that the above solution was not recording audio in real-time, so on the receivng side, since less than 1 second of audio per second was received, glitches occurred.  The problem was that while the buffering scheme worked, the 320 bytes PCM could be recorded and the callbacks handled at a rate of 50/sec (just), but when it came to encoding 700ms of audio into AMR in one uninterrupted block of execution, the time it took to complete was greater than the 20ms period between callbacks from the audio input stream.  It never managed to catch up the lag created each time this 700ms of audio was encoded.  So each second, I was dropping 5-6 frames of audio whilst this encoding took place.

My eventual solution was the encode each 320 byte frame as it was recorded (something that I'd tried before but didn't work).  I also stripped down the code so that it was executing the bare minimum of code in the audio input stream callback:

Since the 6630/6680 are forced to use the MMF to encode/decode AMR (the old AMR APIs available in 2.0/2.1 based phones (CPcmToAmrEncoder, CAmrToPcmDecoder) have been removed) and I'd based the MMF code on top of the existing media server code.  The first improvement to make was to convert ALL descriptor audio buffers into CMMFDescriptorBuffers that have to be used by the CMMFCodecs in use.  This one step removed a significant amount of memory copying from buffer to buffer, (which proved to be really time-consuming as it turns out).

The other improvement, as mentioned, was to encode each frame as it was recorded in the MaiscBufferCopied() callback (following another call to CMdaAudioInputStream::ReadL() - that HAS to be the first line in the callback after checking the error code).

These improvements took the audio recording from around 93% speed to 99.9% speed, good enough for the application in hand.

I also tried another solution that I never got to work.  This was based on the assertion that the audio was the critical path of the application and it HAD to have it's audio callbacks handled in real-time.  Since I have no control over the priority of the active object in CMdaAudioInputStream since it's hidden by the MMdaAudioInputStreamCallback interface, I thought about running that active object on it's own in a real-time priority thread, so taking the application multi-threaded.  This proved more trouble than it was worth after all the shared memory and synchronisation.  I based that solution on the multi-threaded audio-mixer example available from Forum Nokia.

Furthermore, CMMFDevSound works no better than the CMda* stream classes that wrap it.  CMMFDevSound also exhibits this same 20ms frame at a time behaviour.

Hope this helps.

Regards.

Andy
Fri, 2005-08-19 14:36
Joined: 2005-07-19
Forum posts: 16
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi Andy,

That was a crystal clear explanation and gives a lot of input to the problem that I am looking into. Same AMR encoding but the application is VTC and where I am currently looking on is one layer beneath DevSound called HwDevice.

I have configured for one frame encode and one frame decode, but due to the complexity involved (MPEG 4 encode, MPEG 4 decode but ofcourse shared across processors) I am still not able to get the magic figure around 20ms for both amr encoder and decoder. I have to now play around with the priority of the data sender/reciever active object.

And one frame decoding goes for toss when DTX is on and you have SID frames and more over data loss over network resulting in breaks in audio.

Tony
Fri, 2005-08-19 22:54
Joined: 2005-01-24
Forum posts: 76
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi

For the Push-To-Talk application I'm working on, we're using AMR narrow band with DTX turned off, encoding using mode 1 AMR 5.15kbit/s.

I don't have real hard performance figures, but using discontinuous transmission as you are, I'd imagine the AMR encoder would have to put in quite a lot of extra work analysing the input PCM against observed background silence to determine whether anyone was speaking.  This is probably done on a frame-by-frame basis I'd imagine?  I'm sure that I read somewhere that the AMR codec running on the kind of ARM processors available in smartphones today could encode one 20ms frame of PCM in around 4-5ms.  Obviously this will go up when the overhead of DTX is added onto it.

Perhaps these are clock cycles you can't afford, especially if you are encoding video frames on the fly at the same time! 

Could you perhaps turn DTX off, so generating a constant stream of AMR audio even during silence?  While it would increase the amount of data you are transmitting, you may be able to encode audio in real-time.  Would whatever standard for VTC you're using allow this?

If you could use AMR with DTX turned off, perhaps you could take the octet aligned data generated by the codec and pack it into bandwidth efficient mode using a little bit-shifting to save an extra 5-10% of data transmission?

As for AMR decoding, you should have no performance issues there.  As with all lossy compression, encoding is intensive, decoding is quick and easy.

When you say you're working with HWDevice, do you mean your accessing hardware acceleration directly using RHwaDevice?  I'd be interested to learn of how you're doing that and what benefits that can bring.

You said you were playing around with the data sending object in your system too.  Would it be possible to send larger data packets out over the network (or send 2 packets in every asynchronous callback?)  so generating less asynchronous callbacks in that area, allowing more operating space for the audio?

Regards.

Andy.

p.s.

I don't know whether it's of any interest, but as of Symbian 8.1a (Series 60 2.6 Feature Pack 2), CMdaAudioInputStream and CMdaAudioOutputStream have had a function added to their API, SetDataTypeL().  You can pass this function the FourCC identifier of a codec and you can stream directly to/from that format instead of PCM.

I have been told that it does work for AMR, but you have less flexibility to set up the encoding than you would using CMMFCodec.  I don't know whether it offers any performance gains either, I doubt that it would.  Still, it makes streaming AMR code a little neater if you're not too fussy about what it's generating.
Thu, 2005-10-13 06:31
Joined: 2004-11-25
Forum posts: 5
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi Andrew,

I'm trying to run the audio input stream example on 6630, but it doesn't work as you know , could you please advice me how much is the size buffer should be to get this working, I don't need converting to AMR as you do, I just want to get this example running on the phone .

Regards,
Rami

rami75lu

Wed, 2005-11-23 11:43
Joined: 2005-01-24
Forum posts: 22
Re: Audio input streaming problem on Series 60 v2.6 based phones
Quote from: andrew.hayes

I don't know whether it's of any interest, but as of Symbian 8.1a (Series 60 2.6 Feature Pack 2), CMdaAudioInputStream and CMdaAudioOutputStream have had a function added to their API, SetDataTypeL().  You can pass this function the FourCC identifier of a codec and you can stream directly to/from that format instead of PCM.

I have been told that it does work for AMR, but you have less flexibility to set up the encoding than you would using CMMFCodec.  I don't know whether it offers any performance gains either, I doubt that it would.  Still, it makes streaming AMR code a little neater if you're not too fussy about what it's generating.

Hi Andrew, have you ever tried this so far?
I'm experimenting with this alternative way. In my streaming application that works perfectly with "classic" pcm acquisition+amr conversion, if I directly use this technique I encounter a strange behaviour:after a MAiscBufferCopied callback, when I issue a new ReadL from it (obviously in another free buffer) the new callback returns too fast, before the expected 20msec (the buffers passed to ReadL are 13bytes long, exactly for an MR475 20msec  frame)...
So although the first frame is correctly acquired and is being sended , the second returns when this operation "IsActive()"...
This doesn't happen in the "classic way"...

Regards
Rocco
Sat, 2005-11-26 21:29
Joined: 2005-01-24
Forum posts: 76
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi Rocco.

Not too sure what "returning too quickly means".  If this is a problem with your logging, see your other post that I've answered.  Does it return the audio data you expect?

I've not used the SetDataTypeL() method of AMR recording.  I'm told by someone else that it does work.  I'm still using the "classic" method.

Cheers.

Andy Wink
Mon, 2005-11-28 12:35
Joined: 2005-01-24
Forum posts: 22
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi Andrew,
thank you for all your replies to my posts.

With "returning too quickly" I mean that every time MaiscbufferCopied is called, I issue a new ReadL and always in it, I try to pass the returned buffer to socket if it is not occupied with a previous one( !IsAtctive).

With this technique I don't have problems if I use the classic way (via ProcessL). So this proves taht 20ms for an acquisition of the 320bytes PCM are enough for the encoding and sending  the previous one.

With direct AMR acquisition when MaiscbufferCopied is called the second time I find SendTo still active...So I can send an AMR frame every two and at destination this sound as garbage...

Rocco
Tue, 2005-12-13 22:05
Joined: 2005-12-09
Forum posts: 6
Re: Audio input streaming problem on Series 60 v2.6 based phones
Andew great post again. Thank You. Here is my experience wirj CMMFDevSound API. I am actually seeing 4096 byte long buffer in both directions. Verified on emulators for S80 and S60 3rd. The unknown author of full-duplex sample from Nokia also indicated that 4096 byte is what he/she gets on S60 2nd FP2 & FP3.

I would gladly take 20ms chunks if possible. It suites my application better.
Wed, 2006-01-18 07:04
Joined: 2006-01-02
Forum posts: 24
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi Andrew,

I have implemented recording using  CMMFDevSound class. Recording is fine and it is also being recorded in amr and taking the default mode to 12.2 KBPS. Do you know how do set the AMR mode using CMMFDevSound? I.e if i want to change the mode to 1.
Sat, 2006-01-28 00:23
Joined: 2005-01-24
Forum posts: 76
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi

Does your CMMFDevSound implementation use the AMR CMMFCodec?

I can tell you how to change the AMR using CMMFCodec.

If not, I'm not sure.
Wed, 2006-02-08 17:13
Joined: 2004-06-10
Forum posts: 5
Re: Audio input streaming problem on Series 60 v2.6 based phones
For anyone interested, I am using CMdaAudioInputStream::SetDataTypeL(KMMFFourCCCodeAMR) on 6680. It works - in AMR 12.2 only (20ms chunks as usual, i.e. 32 bytes per callback).
I'm quite interested in finding out how to change the AMR rate, no success so far...

Uriah
Wed, 2006-02-08 17:21
Joined: 2006-01-02
Forum posts: 24
Re: Audio input streaming problem on Series 60 v2.6 based phones
iPcm16Buffer = CMMFDescriptorBuffer::NewL( 320    );
       iAmrBuffer = CMMFDescriptorBuffer::NewL( 13 );

Take the buffers accordingly i.e for mode 0 --13 bytes;

and pass it to ProcessL...
cheers Smiley
Thu, 2006-08-17 09:02
Joined: 2005-01-24
Forum posts: 76
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi

There's been a technical post on Forum Nokia:
http://forum.nokia.com/main/technical_library/FNTL/Customizing_the_buffer_size_of_CMdaAudioInputStream.htm

Apparently the maximum buffer size returnable from any audio recording API in S60 2nd edition FP2 & FP3 is 320 bytes (this includes CMMFDevSound).

On S60 3rd edition, this has increased in size to 4096 bytes maximum, giving more flexibility if necessary.

It's all to  do with tailoring the buffer size to best suit the underlying audio hardware.

Regards.

Andy "The Oracle" Wink

Thu, 2006-08-17 09:10
Joined: 2005-01-24
Forum posts: 76
Re: Audio input streaming problem on Series 60 v2.6 based phones
Hi

Also, in answer to some of the questions on this post, from Symbian 9.1 onwards, CMdaAudioInputStream has a new suite of functions added to it's API:

  • void GetSupportedBitRatesL(RArray<TInt>& aSupportedBitRates)
  • TInt BitRateL()
  • SetBitRateL(TInt aBitRate)

Perhaps these functions might be used to solve the problem of setting of the AMR mode when using the SetDataTypeL() function of CMdaAudioInputStream?

I've not tried, so I don't know whether they work with AMR or not.  If someone else wants to give it a whirl, feel free.

Regards.

Andy "The Oracle" Wink
  • Login to reply to this topic.