198
194
* Utility: print sound device error
200
static void snd_perror(const char *title, TInt rc)
196
static void snd_perror (const char *title, TInt rc)
202
PJ_LOG(1,(THIS_FILE, "%s (error code=%d)", title, rc));
198
PJ_LOG (1, (THIS_FILE, "%s (error code=%d)", title, rc));
205
typedef void(*PjAudioCallback)(CVoIPDataBuffer *buf, void *user_data);
201
typedef void (*PjAudioCallback) (CVoIPDataBuffer *buf, void *user_data);
208
204
* Audio setting for CPjAudioEngine.
210
206
class CPjAudioSetting
213
TVoIPCodecFormat format;
209
TVoIPCodecFormat format;
222
218
* Implementation: Symbian Input & Output Stream.
224
220
class CPjAudioEngine : public CBase,
225
public MVoIPDownlinkObserver,
226
public MVoIPUplinkObserver,
227
public MVoIPFormatObserver
221
public MVoIPDownlinkObserver,
222
public MVoIPUplinkObserver,
223
public MVoIPFormatObserver
240
static CPjAudioEngine *NewL(struct vas_stream *parent_strm,
241
PjAudioCallback rec_cb,
242
PjAudioCallback play_cb,
244
const CPjAudioSetting &setting);
249
TInt ActivateSpeaker(TBool active);
251
TInt SetVolume(TInt vol) { return iVoIPDnlink->SetVolume(vol); }
252
TInt GetVolume() { TInt vol;iVoIPDnlink->GetVolume(vol);return vol; }
253
TInt GetMaxVolume() { TInt vol;iVoIPDnlink->GetMaxVolume(vol);return vol; }
255
TInt SetGain(TInt gain) { return iVoIPUplink->SetGain(gain); }
256
TInt GetGain() { TInt gain;iVoIPUplink->GetGain(gain);return gain; }
257
TInt GetMaxGain() { TInt gain;iVoIPUplink->GetMaxGain(gain);return gain; }
262
CPjAudioEngine(struct vas_stream *parent_strm,
263
PjAudioCallback rec_cb,
264
PjAudioCallback play_cb,
266
const CPjAudioSetting &setting);
275
// From MVoIPDownlinkObserver
276
void FillBuffer(const CVoIPAudioDownlinkStream& aSrc,
277
CVoIPDataBuffer* aBuffer);
278
void Event(const CVoIPAudioDownlinkStream& aSrc,
282
// From MVoIPUplinkObserver
283
void EmptyBuffer(const CVoIPAudioUplinkStream& aSrc,
284
CVoIPDataBuffer* aBuffer);
285
void Event(const CVoIPAudioUplinkStream& aSrc,
289
// From MVoIPFormatObserver
290
void Event(const CVoIPFormatIntfc& aSrc, TInt aEventType);
294
struct vas_stream *parentStrm_;
295
CPjAudioSetting setting_;
296
PjAudioCallback rec_cb_;
297
PjAudioCallback play_cb_;
301
CVoIPUtilityFactory *iFactory;
302
CVoIPAudioDownlinkStream *iVoIPDnlink;
303
CVoIPAudioUplinkStream *iVoIPUplink;
304
CVoIPFormatIntfc *enc_fmt_if;
305
CVoIPFormatIntfc *dec_fmt_if;
235
static CPjAudioEngine *NewL (struct vas_stream *parent_strm,
236
PjAudioCallback rec_cb,
237
PjAudioCallback play_cb,
239
const CPjAudioSetting &setting);
244
TInt ActivateSpeaker (TBool active);
246
TInt SetVolume (TInt vol) {
247
return iVoIPDnlink->SetVolume (vol);
251
iVoIPDnlink->GetVolume (vol);
254
TInt GetMaxVolume() {
256
iVoIPDnlink->GetMaxVolume (vol);
260
TInt SetGain (TInt gain) {
261
return iVoIPUplink->SetGain (gain);
265
iVoIPUplink->GetGain (gain);
270
iVoIPUplink->GetMaxGain (gain);
277
CPjAudioEngine (struct vas_stream *parent_strm,
278
PjAudioCallback rec_cb,
279
PjAudioCallback play_cb,
281
const CPjAudioSetting &setting);
290
// From MVoIPDownlinkObserver
291
void FillBuffer (const CVoIPAudioDownlinkStream& aSrc,
292
CVoIPDataBuffer* aBuffer);
293
void Event (const CVoIPAudioDownlinkStream& aSrc,
297
// From MVoIPUplinkObserver
298
void EmptyBuffer (const CVoIPAudioUplinkStream& aSrc,
299
CVoIPDataBuffer* aBuffer);
300
void Event (const CVoIPAudioUplinkStream& aSrc,
304
// From MVoIPFormatObserver
305
void Event (const CVoIPFormatIntfc& aSrc, TInt aEventType);
309
struct vas_stream *parentStrm_;
310
CPjAudioSetting setting_;
311
PjAudioCallback rec_cb_;
312
PjAudioCallback play_cb_;
316
CVoIPUtilityFactory *iFactory;
317
CVoIPAudioDownlinkStream *iVoIPDnlink;
318
CVoIPAudioUplinkStream *iVoIPUplink;
319
CVoIPFormatIntfc *enc_fmt_if;
320
CVoIPFormatIntfc *dec_fmt_if;
309
CPjAudioEngine* CPjAudioEngine::NewL(struct vas_stream *parent_strm,
310
PjAudioCallback rec_cb,
311
PjAudioCallback play_cb,
313
const CPjAudioSetting &setting)
324
CPjAudioEngine* CPjAudioEngine::NewL (struct vas_stream *parent_strm,
325
PjAudioCallback rec_cb,
326
PjAudioCallback play_cb,
328
const CPjAudioSetting &setting)
315
CPjAudioEngine* self = new (ELeave) CPjAudioEngine(parent_strm,
319
CleanupStack::PushL(self);
330
CPjAudioEngine* self = new (ELeave) CPjAudioEngine (parent_strm,
334
CleanupStack::PushL (self);
320
335
self->ConstructL();
321
CleanupStack::Pop(self);
336
CleanupStack::Pop (self);
325
340
void CPjAudioEngine::ConstructL()
328
const TVersion ver(1, 0, 0); /* Not really used at this time */
343
const TVersion ver (1, 0, 0); /* Not really used at this time */
330
err = CVoIPUtilityFactory::CreateFactory(iFactory);
331
User::LeaveIfError(err);
345
err = CVoIPUtilityFactory::CreateFactory (iFactory);
346
User::LeaveIfError (err);
333
348
if (parentStrm_->param.dir != PJMEDIA_DIR_CAPTURE) {
334
err = iFactory->CreateDownlinkStream(ver,
335
CVoIPUtilityFactory::EVoIPCall,
337
User::LeaveIfError(err);
349
err = iFactory->CreateDownlinkStream (ver,
350
CVoIPUtilityFactory::EVoIPCall,
352
User::LeaveIfError (err);
340
355
if (parentStrm_->param.dir != PJMEDIA_DIR_PLAYBACK) {
341
err = iFactory->CreateUplinkStream(ver,
342
CVoIPUtilityFactory::EVoIPCall,
344
User::LeaveIfError(err);
356
err = iFactory->CreateUplinkStream (ver,
357
CVoIPUtilityFactory::EVoIPCall,
359
User::LeaveIfError (err);
348
CPjAudioEngine::CPjAudioEngine(struct vas_stream *parent_strm,
349
PjAudioCallback rec_cb,
350
PjAudioCallback play_cb,
352
const CPjAudioSetting &setting)
353
: dn_state_(STATE_NULL),
354
up_state_(STATE_NULL),
355
parentStrm_(parent_strm),
359
user_data_(user_data),
363
CPjAudioEngine::CPjAudioEngine (struct vas_stream *parent_strm,
364
PjAudioCallback rec_cb,
365
PjAudioCallback play_cb,
367
const CPjAudioSetting &setting)
368
: dn_state_ (STATE_NULL),
369
up_state_ (STATE_NULL),
370
parentStrm_ (parent_strm),
374
user_data_ (user_data),
368
383
CPjAudioEngine::~CPjAudioEngine()
373
iVoIPUplink->Close();
388
iVoIPUplink->Close();
376
iVoIPDnlink->Close();
391
iVoIPDnlink->Close();
378
393
delete iVoIPDnlink;
379
394
delete iVoIPUplink;
382
TRACE_((THIS_FILE, "Sound device destroyed"));
397
TRACE_ ( (THIS_FILE, "Sound device destroyed"));
385
400
TBool CPjAudioEngine::IsStarted()
387
return ((((parentStrm_->param.dir & PJMEDIA_DIR_CAPTURE) == 0) ||
388
up_state_ == STATE_STREAMING) &&
389
(((parentStrm_->param.dir & PJMEDIA_DIR_PLAYBACK) == 0) ||
390
dn_state_ == STATE_STREAMING));
402
return ( ( ( (parentStrm_->param.dir & PJMEDIA_DIR_CAPTURE) == 0) ||
403
up_state_ == STATE_STREAMING) &&
404
( ( (parentStrm_->param.dir & PJMEDIA_DIR_PLAYBACK) == 0) ||
405
dn_state_ == STATE_STREAMING));
393
408
TInt CPjAudioEngine::InitPlay()
397
pj_assert(iVoIPDnlink);
399
err = iVoIPDnlink->SetFormat(setting_.format, dec_fmt_if);
403
err = dec_fmt_if->SetObserver(*this);
407
return iVoIPDnlink->Open(*this);
412
pj_assert (iVoIPDnlink);
414
err = iVoIPDnlink->SetFormat (setting_.format, dec_fmt_if);
419
err = dec_fmt_if->SetObserver (*this);
424
return iVoIPDnlink->Open (*this);
410
427
TInt CPjAudioEngine::InitRec()
414
pj_assert(iVoIPUplink);
416
err = iVoIPUplink->SetFormat(setting_.format, enc_fmt_if);
420
err = enc_fmt_if->SetObserver(*this);
424
return iVoIPUplink->Open(*this);
431
pj_assert (iVoIPUplink);
433
err = iVoIPUplink->SetFormat (setting_.format, enc_fmt_if);
438
err = enc_fmt_if->SetObserver (*this);
443
return iVoIPUplink->Open (*this);
427
446
TInt CPjAudioEngine::StartPlay()
431
pj_assert(iVoIPDnlink);
432
pj_assert(dn_state_ == STATE_READY);
450
pj_assert (iVoIPDnlink);
451
pj_assert (dn_state_ == STATE_READY);
434
453
/* Configure specific codec setting */
435
454
switch (setting_.format) {
438
CVoIPG711DecoderIntfc *g711dec_if = (CVoIPG711DecoderIntfc*)
440
err = g711dec_if->SetMode((CVoIPFormatIntfc::TG711CodecMode)
442
pj_assert(err == KErrNone);
448
CVoIPILBCDecoderIntfc *ilbcdec_if = (CVoIPILBCDecoderIntfc*)
450
err = ilbcdec_if->SetMode((CVoIPFormatIntfc::TILBCCodecMode)
452
pj_assert(err == KErrNone);
456
CVoIPG711DecoderIntfc *g711dec_if = (CVoIPG711DecoderIntfc*)
458
err = g711dec_if->SetMode ( (CVoIPFormatIntfc::TG711CodecMode)
460
pj_assert (err == KErrNone);
465
CVoIPILBCDecoderIntfc *ilbcdec_if = (CVoIPILBCDecoderIntfc*)
467
err = ilbcdec_if->SetMode ( (CVoIPFormatIntfc::TILBCCodecMode)
469
pj_assert (err == KErrNone);
460
477
/* Configure audio routing */
461
ActivateSpeaker(setting_.loudspk);
478
ActivateSpeaker (setting_.loudspk);
463
480
/* Start player */
464
481
err = iVoIPDnlink->Start();
466
483
if (err == KErrNone) {
467
dn_state_ = STATE_STREAMING;
468
TRACE_((THIS_FILE, "Downlink started"));
484
dn_state_ = STATE_STREAMING;
485
TRACE_ ( (THIS_FILE, "Downlink started"));
470
snd_perror("Failed starting downlink", err);
487
snd_perror ("Failed starting downlink", err);
791
819
unsigned samples_processed = 0;
793
821
while (samples_processed < vas_g711_frame_len) {
794
unsigned samples_to_process;
795
unsigned samples_req;
797
samples_to_process = vas_g711_frame_len - samples_processed;
798
samples_req = (strm->param.samples_per_frame /
799
strm->param.channel_count /
800
strm->resample_factor) -
802
if (samples_to_process > samples_req)
803
samples_to_process = samples_req;
805
pjmedia_ulaw_decode(&strm->rec_buf[strm->rec_buf_len],
806
buffer.Ptr() + 2 + samples_processed,
809
strm->rec_buf_len += samples_to_process;
810
samples_processed += samples_to_process;
812
/* Buffer is full, time to call parent callback */
813
if (strm->rec_buf_len == strm->param.samples_per_frame /
814
strm->param.channel_count /
815
strm->resample_factor)
819
/* Need to resample clock rate? */
820
if (strm->rec_resample) {
821
unsigned resampled = 0;
823
while (resampled < strm->rec_buf_len) {
824
pjmedia_resample_run(strm->rec_resample,
825
&strm->rec_buf[resampled],
827
resampled * strm->resample_factor);
830
f.buf = strm->pcm_buf;
832
f.buf = strm->rec_buf;
835
/* Need to convert channel count? */
836
if (strm->param.channel_count != 1) {
837
pjmedia_convert_channel_1ton((pj_int16_t*)f.buf,
839
strm->param.channel_count,
840
strm->param.samples_per_frame /
841
strm->param.channel_count,
845
/* Call parent callback */
846
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
847
f.size = strm->param.samples_per_frame << 1;
848
strm->rec_cb(strm->user_data, &f);
849
strm->rec_buf_len = 0;
822
unsigned samples_to_process;
823
unsigned samples_req;
825
samples_to_process = vas_g711_frame_len - samples_processed;
826
samples_req = (strm->param.samples_per_frame /
827
strm->param.channel_count /
828
strm->resample_factor) -
831
if (samples_to_process > samples_req)
832
samples_to_process = samples_req;
834
pjmedia_ulaw_decode (&strm->rec_buf[strm->rec_buf_len],
835
buffer.Ptr() + 2 + samples_processed,
838
strm->rec_buf_len += samples_to_process;
839
samples_processed += samples_to_process;
841
/* Buffer is full, time to call parent callback */
842
if (strm->rec_buf_len == strm->param.samples_per_frame /
843
strm->param.channel_count /
844
strm->resample_factor) {
847
/* Need to resample clock rate? */
848
if (strm->rec_resample) {
849
unsigned resampled = 0;
851
while (resampled < strm->rec_buf_len) {
852
pjmedia_resample_run (strm->rec_resample,
853
&strm->rec_buf[resampled],
855
resampled * strm->resample_factor);
859
f.buf = strm->pcm_buf;
861
f.buf = strm->rec_buf;
864
/* Need to convert channel count? */
865
if (strm->param.channel_count != 1) {
866
pjmedia_convert_channel_1ton ( (pj_int16_t*) f.buf,
868
strm->param.channel_count,
869
strm->param.samples_per_frame /
870
strm->param.channel_count,
874
/* Call parent callback */
875
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
876
f.size = strm->param.samples_per_frame << 1;
877
strm->rec_cb (strm->user_data, &f);
878
strm->rec_buf_len = 0;
854
883
#endif // USE_NATIVE_PCM
856
static void PlayCbPcm(CVoIPDataBuffer *buf, void *user_data)
885
static void PlayCbPcm (CVoIPDataBuffer *buf, void *user_data)
858
887
struct vas_stream *strm = (struct vas_stream*) user_data;
859
888
unsigned g711_frame_len = vas_g711_frame_len;
860
TPtr8 buffer(0, 0, 0);
889
TPtr8 buffer (0, 0, 0);
862
891
/* Get the buffer */
863
buf->GetPayloadPtr(buffer);
892
buf->GetPayloadPtr (buffer);
865
894
/* Init buffer attributes and header. */
870
899
/* Assume frame size is 10ms if frame size hasn't been known. */
871
900
if (g711_frame_len == 0)
874
903
/* Call parent stream callback to get PCM samples to play,
875
904
* encode the PCM samples into G.711 and put it into VAS buffer.
877
906
unsigned samples_processed = 0;
879
908
while (samples_processed < g711_frame_len) {
880
/* Need more samples to play, time to call parent callback */
881
if (strm->play_buf_len == 0) {
883
unsigned samples_got;
885
f.size = strm->param.samples_per_frame << 1;
886
if (strm->play_resample || strm->param.channel_count != 1)
887
f.buf = strm->pcm_buf;
889
f.buf = strm->play_buf;
891
/* Call parent callback */
892
strm->play_cb(strm->user_data, &f);
893
if (f.type != PJMEDIA_FRAME_TYPE_AUDIO) {
894
pjmedia_zero_samples((pj_int16_t*)f.buf,
895
strm->param.samples_per_frame);
898
samples_got = strm->param.samples_per_frame /
899
strm->param.channel_count /
900
strm->resample_factor;
902
/* Need to convert channel count? */
903
if (strm->param.channel_count != 1) {
904
pjmedia_convert_channel_nto1((pj_int16_t*)f.buf,
906
strm->param.channel_count,
907
strm->param.samples_per_frame,
912
/* Need to resample clock rate? */
913
if (strm->play_resample) {
914
unsigned resampled = 0;
916
while (resampled < samples_got)
918
pjmedia_resample_run(strm->play_resample,
920
resampled * strm->resample_factor,
921
&strm->play_buf[resampled]);
926
strm->play_buf_len = samples_got;
927
strm->play_buf_start = 0;
932
tmp = PJ_MIN(strm->play_buf_len, g711_frame_len - samples_processed);
933
pjmedia_ulaw_encode((pj_uint8_t*)&strm->play_buf[strm->play_buf_start],
934
&strm->play_buf[strm->play_buf_start],
936
buffer.Append((TUint8*)&strm->play_buf[strm->play_buf_start], tmp);
937
samples_processed += tmp;
938
strm->play_buf_len -= tmp;
939
strm->play_buf_start += tmp;
909
/* Need more samples to play, time to call parent callback */
910
if (strm->play_buf_len == 0) {
912
unsigned samples_got;
914
f.size = strm->param.samples_per_frame << 1;
916
if (strm->play_resample || strm->param.channel_count != 1)
917
f.buf = strm->pcm_buf;
919
f.buf = strm->play_buf;
921
/* Call parent callback */
922
strm->play_cb (strm->user_data, &f);
924
if (f.type != PJMEDIA_FRAME_TYPE_AUDIO) {
925
pjmedia_zero_samples ( (pj_int16_t*) f.buf,
926
strm->param.samples_per_frame);
929
samples_got = strm->param.samples_per_frame /
930
strm->param.channel_count /
931
strm->resample_factor;
933
/* Need to convert channel count? */
934
if (strm->param.channel_count != 1) {
935
pjmedia_convert_channel_nto1 ( (pj_int16_t*) f.buf,
937
strm->param.channel_count,
938
strm->param.samples_per_frame,
943
/* Need to resample clock rate? */
944
if (strm->play_resample) {
945
unsigned resampled = 0;
947
while (resampled < samples_got) {
948
pjmedia_resample_run (strm->play_resample,
950
resampled * strm->resample_factor,
951
&strm->play_buf[resampled]);
956
strm->play_buf_len = samples_got;
957
strm->play_buf_start = 0;
962
tmp = PJ_MIN (strm->play_buf_len, g711_frame_len - samples_processed);
963
pjmedia_ulaw_encode ( (pj_uint8_t*) &strm->play_buf[strm->play_buf_start],
964
&strm->play_buf[strm->play_buf_start],
966
buffer.Append ( (TUint8*) &strm->play_buf[strm->play_buf_start], tmp);
967
samples_processed += tmp;
968
strm->play_buf_len -= tmp;
969
strm->play_buf_start += tmp;
942
972
/* Set the buffer */
943
buf->SetPayloadPtr(buffer);
973
buf->SetPayloadPtr (buffer);
946
976
/****************************************************************************
947
977
* Internal VAS callbacks for non-PCM format
950
static void RecCb(CVoIPDataBuffer *buf, void *user_data)
980
static void RecCb (CVoIPDataBuffer *buf, void *user_data)
952
982
struct vas_stream *strm = (struct vas_stream*) user_data;
953
983
pjmedia_frame_ext *frame = (pjmedia_frame_ext*) strm->rec_buf;
954
TPtr8 buffer(0, 0, 0);
984
TPtr8 buffer (0, 0, 0);
956
986
/* Get the buffer */
957
buf->GetPayloadPtr(buffer);
959
switch(strm->param.ext_fmt.id) {
960
case PJMEDIA_FORMAT_AMR:
962
const pj_uint8_t *p = (const pj_uint8_t*)buffer.Ptr() + 1;
963
unsigned len = buffer.Length() - 1;
965
pjmedia_frame_ext_append_subframe(frame, p, len << 3, 160);
966
if (frame->samples_cnt == strm->param.samples_per_frame) {
967
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
968
strm->rec_cb(strm->user_data, (pjmedia_frame*)frame);
969
frame->samples_cnt = 0;
970
frame->subframe_cnt = 0;
975
case PJMEDIA_FORMAT_G729:
977
/* Check if we got a normal or SID frame. */
978
if (buffer[0] != 0) {
979
enum { NORMAL_LEN = 22, SID_LEN = 8 };
980
TBitStream *bitstream = (TBitStream*)strm->strm_data;
981
unsigned src_len = buffer.Length()- 2;
983
pj_assert(src_len == NORMAL_LEN || src_len == SID_LEN);
985
const TDesC8& p = bitstream->CompressG729Frame(
986
buffer.Right(src_len),
989
pjmedia_frame_ext_append_subframe(frame, p.Ptr(),
990
p.Length() << 3, 80);
991
} else { /* We got null frame. */
992
pjmedia_frame_ext_append_subframe(frame, NULL, 0, 80);
995
if (frame->samples_cnt == strm->param.samples_per_frame) {
996
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
997
strm->rec_cb(strm->user_data, (pjmedia_frame*)frame);
998
frame->samples_cnt = 0;
999
frame->subframe_cnt = 0;
1004
case PJMEDIA_FORMAT_ILBC:
1006
unsigned samples_got;
1008
samples_got = strm->param.ext_fmt.bitrate == 15200? 160 : 240;
1010
/* Check if we got a normal or SID frame. */
1011
if (buffer[0] != 0) {
1012
const pj_uint8_t *p = (const pj_uint8_t*)buffer.Ptr() + 2;
1013
unsigned len = buffer.Length() - 2;
1015
pjmedia_frame_ext_append_subframe(frame, p, len << 3,
1017
} else { /* We got null frame. */
1018
pjmedia_frame_ext_append_subframe(frame, NULL, 0, samples_got);
1021
if (frame->samples_cnt == strm->param.samples_per_frame) {
1022
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1023
strm->rec_cb(strm->user_data, (pjmedia_frame*)frame);
1024
frame->samples_cnt = 0;
1025
frame->subframe_cnt = 0;
1030
case PJMEDIA_FORMAT_PCMU:
1031
case PJMEDIA_FORMAT_PCMA:
1033
unsigned samples_processed = 0;
1035
/* Make sure it is normal frame. */
1036
pj_assert(buffer[0] == 1 && buffer[1] == 0);
1038
/* Detect the recorder G.711 frame size, player frame size will
1039
* follow this recorder frame size.
1041
if (vas_g711_frame_len == 0) {
1042
vas_g711_frame_len = buffer.Length() < 160? 80 : 160;
1043
TRACE_((THIS_FILE, "Detected VAS G.711 frame size = %u samples",
1044
vas_g711_frame_len));
1047
/* Convert VAS buffer format into pjmedia_frame_ext. Whenever
1048
* samples count in the frame is equal to stream's samples per
1049
* frame, call parent stream callback.
1051
while (samples_processed < vas_g711_frame_len) {
1053
const pj_uint8_t *pb = (const pj_uint8_t*)buffer.Ptr() +
1054
2 + samples_processed;
1056
tmp = PJ_MIN(strm->param.samples_per_frame - frame->samples_cnt,
1057
vas_g711_frame_len - samples_processed);
1059
pjmedia_frame_ext_append_subframe(frame, pb, tmp << 3, tmp);
1060
samples_processed += tmp;
1062
if (frame->samples_cnt == strm->param.samples_per_frame) {
1063
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1064
strm->rec_cb(strm->user_data, (pjmedia_frame*)frame);
1065
frame->samples_cnt = 0;
1066
frame->subframe_cnt = 0;
987
buf->GetPayloadPtr (buffer);
989
switch (strm->param.ext_fmt.id) {
990
case PJMEDIA_FORMAT_AMR: {
991
const pj_uint8_t *p = (const pj_uint8_t*) buffer.Ptr() + 1;
992
unsigned len = buffer.Length() - 1;
994
pjmedia_frame_ext_append_subframe (frame, p, len << 3, 160);
996
if (frame->samples_cnt == strm->param.samples_per_frame) {
997
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
998
strm->rec_cb (strm->user_data, (pjmedia_frame*) frame);
999
frame->samples_cnt = 0;
1000
frame->subframe_cnt = 0;
1005
case PJMEDIA_FORMAT_G729: {
1006
/* Check if we got a normal or SID frame. */
1007
if (buffer[0] != 0) {
1008
enum { NORMAL_LEN = 22, SID_LEN = 8 };
1009
TBitStream *bitstream = (TBitStream*) strm->strm_data;
1010
unsigned src_len = buffer.Length()- 2;
1012
pj_assert (src_len == NORMAL_LEN || src_len == SID_LEN);
1014
const TDesC8& p = bitstream->CompressG729Frame (
1015
buffer.Right (src_len),
1016
src_len == SID_LEN);
1018
pjmedia_frame_ext_append_subframe (frame, p.Ptr(),
1019
p.Length() << 3, 80);
1020
} else { /* We got null frame. */
1021
pjmedia_frame_ext_append_subframe (frame, NULL, 0, 80);
1024
if (frame->samples_cnt == strm->param.samples_per_frame) {
1025
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1026
strm->rec_cb (strm->user_data, (pjmedia_frame*) frame);
1027
frame->samples_cnt = 0;
1028
frame->subframe_cnt = 0;
1033
case PJMEDIA_FORMAT_ILBC: {
1034
unsigned samples_got;
1036
samples_got = strm->param.ext_fmt.bitrate == 15200? 160 : 240;
1038
/* Check if we got a normal or SID frame. */
1039
if (buffer[0] != 0) {
1040
const pj_uint8_t *p = (const pj_uint8_t*) buffer.Ptr() + 2;
1041
unsigned len = buffer.Length() - 2;
1043
pjmedia_frame_ext_append_subframe (frame, p, len << 3,
1045
} else { /* We got null frame. */
1046
pjmedia_frame_ext_append_subframe (frame, NULL, 0, samples_got);
1049
if (frame->samples_cnt == strm->param.samples_per_frame) {
1050
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1051
strm->rec_cb (strm->user_data, (pjmedia_frame*) frame);
1052
frame->samples_cnt = 0;
1053
frame->subframe_cnt = 0;
1058
case PJMEDIA_FORMAT_PCMU:
1059
case PJMEDIA_FORMAT_PCMA: {
1060
unsigned samples_processed = 0;
1062
/* Make sure it is normal frame. */
1063
pj_assert (buffer[0] == 1 && buffer[1] == 0);
1065
/* Detect the recorder G.711 frame size, player frame size will
1066
* follow this recorder frame size.
1068
if (vas_g711_frame_len == 0) {
1069
vas_g711_frame_len = buffer.Length() < 160? 80 : 160;
1070
TRACE_ ( (THIS_FILE, "Detected VAS G.711 frame size = %u samples",
1071
vas_g711_frame_len));
1074
/* Convert VAS buffer format into pjmedia_frame_ext. Whenever
1075
* samples count in the frame is equal to stream's samples per
1076
* frame, call parent stream callback.
1078
while (samples_processed < vas_g711_frame_len) {
1080
const pj_uint8_t *pb = (const pj_uint8_t*) buffer.Ptr() +
1081
2 + samples_processed;
1083
tmp = PJ_MIN (strm->param.samples_per_frame - frame->samples_cnt,
1084
vas_g711_frame_len - samples_processed);
1086
pjmedia_frame_ext_append_subframe (frame, pb, tmp << 3, tmp);
1087
samples_processed += tmp;
1089
if (frame->samples_cnt == strm->param.samples_per_frame) {
1090
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1091
strm->rec_cb (strm->user_data, (pjmedia_frame*) frame);
1092
frame->samples_cnt = 0;
1093
frame->subframe_cnt = 0;
1077
static void PlayCb(CVoIPDataBuffer *buf, void *user_data)
1104
static void PlayCb (CVoIPDataBuffer *buf, void *user_data)
1079
1106
struct vas_stream *strm = (struct vas_stream*) user_data;
1080
1107
pjmedia_frame_ext *frame = (pjmedia_frame_ext*) strm->play_buf;
1081
TPtr8 buffer(0, 0, 0);
1108
TPtr8 buffer (0, 0, 0);
1083
1110
/* Get the buffer */
1084
buf->GetPayloadPtr(buffer);
1111
buf->GetPayloadPtr (buffer);
1086
1113
/* Init buffer attributes and header. */
1089
switch(strm->param.ext_fmt.id) {
1090
case PJMEDIA_FORMAT_AMR:
1092
if (frame->samples_cnt == 0) {
1093
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1094
strm->play_cb(strm->user_data, (pjmedia_frame*)frame);
1095
pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1096
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1099
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1100
pjmedia_frame_ext_subframe *sf;
1101
unsigned samples_cnt;
1103
sf = pjmedia_frame_ext_get_subframe(frame, 0);
1104
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1106
if (sf->data && sf->bitlen) {
1107
/* AMR header for VAS is one byte, the format (may be!):
1108
* 0xxxxy00, where xxxx:frame type, y:not sure.
1110
unsigned len = (sf->bitlen+7)>>3;
1112
pj_uint8_t amr_header = 4, ft = SID_FT;
1114
if (len >= pjmedia_codec_amrnb_framelen[0])
1115
ft = pjmedia_codec_amr_get_mode2(PJ_TRUE, len);
1117
amr_header |= ft << 3;
1118
buffer.Append(amr_header);
1120
buffer.Append((TUint8*)sf->data, len);
1125
pjmedia_frame_ext_pop_subframes(frame, 1);
1127
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1130
frame->samples_cnt = 0;
1131
frame->subframe_cnt = 0;
1136
case PJMEDIA_FORMAT_G729:
1138
if (frame->samples_cnt == 0) {
1139
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1140
strm->play_cb(strm->user_data, (pjmedia_frame*)frame);
1141
pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1142
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1145
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1146
pjmedia_frame_ext_subframe *sf;
1147
unsigned samples_cnt;
1149
sf = pjmedia_frame_ext_get_subframe(frame, 0);
1150
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1152
if (sf->data && sf->bitlen) {
1153
enum { NORMAL_LEN = 10, SID_LEN = 2 };
1154
pj_bool_t sid_frame = ((sf->bitlen >> 3) == SID_LEN);
1155
TBitStream *bitstream = (TBitStream*)strm->strm_data;
1156
const TPtrC8 src(sf->data, sf->bitlen>>3);
1157
const TDesC8 &dst = bitstream->ExpandG729Frame(src,
1171
buffer.AppendFill(0, 22);
1174
pjmedia_frame_ext_pop_subframes(frame, 1);
1176
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1180
buffer.AppendFill(0, 22);
1185
case PJMEDIA_FORMAT_ILBC:
1187
if (frame->samples_cnt == 0) {
1188
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1189
strm->play_cb(strm->user_data, (pjmedia_frame*)frame);
1190
pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1191
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1194
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1195
pjmedia_frame_ext_subframe *sf;
1196
unsigned samples_cnt;
1198
sf = pjmedia_frame_ext_get_subframe(frame, 0);
1199
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1201
pj_assert((strm->param.ext_fmt.bitrate == 15200 &&
1202
samples_cnt == 160) ||
1203
(strm->param.ext_fmt.bitrate != 15200 &&
1204
samples_cnt == 240));
1206
if (sf->data && sf->bitlen) {
1209
buffer.Append((TUint8*)sf->data, sf->bitlen>>3);
1216
/* VAS iLBC frame is 20ms or 30ms */
1217
frame_len = strm->param.ext_fmt.bitrate == 15200? 38 : 50;
1218
buffer.AppendFill(0, frame_len);
1221
pjmedia_frame_ext_pop_subframes(frame, 1);
1223
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1230
/* VAS iLBC frame is 20ms or 30ms */
1231
frame_len = strm->param.ext_fmt.bitrate == 15200? 38 : 50;
1232
buffer.AppendFill(0, frame_len);
1238
case PJMEDIA_FORMAT_PCMU:
1239
case PJMEDIA_FORMAT_PCMA:
1241
unsigned samples_ready = 0;
1242
unsigned samples_req = vas_g711_frame_len;
1244
/* Assume frame size is 10ms if frame size hasn't been known. */
1245
if (samples_req == 0)
1251
/* Call parent stream callback to get samples to play. */
1252
while (samples_ready < samples_req) {
1253
if (frame->samples_cnt == 0) {
1254
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1255
strm->play_cb(strm->user_data, (pjmedia_frame*)frame);
1256
pj_assert(frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1257
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1260
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1261
pjmedia_frame_ext_subframe *sf;
1262
unsigned samples_cnt;
1264
sf = pjmedia_frame_ext_get_subframe(frame, 0);
1265
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1266
if (sf->data && sf->bitlen) {
1267
buffer.Append((TUint8*)sf->data, sf->bitlen>>3);
1270
silc = (strm->param.ext_fmt.id==PJMEDIA_FORMAT_PCMU)?
1271
pjmedia_linear2ulaw(0) : pjmedia_linear2alaw(0);
1272
buffer.AppendFill(silc, samples_cnt);
1274
samples_ready += samples_cnt;
1276
pjmedia_frame_ext_pop_subframes(frame, 1);
1278
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1281
silc = (strm->param.ext_fmt.id==PJMEDIA_FORMAT_PCMU)?
1282
pjmedia_linear2ulaw(0) : pjmedia_linear2alaw(0);
1283
buffer.AppendFill(silc, samples_req - samples_ready);
1285
samples_ready = samples_req;
1286
frame->samples_cnt = 0;
1287
frame->subframe_cnt = 0;
1116
switch (strm->param.ext_fmt.id) {
1117
case PJMEDIA_FORMAT_AMR: {
1118
if (frame->samples_cnt == 0) {
1119
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1120
strm->play_cb (strm->user_data, (pjmedia_frame*) frame);
1121
pj_assert (frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1122
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1125
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1126
pjmedia_frame_ext_subframe *sf;
1127
unsigned samples_cnt;
1129
sf = pjmedia_frame_ext_get_subframe (frame, 0);
1130
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1132
if (sf->data && sf->bitlen) {
1133
/* AMR header for VAS is one byte, the format (may be!):
1134
* 0xxxxy00, where xxxx:frame type, y:not sure.
1136
unsigned len = (sf->bitlen+7) >>3;
1138
pj_uint8_t amr_header = 4, ft = SID_FT;
1140
if (len >= pjmedia_codec_amrnb_framelen[0])
1141
ft = pjmedia_codec_amr_get_mode2 (PJ_TRUE, len);
1143
amr_header |= ft << 3;
1144
buffer.Append (amr_header);
1146
buffer.Append ( (TUint8*) sf->data, len);
1151
pjmedia_frame_ext_pop_subframes (frame, 1);
1153
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1156
frame->samples_cnt = 0;
1157
frame->subframe_cnt = 0;
1162
case PJMEDIA_FORMAT_G729: {
1163
if (frame->samples_cnt == 0) {
1164
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1165
strm->play_cb (strm->user_data, (pjmedia_frame*) frame);
1166
pj_assert (frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1167
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1170
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1171
pjmedia_frame_ext_subframe *sf;
1172
unsigned samples_cnt;
1174
sf = pjmedia_frame_ext_get_subframe (frame, 0);
1175
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1177
if (sf->data && sf->bitlen) {
1178
enum { NORMAL_LEN = 10, SID_LEN = 2 };
1179
pj_bool_t sid_frame = ( (sf->bitlen >> 3) == SID_LEN);
1180
TBitStream *bitstream = (TBitStream*) strm->strm_data;
1181
const TPtrC8 src (sf->data, sf->bitlen>>3);
1182
const TDesC8 &dst = bitstream->ExpandG729Frame (src,
1193
buffer.Append (dst);
1198
buffer.AppendFill (0, 22);
1201
pjmedia_frame_ext_pop_subframes (frame, 1);
1203
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1207
buffer.AppendFill (0, 22);
1212
case PJMEDIA_FORMAT_ILBC: {
1213
if (frame->samples_cnt == 0) {
1214
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1215
strm->play_cb (strm->user_data, (pjmedia_frame*) frame);
1216
pj_assert (frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1217
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1220
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1221
pjmedia_frame_ext_subframe *sf;
1222
unsigned samples_cnt;
1224
sf = pjmedia_frame_ext_get_subframe (frame, 0);
1225
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1227
pj_assert ( (strm->param.ext_fmt.bitrate == 15200 &&
1228
samples_cnt == 160) ||
1229
(strm->param.ext_fmt.bitrate != 15200 &&
1230
samples_cnt == 240));
1232
if (sf->data && sf->bitlen) {
1235
buffer.Append ( (TUint8*) sf->data, sf->bitlen>>3);
1242
/* VAS iLBC frame is 20ms or 30ms */
1243
frame_len = strm->param.ext_fmt.bitrate == 15200? 38 : 50;
1244
buffer.AppendFill (0, frame_len);
1247
pjmedia_frame_ext_pop_subframes (frame, 1);
1249
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1256
/* VAS iLBC frame is 20ms or 30ms */
1257
frame_len = strm->param.ext_fmt.bitrate == 15200? 38 : 50;
1258
buffer.AppendFill (0, frame_len);
1264
case PJMEDIA_FORMAT_PCMU:
1265
case PJMEDIA_FORMAT_PCMA: {
1266
unsigned samples_ready = 0;
1267
unsigned samples_req = vas_g711_frame_len;
1269
/* Assume frame size is 10ms if frame size hasn't been known. */
1270
if (samples_req == 0)
1276
/* Call parent stream callback to get samples to play. */
1277
while (samples_ready < samples_req) {
1278
if (frame->samples_cnt == 0) {
1279
frame->base.type = PJMEDIA_FRAME_TYPE_EXTENDED;
1280
strm->play_cb (strm->user_data, (pjmedia_frame*) frame);
1281
pj_assert (frame->base.type==PJMEDIA_FRAME_TYPE_EXTENDED ||
1282
frame->base.type==PJMEDIA_FRAME_TYPE_NONE);
1285
if (frame->base.type == PJMEDIA_FRAME_TYPE_EXTENDED) {
1286
pjmedia_frame_ext_subframe *sf;
1287
unsigned samples_cnt;
1289
sf = pjmedia_frame_ext_get_subframe (frame, 0);
1290
samples_cnt = frame->samples_cnt / frame->subframe_cnt;
1292
if (sf->data && sf->bitlen) {
1293
buffer.Append ( (TUint8*) sf->data, sf->bitlen>>3);
1296
silc = (strm->param.ext_fmt.id==PJMEDIA_FORMAT_PCMU) ?
1297
pjmedia_linear2ulaw (0) : pjmedia_linear2alaw (0);
1298
buffer.AppendFill (silc, samples_cnt);
1301
samples_ready += samples_cnt;
1303
pjmedia_frame_ext_pop_subframes (frame, 1);
1305
} else { /* PJMEDIA_FRAME_TYPE_NONE */
1308
silc = (strm->param.ext_fmt.id==PJMEDIA_FORMAT_PCMU) ?
1309
pjmedia_linear2ulaw (0) : pjmedia_linear2alaw (0);
1310
buffer.AppendFill (silc, samples_req - samples_ready);
1312
samples_ready = samples_req;
1313
frame->samples_cnt = 0;
1314
frame->subframe_cnt = 0;
1297
1324
/* Set the buffer */
1298
buf->SetPayloadPtr(buffer);
1325
buf->SetPayloadPtr (buffer);
1524
1556
PjAudioCallback vas_play_cb;
1526
1558
/* Can only support 16bits per sample */
1527
PJ_ASSERT_RETURN(param->bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
1559
PJ_ASSERT_RETURN (param->bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
1529
1561
/* Supported clock rates:
1530
* - for non-PCM format: 8kHz
1531
* - for PCM format: 8kHz and 16kHz
1562
* - for non-PCM format: 8kHz
1563
* - for PCM format: 8kHz and 16kHz
1533
PJ_ASSERT_RETURN(param->clock_rate == 8000 ||
1534
(param->clock_rate == 16000 &&
1535
param->ext_fmt.id == PJMEDIA_FORMAT_L16),
1565
PJ_ASSERT_RETURN (param->clock_rate == 8000 ||
1566
(param->clock_rate == 16000 &&
1567
param->ext_fmt.id == PJMEDIA_FORMAT_L16),
1538
1570
/* Supported channels number:
1539
1571
* - for non-PCM format: mono
1540
* - for PCM format: mono and stereo
1572
* - for PCM format: mono and stereo
1542
PJ_ASSERT_RETURN(param->channel_count == 1 ||
1543
(param->channel_count == 2 &&
1544
param->ext_fmt.id == PJMEDIA_FORMAT_L16),
1574
PJ_ASSERT_RETURN (param->channel_count == 1 ||
1575
(param->channel_count == 2 &&
1576
param->ext_fmt.id == PJMEDIA_FORMAT_L16),
1547
1579
/* Create and Initialize stream descriptor */
1548
pool = pj_pool_create(af->pf, "vas-dev", 1000, 1000, NULL);
1549
PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
1580
pool = pj_pool_create (af->pf, "vas-dev", 1000, 1000, NULL);
1581
PJ_ASSERT_RETURN (pool, PJ_ENOMEM);
1551
strm = PJ_POOL_ZALLOC_T(pool, struct vas_stream);
1583
strm = PJ_POOL_ZALLOC_T (pool, struct vas_stream);
1552
1584
strm->pool = pool;
1553
1585
strm->param = *param;
1555
1587
if (strm->param.flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT == 0)
1556
strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
1588
strm->param.ext_fmt.id = PJMEDIA_FORMAT_L16;
1558
1590
/* Set audio engine fourcc. */
1559
switch(strm->param.ext_fmt.id) {
1560
case PJMEDIA_FORMAT_L16:
1561
#ifdef USE_NATIVE_PCM
1562
vas_setting.format = EPCM16;
1591
switch (strm->param.ext_fmt.id) {
1592
case PJMEDIA_FORMAT_L16:
1593
#ifdef USE_NATIVE_PCM
1594
vas_setting.format = EPCM16;
1564
vas_setting.format = EG711;
1596
vas_setting.format = EG711;
1567
case PJMEDIA_FORMAT_PCMU:
1568
case PJMEDIA_FORMAT_PCMA:
1569
vas_setting.format = EG711;
1571
case PJMEDIA_FORMAT_AMR:
1572
vas_setting.format = EAMR_NB;
1574
case PJMEDIA_FORMAT_G729:
1575
vas_setting.format = EG729;
1577
case PJMEDIA_FORMAT_ILBC:
1578
vas_setting.format = EILBC;
1581
vas_setting.format = ENULL;
1599
case PJMEDIA_FORMAT_PCMU:
1600
case PJMEDIA_FORMAT_PCMA:
1601
vas_setting.format = EG711;
1603
case PJMEDIA_FORMAT_AMR:
1604
vas_setting.format = EAMR_NB;
1606
case PJMEDIA_FORMAT_G729:
1607
vas_setting.format = EG729;
1609
case PJMEDIA_FORMAT_ILBC:
1610
vas_setting.format = EILBC;
1613
vas_setting.format = ENULL;
1585
1617
/* Set audio engine mode. */
1586
if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_L16)
1588
#ifdef USE_NATIVE_PCM
1589
vas_setting.mode = 0;
1618
if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_L16) {
1619
#ifdef USE_NATIVE_PCM
1620
vas_setting.mode = 0;
1591
vas_setting.mode = CVoIPFormatIntfc::EG711uLaw;
1622
vas_setting.mode = CVoIPFormatIntfc::EG711uLaw;
1594
else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_AMR)
1596
vas_setting.mode = strm->param.ext_fmt.bitrate;
1598
else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_PCMU)
1600
vas_setting.mode = CVoIPFormatIntfc::EG711uLaw;
1602
else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_PCMA)
1604
vas_setting.mode = CVoIPFormatIntfc::EG711ALaw;
1606
else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_ILBC)
1608
if (strm->param.ext_fmt.bitrate == 15200)
1609
vas_setting.mode = CVoIPFormatIntfc::EiLBC20mSecFrame;
1611
vas_setting.mode = CVoIPFormatIntfc::EiLBC30mSecFrame;
1624
} else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_AMR) {
1625
vas_setting.mode = strm->param.ext_fmt.bitrate;
1626
} else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_PCMU) {
1627
vas_setting.mode = CVoIPFormatIntfc::EG711uLaw;
1628
} else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_PCMA) {
1629
vas_setting.mode = CVoIPFormatIntfc::EG711ALaw;
1630
} else if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_ILBC) {
1631
if (strm->param.ext_fmt.bitrate == 15200)
1632
vas_setting.mode = CVoIPFormatIntfc::EiLBC20mSecFrame;
1634
vas_setting.mode = CVoIPFormatIntfc::EiLBC30mSecFrame;
1613
vas_setting.mode = 0;
1636
vas_setting.mode = 0;
1616
/* Disable VAD on L16, G711, iLBC, and also G729 (G729's SID
1639
/* Disable VAD on L16, G711, iLBC, and also G729 (G729's SID
1617
1640
* potentially cause noise?).
1619
1642
if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_PCMU ||
1620
strm->param.ext_fmt.id == PJMEDIA_FORMAT_PCMA ||
1621
strm->param.ext_fmt.id == PJMEDIA_FORMAT_L16 ||
1622
strm->param.ext_fmt.id == PJMEDIA_FORMAT_ILBC ||
1623
strm->param.ext_fmt.id == PJMEDIA_FORMAT_G729)
1625
vas_setting.vad = EFalse;
1643
strm->param.ext_fmt.id == PJMEDIA_FORMAT_PCMA ||
1644
strm->param.ext_fmt.id == PJMEDIA_FORMAT_L16 ||
1645
strm->param.ext_fmt.id == PJMEDIA_FORMAT_ILBC ||
1646
strm->param.ext_fmt.id == PJMEDIA_FORMAT_G729) {
1647
vas_setting.vad = EFalse;
1627
vas_setting.vad = strm->param.ext_fmt.vad;
1649
vas_setting.vad = strm->param.ext_fmt.vad;
1630
1652
/* Set other audio engine attributes. */
1631
1653
vas_setting.plc = strm->param.plc_enabled;
1632
1654
vas_setting.cng = vas_setting.vad;
1633
vas_setting.loudspk =
1634
strm->param.output_route==PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER;
1655
vas_setting.loudspk =
1656
strm->param.output_route==PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER;
1636
1658
/* Set audio engine callbacks. */
1637
1659
if (strm->param.ext_fmt.id == PJMEDIA_FORMAT_L16) {
1638
1660
#ifdef USE_NATIVE_PCM
1639
vas_play_cb = &PlayCbPcm2;
1640
vas_rec_cb = &RecCbPcm2;
1661
vas_play_cb = &PlayCbPcm2;
1662
vas_rec_cb = &RecCbPcm2;
1642
vas_play_cb = &PlayCbPcm;
1643
vas_rec_cb = &RecCbPcm;
1664
vas_play_cb = &PlayCbPcm;
1665
vas_rec_cb = &RecCbPcm;
1646
vas_play_cb = &PlayCb;
1647
vas_rec_cb = &RecCb;
1668
vas_play_cb = &PlayCb;
1669
vas_rec_cb = &RecCb;
1650
1672
strm->rec_cb = rec_cb;
1739
1762
/* API: Get stream info. */
1740
static pj_status_t stream_get_param(pjmedia_aud_stream *s,
1741
pjmedia_aud_param *pi)
1763
static pj_status_t stream_get_param (pjmedia_aud_stream *s,
1764
pjmedia_aud_param *pi)
1743
struct vas_stream *strm = (struct vas_stream*)s;
1745
PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
1747
pj_memcpy(pi, &strm->param, sizeof(*pi));
1766
struct vas_stream *strm = (struct vas_stream*) s;
1768
PJ_ASSERT_RETURN (strm && pi, PJ_EINVAL);
1770
pj_memcpy (pi, &strm->param, sizeof (*pi));
1749
1772
/* Update the output volume setting */
1750
if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1751
&pi->output_vol) == PJ_SUCCESS)
1753
pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
1773
if (stream_get_cap (s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1774
&pi->output_vol) == PJ_SUCCESS) {
1775
pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
1756
1778
return PJ_SUCCESS;
1759
1781
/* API: get capability */
1760
static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
1761
pjmedia_aud_dev_cap cap,
1782
static pj_status_t stream_get_cap (pjmedia_aud_stream *s,
1783
pjmedia_aud_dev_cap cap,
1764
struct vas_stream *strm = (struct vas_stream*)s;
1786
struct vas_stream *strm = (struct vas_stream*) s;
1765
1787
pj_status_t status = PJ_ENOTSUP;
1767
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
1789
PJ_ASSERT_RETURN (s && pval, PJ_EINVAL);
1770
case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
1771
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1772
*(pjmedia_aud_dev_route*)pval = strm->param.output_route;
1773
status = PJ_SUCCESS;
1777
/* There is a case that GetMaxGain() stucks, e.g: in N95. */
1779
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1780
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1781
PJ_ASSERT_RETURN(strm->engine, PJ_EINVAL);
1783
TInt max_gain = strm->engine->GetMaxGain();
1784
TInt gain = strm->engine->GetGain();
1786
if (max_gain > 0 && gain >= 0) {
1787
*(unsigned*)pval = gain * 100 / max_gain;
1788
status = PJ_SUCCESS;
1790
status = PJMEDIA_EAUD_NOTREADY;
1796
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1797
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1798
PJ_ASSERT_RETURN(strm->engine, PJ_EINVAL);
1800
TInt max_vol = strm->engine->GetMaxVolume();
1801
TInt vol = strm->engine->GetVolume();
1803
if (max_vol > 0 && vol >= 0) {
1804
*(unsigned*)pval = vol * 100 / max_vol;
1805
status = PJ_SUCCESS;
1807
status = PJMEDIA_EAUD_NOTREADY;
1792
case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
1794
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1795
* (pjmedia_aud_dev_route*) pval = strm->param.output_route;
1796
status = PJ_SUCCESS;
1801
/* There is a case that GetMaxGain() stucks, e.g: in N95. */
1803
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1804
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1805
PJ_ASSERT_RETURN(strm->engine, PJ_EINVAL);
1807
TInt max_gain = strm->engine->GetMaxGain();
1808
TInt gain = strm->engine->GetGain();
1810
if (max_gain > 0 && gain >= 0) {
1811
*(unsigned*)pval = gain * 100 / max_gain;
1812
status = PJ_SUCCESS;
1814
status = PJMEDIA_EAUD_NOTREADY;
1820
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1822
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1823
PJ_ASSERT_RETURN (strm->engine, PJ_EINVAL);
1825
TInt max_vol = strm->engine->GetMaxVolume();
1826
TInt vol = strm->engine->GetVolume();
1828
if (max_vol > 0 && vol >= 0) {
1829
* (unsigned*) pval = vol * 100 / max_vol;
1830
status = PJ_SUCCESS;
1832
status = PJMEDIA_EAUD_NOTREADY;
1818
1844
/* API: set capability */
1819
static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
1820
pjmedia_aud_dev_cap cap,
1845
static pj_status_t stream_set_cap (pjmedia_aud_stream *s,
1846
pjmedia_aud_dev_cap cap,
1823
struct vas_stream *strm = (struct vas_stream*)s;
1849
struct vas_stream *strm = (struct vas_stream*) s;
1824
1850
pj_status_t status = PJ_ENOTSUP;
1826
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
1852
PJ_ASSERT_RETURN (s && pval, PJ_EINVAL);
1829
case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
1830
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1831
pjmedia_aud_dev_route r = *(const pjmedia_aud_dev_route*)pval;
1834
PJ_ASSERT_RETURN(strm->engine, PJ_EINVAL);
1837
case PJMEDIA_AUD_DEV_ROUTE_DEFAULT:
1838
case PJMEDIA_AUD_DEV_ROUTE_EARPIECE:
1839
err = strm->engine->ActivateSpeaker(EFalse);
1840
status = (err==KErrNone)? PJ_SUCCESS:PJ_RETURN_OS_ERROR(err);
1842
case PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER:
1843
err = strm->engine->ActivateSpeaker(ETrue);
1844
status = (err==KErrNone)? PJ_SUCCESS:PJ_RETURN_OS_ERROR(err);
1850
if (status == PJ_SUCCESS)
1851
strm->param.output_route = r;
1855
/* There is a case that GetMaxGain() stucks, e.g: in N95. */
1857
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1858
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1859
PJ_ASSERT_RETURN(strm->engine, PJ_EINVAL);
1861
TInt max_gain = strm->engine->GetMaxGain();
1865
gain = *(unsigned*)pval * max_gain / 100;
1866
err = strm->engine->SetGain(gain);
1867
status = (err==KErrNone)? PJ_SUCCESS:PJ_RETURN_OS_ERROR(err);
1869
status = PJMEDIA_EAUD_NOTREADY;
1871
if (status == PJ_SUCCESS)
1872
strm->param.input_vol = *(unsigned*)pval;
1877
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1878
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1879
PJ_ASSERT_RETURN(strm->engine, PJ_EINVAL);
1881
TInt max_vol = strm->engine->GetMaxVolume();
1885
vol = *(unsigned*)pval * max_vol / 100;
1886
err = strm->engine->SetVolume(vol);
1887
status = (err==KErrNone)? PJ_SUCCESS:PJ_RETURN_OS_ERROR(err);
1889
status = PJMEDIA_EAUD_NOTREADY;
1891
if (status == PJ_SUCCESS)
1892
strm->param.output_vol = *(unsigned*)pval;
1855
case PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE:
1857
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1858
pjmedia_aud_dev_route r = * (const pjmedia_aud_dev_route*) pval;
1861
PJ_ASSERT_RETURN (strm->engine, PJ_EINVAL);
1864
case PJMEDIA_AUD_DEV_ROUTE_DEFAULT:
1865
case PJMEDIA_AUD_DEV_ROUTE_EARPIECE:
1866
err = strm->engine->ActivateSpeaker (EFalse);
1867
status = (err==KErrNone) ? PJ_SUCCESS:PJ_RETURN_OS_ERROR (err);
1869
case PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER:
1870
err = strm->engine->ActivateSpeaker (ETrue);
1871
status = (err==KErrNone) ? PJ_SUCCESS:PJ_RETURN_OS_ERROR (err);
1878
if (status == PJ_SUCCESS)
1879
strm->param.output_route = r;
1884
/* There is a case that GetMaxGain() stucks, e.g: in N95. */
1886
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1887
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1888
PJ_ASSERT_RETURN(strm->engine, PJ_EINVAL);
1890
TInt max_gain = strm->engine->GetMaxGain();
1894
gain = *(unsigned*)pval * max_gain / 100;
1895
err = strm->engine->SetGain(gain);
1896
status = (err==KErrNone)? PJ_SUCCESS:PJ_RETURN_OS_ERROR(err);
1898
status = PJMEDIA_EAUD_NOTREADY;
1900
if (status == PJ_SUCCESS)
1901
strm->param.input_vol = *(unsigned*)pval;
1906
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1908
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1909
PJ_ASSERT_RETURN (strm->engine, PJ_EINVAL);
1911
TInt max_vol = strm->engine->GetMaxVolume();
1916
vol = * (unsigned*) pval * max_vol / 100;
1917
err = strm->engine->SetVolume (vol);
1918
status = (err==KErrNone) ? PJ_SUCCESS:PJ_RETURN_OS_ERROR (err);
1920
status = PJMEDIA_EAUD_NOTREADY;
1923
if (status == PJ_SUCCESS)
1924
strm->param.output_vol = * (unsigned*) pval;
1902
1935
/* API: Start stream. */
1903
static pj_status_t stream_start(pjmedia_aud_stream *strm)
1936
static pj_status_t stream_start (pjmedia_aud_stream *strm)
1905
struct vas_stream *stream = (struct vas_stream*)strm;
1938
struct vas_stream *stream = (struct vas_stream*) strm;
1907
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
1940
PJ_ASSERT_RETURN (stream, PJ_EINVAL);
1909
1942
if (stream->engine) {
1910
enum { VAS_WAIT_START = 2000 }; /* in msecs */
1912
TInt err = stream->engine->Start();
1914
if (err != KErrNone)
1915
return PJ_RETURN_OS_ERROR(err);
1917
/* Perform synchronous start, timeout after VAS_WAIT_START ms */
1918
start.UniversalTime();
1920
pj_symbianos_poll(-1, 100);
1921
now.UniversalTime();
1922
} while (!stream->engine->IsStarted() &&
1923
(now.MicroSecondsFrom(start) < VAS_WAIT_START * 1000));
1925
if (stream->engine->IsStarted())
1928
return PJ_ETIMEDOUT;
1943
enum { VAS_WAIT_START = 2000 }; /* in msecs */
1945
TInt err = stream->engine->Start();
1947
if (err != KErrNone)
1948
return PJ_RETURN_OS_ERROR (err);
1950
/* Perform synchronous start, timeout after VAS_WAIT_START ms */
1951
start.UniversalTime();
1954
pj_symbianos_poll (-1, 100);
1955
now.UniversalTime();
1956
} while (!stream->engine->IsStarted() &&
1957
(now.MicroSecondsFrom (start) < VAS_WAIT_START * 1000));
1959
if (stream->engine->IsStarted())
1962
return PJ_ETIMEDOUT;
1931
1965
return PJ_EINVALIDOP;
1934
1968
/* API: Stop stream. */
1935
static pj_status_t stream_stop(pjmedia_aud_stream *strm)
1969
static pj_status_t stream_stop (pjmedia_aud_stream *strm)
1937
struct vas_stream *stream = (struct vas_stream*)strm;
1971
struct vas_stream *stream = (struct vas_stream*) strm;
1939
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
1973
PJ_ASSERT_RETURN (stream, PJ_EINVAL);
1941
1975
if (stream->engine) {
1942
stream->engine->Stop();
1976
stream->engine->Stop();
1945
1979
return PJ_SUCCESS;