00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "config.h"
00010
00011 #if defined(AD_BACKEND_S60)
00012
00013
00014
00015
00016
00017
00018
00019 #include <e32base.h>
00020 #include <e32msgqueue.h>
00021 #include <e32debug.h>
00022 #include <MdaAudioInputStream.h>
00023 #include <mda/common/audio.h>
00024
00025 #include "ad.h"
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 enum TMessage {
00045 ENullMessage = 0,
00046 EInited,
00047 EStartRecording,
00048 ERecordingStarted,
00049 EStopRecording,
00050 ERecordingStopped,
00051 EClose,
00052 EClosed
00053 };
00054
00055
00056
00057
00058 const TInt KQueueLength = 10;
00059
00060
00061
00062
00063 const TInt KBytesPerSample = 2;
00064
00065
00066
00067
00068 const TInt KSampleRate = 16000;
00069
00070
00071
00072
00073
00074
00075 const TInt KTemporaryBufferTime = 150;
00076
00077
00078
00079
00080 const TInt KTemporaryBufferSize = (KTemporaryBufferTime * KSampleRate * KBytesPerSample) / 1000;
00081
00082
00083
00084
00085 _LIT(KHelperThreadName, "HelperThread");
00086
00087
00088
00089
00090 enum THelperThreadState {EPaused = 0, ERecording, EClosing};
00091
00092
00093
00094
00095
00096
00097 class CHelperThreadHost : public MMdaAudioInputStreamCallback {
00098 public:
00099 CHelperThreadHost(CBufSeg*, RFastLock*, RMsgQueue<TInt>*, RMsgQueue<TInt>*);
00100 virtual ~CHelperThreadHost();
00101 static TInt ThreadFunction(TAny*);
00102 void InitializeL();
00103 void DestroyL();
00104
00105 virtual void MaiscOpenComplete(TInt);
00106 virtual void MaiscBufferCopied(TInt, const TDesC8&);
00107 virtual void MaiscRecordComplete(TInt);
00108
00109 private:
00110 CMdaAudioInputStream* iStream;
00111 TMdaAudioDataSettings iStreamSettings;
00112 THelperThreadState iState;
00113
00114 RBuf8 iTemporaryBuffer;
00115
00116 CBufSeg* iBuffer;
00117 RFastLock* iBufferLock;
00118
00119 RMsgQueue<TInt>* iCommandQueue;
00120 RMsgQueue<TInt>* iNotificationQueue;
00121 };
00122
00123
00124
00125
00126 class CAudioDevice {
00127 public:
00128 CAudioDevice();
00129 void ConstructL();
00130 static CAudioDevice* NewL();
00131 virtual ~CAudioDevice();
00132
00133 void ResumeRecording();
00134 void PauseRecording();
00135 TInt ReadSamples(TAny*, TInt);
00136
00137 private:
00138 RThread iThread;
00139 CHelperThreadHost* iThreadHost;
00140
00141 CBufSeg* iBuffer;
00142 RFastLock iBufferLock;
00143
00144 RMsgQueue<TInt> iCommandQueue;
00145 RMsgQueue<TInt> iNotificationQueue;
00146 };
00147
00148 CAudioDevice::CAudioDevice(){
00149 iCommandQueue.CreateLocal(KQueueLength);
00150 iNotificationQueue.CreateLocal(KQueueLength);
00151 }
00152
00153 void CAudioDevice::ConstructL(){
00154 iBuffer = CBufSeg::NewL(KTemporaryBufferSize);
00155 iBufferLock.CreateLocal();
00156
00157 iThreadHost = new (ELeave) CHelperThreadHost(iBuffer, &(iBufferLock), &(iCommandQueue), &(iNotificationQueue));
00158 iThread.Create(KHelperThreadName, CHelperThreadHost::ThreadFunction, KDefaultStackSize, NULL, iThreadHost);
00159 iThread.Resume();
00160
00161
00162 TInt message = ENullMessage;
00163 iNotificationQueue.ReceiveBlocking(message);
00164 if(message != EInited){
00165 RDebug::Print(_L("expecting %d, got %d"), EInited, message);
00166 }
00167 }
00168
00169 CAudioDevice* CAudioDevice::NewL(){
00170 CAudioDevice* self = new (ELeave) CAudioDevice();
00171 CleanupStack::PushL(self);
00172 self->ConstructL();
00173 CleanupStack::Pop(self);
00174 return self;
00175 }
00176
00177
00178
00179
00180 void CAudioDevice::ResumeRecording(){
00181 iCommandQueue.SendBlocking(EStartRecording);
00182
00183 TInt message = ENullMessage;
00184 iNotificationQueue.ReceiveBlocking(message);
00185 if(message != ERecordingStarted){
00186 RDebug::Print(_L("expecting %d, got %d"), ERecordingStarted, message);
00187 }
00188 }
00189
00190
00191
00192
00193
00194 void CAudioDevice::PauseRecording(){
00195 iCommandQueue.SendBlocking(EStopRecording);
00196
00197 TInt message = ENullMessage;
00198 iNotificationQueue.ReceiveBlocking(message);
00199 if(message != ERecordingStopped){
00200 RDebug::Print(_L("expecting %d, got %d"), ERecordingStopped, message);
00201 }
00202 }
00203
00204
00205
00206
00207
00208 TInt CAudioDevice::ReadSamples(TAny* aDestinationBuffer, TInt aMaxSamples){
00209 iBufferLock.Wait();
00210 TInt availableSamples = iBuffer->Size() / KBytesPerSample;
00211 TInt samplesToCopy = aMaxSamples;
00212 if (availableSamples < aMaxSamples){
00213 samplesToCopy = availableSamples;
00214 }
00215 TInt bytesToCopy = samplesToCopy * KBytesPerSample;
00216 iBuffer->Read(0, aDestinationBuffer, bytesToCopy);
00217 iBuffer->Delete(0, bytesToCopy);
00218 iBufferLock.Signal();
00219
00220 return samplesToCopy;
00221 }
00222
00223 CAudioDevice::~CAudioDevice(){
00224
00225 iCommandQueue.SendBlocking(EClose);
00226
00227 TInt message = ENullMessage;
00228 iNotificationQueue.ReceiveBlocking(message);
00229 if(message != EClosed){
00230 RDebug::Print(_L("expecting %d, got %d"), EClosed, message);
00231 }
00232
00233
00234 TRequestStatus status;
00235 iThread.Logon(status);
00236 User::WaitForRequest(status);
00237
00238
00239 delete iThreadHost;
00240 iThread.Close();
00241 iBufferLock.Close();
00242 delete iBuffer;
00243 iNotificationQueue.Close();
00244 iCommandQueue.Close();
00245 }
00246
00247 CHelperThreadHost::CHelperThreadHost(CBufSeg* aBuffer, RFastLock* aBufferLock, RMsgQueue<TInt>* aCommandQueue, RMsgQueue<TInt>* aNotificationQueue){
00248 iBuffer = aBuffer;
00249 iBufferLock = aBufferLock;
00250 iCommandQueue = aCommandQueue;
00251 iNotificationQueue = aNotificationQueue;
00252 iState = EPaused;
00253 }
00254
00255 TInt CHelperThreadHost::ThreadFunction(TAny* aParam){
00256 CHelperThreadHost* host = (CHelperThreadHost*) aParam;
00257
00258
00259 CTrapCleanup* cleanupStack = CTrapCleanup::New();
00260
00261
00262 TRAPD(error,
00263 CActiveScheduler* activeScheduler = new (ELeave) CActiveScheduler;
00264 CleanupStack::PushL(activeScheduler);
00265 CActiveScheduler::Install(activeScheduler);
00266
00267
00268 host->InitializeL();
00269
00270
00271 CActiveScheduler::Start();
00272
00273
00274 CleanupStack::PopAndDestroy(activeScheduler);
00275 );
00276 if(error != KErrNone){
00277 RDebug::Print(_L("thread error: %d"), error);
00278 }
00279
00280 delete cleanupStack;
00281 return KErrNone;
00282 }
00283
00284
00285
00286
00287 void CHelperThreadHost::InitializeL(){
00288 iStream = CMdaAudioInputStream::NewL(*this, EMdaPriorityMax, EMdaPriorityPreferenceTime);
00289 iStream->Open(&(iStreamSettings));
00290 iTemporaryBuffer.CreateL(KTemporaryBufferSize);
00291 }
00292
00293
00294
00295
00296 void CHelperThreadHost::DestroyL(){
00297 iTemporaryBuffer.Close();
00298 delete iStream;
00299 }
00300
00301
00302
00303
00304 void CHelperThreadHost::MaiscOpenComplete(TInt aError){
00305 if (aError == KErrNone){
00306 iNotificationQueue->SendBlocking(EInited);
00307
00308 iStream->SetAudioPropertiesL(TMdaAudioDataSettings::ESampleRate16000Hz, TMdaAudioDataSettings::EChannelsMono);
00309 iStream->SetGain(iStream->MaxGain());
00310
00311 iStream->ReadL(iTemporaryBuffer);
00312 }
00313 else{
00314 RDebug::Print(_L("error %d in MaiscOpenComplete"), aError);
00315 }
00316 }
00317
00318
00319
00320
00321 void CHelperThreadHost::MaiscBufferCopied(TInt aError, const TDesC8 &aBuffer){
00322 if (aError == KErrNone){
00323
00324 if(iState == ERecording){
00325 TInt availableBytes = aBuffer.Size();
00326 iBufferLock->Wait();
00327 TInt bufferSize = iBuffer->Size();
00328 iBuffer->ExpandL(bufferSize, availableBytes);
00329 iBuffer->Write(bufferSize, aBuffer, availableBytes);
00330 iBufferLock->Signal();
00331 }
00332
00333
00334 iTemporaryBuffer.Zero();
00335
00336
00337 TInt message = ENullMessage;
00338 TInt result = iCommandQueue->Receive(message);
00339 if (result == KErrNone){
00340 if(message == EStartRecording){
00341 iState = ERecording;
00342 iNotificationQueue->SendBlocking(ERecordingStarted);
00343 }
00344 else if(message == EStopRecording){
00345 iState = EPaused;
00346 iNotificationQueue->SendBlocking(ERecordingStopped);
00347 }
00348 else if(message == EClose){
00349 iState = EClosing;
00350 iStream->Stop();
00351 this->DestroyL();
00352 iNotificationQueue->SendBlocking(EClosed);
00353 User::Exit(0);
00354 }
00355 else{
00356 RDebug::Print(_L("received unexpected %d"), message);
00357 }
00358 }
00359
00360
00361 if (iState != EClosing){
00362 iStream->ReadL(iTemporaryBuffer);
00363 }
00364 }
00365 else if (aError == KErrAbort){
00366
00367 }
00368 else{
00369 RDebug::Print(_L("error %d in MaiscBufferCopied"), aError);
00370 }
00371 }
00372
00373
00374
00375
00376
00377
00378 void CHelperThreadHost::MaiscRecordComplete(TInt aError){
00379
00380 }
00381
00382 CHelperThreadHost::~CHelperThreadHost(){
00383
00384 }
00385
00386
00387
00388 ad_rec_t* ad_open(void){
00389 ad_rec_t* result = new ad_rec_t;
00390 result->recorder = CAudioDevice::NewL();
00391 result->recording = FALSE;
00392 result->sps = KSampleRate;
00393 result->bps = KBytesPerSample;
00394 return result;
00395 }
00396
00397 ad_rec_t* ad_open_dev(const char* dev, int32 sps){
00398
00399 return ad_open();
00400 }
00401
00402 ad_rec_t* ad_open_sps(int32 sps){
00403
00404 return ad_open();
00405 }
00406
00407 ad_rec_t* ad_open_sps_bufsize(int32 sps, int32 bufsize_msec){
00408
00409 return ad_open();
00410 }
00411
00412 int32 ad_start_rec(ad_rec_t* r){
00413 ((CAudioDevice*)r->recorder)->ResumeRecording();
00414 r->recording = TRUE;
00415 return AD_OK;
00416 }
00417
00418 int32 ad_read(ad_rec_t* r, int16* buf, int32 max){
00419 int32 result = (int32) ((CAudioDevice*)r->recorder)->ReadSamples((TAny*) buf, (TInt)max);
00420 if(result == 0 && r->recording == FALSE){
00421 result = AD_EOF;
00422 }
00423 return result;
00424 }
00425
00426 int32 ad_stop_rec(ad_rec_t* r){
00427 ((CAudioDevice*)r->recorder)->PauseRecording();
00428 r->recording = FALSE;
00429 return AD_OK;
00430 }
00431
00432 int32 ad_close(ad_rec_t* r){
00433 delete ((CAudioDevice*)r->recorder);
00434 delete r;
00435 return AD_OK;
00436 }
00437
00438 #endif //defined(AD_BACKEND_S60)